29 Commits

Author SHA1 Message Date
neon443
ee2e05c523 fix the cooked addeventview 2025-06-11 18:49:09 +01:00
neon443
e9e19e2659 Large rework:
Liquid Glass:
- remove ultrathinmaterial from all sheets
- button color change

remove the eventName eventDate etcs and replaced with an event var

Add addeventview for mac, cleanup #if s

clean up homeview
add .searchable
addeventview is horizontal i have no idea why
2025-06-11 18:34:17 +01:00
neon443
5ce48a4bc2 add new buttons 2025-06-10 15:09:10 +01:00
neon443
a7e09692f6 liquid glass update 1 2025-06-10 13:14:19 +01:00
neon443
559f891719 new liquid glass icon 2025-06-10 12:28:03 +01:00
neon443
2ef000458f minor concurrency improvements 2025-05-29 18:32:54 +01:00
neon443
69047010d7 made it better 2025-05-28 15:47:55 +01:00
neon443
dfb1dae545 added a cancel button, extract logic 2025-05-28 14:52:43 +01:00
neon443
0f3b86fe8c New: custom alert for merge/replace imported events 2025-05-28 14:47:05 +01:00
neon443
1902c5102c can now edit events, need to make it apply on the fly
added about window
2025-05-28 13:42:53 +01:00
neon443
1179810ac2 move to contentview
add homeView
respect show completed events in home
archive view
move inot contentview
new mac icon
remove mac icons from the variants
2025-05-28 12:59:35 +01:00
neon443
dfc3a9290a mac icons for all the color variants 2025-05-28 11:47:37 +01:00
neon443
7236f0640e asset catalog: add mac &watchos icons 2025-05-28 11:32:08 +01:00
neon443
d1c1144ad8 you asked for the haptics... 2025-05-21 21:43:47 +01:00
neon443
bcfe23a17e info plist shenanigans for ios 2025-05-21 20:53:35 +01:00
neon443
74ef5db2cf trying to impement a menu bar 2025-05-21 20:50:53 +01:00
neon443
389fdf6812 fix taget memberships and Settings -> NFSettings 2025-05-21 20:41:01 +01:00
neon443
b153d127a6 fix padding on the eventlistView extract settings to Settings.swift rename some files 2025-05-21 20:38:54 +01:00
neon443
62318c5ddc mac ui 2025-05-21 18:10:22 +01:00
neon443
773a083682 making mac ui 2025-05-21 17:21:04 +01:00
neon443
e051d73b7e declared types on all views, trying to make a nice mac app 2025-05-21 17:02:21 +01:00
neon443
4bf33d50d6 moved colours to tints.xcassets 2025-05-21 15:37:32 +01:00
neon443
74603cc588 fixed appkit and uikit conflicts 2025-05-21 15:28:35 +01:00
neon443
ed016217db added item and assets to macnearfuture 2025-05-21 14:52:55 +01:00
neon443
a64eb03cad add Mac target and delet tests 2025-05-21 14:45:04 +01:00
neon443
7c7f72a5d4 more reorgs 2025-05-21 14:40:50 +01:00
neon443
831305ba55 massive reorg: source and assets 2025-05-21 14:20:05 +01:00
neon443
69856e2857 fix concurrency warinings 2025-05-21 14:16:54 +01:00
neon443
7be2e3848a reorg 2025-05-21 14:14:40 +01:00
72 changed files with 1647 additions and 1201 deletions

View File

@@ -0,0 +1,40 @@
//
// AboutView.swift
// MacNearFuture
//
// Created by neon443 on 28/05/2025.
//
import SwiftUI
struct AboutView: View {
var body: some View {
VStack(alignment: .center) {
Image(nsImage: #imageLiteral(resourceName: "NearFutureIcon.png"))
.resizable()
.scaledToFit()
.frame(width: 100)
.clipShape(RoundedRectangle(cornerRadius: 25))
Text("Near Future")
.bold()
.monospaced()
.font(.title)
Text("Version " + getVersion() + " (\(getBuildID()))")
.padding(.bottom)
Text("© 2024-2025 neon443, Inc")
.padding(.bottom)
Link("Developer Website", destination: URL(string: "https://neon443.xyz")!)
}
.padding()
.padding()
.containerBackground(.ultraThinMaterial, for: .window)
.toolbar(removing: .title)
.toolbarBackground(.hidden, for: .windowToolbar)
.windowMinimizeBehavior(.disabled)
.windowFullScreenBehavior(.disabled)
}
}
#Preview {
AboutView()
}

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.icloud-container-identifiers</key>
<array/>
<key>com.apple.developer.ubiquity-kvstore-identifier</key>
<string>$(TeamIdentifierPrefix)$(CFBundleIdentifier)</string>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.application-groups</key>
<array>
<string>group.NearFuture</string>
</array>
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
</dict>
</plist>

View File

@@ -0,0 +1,66 @@
//
// MacNearFutureApp.swift
// MacNearFuture
//
// Created by neon443 on 21/05/2025.
//
import Foundation
import SwiftUI
@main
struct NearFutureApp: App {
@Environment(\.openWindow) var openWindow
@StateObject var viewModel: EventViewModel = EventViewModel()
@StateObject var settingsModel: SettingsViewModel = SettingsViewModel()
var body: some Scene {
WindowGroup {
ContentView(
viewModel: viewModel,
settingsModel: settingsModel
)
}
.defaultSize(width: 550, height: 650)
.commands {
CommandGroup(replacing: CommandGroupPlacement.appInfo) {
Button("about nf") {
openWindow(id: "about")
}
}
NearFutureCommands()
}
WindowGroup("edit Event", for: Event.ID.self) { $eventID in
EditEventView(
viewModel: viewModel,
event: Binding(
get: {
viewModel.events.first(where: {$0.id == eventID}) ?? viewModel.template
},
set: { newValue in
if let eventIndex = viewModel.events.firstIndex(where: {
$0.id == eventID
}) {
viewModel.events[eventIndex] = newValue
}
viewModel.saveEvents()
}
)
)
}
.restorationBehavior(.disabled)
Window("About Near Future", id: "about") {
AboutView()
}
.windowBackgroundDragBehavior(.enabled)
.windowResizability(.contentSize)
.restorationBehavior(.disabled)
.defaultPosition(UnitPoint.center)
Settings {
Text("wip")
}
}
}

View File

@@ -0,0 +1,17 @@
//
// NFCommands.swift
// MacNearFuture
//
// Created by neon443 on 21/05/2025.
//
import Foundation
import SwiftUI
struct NearFutureCommands: Commands {
var body: some Commands {
CommandGroup(after: CommandGroupPlacement.appInfo) {
Text("hi")
}
}
}

View File

@@ -0,0 +1,33 @@
//
// ArchiveView.swift
// MacNearFuture
//
// Created by neon443 on 28/05/2025.
//
import SwiftUI
struct ArchiveView: View {
@StateObject var viewModel: EventViewModel
@StateObject var settingsModel: SettingsViewModel
var filteredEvents: [Event] {
return viewModel.events.filter { $0.complete }
}
var body: some View {
ScrollView {
ForEach(filteredEvents) { event in
EventListView(viewModel: viewModel, event: event)
}
}
.scrollContentBackground(.hidden)
}
}
#Preview {
ArchiveView(
viewModel: dummyEventViewModel(),
settingsModel: dummySettingsViewModel()
)
}

View File

@@ -0,0 +1,50 @@
//
// ContentView.swift
// MacNearFuture
//
// Created by neon443 on 21/05/2025.
//
import SwiftUI
struct ContentView: View {
@StateObject var viewModel: EventViewModel
@StateObject var settingsModel: SettingsViewModel
var body: some View {
NavigationSplitView(preferredCompactColumn: .constant(.sidebar)) {
List {
NavigationLink {
HomeView(
viewModel: viewModel,
settingsModel: settingsModel
)
} label: {
Image(systemName: "house")
Text("Home")
}
NavigationLink {
ArchiveView(
viewModel: viewModel,
settingsModel: settingsModel
)
} label: {
Image(systemName: "tray.full")
Text("Archive")
}
}
} detail: {
}
.tint(settingsModel.settings.tint.color)
.frame(minWidth: 450, minHeight: 550)
.containerBackground(.ultraThinMaterial, for: .window)
}
}
#Preview {
ContentView(
viewModel: dummyEventViewModel(),
settingsModel: dummySettingsViewModel()
)
}

View File

@@ -0,0 +1,185 @@
//
// EventListView.swift
// MacNearFuture
//
// Created by neon443 on 21/05/2025.
//
import SwiftUI
struct EventListView: View {
@ObservedObject var viewModel: EventViewModel
@State var event: Event
@State var largeTick: Bool = false
@State var hovering: Bool = false
@Environment(\.openWindow) var openWindow
var body: some View {
ZStack {
Color.black.opacity(hovering ? 0.5 : 0.0)
HStack {
RoundedRectangle(cornerRadius: 5)
.frame(width: 7)
.foregroundStyle(
event.color.color.opacity(
event.complete ? 0.5 : 1
)
)
VStack(alignment: .leading) {
HStack {
Image(systemName: event.symbol)
.resizable()
.scaledToFit()
.frame(width: 20, height: 20)
.shadow(radius: 5)
.foregroundStyle(
.one.opacity(
event.complete ? 0.5 : 1
)
)
Text("\(event.name)")
.bold()
.foregroundStyle(.one)
.strikethrough(event.complete)
.multilineTextAlignment(.leading)
}
if !event.notes.isEmpty {
Text(event.notes)
.foregroundStyle(.one.opacity(0.8))
.multilineTextAlignment(.leading)
}
Text(
event.date.formatted(
date: .long,
time: .shortened
)
)
.foregroundStyle(
.one.opacity(
event.complete ? 0.5 : 1
)
)
if event.recurrence != .none {
Text("Occurs \(event.recurrence.rawValue)")
.font(.subheadline)
.foregroundStyle(
.one.opacity(event.complete ? 0.5 : 1))
}
}
Spacer()
VStack {
Text("\(daysUntilEvent(event.date).long)")
.multilineTextAlignment(.trailing)
.foregroundStyle(event.date.timeIntervalSinceNow < 0 ? .red : .one)
}
Button() {
withAnimation {
event.complete.toggle()
}
let eventToModify = viewModel.events.firstIndex() { currEvent in
currEvent.id == event.id
}
if let eventToModify = eventToModify {
viewModel.events[eventToModify] = event
viewModel.saveEvents()
}
} label: {
if event.complete {
ZStack {
Circle()
.foregroundStyle(.green)
Image(systemName: "checkmark")
.resizable()
.foregroundStyle(.white)
.scaledToFit()
.bold()
.frame(width: 15)
}
} else {
Image(systemName: "circle")
.resizable()
.scaledToFit()
.foregroundStyle(event.color.color)
}
}
.onHover() { hovering in
withAnimation {
largeTick.toggle()
}
}
.buttonStyle(.borderless)
.scaleEffect(largeTick ? 1.5 : 1)
.frame(maxWidth: 20)
.shadow(radius: 5)
.padding(.trailing, 15)
.animation(
.spring(response: 0.2, dampingFraction: 0.75, blendDuration: 2),
value: largeTick
)
.apply {
if #available(iOS 17, *) {
$0.sensoryFeedback(.success, trigger: event.complete)
}
}
}
.transition(.opacity)
.fixedSize(horizontal: false, vertical: true)
}
.onHover { isHovering in
withAnimation {
hovering.toggle()
}
}
.onTapGesture {
openWindow(value: event.id)
}
.contextMenu() {
Button(role: .destructive) {
let eventToModify = viewModel.events.firstIndex() { currEvent in
currEvent.id == event.id
}
if let eventToModify = eventToModify {
viewModel.events.remove(at: eventToModify)
viewModel.saveEvents()
}
} label: {
Label("Delete", systemImage: "trash")
}
}
}
}
#Preview("EventListView") {
let vm = dummyEventViewModel()
ZStack {
Color.black
VStack {
ForEach(0..<50) { _ in
Rectangle()
.foregroundStyle(randomColor().opacity(0.5))
.padding(-10)
}
.ignoresSafeArea(.all)
.blur(radius: 5)
}
VStack {
ForEach(vm.events) { event in
EventListView(
viewModel: vm,
event: event
)
}
}
.padding(.horizontal, 10)
}
}
#Preview {
EventListView(
viewModel: dummyEventViewModel(),
event: dummyEventViewModel().template
)
}

View File

@@ -0,0 +1,199 @@
//
// AddEventView.swift
// MacNearFuture
//
// Created by neon443 on 11/06/2025.
//
import SwiftUI
import SFSymbolsPicker
struct AddEventView: View {
@ObservedObject var viewModel: EventViewModel
@Binding var event: Event
@State var adding: Bool
@State var showNeedsNameAlert: Bool = false
@State var isSymbolPickerPresented: Bool = false
@State private var bye: Bool = false
@FocusState private var focusedField: Field?
private enum Field {
case Name, Notes
}
@Environment(\.dismiss) var dismiss
var body: some View {
ZStack {
if !adding {
backgroundGradient
}
List {
Section(
header:
Text("Event Details")
.font(.headline)
.foregroundColor(.accentColor)
) {
// name & symbol
HStack(spacing: 5) {
Button() {
isSymbolPickerPresented.toggle()
} label: {
Image(systemName: event.symbol)
.resizable()
.scaledToFit()
.frame(width: 20, height: 20)
.foregroundStyle(event.color.color)
}
.frame(width: 20)
.buttonStyle(.borderless)
.sheet(isPresented: $isSymbolPickerPresented) {
SymbolsPicker(
selection: $event.symbol,
title: "Choose a Symbol",
searchLabel: "Search...",
autoDismiss: true)
.presentationDetents([.medium])
}
// dscription
ZStack {
TextField("Event Notes", text: $event.notes)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding(.trailing, event.notes.isEmpty ? 0 : 30)
.animation(.spring, value: event.notes)
.focused($focusedField, equals: Field.Notes)
.submitLabel(.done)
.onSubmit {
focusedField = nil
}
// MagicClearButton(text: $eventNotes)
}
// date picker
HStack {
Spacer()
DatePicker("", selection: $event.date, displayedComponents: .date)
Spacer()
Button() {
event.date = Date()
} label: {
Image(systemName: "arrow.uturn.left")
.resizable()
.scaledToFit()
}
.buttonStyle(BorderlessButtonStyle())
.frame(width: 20)
}
DatePicker(
"",
selection: $event.date,
displayedComponents: .hourAndMinute
)
// re-ocurrence Picker
Picker("Recurrence", selection: $event.recurrence) {
ForEach(Event.RecurrenceType.allCases, id: \.self) { recurrence in
Text(recurrence.rawValue.capitalized)
}
}
.pickerStyle(SegmentedPickerStyle())
Text(
describeOccurrence(
date: event.date,
recurrence: event.recurrence
)
)
}
}
.scrollContentBackground(.hidden)
.navigationTitle("\(adding ? "Add Event" : "")")
.toolbar {
ToolbarItem() {
if adding {
Button() {
resetAddEventView()
dismiss()
} label: {
Image(systemName: "xmark")
.resizable()
.scaledToFit()
.frame(width: 30)
}
}
}
ToolbarItem/*(placement: .topBarTrailing)*/ {
if adding {
Button {
viewModel.addEvent(
newEvent: event
)
bye.toggle()
resetAddEventView()
} label: {
Text("Save")
.font(.headline)
.cornerRadius(10)
.buttonStyle(BorderedProminentButtonStyle())
}
.tint(.accent)
.apply {
if #available(iOS 17, *) {
$0.sensoryFeedback(.success, trigger: bye)
}
}
.disabled(event.name.isEmpty)
.onTapGesture {
if event.name.isEmpty {
showNeedsNameAlert.toggle()
}
}
.alert("Missing Name", isPresented: $showNeedsNameAlert) {
Button("OK", role: .cancel) {
showNeedsNameAlert.toggle()
focusedField = .Name
}
} message: {
Text("Give your Event a name before saving.")
}
if event.name.isEmpty {
HStack {
Image(systemName: "exclamationmark")
.foregroundStyle(.red)
Text("Give your event a name.")
}
}
}
}
}
}
.scrollContentBackground(.hidden)
.presentationDragIndicator(.visible)
}
}
func resetAddEventView() {
//reset addeventView
event = viewModel.template
dismiss()
}
}
#Preview {
let vm = dummyEventViewModel()
Color.orange
.ignoresSafeArea(.all)
.sheet(isPresented: .constant(true)) {
AddEventView(
viewModel: vm,
event: .constant(vm.template),
adding: true
)
}
}

View File

@@ -0,0 +1,41 @@
//
// EditEventView.swift
// NearFuture
//
// Created by neon443 on 21/05/2025.
//
import SwiftUI
struct EditEventView: View {
@Environment(\.dismiss) var dismiss
@ObservedObject var viewModel: EventViewModel
@Binding var event: Event
var body: some View {
AddEventView(
viewModel: viewModel,
event: $event,
adding: false //bc we editing existing event
)
.navigationTitle("Edit Event")
.toolbar {
ToolbarItem(placement: .primaryAction) {
Button() {
dismiss()
} label: {
Text("Done")
.bold()
}
.disabled(event.name == "")
}
}
}
}
#Preview {
EditEventView(
viewModel: dummyEventViewModel(),
event: .constant(dummyEventViewModel().template)
)
}

View File

@@ -0,0 +1,37 @@
//
// HomeView.swift
// MacNearFuture
//
// Created by neon443 on 28/05/2025.
//
import SwiftUI
struct HomeView: View {
@StateObject var viewModel: EventViewModel
@StateObject var settingsModel: SettingsViewModel
var filteredEvents: [Event] {
switch settingsModel.settings.showCompletedInHome {
case true:
return viewModel.events
case false:
return viewModel.events.filter { !$0.complete }
}
}
var body: some View {
ScrollView {
ForEach(filteredEvents) { event in
EventListView(viewModel: viewModel, event: event)
}
}
.scrollContentBackground(.hidden)
}
}
#Preview {
HomeView(
viewModel: dummyEventViewModel(),
settingsModel: dummySettingsViewModel()
)
}

View File

@@ -7,11 +7,27 @@
objects = {
/* Begin PBXBuildFile section */
A90D49382DDE0FAF00781124 /* ContentViewMac.swift in Sources */ = {isa = PBXBuildFile; fileRef = A90D49332DDE0FAF00781124 /* ContentViewMac.swift */; };
A90D493D2DDE10B200781124 /* NearFutureIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = A949F8312DCAAA8A0064DCA0 /* NearFutureIcon.png */; };
A90D493E2DDE10CF00781124 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A920C28D2D24011A00E4F9B1 /* Assets.xcassets */; };
A90D49422DDE114100781124 /* Events.swift in Sources */ = {isa = PBXBuildFile; fileRef = A920C28B2D24011400E4F9B1 /* Events.swift */; };
A90D49442DDE1C7600781124 /* Tints.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A90D49432DDE1C1100781124 /* Tints.xcassets */; };
A90D49452DDE1C7600781124 /* Tints.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A90D49432DDE1C1100781124 /* Tints.xcassets */; };
A90D49462DDE1C7A00781124 /* Tints.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A90D49432DDE1C1100781124 /* Tints.xcassets */; };
A90D49522DDE2D0000781124 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A90D49512DDE2D0000781124 /* Extensions.swift */; };
A90D49532DDE2D0000781124 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A90D49512DDE2D0000781124 /* Extensions.swift */; };
A90D49562DDE2D5800781124 /* SFSymbolsPicker in Frameworks */ = {isa = PBXBuildFile; productRef = A90D49552DDE2D5800781124 /* SFSymbolsPicker */; };
A90D495B2DDE2EDB00781124 /* MacNearFutureApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = A90D495A2DDE2EDB00781124 /* MacNearFutureApp.swift */; };
A90D495E2DDE3C7400781124 /* NFCommands.swift in Sources */ = {isa = PBXBuildFile; fileRef = A90D495D2DDE3C7400781124 /* NFCommands.swift */; };
A90D495F2DDE3C7400781124 /* NFCommands.swift in Sources */ = {isa = PBXBuildFile; fileRef = A90D495D2DDE3C7400781124 /* NFCommands.swift */; };
A90D49612DDE626300781124 /* Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = A90D49602DDE626300781124 /* Settings.swift */; };
A90D49622DDE626300781124 /* Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = A90D49602DDE626300781124 /* Settings.swift */; };
A90D49632DDE626300781124 /* Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = A90D49602DDE626300781124 /* Settings.swift */; };
A914FA4B2DD26C6800856265 /* HomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A914FA4A2DD26C0F00856265 /* HomeView.swift */; };
A914FA4D2DD2768900856265 /* WhatsNewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A914FA4C2DD2768900856265 /* WhatsNewView.swift */; };
A914FA4F2DD276D200856265 /* AboutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A914FA4E2DD276D200856265 /* AboutView.swift */; };
A920C2882D24011400E4F9B1 /* NearFutureApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = A920C2872D24011400E4F9B1 /* NearFutureApp.swift */; };
A920C28C2D24011400E4F9B1 /* Item.swift in Sources */ = {isa = PBXBuildFile; fileRef = A920C28B2D24011400E4F9B1 /* Item.swift */; };
A920C28C2D24011400E4F9B1 /* Events.swift in Sources */ = {isa = PBXBuildFile; fileRef = A920C28B2D24011400E4F9B1 /* Events.swift */; };
A920C28E2D24011A00E4F9B1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A920C28D2D24011A00E4F9B1 /* Assets.xcassets */; };
A920C2922D24011A00E4F9B1 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A920C2912D24011A00E4F9B1 /* Preview Assets.xcassets */; };
A920C2BE2D24021A00E4F9B1 /* SFSymbolsPicker in Frameworks */ = {isa = PBXBuildFile; productRef = A920C2BD2D24021A00E4F9B1 /* SFSymbolsPicker */; };
@@ -27,16 +43,18 @@
A949F8532DCAABE00064DCA0 /* ImportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A949F8452DCAABE00064DCA0 /* ImportView.swift */; };
A949F8542DCAABE00064DCA0 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A949F8462DCAABE00064DCA0 /* SettingsView.swift */; };
A949F8552DCAABE00064DCA0 /* StatsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A949F8482DCAABE00064DCA0 /* StatsView.swift */; };
A949F8562DCAABE00064DCA0 /* ExportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A949F8432DCAABE00064DCA0 /* ExportView.swift */; };
A949F8592DCAAD670064DCA0 /* NearFutureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A949F8572DCAAD670064DCA0 /* NearFutureTests.swift */; };
A949F85F2DCABB420064DCA0 /* Buttons.swift in Sources */ = {isa = PBXBuildFile; fileRef = A949F85D2DCABB420064DCA0 /* Buttons.swift */; };
A979F6052D270AF00094C0B3 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A979F6042D270AF00094C0B3 /* WidgetKit.framework */; };
A979F6072D270AF00094C0B3 /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A979F6062D270AF00094C0B3 /* SwiftUI.framework */; };
A979F60A2D270AF00094C0B3 /* NearFutureWidgetsBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = A979F6092D270AF00094C0B3 /* NearFutureWidgetsBundle.swift */; };
A979F60C2D270AF00094C0B3 /* NearFutureWidgetsLiveActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = A979F60B2D270AF00094C0B3 /* NearFutureWidgetsLiveActivity.swift */; };
A979F6102D270AF90094C0B3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A979F60F2D270AF80094C0B3 /* Assets.xcassets */; };
A979F6142D270AF90094C0B3 /* NearFutureWidgetsExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = A979F6022D270AF00094C0B3 /* NearFutureWidgetsExtension.appex */; platformFilter = ios; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
A979F6182D2714310094C0B3 /* Item.swift in Sources */ = {isa = PBXBuildFile; fileRef = A920C28B2D24011400E4F9B1 /* Item.swift */; };
A979F6182D2714310094C0B3 /* Events.swift in Sources */ = {isa = PBXBuildFile; fileRef = A920C28B2D24011400E4F9B1 /* Events.swift */; };
A98C20CB2DE730740008D61C /* EventListViewMac.swift in Sources */ = {isa = PBXBuildFile; fileRef = A98C20CA2DE730740008D61C /* EventListViewMac.swift */; };
A98C20CC2DE730740008D61C /* EditEventView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A98C20C92DE730740008D61C /* EditEventView.swift */; };
A98C20CE2DE7308E0008D61C /* ArchiveView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A98C20CD2DE7308E0008D61C /* ArchiveView.swift */; };
A98C20D02DE731BD0008D61C /* HomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A98C20CF2DE731BD0008D61C /* HomeView.swift */; };
A98C20D42DE7339E0008D61C /* AboutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A98C20D32DE7339E0008D61C /* AboutView.swift */; };
A9B78B942DF9F3CF00647399 /* AddEventView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9B78B932DF9F3CF00647399 /* AddEventView.swift */; };
A9FC7EEA2D2823920020D75B /* NearFutureWidgets.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9FC7EE92D28238A0020D75B /* NearFutureWidgets.swift */; };
/* End PBXBuildFile section */
@@ -48,12 +66,12 @@
remoteGlobalIDString = A979F6012D270AF00094C0B3;
remoteInfo = NearFutureWidgetsExtension;
};
A980FC3B2D93FB2B006A778F /* PBXContainerItemProxy */ = {
A98C20D12DE732B10008D61C /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = A920C27C2D24011300E4F9B1 /* Project object */;
proxyType = 1;
remoteGlobalIDString = A920C2832D24011300E4F9B1;
remoteInfo = NearFuture;
remoteGlobalIDString = A979F6012D270AF00094C0B3;
remoteInfo = NearFutureWidgetsExtension;
};
/* End PBXContainerItemProxy section */
@@ -72,15 +90,24 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
A90D491F2DDE08E400781124 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
A90D49262DDE0FA400781124 /* Near Future.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Near Future.app"; sourceTree = BUILT_PRODUCTS_DIR; };
A90D49332DDE0FAF00781124 /* ContentViewMac.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentViewMac.swift; sourceTree = "<group>"; };
A90D49342DDE0FAF00781124 /* MacNearFuture.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = MacNearFuture.entitlements; sourceTree = "<group>"; };
A90D49432DDE1C1100781124 /* Tints.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Tints.xcassets; sourceTree = "<group>"; };
A90D49512DDE2D0000781124 /* Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = "<group>"; };
A90D495A2DDE2EDB00781124 /* MacNearFutureApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MacNearFutureApp.swift; path = MacNearFuture/MacNearFutureApp.swift; sourceTree = SOURCE_ROOT; };
A90D495D2DDE3C7400781124 /* NFCommands.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NFCommands.swift; sourceTree = "<group>"; };
A90D49602DDE626300781124 /* Settings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Settings.swift; sourceTree = "<group>"; };
A90D49652DDE658100781124 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
A90FDE222DC0D4310012790C /* Config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = "<group>"; };
A914FA4A2DD26C0F00856265 /* HomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeView.swift; sourceTree = "<group>"; };
A914FA4C2DD2768900856265 /* WhatsNewView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = WhatsNewView.swift; path = NearFuture/Views/Settings/WhatsNewView.swift; sourceTree = SOURCE_ROOT; };
A914FA4E2DD276D200856265 /* AboutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AboutView.swift; path = NearFuture/Views/Misc/AboutView.swift; sourceTree = SOURCE_ROOT; };
A920C2842D24011400E4F9B1 /* NearFuture.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = NearFuture.app; sourceTree = BUILT_PRODUCTS_DIR; };
A920C2872D24011400E4F9B1 /* NearFutureApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NearFutureApp.swift; sourceTree = "<group>"; };
A920C28B2D24011400E4F9B1 /* Item.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Item.swift; sourceTree = "<group>"; };
A920C28B2D24011400E4F9B1 /* Events.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Events.swift; sourceTree = "<group>"; };
A920C28D2D24011A00E4F9B1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
A920C28F2D24011A00E4F9B1 /* NearFuture.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = NearFuture.entitlements; sourceTree = "<group>"; };
A920C2912D24011A00E4F9B1 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
A949F82E2DCAAA640064DCA0 /* NearFutureIcon.pxd */ = {isa = PBXFileReference; lastKnownFileType = file; path = NearFutureIcon.pxd; sourceTree = "<group>"; };
A949F82F2DCAAA640064DCA0 /* NearFutureIconDark.pxd */ = {isa = PBXFileReference; lastKnownFileType = file; path = NearFutureIconDark.pxd; sourceTree = "<group>"; };
@@ -97,28 +124,29 @@
A949F8452DCAABE00064DCA0 /* ImportView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImportView.swift; sourceTree = "<group>"; };
A949F8462DCAABE00064DCA0 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
A949F8482DCAABE00064DCA0 /* StatsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatsView.swift; sourceTree = "<group>"; };
A949F8572DCAAD670064DCA0 /* NearFutureTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NearFutureTests.swift; sourceTree = "<group>"; };
A949F85D2DCABB420064DCA0 /* Buttons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Buttons.swift; sourceTree = "<group>"; };
A979F58B2D2700680094C0B3 /* NearFutureWidgetsBundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NearFutureWidgetsBundle.swift; sourceTree = "<group>"; };
A979F58D2D2700680094C0B3 /* NearFutureWidgetsLiveActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NearFutureWidgetsLiveActivity.swift; sourceTree = "<group>"; };
A979F58F2D2700680094C0B3 /* NearFutureWidgets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NearFutureWidgets.swift; sourceTree = "<group>"; };
A979F5912D2700680094C0B3 /* AppIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppIntent.swift; sourceTree = "<group>"; };
A979F5932D27006D0094C0B3 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
A979F5952D27006D0094C0B3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
A979F6022D270AF00094C0B3 /* NearFutureWidgetsExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = NearFutureWidgetsExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
A979F6042D270AF00094C0B3 /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; };
A979F6062D270AF00094C0B3 /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; };
A979F6092D270AF00094C0B3 /* NearFutureWidgetsBundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NearFutureWidgetsBundle.swift; sourceTree = "<group>"; };
A979F60B2D270AF00094C0B3 /* NearFutureWidgetsLiveActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NearFutureWidgetsLiveActivity.swift; sourceTree = "<group>"; };
A979F60F2D270AF80094C0B3 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
A979F6112D270AF90094C0B3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
A980FC302D920097006A778F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
A980FC372D93FB2B006A778F /* NearFutureTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NearFutureTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
A9C05E412D2805D7007DC497 /* NearFutureWidgetsExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = NearFutureWidgetsExtension.entitlements; sourceTree = "<group>"; };
A98C20C92DE730740008D61C /* EditEventView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditEventView.swift; sourceTree = "<group>"; };
A98C20CA2DE730740008D61C /* EventListViewMac.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventListViewMac.swift; sourceTree = "<group>"; };
A98C20CD2DE7308E0008D61C /* ArchiveView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArchiveView.swift; sourceTree = "<group>"; };
A98C20CF2DE731BD0008D61C /* HomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeView.swift; sourceTree = "<group>"; };
A98C20D32DE7339E0008D61C /* AboutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutView.swift; sourceTree = "<group>"; };
A9B78B932DF9F3CF00647399 /* AddEventView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddEventView.swift; sourceTree = "<group>"; };
A9FC7EE92D28238A0020D75B /* NearFutureWidgets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NearFutureWidgets.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
A90D49232DDE0FA400781124 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
A90D49562DDE2D5800781124 /* SFSymbolsPicker in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
A920C2812D24011300E4F9B1 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@@ -128,15 +156,6 @@
runOnlyForDeploymentPostprocessing = 0;
};
A979F5FF2D270AF00094C0B3 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
A979F6072D270AF00094C0B3 /* SwiftUI.framework in Frameworks */,
A979F6052D270AF00094C0B3 /* WidgetKit.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
A980FC342D93FB2B006A778F /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -146,15 +165,67 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
A90D49202DDE0A3B00781124 /* Model */ = {
isa = PBXGroup;
children = (
A920C28B2D24011400E4F9B1 /* Events.swift */,
A90D49602DDE626300781124 /* Settings.swift */,
);
path = Model;
sourceTree = "<group>";
};
A90D49362DDE0FAF00781124 /* MacNearFuture */ = {
isa = PBXGroup;
children = (
A90D495A2DDE2EDB00781124 /* MacNearFutureApp.swift */,
A98C20D32DE7339E0008D61C /* AboutView.swift */,
A90D495D2DDE3C7400781124 /* NFCommands.swift */,
A90D493F2DDE10EC00781124 /* Views */,
A90D49342DDE0FAF00781124 /* MacNearFuture.entitlements */,
);
path = MacNearFuture;
sourceTree = "<group>";
};
A90D493F2DDE10EC00781124 /* Views */ = {
isa = PBXGroup;
children = (
A90D49332DDE0FAF00781124 /* ContentViewMac.swift */,
A98C20CF2DE731BD0008D61C /* HomeView.swift */,
A98C20CA2DE730740008D61C /* EventListViewMac.swift */,
A98C20CD2DE7308E0008D61C /* ArchiveView.swift */,
A98C20C82DE730420008D61C /* Events */,
);
path = Views;
sourceTree = "<group>";
};
A90D49412DDE112700781124 /* Shared */ = {
isa = PBXGroup;
children = (
A920C2872D24011400E4F9B1 /* NearFutureApp.swift */,
A90D49512DDE2D0000781124 /* Extensions.swift */,
A90D49202DDE0A3B00781124 /* Model */,
);
path = Shared;
sourceTree = "<group>";
};
A90D49542DDE2D5800781124 /* Frameworks */ = {
isa = PBXGroup;
children = (
);
name = Frameworks;
sourceTree = "<group>";
};
A920C27B2D24011300E4F9B1 = {
isa = PBXGroup;
children = (
A90D491F2DDE08E400781124 /* README.md */,
A90FDE222DC0D4310012790C /* Config.xcconfig */,
A949F8002DCAA0340064DCA0 /* Resources */,
A90D49412DDE112700781124 /* Shared */,
A920C2862D24011400E4F9B1 /* NearFuture */,
A90D49362DDE0FAF00781124 /* MacNearFuture */,
A949F8002DCAA0340064DCA0 /* Resources */,
A979F6082D270AF00094C0B3 /* NearFutureWidgets */,
A949F8582DCAAD670064DCA0 /* NearFutureTests */,
A979F6032D270AF00094C0B3 /* Frameworks */,
A90D49542DDE2D5800781124 /* Frameworks */,
A920C2852D24011400E4F9B1 /* Products */,
);
sourceTree = "<group>";
@@ -164,7 +235,7 @@
children = (
A920C2842D24011400E4F9B1 /* NearFuture.app */,
A979F6022D270AF00094C0B3 /* NearFutureWidgetsExtension.appex */,
A980FC372D93FB2B006A778F /* NearFutureTests.xctest */,
A90D49262DDE0FA400781124 /* Near Future.app */,
);
name = Products;
sourceTree = "<group>";
@@ -172,11 +243,7 @@
A920C2862D24011400E4F9B1 /* NearFuture */ = {
isa = PBXGroup;
children = (
A920C2872D24011400E4F9B1 /* NearFutureApp.swift */,
A920C28B2D24011400E4F9B1 /* Item.swift */,
A949F84A2DCAABE00064DCA0 /* Views */,
A980FC302D920097006A778F /* Info.plist */,
A920C28F2D24011A00E4F9B1 /* NearFuture.entitlements */,
A920C2902D24011A00E4F9B1 /* Preview Content */,
);
path = NearFuture;
@@ -185,7 +252,6 @@
A920C2902D24011A00E4F9B1 /* Preview Content */ = {
isa = PBXGroup;
children = (
A979F58A2D2700680094C0B3 /* NearFutureWidgets */,
A920C2912D24011A00E4F9B1 /* Preview Assets.xcassets */,
);
path = "Preview Content";
@@ -196,6 +262,7 @@
children = (
A949F8312DCAAA8A0064DCA0 /* NearFutureIcon.png */,
A920C28D2D24011A00E4F9B1 /* Assets.xcassets */,
A90D49432DDE1C1100781124 /* Tints.xcassets */,
A949F82E2DCAAA640064DCA0 /* NearFutureIcon.pxd */,
A949F82F2DCAAA640064DCA0 /* NearFutureIconDark.pxd */,
A949F8302DCAAA640064DCA0 /* NearFutureIconTint.pxd */,
@@ -223,10 +290,9 @@
A949F8422DCAABE00064DCA0 /* Home */ = {
isa = PBXGroup;
children = (
A949F83F2DCAABE00064DCA0 /* ContentView.swift */,
A914FA4A2DD26C0F00856265 /* HomeView.swift */,
A949F8402DCAABE00064DCA0 /* EventListView.swift */,
A949F8412DCAABE00064DCA0 /* HelpView.swift */,
A914FA4A2DD26C0F00856265 /* HomeView.swift */,
);
path = Home;
sourceTree = "<group>";
@@ -254,6 +320,7 @@
A949F84A2DCAABE00064DCA0 /* Views */ = {
isa = PBXGroup;
children = (
A949F83F2DCAABE00064DCA0 /* ContentView.swift */,
A949F8422DCAABE00064DCA0 /* Home */,
A949F83E2DCAABE00064DCA0 /* Events */,
A949F83B2DCAABE00064DCA0 /* Archive */,
@@ -264,14 +331,6 @@
path = Views;
sourceTree = "<group>";
};
A949F8582DCAAD670064DCA0 /* NearFutureTests */ = {
isa = PBXGroup;
children = (
A949F8572DCAAD670064DCA0 /* NearFutureTests.swift */,
);
path = NearFutureTests;
sourceTree = "<group>";
};
A949F85E2DCABB420064DCA0 /* Misc */ = {
isa = PBXGroup;
children = (
@@ -281,28 +340,6 @@
path = Misc;
sourceTree = "<group>";
};
A979F58A2D2700680094C0B3 /* NearFutureWidgets */ = {
isa = PBXGroup;
children = (
A979F58B2D2700680094C0B3 /* NearFutureWidgetsBundle.swift */,
A979F58D2D2700680094C0B3 /* NearFutureWidgetsLiveActivity.swift */,
A979F58F2D2700680094C0B3 /* NearFutureWidgets.swift */,
A979F5912D2700680094C0B3 /* AppIntent.swift */,
A979F5932D27006D0094C0B3 /* Assets.xcassets */,
A979F5952D27006D0094C0B3 /* Info.plist */,
);
path = NearFutureWidgets;
sourceTree = "<group>";
};
A979F6032D270AF00094C0B3 /* Frameworks */ = {
isa = PBXGroup;
children = (
A979F6042D270AF00094C0B3 /* WidgetKit.framework */,
A979F6062D270AF00094C0B3 /* SwiftUI.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
A979F6082D270AF00094C0B3 /* NearFutureWidgets */ = {
isa = PBXGroup;
children = (
@@ -310,15 +347,45 @@
A979F6092D270AF00094C0B3 /* NearFutureWidgetsBundle.swift */,
A979F60B2D270AF00094C0B3 /* NearFutureWidgetsLiveActivity.swift */,
A979F60F2D270AF80094C0B3 /* Assets.xcassets */,
A979F6112D270AF90094C0B3 /* Info.plist */,
A9C05E412D2805D7007DC497 /* NearFutureWidgetsExtension.entitlements */,
A90D49652DDE658100781124 /* Info.plist */,
);
path = NearFutureWidgets;
sourceTree = "<group>";
};
A98C20C82DE730420008D61C /* Events */ = {
isa = PBXGroup;
children = (
A9B78B932DF9F3CF00647399 /* AddEventView.swift */,
A98C20C92DE730740008D61C /* EditEventView.swift */,
);
path = Events;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
A90D49252DDE0FA400781124 /* MacNearFuture */ = {
isa = PBXNativeTarget;
buildConfigurationList = A90D492F2DDE0FA600781124 /* Build configuration list for PBXNativeTarget "MacNearFuture" */;
buildPhases = (
A90D49222DDE0FA400781124 /* Sources */,
A90D49232DDE0FA400781124 /* Frameworks */,
A90D49242DDE0FA400781124 /* Resources */,
);
buildRules = (
);
dependencies = (
A98C20D22DE732B10008D61C /* PBXTargetDependency */,
A90D494D2DDE2C6000781124 /* PBXTargetDependency */,
);
name = MacNearFuture;
packageProductDependencies = (
A90D49552DDE2D5800781124 /* SFSymbolsPicker */,
);
productName = MacNearFuture;
productReference = A90D49262DDE0FA400781124 /* Near Future.app */;
productType = "com.apple.product-type.application";
};
A920C2832D24011300E4F9B1 /* NearFuture */ = {
isa = PBXNativeTarget;
buildConfigurationList = A920C2AB2D24011B00E4F9B1 /* Build configuration list for PBXNativeTarget "NearFuture" */;
@@ -358,26 +425,6 @@
productReference = A979F6022D270AF00094C0B3 /* NearFutureWidgetsExtension.appex */;
productType = "com.apple.product-type.app-extension";
};
A980FC362D93FB2B006A778F /* NearFutureTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = A980FC3D2D93FB2B006A778F /* Build configuration list for PBXNativeTarget "NearFutureTests" */;
buildPhases = (
A980FC332D93FB2B006A778F /* Sources */,
A980FC342D93FB2B006A778F /* Frameworks */,
A980FC352D93FB2B006A778F /* Resources */,
);
buildRules = (
);
dependencies = (
A980FC3C2D93FB2B006A778F /* PBXTargetDependency */,
);
name = NearFutureTests;
packageProductDependencies = (
);
productName = NearFutureTests;
productReference = A980FC372D93FB2B006A778F /* NearFutureTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
@@ -385,19 +432,18 @@
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = 1;
LastSwiftUpdateCheck = 1620;
LastSwiftUpdateCheck = 1640;
LastUpgradeCheck = 1630;
TargetAttributes = {
A90D49252DDE0FA400781124 = {
CreatedOnToolsVersion = 16.4;
};
A920C2832D24011300E4F9B1 = {
CreatedOnToolsVersion = 15.4;
};
A979F6012D270AF00094C0B3 = {
CreatedOnToolsVersion = 15.4;
};
A980FC362D93FB2B006A778F = {
CreatedOnToolsVersion = 16.2;
TestTargetID = A920C2832D24011300E4F9B1;
};
};
};
buildConfigurationList = A920C27F2D24011300E4F9B1 /* Build configuration list for PBXProject "NearFuture" */;
@@ -417,17 +463,28 @@
projectRoot = "";
targets = (
A920C2832D24011300E4F9B1 /* NearFuture */,
A90D49252DDE0FA400781124 /* MacNearFuture */,
A979F6012D270AF00094C0B3 /* NearFutureWidgetsExtension */,
A980FC362D93FB2B006A778F /* NearFutureTests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
A90D49242DDE0FA400781124 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
A90D49452DDE1C7600781124 /* Tints.xcassets in Resources */,
A90D493E2DDE10CF00781124 /* Assets.xcassets in Resources */,
A90D493D2DDE10B200781124 /* NearFutureIcon.png in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
A920C2822D24011300E4F9B1 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
A90D49442DDE1C7600781124 /* Tints.xcassets in Resources */,
A920C2922D24011A00E4F9B1 /* Preview Assets.xcassets in Resources */,
A949F8322DCAAA8A0064DCA0 /* NearFutureIcon.png in Resources */,
A920C28E2D24011A00E4F9B1 /* Assets.xcassets in Resources */,
@@ -438,36 +495,52 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
A90D49462DDE1C7A00781124 /* Tints.xcassets in Resources */,
A979F6102D270AF90094C0B3 /* Assets.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
A980FC352D93FB2B006A778F /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
A90D49222DDE0FA400781124 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
A98C20CB2DE730740008D61C /* EventListViewMac.swift in Sources */,
A98C20CC2DE730740008D61C /* EditEventView.swift in Sources */,
A90D495E2DDE3C7400781124 /* NFCommands.swift in Sources */,
A98C20D42DE7339E0008D61C /* AboutView.swift in Sources */,
A98C20CE2DE7308E0008D61C /* ArchiveView.swift in Sources */,
A98C20D02DE731BD0008D61C /* HomeView.swift in Sources */,
A90D495B2DDE2EDB00781124 /* MacNearFutureApp.swift in Sources */,
A9B78B942DF9F3CF00647399 /* AddEventView.swift in Sources */,
A90D49522DDE2D0000781124 /* Extensions.swift in Sources */,
A90D49422DDE114100781124 /* Events.swift in Sources */,
A90D49382DDE0FAF00781124 /* ContentViewMac.swift in Sources */,
A90D49622DDE626300781124 /* Settings.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
A920C2802D24011300E4F9B1 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
A920C28C2D24011400E4F9B1 /* Item.swift in Sources */,
A920C28C2D24011400E4F9B1 /* Events.swift in Sources */,
A949F84B2DCAABE00064DCA0 /* ArchiveView.swift in Sources */,
A914FA4F2DD276D200856265 /* AboutView.swift in Sources */,
A949F84C2DCAABE00064DCA0 /* AddEventView.swift in Sources */,
A914FA4B2DD26C6800856265 /* HomeView.swift in Sources */,
A949F84D2DCAABE00064DCA0 /* EditEventView.swift in Sources */,
A949F84E2DCAABE00064DCA0 /* ContentView.swift in Sources */,
A90D49612DDE626300781124 /* Settings.swift in Sources */,
A90D495F2DDE3C7400781124 /* NFCommands.swift in Sources */,
A949F84F2DCAABE00064DCA0 /* EventListView.swift in Sources */,
A949F8502DCAABE00064DCA0 /* HelpView.swift in Sources */,
A949F85F2DCABB420064DCA0 /* Buttons.swift in Sources */,
A914FA4D2DD2768900856265 /* WhatsNewView.swift in Sources */,
A949F8512DCAABE00064DCA0 /* ExportView.swift in Sources */,
A90D49532DDE2D0000781124 /* Extensions.swift in Sources */,
A949F8522DCAABE00064DCA0 /* iCloudSettingsView.swift in Sources */,
A949F8532DCAABE00064DCA0 /* ImportView.swift in Sources */,
A949F8542DCAABE00064DCA0 /* SettingsView.swift in Sources */,
@@ -480,39 +553,97 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
A979F6182D2714310094C0B3 /* Item.swift in Sources */,
A979F6182D2714310094C0B3 /* Events.swift in Sources */,
A979F60A2D270AF00094C0B3 /* NearFutureWidgetsBundle.swift in Sources */,
A9FC7EEA2D2823920020D75B /* NearFutureWidgets.swift in Sources */,
A979F60C2D270AF00094C0B3 /* NearFutureWidgetsLiveActivity.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
A980FC332D93FB2B006A778F /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
A949F8592DCAAD670064DCA0 /* NearFutureTests.swift in Sources */,
A949F8562DCAABE00064DCA0 /* ExportView.swift in Sources */,
A90D49632DDE626300781124 /* Settings.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
A90D494D2DDE2C6000781124 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
productRef = A90D494C2DDE2C6000781124 /* SFSymbolsPicker */;
};
A979F6132D270AF90094C0B3 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
platformFilter = ios;
target = A979F6012D270AF00094C0B3 /* NearFutureWidgetsExtension */;
targetProxy = A979F6122D270AF90094C0B3 /* PBXContainerItemProxy */;
};
A980FC3C2D93FB2B006A778F /* PBXTargetDependency */ = {
A98C20D22DE732B10008D61C /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = A920C2832D24011300E4F9B1 /* NearFuture */;
targetProxy = A980FC3B2D93FB2B006A778F /* PBXContainerItemProxy */;
target = A979F6012D270AF00094C0B3 /* NearFutureWidgetsExtension */;
targetProxy = A98C20D12DE732B10008D61C /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
A90D49302DDE0FA600781124 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = A90FDE222DC0D4310012790C /* Config.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_ALTERNATE_APPICON_NAMES = "bloo blue green pink purple red yellow";
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = MacNearFuture/MacNearFuture.entitlements;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = "$(BUILD_NUMBER)";
DEVELOPMENT_TEAM = 8JGND254B7;
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 15;
MARKETING_VERSION = "$(VERSION)";
PRODUCT_BUNDLE_IDENTIFIER = com.neon443.NearFuture;
PRODUCT_NAME = "Near Future";
REGISTER_APP_GROUPS = YES;
SDKROOT = macosx;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
};
name = Debug;
};
A90D49312DDE0FA600781124 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = A90FDE222DC0D4310012790C /* Config.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_ALTERNATE_APPICON_NAMES = "bloo blue green pink purple red yellow";
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = MacNearFuture/MacNearFuture.entitlements;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = "$(BUILD_NUMBER)";
DEVELOPMENT_TEAM = 8JGND254B7;
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 15;
MARKETING_VERSION = "$(VERSION)";
PRODUCT_BUNDLE_IDENTIFIER = com.neon443.NearFuture;
PRODUCT_NAME = "Near Future";
REGISTER_APP_GROUPS = YES;
SDKROOT = macosx;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
};
name = Release;
};
A920C2A92D24011B00E4F9B1 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
@@ -660,8 +791,7 @@
ENABLE_HARDENED_RUNTIME = NO;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = NearFuture/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "$(NAME)";
INFOPLIST_KEY_CFBundleDisplayName = "Near Future";
INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO;
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES;
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES;
@@ -687,8 +817,8 @@
REGISTER_APP_GROUPS = YES;
SDKROOT = auto;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = YES;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
@@ -713,8 +843,7 @@
ENABLE_HARDENED_RUNTIME = NO;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = NearFuture/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "$(NAME)";
INFOPLIST_KEY_CFBundleDisplayName = "Near Future";
INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO;
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES;
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES;
@@ -737,8 +866,8 @@
REGISTER_APP_GROUPS = YES;
SDKROOT = auto;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = YES;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
@@ -758,7 +887,7 @@
CURRENT_PROJECT_VERSION = "$(BUILD_NUMBER)";
DEVELOPMENT_TEAM = "$(TEAM_ID)";
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = NearFutureWidgets/Info.plist;
INFOPLIST_FILE = "$(SRCROOT)/NearFutureWidgets/Info.plist";
INFOPLIST_KEY_CFBundleDisplayName = NearFutureWidgets;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 17;
@@ -778,8 +907,9 @@
REGISTER_APP_GROUPS = YES;
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = YES;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
@@ -799,7 +929,7 @@
CURRENT_PROJECT_VERSION = "$(BUILD_NUMBER)";
DEVELOPMENT_TEAM = "$(TEAM_ID)";
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = NearFutureWidgets/Info.plist;
INFOPLIST_FILE = "$(SRCROOT)/NearFutureWidgets/Info.plist";
INFOPLIST_KEY_CFBundleDisplayName = NearFutureWidgets;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 17;
@@ -815,8 +945,9 @@
REGISTER_APP_GROUPS = YES;
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = YES;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
@@ -825,61 +956,18 @@
};
name = Release;
};
A980FC3E2D93FB2B006A778F /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = A90FDE222DC0D4310012790C /* Config.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 16;
MACOSX_DEPLOYMENT_TARGET = 13;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = dev.neon443.NearFutureTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = auto;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = YES;
SWIFT_EMIT_LOC_STRINGS = NO;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/NearFuture.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/NearFuture";
XROS_DEPLOYMENT_TARGET = 1;
};
name = Debug;
};
A980FC3F2D93FB2B006A778F /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = A90FDE222DC0D4310012790C /* Config.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 16;
MACOSX_DEPLOYMENT_TARGET = 13;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = dev.neon443.NearFutureTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = auto;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = YES;
SWIFT_EMIT_LOC_STRINGS = NO;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/NearFuture.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/NearFuture";
XROS_DEPLOYMENT_TARGET = 1;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
A90D492F2DDE0FA600781124 /* Build configuration list for PBXNativeTarget "MacNearFuture" */ = {
isa = XCConfigurationList;
buildConfigurations = (
A90D49302DDE0FA600781124 /* Debug */,
A90D49312DDE0FA600781124 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
A920C27F2D24011300E4F9B1 /* Build configuration list for PBXProject "NearFuture" */ = {
isa = XCConfigurationList;
buildConfigurations = (
@@ -907,15 +995,6 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
A980FC3D2D93FB2B006A778F /* Build configuration list for PBXNativeTarget "NearFutureTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
A980FC3E2D93FB2B006A778F /* Debug */,
A980FC3F2D93FB2B006A778F /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
/* Begin XCRemoteSwiftPackageReference section */
@@ -930,6 +1009,16 @@
/* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
A90D494C2DDE2C6000781124 /* SFSymbolsPicker */ = {
isa = XCSwiftPackageProductDependency;
package = A920C2BC2D24021900E4F9B1 /* XCRemoteSwiftPackageReference "SFSymbolsPicker" */;
productName = SFSymbolsPicker;
};
A90D49552DDE2D5800781124 /* SFSymbolsPicker */ = {
isa = XCSwiftPackageProductDependency;
package = A920C2BC2D24021900E4F9B1 /* XCRemoteSwiftPackageReference "SFSymbolsPicker" */;
productName = SFSymbolsPicker;
};
A920C2BD2D24021A00E4F9B1 /* SFSymbolsPicker */ = {
isa = XCSwiftPackageProductDependency;
package = A920C2BC2D24021900E4F9B1 /* XCRemoteSwiftPackageReference "SFSymbolsPicker" */;

View File

@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1640"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "A90D49252DDE0FA400781124"
BuildableName = "Near Future.app"
BlueprintName = "MacNearFuture"
ReferencedContainer = "container:NearFuture.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "A90D49252DDE0FA400781124"
BuildableName = "Near Future.app"
BlueprintName = "MacNearFuture"
ReferencedContainer = "container:NearFuture.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "A90D49252DDE0FA400781124"
BuildableName = "Near Future.app"
BlueprintName = "MacNearFuture"
ReferencedContainer = "container:NearFuture.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@@ -4,19 +4,29 @@
<dict>
<key>SchemeUserState</key>
<dict>
<key>NearFuture.xcscheme_^#shared#^_</key>
<key>MacNearFuture.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>1</integer>
</dict>
<key>NearFutureWidgetsExtension.xcscheme_^#shared#^_</key>
<key>NearFuture.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>0</integer>
</dict>
<key>NearFutureWidgetsExtension.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>2</integer>
</dict>
</dict>
<key>SuppressBuildableAutocreation</key>
<dict>
<key>A90D49252DDE0FA400781124</key>
<dict>
<key>primary</key>
<true/>
</dict>
<key>A920C2832D24011300E4F9B1</key>
<dict>
<key>primary</key>

View File

@@ -1,170 +0,0 @@
//
// EventListView.swift
// NearFuture
//
// Created by neon443 on 18/04/2025.
//
import SwiftUI
import SwiftData
struct EventListView: View {
@ObservedObject var viewModel: EventViewModel
@State var event: Event
var body: some View {
NavigationLink() {
EditEventView(
viewModel: viewModel,
event: $event
)
} label: {
ZStack {
HStack {
RoundedRectangle(cornerRadius: 5)
.frame(width: 7)
.foregroundStyle(
event.color.color.opacity(
event.complete ? 0.5 : 1
)
)
VStack(alignment: .leading) {
HStack {
Image(systemName: event.symbol)
.resizable()
.scaledToFit()
.frame(width: 20, height: 20)
.shadow(radius: 5)
.foregroundStyle(
.one.opacity(
event.complete ? 0.5 : 1
)
)
Text("\(event.name)")
.font(.headline)
.foregroundStyle(.one)
.strikethrough(event.complete)
.multilineTextAlignment(.leading)
}
if !event.notes.isEmpty {
Text(event.notes)
.font(.subheadline)
.foregroundStyle(.one.opacity(0.8))
.multilineTextAlignment(.leading)
}
Text(
event.date.formatted(
date: .long,
time: .shortened
)
)
.font(.subheadline)
.foregroundStyle(
.one.opacity(
event.complete ? 0.5 : 1
)
)
if event.recurrence != .none {
Text("Occurs \(event.recurrence.rawValue)")
.font(.subheadline)
.foregroundStyle(
.one.opacity(event.complete ? 0.5 : 1))
}
}
Spacer()
VStack {
Text("\(daysUntilEvent(event.date).long)")
.font(.subheadline)
.foregroundStyle(.one)
}
Button() {
withAnimation {
event.complete.toggle()
}
let eventToModify = viewModel.events.firstIndex() { currEvent in
currEvent.id == event.id
}
if let eventToModify = eventToModify {
viewModel.events[eventToModify] = event
viewModel.saveEvents()
}
} label: {
if event.complete {
ZStack {
Circle()
.foregroundStyle(.green)
Image(systemName: "checkmark")
.resizable()
.foregroundStyle(.white)
.scaledToFit()
.bold()
.frame(width: 15)
}
} else {
Image(systemName: "circle")
.resizable()
.scaledToFit()
.foregroundStyle(event.color.color)
}
}
.buttonStyle(.borderless)
.frame(maxWidth: 25, maxHeight: 25)
.shadow(radius: 5)
.padding(.trailing, 5)
}
.padding(.vertical, 5)
.background(.ultraThinMaterial)
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(
.one.opacity(appearance == .dark ? 0.5 : 1),
lineWidth: 1
)
)
.clipShape(
RoundedRectangle(cornerRadius: 10)
)
.fixedSize(horizontal: false, vertical: true)
}
.transition(.opacity)
.contextMenu() {
Button(role: .destructive) {
let eventToModify = viewModel.events.firstIndex() { currEvent in
currEvent.id == event.id
}
if let eventToModify = eventToModify {
viewModel.events.remove(at: eventToModify)
viewModel.saveEvents()
}
} label: {
Label("Delete", systemImage: "trash")
}
}
}
}
}
#Preview("EventListView") {
let vm = dummyEventViewModel()
ZStack {
Color.black
VStack {
ForEach(0..<50) { _ in
Rectangle()
.foregroundStyle(randomColor().opacity(0.5))
.padding(-10)
}
.ignoresSafeArea(.all)
.blur(radius: 5)
}
VStack {
ForEach(vm.events) { event in
EventListView(
viewModel: vm,
event: event
)
}
}
.padding(.horizontal, 10)
}
}

View File

@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>AppIntents</key>
<array>
<string>com.neon443.NearFuture.CompleteEvent</string>
</array>
</dict>
</plist>

View File

@@ -1,112 +0,0 @@
//
// ArchiveHelp.swift
// NearFuture
//
// Created by neon443 on 26/04/2025.
//
import SwiftUI
enum HelpType {
case Search
case Archive
}
struct HelpView: View {
/// initialises a Search HelpView
///
init(searchInput: Binding<String>, focusedField: Field?) {
_searchInput = searchInput
self.helpType = .Search
_showAddEvent = .constant(false)
}
/// initialises an Archive HelpView
///
init(showAddEvent: Binding<Bool>) {
_showAddEvent = showAddEvent
self.helpType = .Archive
_searchInput = .constant("")
self.focusedField = nil
}
@Binding var searchInput: String
@FocusState var focusedField: Field?
@Binding var showAddEvent: Bool
var helpType: HelpType
var details: (
symbol: String,
title: String,
body: String,
buttonAction: () -> (),
buttonSymbol: String,
buttonText: String
) {
switch helpType {
case .Search:
return (
symbol: "questionmark.app.dashed",
title: "Looking for something?",
body: "Tip: The Search bar searches event names and notes.",
buttonAction: {
searchInput = ""
focusedField = nil
},
buttonSymbol: "xmark",
buttonText: "Clear Filters"
)
case .Archive:
return (
symbol: "eyes",
title: "Nothing to see here...",
body: "The Archive contains events that have been marked as complete.",
buttonAction: {
showAddEvent.toggle()
},
buttonSymbol: "plus",
buttonText: "Create an event"
)
}
}
var body: some View {
List {
ZStack {
Color(.tintColor)
.opacity(0.4)
.padding(.horizontal, -15)
.blur(radius: 5)
HStack {
Image(systemName: details.symbol)
.resizable()
.scaledToFit()
.frame(width: 30, height: 30)
.padding(.trailing)
Text(details.title)
.bold()
.font(.title2)
}
}
.listRowSeparator(.hidden)
Text(details.body)
Button() {
details.buttonAction()
} label: {
HStack {
Image(systemName: details.buttonSymbol)
.bold()
Text(details.buttonText)
}
.foregroundStyle(Color.accentColor)
}
}
.scrollContentBackground(.hidden)
}
}
#Preview {
HelpView(searchInput: .constant(""), focusedField: nil)
HelpView(showAddEvent: .constant(false))
}

View File

@@ -2,10 +2,6 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>aps-environment</key>
<string>development</string>
<key>com.apple.developer.aps-environment</key>
<string>development</string>
<key>com.apple.developer.icloud-container-identifiers</key>
<array/>
<key>com.apple.developer.ubiquity-kvstore-identifier</key>

View File

@@ -1,36 +0,0 @@
//
// NearFutureApp.swift
// NearFuture
//
// Created by neon443 on 24/12/2024.
//
import SwiftUI
import SwiftData
@main
struct NearFutureApp: App {
// var sharedModelContainer: ModelContainer = {
// let schema = Schema([
// Item.self,
// ])
// let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false)
//
// do {
// return try ModelContainer(for: schema, configurations: [modelConfiguration])
// } catch {
// fatalError("Could not create ModelContainer: \(error)")
// }
// }()
@StateObject var settingsModel: SettingsViewModel = SettingsViewModel()
var body: some Scene {
WindowGroup {
ContentView(
viewModel: EventViewModel(),
settingsModel: settingsModel
)
.tint(settingsModel.settings.tint.color)
}
// .modelContainer(sharedModelContainer)
}
}

View File

@@ -1,18 +0,0 @@
//
// AppIntent.swift
// NearFutureWidgets
//
// Created by neon443 on 02/01/2025.
//
import WidgetKit
import AppIntents
struct ConfigurationAppIntent: WidgetConfigurationIntent {
static var title: LocalizedStringResource = "Configuration"
static var description = IntentDescription("This is an example widget.")
// An example configurable parameter.
@Parameter(title: "Favorite Emoji", default: "😃")
var favoriteEmoji: String
}

View File

@@ -1,11 +0,0 @@
{
"colors" : [
{
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@@ -1,13 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@@ -1,11 +0,0 @@
{
"colors" : [
{
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSExtension</key>
<dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.widgetkit-extension</string>
</dict>
</dict>
</plist>

View File

@@ -1,84 +0,0 @@
//
// NearFutureWidgets.swift
// NearFutureWidgets
//
// Created by neon443 on 02/01/2025.
//
import WidgetKit
import SwiftUI
struct Provider: AppIntentTimelineProvider {
func placeholder(in context: Context) -> SimpleEntry {
SimpleEntry(date: Date(), configuration: ConfigurationAppIntent())
}
func snapshot(for configuration: ConfigurationAppIntent, in context: Context) async -> SimpleEntry {
SimpleEntry(date: Date(), configuration: configuration)
}
func timeline(for configuration: ConfigurationAppIntent, in context: Context) async -> Timeline<SimpleEntry> {
var entries: [SimpleEntry] = []
// Generate a timeline consisting of five entries an hour apart, starting from the current date.
let currentDate = Date()
for hourOffset in 0 ..< 5 {
let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)!
let entry = SimpleEntry(date: entryDate, configuration: configuration)
entries.append(entry)
}
return Timeline(entries: entries, policy: .atEnd)
}
}
struct SimpleEntry: TimelineEntry {
let date: Date
let configuration: ConfigurationAppIntent
}
struct NearFutureWidgetsEntryView : View {
var entry: Provider.Entry
var body: some View {
VStack {
Text("Time:")
Text(entry.date, style: .time)
Text("Favorite Emoji:")
Text(entry.configuration.favoriteEmoji)
}
}
}
struct NearFutureWidgets: Widget {
let kind: String = "NearFutureWidgets"
var body: some WidgetConfiguration {
AppIntentConfiguration(kind: kind, intent: ConfigurationAppIntent.self, provider: Provider()) { entry in
NearFutureWidgetsEntryView(entry: entry)
.containerBackground(.fill.tertiary, for: .widget)
}
}
}
extension ConfigurationAppIntent {
fileprivate static var smiley: ConfigurationAppIntent {
let intent = ConfigurationAppIntent()
intent.favoriteEmoji = "😀"
return intent
}
fileprivate static var starEyes: ConfigurationAppIntent {
let intent = ConfigurationAppIntent()
intent.favoriteEmoji = "🤩"
return intent
}
}
#Preview(as: .systemSmall) {
NearFutureWidgets()
} timeline: {
SimpleEntry(date: .now, configuration: .smiley)
SimpleEntry(date: .now, configuration: .starEyes)
}

View File

@@ -1,17 +0,0 @@
//
// NearFutureWidgetsBundle.swift
// NearFutureWidgets
//
// Created by neon443 on 02/01/2025.
//
import WidgetKit
import SwiftUI
@main
struct NearFutureWidgetsBundle: WidgetBundle {
var body: some Widget {
NearFutureWidgets()
NearFutureWidgetsLiveActivity()
}
}

View File

@@ -1,80 +0,0 @@
//
// NearFutureWidgetsLiveActivity.swift
// NearFutureWidgets
//
// Created by neon443 on 02/01/2025.
//
import ActivityKit
import WidgetKit
import SwiftUI
struct NearFutureWidgetsAttributes: ActivityAttributes {
public struct ContentState: Codable, Hashable {
// Dynamic stateful properties about your activity go here!
var emoji: String
}
// Fixed non-changing properties about your activity go here!
var name: String
}
struct NearFutureWidgetsLiveActivity: Widget {
var body: some WidgetConfiguration {
ActivityConfiguration(for: NearFutureWidgetsAttributes.self) { context in
// Lock screen/banner UI goes here
VStack {
Text("Hello \(context.state.emoji)")
}
.activityBackgroundTint(Color.cyan)
.activitySystemActionForegroundColor(Color.black)
} dynamicIsland: { context in
DynamicIsland {
// Expanded UI goes here. Compose the expanded UI through
// various regions, like leading/trailing/center/bottom
DynamicIslandExpandedRegion(.leading) {
Text("Leading")
}
DynamicIslandExpandedRegion(.trailing) {
Text("Trailing")
}
DynamicIslandExpandedRegion(.bottom) {
Text("Bottom \(context.state.emoji)")
// more content
}
} compactLeading: {
Text("L")
} compactTrailing: {
Text("T \(context.state.emoji)")
} minimal: {
Text(context.state.emoji)
}
.widgetURL(URL(string: "http://www.apple.com"))
.keylineTint(Color.red)
}
}
}
extension NearFutureWidgetsAttributes {
fileprivate static var preview: NearFutureWidgetsAttributes {
NearFutureWidgetsAttributes(name: "World")
}
}
extension NearFutureWidgetsAttributes.ContentState {
fileprivate static var smiley: NearFutureWidgetsAttributes.ContentState {
NearFutureWidgetsAttributes.ContentState(emoji: "😀")
}
fileprivate static var starEyes: NearFutureWidgetsAttributes.ContentState {
NearFutureWidgetsAttributes.ContentState(emoji: "🤩")
}
}
#Preview("Notification", as: .content, using: NearFutureWidgetsAttributes.preview) {
NearFutureWidgetsLiveActivity()
} contentStates: {
NearFutureWidgetsAttributes.ContentState.smiley
NearFutureWidgetsAttributes.ContentState.starEyes
}

View File

@@ -49,14 +49,7 @@ struct ArchiveView: View {
.sheet(isPresented: $showAddEvent) {
AddEventView(
viewModel: viewModel,
eventName: $viewModel.editableTemplate.name,
eventComplete: $viewModel.editableTemplate.complete,
eventCompleteDesc: $viewModel.editableTemplate.completeDesc,
eventSymbol: $viewModel.editableTemplate.symbol,
eventColor: $viewModel.editableTemplate.color.colorBind,
eventNotes: $viewModel.editableTemplate.notes,
eventDate: $viewModel.editableTemplate.date,
eventRecurrence: $viewModel.editableTemplate.recurrence,
event: $viewModel.editableTemplate,
adding: true
)
}

View File

@@ -27,10 +27,10 @@ struct ContentView: View {
var body: some View {
TabView(selection: $selection) {
HomeView(viewModel: viewModel, settingsModel: settingsModel)
.tabItem {
Label("Home", systemImage: "house")
}
.tag(Tab.home)
.tabItem {
Label("Home", systemImage: "house")
}
.tag(Tab.home)
ArchiveView(viewModel: viewModel)
.tabItem() {
Label("Archive", systemImage: "tray.full")
@@ -64,33 +64,3 @@ struct ContentView: View {
settingsModel: dummySettingsViewModel()
)
}
extension View {
var backgroundGradient: some View {
return LinearGradient(
gradient: Gradient(colors: [.bgTop, .two]),
startPoint: .top,
endPoint: .bottom
)
.ignoresSafeArea(.all)
}
func apply<V: View>(@ViewBuilder _ block: (Self) -> V) -> V { block(self) }
}
extension AnyTransition {
static var moveAndFade: AnyTransition {
.asymmetric(
insertion: .move(edge: .leading),
removal: .move(edge: .trailing)
)
.combined(with: .opacity)
}
static var moveAndFadeReversed: AnyTransition {
.asymmetric(
insertion: .move(edge: .trailing),
removal: .move(edge: .leading)
)
.combined(with: .opacity)
}
}

View File

@@ -11,18 +11,11 @@ import SFSymbolsPicker
struct AddEventView: View {
@ObservedObject var viewModel: EventViewModel
@Binding var eventName: String
@Binding var eventComplete: Bool
@Binding var eventCompleteDesc: String
@Binding var eventSymbol: String
@Binding var eventColor: Color
@Binding var eventNotes: String
@Binding var eventDate: Date
@Binding var eventRecurrence: Event.RecurrenceType
@Binding var event: Event
@State var adding: Bool
@State var showNeedsNameAlert: Bool = false
@State var isSymbolPickerPresented = false
@State var isSymbolPickerPresented: Bool = false
@State private var bye: Bool = false
@@ -38,108 +31,88 @@ struct AddEventView: View {
if !adding {
backgroundGradient
}
NavigationStack {
Form {
Section(
header:
Text("Event Details")
.font(.headline)
.foregroundColor(.accentColor)
) {
// name & symbol
HStack(spacing: 5) {
Button() {
isSymbolPickerPresented.toggle()
} label: {
Image(systemName: eventSymbol)
.resizable()
.scaledToFit()
.frame(width: 20, height: 20)
.foregroundStyle(eventColor)
}
.frame(width: 20)
.buttonStyle(.borderless)
.sheet(isPresented: $isSymbolPickerPresented) {
SymbolsPicker(
selection: $eventSymbol,
title: "Choose a Symbol",
searchLabel: "Search...",
autoDismiss: true)
.presentationDetents([.medium])
.apply {
if #available(iOS 16.4, *) {
$0.presentationBackground(.ultraThinMaterial)
}
}
}
ColorPicker("", selection: $eventColor, supportsOpacity: false)
.fixedSize()
ZStack {
TextField("Event Name", text: $eventName)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding(.trailing, eventName.isEmpty ? 0 : 30)
.animation(.spring, value: eventName)
.focused($focusedField, equals: Field.Name)
.submitLabel(.next)
.onSubmit {
focusedField = .Notes
}
MagicClearButton(text: $eventName)
}
List {
Section(
header:
Text("Event Details")
.font(.headline)
.foregroundColor(.accentColor)
) {
// name & symbol
HStack(spacing: 5) {
Button() {
isSymbolPickerPresented.toggle()
} label: {
Image(systemName: event.symbol)
.resizable()
.scaledToFit()
.frame(width: 20, height: 20)
.foregroundStyle(event.color.color)
}
// dscription
ZStack {
TextField("Event Notes", text: $eventNotes)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding(.trailing, eventNotes.isEmpty ? 0 : 30)
.animation(.spring, value: eventNotes)
.focused($focusedField, equals: Field.Notes)
.submitLabel(.done)
.onSubmit {
focusedField = nil
}
MagicClearButton(text: $eventNotes)
.frame(width: 20)
.buttonStyle(.borderless)
.sheet(isPresented: $isSymbolPickerPresented) {
SymbolsPicker(
selection: $event.symbol,
title: "Choose a Symbol",
searchLabel: "Search...",
autoDismiss: true)
.presentationDetents([.medium])
}
// date picker
HStack {
Spacer()
DatePicker("", selection: $eventDate, displayedComponents: .date)
.datePickerStyle(WheelDatePickerStyle())
Spacer()
Button() {
eventDate = Date()
} label: {
Image(systemName: "arrow.uturn.left")
.resizable()
.scaledToFit()
}
.buttonStyle(BorderlessButtonStyle())
.frame(width: 20)
}
DatePicker(
"",
selection: $eventDate,
displayedComponents: .hourAndMinute
)
// re-ocurrence Picker
Picker("Recurrence", selection: $eventRecurrence) {
ForEach(Event.RecurrenceType.allCases, id: \.self) { recurrence in
Text(recurrence.rawValue.capitalized)
}
}
.pickerStyle(SegmentedPickerStyle())
Text(
describeOccurrence(
date: eventDate,
recurrence: eventRecurrence
)
)
}
// dscription
ZStack {
TextField("Event Notes", text: $event.notes)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding(.trailing, event.notes.isEmpty ? 0 : 30)
.animation(.spring, value: event.notes)
.focused($focusedField, equals: Field.Notes)
.submitLabel(.done)
.onSubmit {
focusedField = nil
}
// MagicClearButton(text: $eventNotes)
}
// date picker
HStack {
Spacer()
DatePicker("", selection: $event.date, displayedComponents: .date)
.datePickerStyle(.wheel)
Spacer()
Button() {
event.date = Date()
} label: {
Image(systemName: "arrow.uturn.left")
.resizable()
.scaledToFit()
}
.buttonStyle(BorderlessButtonStyle())
.frame(width: 20)
}
DatePicker(
"",
selection: $event.date,
displayedComponents: .hourAndMinute
)
.datePickerStyle(.wheel)
// re-ocurrence Picker
Picker("Recurrence", selection: $event.recurrence) {
ForEach(Event.RecurrenceType.allCases, id: \.self) { recurrence in
Text(recurrence.rawValue.capitalized)
}
}
.pickerStyle(SegmentedPickerStyle())
Text(
describeOccurrence(
date: event.date,
recurrence: event.recurrence
)
)
}
.scrollContentBackground(.hidden)
.navigationTitle("\(adding ? "Add Event" : "")")
@@ -151,8 +124,7 @@ struct AddEventView: View {
resetAddEventView()
dismiss()
} label: {
Image(systemName: "xmark.circle.fill")
.symbolRenderingMode(.hierarchical)
Image(systemName: "xmark")
.resizable()
.scaledToFit()
.frame(width: 30)
@@ -163,16 +135,7 @@ struct AddEventView: View {
if adding {
Button {
viewModel.addEvent(
newEvent: Event(
name: eventName,
complete: eventComplete,
completeDesc: eventCompleteDesc,
symbol: eventSymbol,
color: ColorCodable(eventColor),
notes: eventNotes,
date: eventDate,
recurrence: eventRecurrence
)
newEvent: event
)
bye.toggle()
resetAddEventView()
@@ -182,14 +145,15 @@ struct AddEventView: View {
.cornerRadius(10)
.buttonStyle(BorderedProminentButtonStyle())
}
.tint(.accent)
.apply {
if #available(iOS 17, *) {
$0.sensoryFeedback(.success, trigger: bye)
}
}
.disabled(eventName.isEmpty)
.disabled(event.name.isEmpty)
.onTapGesture {
if eventName.isEmpty {
if event.name.isEmpty {
showNeedsNameAlert.toggle()
}
}
@@ -201,7 +165,7 @@ struct AddEventView: View {
} message: {
Text("Give your Event a name before saving.")
}
if eventName.isEmpty {
if event.name.isEmpty {
HStack {
Image(systemName: "exclamationmark")
.foregroundStyle(.red)
@@ -212,25 +176,13 @@ struct AddEventView: View {
}
}
}
.presentationDragIndicator(.visible)
.scrollContentBackground(.hidden)
}
.apply {
if #available(iOS 16.4, *) {
$0.presentationBackground(.ultraThinMaterial)
}
.presentationDragIndicator(.visible)
}
}
func resetAddEventView() {
//reset addeventView
eventName = viewModel.template.name
eventComplete = viewModel.template.complete
eventCompleteDesc = viewModel.template.completeDesc
eventSymbol = viewModel.template.symbol
eventColor = randomColor()
eventNotes = viewModel.template.notes
eventDate = viewModel.template.date
eventRecurrence = viewModel.template.recurrence
event = viewModel.template
dismiss()
}
@@ -243,14 +195,7 @@ struct AddEventView: View {
.sheet(isPresented: .constant(true)) {
AddEventView(
viewModel: vm,
eventName: .constant(vm.template.notes),
eventComplete: .constant(vm.template.complete),
eventCompleteDesc: .constant(vm.template.completeDesc),
eventSymbol: .constant(vm.template.symbol),
eventColor: .constant(vm.template.color.color),
eventNotes: .constant(vm.template.notes),
eventDate: .constant(vm.template.date),
eventRecurrence: .constant(vm.template.recurrence),
event: .constant(vm.template),
adding: true
)
}

View File

@@ -28,14 +28,7 @@ struct EditEventView: View {
var body: some View {
AddEventView(
viewModel: viewModel,
eventName: $event.name,
eventComplete: $event.complete,
eventCompleteDesc: $event.completeDesc,
eventSymbol: $event.symbol,
eventColor: $event.color.colorBind,
eventNotes: $event.notes,
eventDate: $event.date,
eventRecurrence: $event.recurrence,
event: $event,
adding: false //bc we editing existing event
)
.navigationTitle("Edit Event")

View File

@@ -76,6 +76,7 @@ struct EventListView: View {
Text("\(daysUntilEvent(event.date).long)")
.font(.subheadline)
.foregroundStyle(event.date.timeIntervalSinceNow < 0 ? .red : .one)
.multilineTextAlignment(.trailing)
}
Button() {
withAnimation {
@@ -119,7 +120,6 @@ struct EventListView: View {
}
.transition(.opacity)
.padding(.vertical, 5)
.background(.ultraThinMaterial)
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(

View File

@@ -5,20 +5,15 @@
// Created by neon443 on 12/05/2025.
//
import SwiftUI;import AppIntents
import SwiftUI
import AppIntents
struct HomeView: View {
@ObservedObject var viewModel: EventViewModel
@ObservedObject var settingsModel: SettingsViewModel
@State private var eventName = ""
@State private var eventComplete = false
@State private var eventCompleteDesc = ""
@State private var eventSymbol = "star"
@State private var eventColor: Color = randomColor()
@State private var eventNotes = ""
@State private var eventDate = Date()
@State private var eventRecurrence: Event.RecurrenceType = .none
@State private var showingAddEventView = false
@State private var event: Event = dummyEventViewModel().template
@State private var showingAddEventView: Bool = false
@State private var searchInput: String = ""
@Environment(\.colorScheme) var appearance
var darkMode: Bool {
@@ -47,36 +42,18 @@ struct HomeView: View {
ZStack {
backgroundGradient
VStack {
ZStack {
TextField(
"\(Image(systemName: "magnifyingglass")) Search",
text: $searchInput
)
.padding(.trailing, searchInput.isEmpty ? 0 : 30)
.animation(.spring, value: searchInput)
.textFieldStyle(RoundedBorderTextFieldStyle())
.submitLabel(.done)
.focused($focusedField, equals: Field.Search)
.onSubmit {
focusedField = nil
}
MagicClearButton(text: $searchInput)
.onTapGesture {
focusedField = nil
}
}
.padding(.horizontal)
if filteredEvents.isEmpty && !searchInput.isEmpty {
HelpView(searchInput: $searchInput, focusedField: focusedField)
} else {
ScrollView {
ForEach(filteredEvents) { event in
EventListView(viewModel: viewModel, event: event)
.transition(.moveAndFade)
.id(event.complete)
}
.padding(.horizontal)
// LazyVStack {
ForEach(filteredEvents) { event in
EventListView(viewModel: viewModel, event: event)
.transition(.moveAndFade)
.id(event.complete)
}
.padding(.horizontal)
// }
if filteredEvents.isEmpty {
HelpView(
searchInput: $searchInput,
@@ -88,6 +65,7 @@ struct HomeView: View {
.animation(.default, value: filteredEvents)
}
}
.searchable(text: $searchInput)
.navigationTitle("Near Future")
.apply {
if #available(iOS 17, *) {
@@ -99,14 +77,7 @@ struct HomeView: View {
.sheet(isPresented: $showingAddEventView) {
AddEventView(
viewModel: viewModel,
eventName: $eventName,
eventComplete: $eventComplete,
eventCompleteDesc: $eventCompleteDesc,
eventSymbol: $eventSymbol,
eventColor: $eventColor,
eventNotes: $eventNotes,
eventDate: $eventDate,
eventRecurrence: $eventRecurrence,
event: $event,
adding: true //adding event
)
}

View File

@@ -34,17 +34,12 @@ struct AddEventButton: View {
Button() {
showingAddEventView.toggle()
} label: {
ZStack {
Circle()
.frame(width: 33)
.foregroundStyle(.one)
Image(systemName: "plus")
.resizable()
.scaledToFit()
.frame(width: 15)
.bold()
.foregroundStyle(.two)
}
Image(systemName: "plus")
.resizable()
.scaledToFit()
.frame(width: 15)
.bold()
.foregroundStyle(.one)
}
}
}

View File

@@ -15,47 +15,117 @@ struct ImportView: View {
@State private var text: String = "Ready..."
@State private var fgColor: Color = .yellow
var body: some View {
List {
Section("Status") {
Label(text, systemImage: image)
.contentTransition(.numericText())
.foregroundStyle(fgColor)
@State private var showAlert: Bool = false
@State private var replaceCurrentEvents: Bool = false
fileprivate func importEvents() {
do throws {
try viewModel.importEvents(importStr, replace: replaceCurrentEvents)
withAnimation {
image = "checkmark.circle.fill"
text = "Complete"
fgColor = .green
}
TextField("", text: $importStr)
Button() {
do throws {
try viewModel.importEvents(importStr)
withAnimation {
image = "checkmark.circle.fill"
text = "Complete"
fgColor = .green
}
} catch importError.invalidB64 {
withAnimation {
image = "xmark.app.fill"
text = "Invalid base64 input."
fgColor = .red
}
} catch {
withAnimation {
image = "xmark.app.fill"
text = error.localizedDescription
fgColor = .red
}
}
} label: {
Label("Import", systemImage: "tray.and.arrow.down.fill")
} catch importError.invalidB64 {
withAnimation {
image = "xmark.app.fill"
text = "Invalid base64 input."
fgColor = .red
}
.disabled(importStr.isEmpty)
.onAppear() {
importStr = ""
image = "clock.fill"
text = "Ready..."
fgColor = .yellow
} catch {
withAnimation {
image = "xmark.app.fill"
text = error.localizedDescription
fgColor = .red
}
}
}
var body: some View {
ZStack(alignment: .center) {
List {
Section("Status") {
Label(text, systemImage: image)
.contentTransition(.numericText())
.foregroundStyle(fgColor)
}
TextField("", text: $importStr)
Button() {
withAnimation {
showAlert.toggle()
}
} label: {
Label("Import", systemImage: "tray.and.arrow.down.fill")
}
.disabled(importStr.isEmpty)
.onAppear() {
importStr = ""
image = "clock.fill"
text = "Ready..."
fgColor = .yellow
}
}
.blur(radius: showAlert ? 2 : 0)
Group {
Rectangle()
.frame(maxWidth: .infinity, maxHeight: .infinity)
.foregroundStyle(replaceCurrentEvents ? .red.opacity(0.25) : .black.opacity(0.2))
.animation(.default, value: replaceCurrentEvents)
.ignoresSafeArea()
ZStack {
Rectangle()
.clipShape(RoundedRectangle(cornerRadius: 25))
VStack(alignment: .center) {
Text("Are you sure?")
.font(.largeTitle)
.bold()
.foregroundStyle(replaceCurrentEvents ? .red : .two)
.animation(.default, value: replaceCurrentEvents)
Text("This will replace your current events!")
.lineLimit(nil)
.multilineTextAlignment(.center)
.opacity(replaceCurrentEvents ? 1 : 0)
.animation(.default, value: replaceCurrentEvents)
.foregroundStyle(.two)
Toggle("Replace Events", isOn: $replaceCurrentEvents)
.foregroundStyle(.two)
Spacer()
HStack {
Button() {
withAnimation {
showAlert.toggle()
}
importEvents()
} label: {
Text("cancel")
.font(.title2)
.bold()
}
.buttonStyle(BorderedProminentButtonStyle())
Spacer()
Button() {
withAnimation {
showAlert.toggle()
}
importEvents()
} label: {
Text("yes")
.font(.title2)
.bold()
}
.buttonStyle(BorderedProminentButtonStyle())
}
.padding()
}
.padding()
}
.frame(maxWidth: 250, maxHeight: 250)
}
.opacity(showAlert ? 1 : 0)
}
}
}

View File

@@ -95,8 +95,11 @@ struct SettingsView: View {
List {
if !settingsModel.notifsGranted {
Button("Request Notifications") {
Task {
settingsModel.notifsGranted = await requestNotifs()
Task.detached {
let requestNotifsResult = await requestNotifs()
await MainActor.run {
settingsModel.notifsGranted = requestNotifsResult
}
}
}
Text("\(Image(systemName: "xmark")) Notifications disabled for Near Future")

View File

@@ -16,7 +16,7 @@ struct WhatsNewView: View {
var title: String
var subtitle: String
}
@State var bye = false
@State var bye: Bool = false
var whatsNewChunks: [WhatsNewChunk] {
return [
WhatsNewChunk(
@@ -92,11 +92,6 @@ struct WhatsNewView: View {
}
.scrollContentBackground(.hidden)
.presentationDragIndicator(.visible)
.apply {
if #available(iOS 16.4, *) {
$0.presentationBackground(.ultraThinMaterial)
}
}
.onDisappear {
settingsModel.settings.prevAppVersion = getVersion()+getBuildID()
settingsModel.saveSettings()

View File

@@ -1,16 +0,0 @@
//
// NearFutureTests.swift
// NearFutureTests
//
// Created by neon443 on 26/03/2025.
//
import Testing
struct NearFutureTests {
@Test func example() async throws {
// Write your test here and use APIs like `#expect(...)` to check expected conditions.
}
}

View File

@@ -31,54 +31,70 @@
"size" : "1024x1024"
},
{
"filename" : "MacNearFutureIcon16.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "16x16"
},
{
"filename" : "MacNearFutureIcon32.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "16x16"
},
{
"filename" : "MacNearFutureIcon32.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "32x32"
},
{
"filename" : "MacNearFutureIcon64.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "32x32"
},
{
"filename" : "MacNearFutureIcon128.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "128x128"
},
{
"filename" : "MacNearFutureIcon256.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "128x128"
},
{
"filename" : "MacNearFutureIcon256.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "256x256"
},
{
"filename" : "MacNearFutureIcon512.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "256x256"
},
{
"filename" : "MacNearFutureIcon512.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "512x512"
},
{
"filename" : "MacNearFutureIcon.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "512x512"
},
{
"filename" : "NearFutureIcon.png",
"idiom" : "universal",
"platform" : "watchos",
"size" : "1024x1024"
}
],
"info" : {

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 893 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

@@ -29,6 +29,12 @@
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
},
{
"filename" : "bloo.png",
"idiom" : "universal",
"platform" : "watchos",
"size" : "1024x1024"
}
],
"info" : {

View File

@@ -29,6 +29,12 @@
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
},
{
"filename" : "blue.png",
"idiom" : "universal",
"platform" : "watchos",
"size" : "1024x1024"
}
],
"info" : {

View File

@@ -29,6 +29,12 @@
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
},
{
"filename" : "green.png",
"idiom" : "universal",
"platform" : "watchos",
"size" : "1024x1024"
}
],
"info" : {

View File

@@ -29,6 +29,12 @@
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
},
{
"filename" : "pink.png",
"idiom" : "universal",
"platform" : "watchos",
"size" : "1024x1024"
}
],
"info" : {

View File

@@ -29,6 +29,12 @@
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
},
{
"filename" : "purple.png",
"idiom" : "universal",
"platform" : "watchos",
"size" : "1024x1024"
}
],
"info" : {

View File

@@ -29,6 +29,12 @@
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
},
{
"filename" : "red.png",
"idiom" : "universal",
"platform" : "watchos",
"size" : "1024x1024"
}
],
"info" : {

View File

@@ -29,6 +29,12 @@
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
},
{
"filename" : "yellow.png",
"idiom" : "universal",
"platform" : "watchos",
"size" : "1024x1024"
}
],
"info" : {

View File

Binary file not shown.

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 551 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

View File

@@ -0,0 +1,50 @@
{
"fill" : {
"linear-gradient" : [
"display-p3:0.12307,0.73184,0.43944,1.00000",
"display-p3:0.12142,0.28022,0.58006,1.00000"
]
},
"groups" : [
{
"layers" : [
{
"fill" : {
"automatic-gradient" : "display-p3:1.00000,0.30347,0.00000,1.00000"
},
"image-name" : "Rounded Rectangle.png",
"name" : "Rounded Rectangle",
"position" : {
"scale" : 1,
"translation-in-points" : [
-466.2265625,
37.9921875
]
}
},
{
"fill" : {
"automatic-gradient" : "display-p3:0.96611,0.36599,0.00000,1.00000"
},
"hidden" : false,
"image-name" : "Oval copy.png",
"name" : "Oval copy"
}
],
"shadow" : {
"kind" : "neutral",
"opacity" : 0.5
},
"translucency" : {
"enabled" : true,
"value" : 0.5
}
}
],
"supported-platforms" : {
"circles" : [
"watchOS"
],
"squares" : "shared"
}
}

39
Shared/Extensions.swift Normal file
View File

@@ -0,0 +1,39 @@
//
// Extension.swift
// NearFuture
//
// Created by neon443 on 21/05/2025.
//
import Foundation
import SwiftUI
extension View {
var backgroundGradient: some View {
return LinearGradient(
gradient: Gradient(colors: [.bgTop, .two]),
startPoint: .top,
endPoint: .bottom
)
.ignoresSafeArea(.all)
}
func apply<V: View>(@ViewBuilder _ block: (Self) -> V) -> V { block(self) }
}
extension AnyTransition {
static var moveAndFade: AnyTransition {
.asymmetric(
insertion: .move(edge: .leading),
removal: .move(edge: .trailing)
)
.combined(with: .opacity)
}
static var moveAndFadeReversed: AnyTransition {
.asymmetric(
insertion: .move(edge: .trailing),
removal: .move(edge: .leading)
)
.combined(with: .opacity)
}
}

View File

@@ -11,6 +11,11 @@ import SwiftUI
import WidgetKit
import UserNotifications
import AppIntents
import AudioToolbox
#if canImport(AppKit)
import AppKit
import IOKit
#endif
//@Model
//final class Item {
@@ -39,21 +44,44 @@ struct Event: Identifiable, Codable, Equatable, Animatable {
struct ColorCodable: Codable, Equatable {
init(_ color: Color) {
let uiColor = UIColor(color)
var r: CGFloat = 0, g: CGFloat = 0, b: CGFloat = 0, a: CGFloat = 1.0
uiColor.getRed(&r, green: &g, blue: &b, alpha: &a)
var r: CGFloat = 0, g: CGFloat = 0, b: CGFloat = 0, a: CGFloat = 1
self.red = Double(r)
self.green = Double(g)
self.blue = Double(b)
#if canImport(UIKit)
let uiColor = UIColor(color)
uiColor.getRed(&r, green: &g, blue: &b, alpha: &a)
#elseif canImport(AppKit)
let nscolor = NSColor(color).usingColorSpace(.deviceRGB)
nscolor!.getRed(&r, green: &g, blue: &b, alpha: &a)
#endif
self = ColorCodable(
red: r,
green: g,
blue: b
)
}
#if canImport(UIKit)
init(uiColor: UIColor) {
var r: CGFloat = 0, g: CGFloat = 0, b: CGFloat = 0, a: CGFloat = 1.0
uiColor.getRed(&r, green: &g, blue: &b, alpha: &a)
self.red = Double(r)
self.green = Double(g)
self.blue = Double(b)
self = ColorCodable(
red: r,
green: g,
blue: b
)
}
#elseif canImport(AppKit)
init(nsColor: NSColor) {
var r: CGFloat = 0, g: CGFloat = 0, b: CGFloat = 0, a: CGFloat = 1.0
let nsColor = nsColor.usingColorSpace(.deviceRGB)
nsColor!.getRed(&r, green: &g, blue: &b, alpha: &a)
self = ColorCodable(
red: r,
green: g,
blue: b
)
}
#endif
init(red: Double, green: Double, blue: Double) {
self.red = red
self.green = green
@@ -93,114 +121,18 @@ func daysUntilEvent(_ eventDate: Date) -> (long: String, short: String) {
if days < 0 {
//past
return (
"\(-days) day\(plu(days)) ago",
"\(-days)\nday\(plu(days)) ago",
"\(days)d"
)
} else {
//future
return (
"\(days) day\(plu(days))",
"\(days)\nday\(plu(days))",
"\(days)d"
)
}
}
struct Settings: Codable, Equatable {
var showCompletedInHome: Bool
var tint: ColorCodable
var showWhatsNew: Bool
var prevAppVersion: String
}
struct AccentIcon {
var icon: UIImage
var color: Color
var name: String
init(_ colorName: String) {
if colorName == "orange" {
self.icon = UIImage(named: "AppIcon")!
} else {
self.icon = UIImage(named: colorName)!
}
self.color = Color(uiColor: UIColor(named: "uiColors/\(colorName)")!)
self.name = colorName
}
}
class SettingsViewModel: ObservableObject {
@Published var settings: Settings = Settings(
showCompletedInHome: false,
tint: ColorCodable(uiColor: UIColor(named: "AccentColor")!),
showWhatsNew: true,
prevAppVersion: getVersion()+getBuildID()
)
@Published var notifsGranted: Bool = false
@Published var colorChoices: [AccentIcon] = []
let accentChoices: [String] = [
"red",
"orange",
"yellow",
"green",
"blue",
"bloo",
"purple",
"pink"
]
@Published var device: (sf: String, label: String)
init(load: Bool = true) {
self.device = getDevice()
if load {
loadSettings()
Task {
let requestResult = await requestNotifs()
await MainActor.run {
self.notifsGranted = requestResult
}
}
}
}
func changeTint(to: String) {
if let uicolor = UIColor(named: "uiColors/\(to)") {
self.settings.tint = ColorCodable(uiColor: uicolor)
saveSettings()
}
}
let appGroupSettingsStore = UserDefaults(suiteName: "group.NearFuture") ?? UserDefaults.standard
let icSettStore = NSUbiquitousKeyValueStore.default
func loadSettings() {
let decoder = JSONDecoder()
if let icSettings = icSettStore.data(forKey: "settings") {
if let decodedSetts = try? decoder.decode(Settings.self, from: icSettings) {
self.settings = decodedSetts
}
} else if let savedData = appGroupSettingsStore.data(forKey: "settings") {
if let decodedSetts = try? decoder.decode(Settings.self, from: savedData) {
self.settings = decodedSetts
}
}
if self.settings.prevAppVersion != getVersion()+getBuildID() {
self.settings.showWhatsNew = true
}
}
func saveSettings() {
let encoder = JSONEncoder()
if let encoded = try? encoder.encode(settings) {
appGroupSettingsStore.set(encoded, forKey: "settings")
icSettStore.set(encoded, forKey: "settings")
icSettStore.synchronize()
loadSettings()
}
}
}
class EventViewModel: ObservableObject, @unchecked Sendable {
@Published var events: [Event] = []
@Published var icloudData: [Event] = []
@@ -237,6 +169,7 @@ class EventViewModel: ObservableObject, @unchecked Sendable {
if load {
loadEvents()
}
// AudioServicesPlaySystemSound(kSystemSoundID_Vibrate)
}
//appgroup or regular userdefaults
@@ -315,8 +248,8 @@ class EventViewModel: ObservableObject, @unchecked Sendable {
updateSyncStatus()
loadEvents()
Task {
await checkPendingNotifs(getNotifs())
Task.detached {
await self.checkPendingNotifs(self.getNotifs())
}
WidgetCenter.shared.reloadAllTimelines()//reload all widgets when saving events
objectWillChange.send()
@@ -392,14 +325,18 @@ class EventViewModel: ObservableObject, @unchecked Sendable {
return ""
}
func importEvents(_ imported: String) throws {
func importEvents(_ imported: String, replace: Bool) throws {
guard let data = Data(base64Encoded: imported) else {
throw importError.invalidB64
}
let decoder = JSONDecoder()
do {
let decoded = try decoder.decode([Event].self, from: data)
self.events = decoded
if replace {
self.events = decoded
} else {
self.events = self.events + decoded
}
saveEvents()
} catch {
throw error
@@ -451,7 +388,7 @@ class EventViewModel: ObservableObject, @unchecked Sendable {
}
}
class dummyEventViewModel: EventViewModel, @unchecked Sendable {
class dummyEventViewModel: EventViewModel, @unchecked Sendable{
var template2: Event
override init(load: Bool = false) {
self.template2 = Event(
@@ -580,6 +517,7 @@ func getBuildID() -> String {
}
func getDevice() -> (sf: String, label: String) {
#if canImport(UIKit)
let asi = ProcessInfo().isiOSAppOnMac
let model = UIDevice().model
if asi {
@@ -590,6 +528,10 @@ func getDevice() -> (sf: String, label: String) {
return (sf: model.lowercased(), label: model)
}
return (sf: "iphone", label: "iPhone")
#elseif canImport(AppKit)
return (sf: "desktopcomputer", label: "Mac")
#endif
}
extension Event: AppEntity {

129
Shared/Model/Settings.swift Normal file
View File

@@ -0,0 +1,129 @@
//
// Settings.swift
// MacNearFuture
//
// Created by neon443 on 21/05/2025.
//
import Foundation
import SwiftUI
#if canImport(AppKit)
import AppKit
#endif
struct NFSettings: Codable, Equatable {
var showCompletedInHome: Bool = false
var tint: ColorCodable = ColorCodable(.accentColor)
var showWhatsNew: Bool = true
var prevAppVersion: String = getVersion()+getBuildID()
}
class AccentIcon {
#if canImport(UIKit)
var icon: UIImage
#elseif canImport(AppKit)
var icon: NSImage
#endif
var color: Color
var name: String
init(_ colorName: String) {
#if canImport(UIKit)
self.icon = UIImage(named: "AppIcon")!
self.color = Color(uiColor: UIColor(named: "uiColors/\(colorName)")!)
#elseif canImport(AppKit)
self.icon = NSImage(imageLiteralResourceName: "AppIcon")
self.color = Color(nsColor: NSColor(named: "uiColors/\(colorName)")!)
#endif
self.name = colorName
if colorName != "orange" {
setSelfIcon(to: colorName)
}
}
func setSelfIcon(to name: String) {
#if canImport(UIKit)
self.icon = UIImage(named: name)!
#elseif canImport(AppKit)
self.icon = NSImage(imageLiteralResourceName: name)
#endif
}
}
class SettingsViewModel: ObservableObject {
@Published var settings: NFSettings = NFSettings()
@Published var notifsGranted: Bool = false
@Published var colorChoices: [AccentIcon] = []
let accentChoices: [String] = [
"red",
"orange",
"yellow",
"green",
"blue",
"bloo",
"purple",
"pink"
]
@Published var device: (sf: String, label: String)
init(load: Bool = true) {
self.device = getDevice()
if load {
loadSettings()
Task.detached {
let requestResult = await requestNotifs()
await MainActor.run {
self.notifsGranted = requestResult
}
}
}
}
func changeTint(to: String) {
#if canImport(UIKit)
if let uicolor = UIColor(named: "uiColors/\(to)") {
self.settings.tint = ColorCodable(uiColor: uicolor)
saveSettings()
}
#elseif canImport(AppKit)
if let nscolor = NSColor(named: "uiColors/\(to)") {
self.settings.tint = ColorCodable(nsColor: nscolor)
}
#endif
}
let appGroupSettingsStore = UserDefaults(suiteName: "group.NearFuture") ?? UserDefaults.standard
let icSettStore = NSUbiquitousKeyValueStore.default
func loadSettings() {
let decoder = JSONDecoder()
if let icSettings = icSettStore.data(forKey: "settings") {
if let decodedSetts = try? decoder.decode(NFSettings.self, from: icSettings) {
self.settings = decodedSetts
}
} else if let savedData = appGroupSettingsStore.data(forKey: "settings") {
if let decodedSetts = try? decoder.decode(NFSettings.self, from: savedData) {
self.settings = decodedSetts
}
}
if self.settings.prevAppVersion != getVersion()+getBuildID() {
self.settings.showWhatsNew = true
}
}
func saveSettings() {
let encoder = JSONEncoder()
if let encoded = try? encoder.encode(settings) {
appGroupSettingsStore.set(encoded, forKey: "settings")
icSettStore.set(encoded, forKey: "settings")
icSettStore.synchronize()
loadSettings()
}
}
}

View File

@@ -0,0 +1,23 @@
//
// NearFutureApp.swift
// NearFuture
//
// Created by neon443 on 24/12/2024.
//
import SwiftUI
import SwiftData
@main
struct NearFutureApp: App {
@StateObject var settingsModel: SettingsViewModel = SettingsViewModel()
var body: some Scene {
WindowGroup {
ContentView(
viewModel: EventViewModel(),
settingsModel: settingsModel
)
.tint(settingsModel.settings.tint.color)
}
}
}