Compare commits
1 Commits
a40d4f4300
...
feat-inten
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ca64157923 |
@@ -12,6 +12,6 @@ TEAM_ID = 8JGND254B7
|
|||||||
BUNDLE_ID = com.neon443.NearFuture
|
BUNDLE_ID = com.neon443.NearFuture
|
||||||
BUNDLE_ID_WIDGETS = com.neon443.NearFuture.widgets
|
BUNDLE_ID_WIDGETS = com.neon443.NearFuture.widgets
|
||||||
GROUP_ID = group.NearFuture
|
GROUP_ID = group.NearFuture
|
||||||
VERSION = 5
|
VERSION = 4.4.0
|
||||||
NAME = Near Future
|
NAME = Near Future
|
||||||
BUILD_NUMBER = 1
|
BUILD_NUMBER = 1
|
||||||
|
|||||||
@@ -1,40 +0,0 @@
|
|||||||
//
|
|
||||||
// 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()
|
|
||||||
}
|
|
||||||
@@ -1,18 +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>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>
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
//
|
|
||||||
// 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 Near Future") {
|
|
||||||
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 {
|
|
||||||
SettingsView(
|
|
||||||
viewModel: viewModel,
|
|
||||||
settingsModel: settingsModel
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
//
|
|
||||||
// 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")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
//
|
|
||||||
// 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()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
//
|
|
||||||
// ContentView.swift
|
|
||||||
// MacNearFuture
|
|
||||||
//
|
|
||||||
// Created by neon443 on 21/05/2025.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
struct ContentView: View {
|
|
||||||
@StateObject var viewModel: EventViewModel
|
|
||||||
@StateObject var settingsModel: SettingsViewModel
|
|
||||||
|
|
||||||
@State private var showAddEventView: Bool = false
|
|
||||||
@State private var symbolSearchInput: String = ""
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
NavigationSplitView {
|
|
||||||
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")
|
|
||||||
}
|
|
||||||
NavigationLink {
|
|
||||||
SymbolsPicker(
|
|
||||||
selection: $symbolSearchInput
|
|
||||||
)
|
|
||||||
} label: {
|
|
||||||
Image(systemName: "star.circle")
|
|
||||||
Text("Symbols")
|
|
||||||
}
|
|
||||||
NavigationLink {
|
|
||||||
SettingsView(
|
|
||||||
viewModel: viewModel,
|
|
||||||
settingsModel: settingsModel
|
|
||||||
)
|
|
||||||
} label: {
|
|
||||||
Image(systemName: "gear")
|
|
||||||
Text("Settings")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} detail: {
|
|
||||||
Text("Welcome to Near Future")
|
|
||||||
}
|
|
||||||
.tint(settingsModel.settings.tint.color)
|
|
||||||
.frame(minWidth: 450, minHeight: 550)
|
|
||||||
.containerBackground(.regularMaterial, for: .window)
|
|
||||||
.sheet(isPresented: $settingsModel.settings.showWhatsNew) {
|
|
||||||
WhatsNewView(settingsModel: settingsModel)
|
|
||||||
.presentationSizing(.form)
|
|
||||||
}
|
|
||||||
.sheet(isPresented: $showAddEventView) {
|
|
||||||
AddEventView(
|
|
||||||
viewModel: viewModel,
|
|
||||||
event: $viewModel.editableTemplate,
|
|
||||||
adding: true
|
|
||||||
)
|
|
||||||
.presentationSizing(.page)
|
|
||||||
}
|
|
||||||
.toolbar {
|
|
||||||
Button() {
|
|
||||||
showAddEventView.toggle()
|
|
||||||
} label: {
|
|
||||||
Image(systemName: "plus")
|
|
||||||
Text("New")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#Preview {
|
|
||||||
ContentView(
|
|
||||||
viewModel: dummyEventViewModel(),
|
|
||||||
settingsModel: dummySettingsViewModel()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,180 +0,0 @@
|
|||||||
//
|
|
||||||
// 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
|
|
||||||
)
|
|
||||||
}
|
|
||||||
.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
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
//
|
|
||||||
// HomeView.swift
|
|
||||||
// MacNearFuture
|
|
||||||
//
|
|
||||||
// Created by neon443 on 28/05/2025.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
struct HomeView: View {
|
|
||||||
@StateObject var viewModel: EventViewModel
|
|
||||||
@StateObject var settingsModel: SettingsViewModel
|
|
||||||
|
|
||||||
@State private var searchInput: String = ""
|
|
||||||
|
|
||||||
var filteredEvents: [Event] {
|
|
||||||
if searchInput.isEmpty {
|
|
||||||
if settingsModel.settings.showCompletedInHome {
|
|
||||||
return viewModel.events
|
|
||||||
} else {
|
|
||||||
return viewModel.events.filter() { !$0.complete }
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return viewModel.events.filter {
|
|
||||||
$0.name.localizedCaseInsensitiveContains(searchInput) ||
|
|
||||||
$0.notes.localizedCaseInsensitiveContains(searchInput)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
ScrollView {
|
|
||||||
ForEach(viewModel.events) { event in
|
|
||||||
if filteredEvents.contains(event) {
|
|
||||||
EventListView(viewModel: viewModel, event: event)
|
|
||||||
.id(event)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.searchable(text: $searchInput)
|
|
||||||
.scrollContentBackground(.hidden)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#Preview {
|
|
||||||
HomeView(
|
|
||||||
viewModel: dummyEventViewModel(),
|
|
||||||
settingsModel: dummySettingsViewModel()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,155 +0,0 @@
|
|||||||
//
|
|
||||||
// SettingsView.swift
|
|
||||||
// NearFuture
|
|
||||||
//
|
|
||||||
// Created by neon443 on 13/06/2025.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
struct SettingsView: View {
|
|
||||||
@ObservedObject var viewModel: EventViewModel
|
|
||||||
@ObservedObject var settingsModel: SettingsViewModel
|
|
||||||
|
|
||||||
@State private var importStr: String = ""
|
|
||||||
|
|
||||||
func changeIcon(to toIcon: String) {
|
|
||||||
if let nsimage = NSImage(named: toIcon) {
|
|
||||||
let nsImageView = NSImageView(image: nsimage)
|
|
||||||
nsImageView.frame = NSRect(x: 0, y: 0, width: 128, height: 128)
|
|
||||||
NSApplication.shared.dockTile.contentView = nsImageView
|
|
||||||
NSApplication.shared.dockTile.display()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
NavigationStack {
|
|
||||||
List {
|
|
||||||
ScrollView(.horizontal) {
|
|
||||||
HStack {
|
|
||||||
ForEach(settingsModel.accentChoices, id: \.self) { choice in
|
|
||||||
let color = Color(nsColor: NSColor(named: "uiColors/\(choice)")!)
|
|
||||||
ZStack {
|
|
||||||
Button() {
|
|
||||||
settingsModel.changeTint(to: choice)
|
|
||||||
changeIcon(to: choice)
|
|
||||||
} label: {
|
|
||||||
Circle()
|
|
||||||
.foregroundStyle(color)
|
|
||||||
.frame(width: 30)
|
|
||||||
}
|
|
||||||
.buttonStyle(.plain)
|
|
||||||
if ColorCodable(color) == settingsModel.settings.tint {
|
|
||||||
let needContrast: Bool = ColorCodable(color) == settingsModel.settings.tint
|
|
||||||
Circle()
|
|
||||||
.foregroundStyle(needContrast ? .two : .one)
|
|
||||||
.frame(width: 10)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Button("Show What's New") {
|
|
||||||
settingsModel.settings.showWhatsNew = true
|
|
||||||
}
|
|
||||||
Toggle("Show completed Events in Home", isOn: $settingsModel.settings.showCompletedInHome)
|
|
||||||
.onChange(of: settingsModel.settings.showCompletedInHome) { _ in
|
|
||||||
settingsModel.saveSettings()
|
|
||||||
}
|
|
||||||
NavigationLink() {
|
|
||||||
List {
|
|
||||||
if !settingsModel.notifsGranted {
|
|
||||||
Text("\(Image(systemName: "xmark")) Notifications disabled for Near Future")
|
|
||||||
.foregroundStyle(.red)
|
|
||||||
Button("Request Notifications") {
|
|
||||||
Task.detached {
|
|
||||||
let requestNotifsResult = await requestNotifs()
|
|
||||||
await MainActor.run {
|
|
||||||
settingsModel.notifsGranted = requestNotifsResult
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Text("\(Image(systemName: "checkmark")) Notifications enabled for Near Future")
|
|
||||||
.foregroundStyle(.green)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} label: {
|
|
||||||
Image(systemName: "bell.badge.fill")
|
|
||||||
Text("Notifications")
|
|
||||||
}
|
|
||||||
NavigationLink() {
|
|
||||||
iCloudSettingsView(
|
|
||||||
viewModel: viewModel,
|
|
||||||
settingsModel: settingsModel
|
|
||||||
)
|
|
||||||
} label: {
|
|
||||||
HStack {
|
|
||||||
Image(systemName: "icloud.fill")
|
|
||||||
Text("iCloud")
|
|
||||||
Spacer()
|
|
||||||
Circle()
|
|
||||||
.frame(width: 20, height: 20)
|
|
||||||
.foregroundStyle(viewModel.iCloudStatusColor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.onAppear {
|
|
||||||
viewModel.sync()
|
|
||||||
viewModel.updateiCStatus()
|
|
||||||
}
|
|
||||||
NavigationLink() {
|
|
||||||
ImportView(viewModel: viewModel, importStr: $importStr)
|
|
||||||
} label: {
|
|
||||||
Label("Import Events", systemImage: "tray.and.arrow.down.fill")
|
|
||||||
.foregroundStyle(.one)
|
|
||||||
}
|
|
||||||
NavigationLink() {
|
|
||||||
ExportView(viewModel: viewModel)
|
|
||||||
} label: {
|
|
||||||
Label("Export Events", systemImage: "square.and.arrow.up")
|
|
||||||
.foregroundStyle(.one)
|
|
||||||
}
|
|
||||||
|
|
||||||
Text("Tip")
|
|
||||||
.font(.subheadline)
|
|
||||||
Text("Near Future has Widgets!")
|
|
||||||
|
|
||||||
Text("Danger Zone")
|
|
||||||
.foregroundStyle(.red)
|
|
||||||
.font(.subheadline)
|
|
||||||
Button("Delete local data", role: .destructive) {
|
|
||||||
viewModel.dangerClearLocalData()
|
|
||||||
}
|
|
||||||
Button("Delete iCloud data", role: .destructive) {
|
|
||||||
viewModel.dangerCleariCloudData()
|
|
||||||
}
|
|
||||||
Button("Delete all data", role: .destructive) {
|
|
||||||
viewModel.dangerClearLocalData()
|
|
||||||
viewModel.dangerCleariCloudData()
|
|
||||||
}
|
|
||||||
|
|
||||||
Text("Debug")
|
|
||||||
.foregroundStyle(.red)
|
|
||||||
.font(.subheadline)
|
|
||||||
Button("Reset UserDefaults", role: .destructive) {
|
|
||||||
viewModel.dangerResetLocalData()
|
|
||||||
}
|
|
||||||
Button("Reset iCloud", role: .destructive) {
|
|
||||||
viewModel.dangerResetiCloud()
|
|
||||||
}
|
|
||||||
|
|
||||||
// AboutView()
|
|
||||||
|
|
||||||
.modifier(navigationInlineLarge())
|
|
||||||
.scrollContentBackground(.hidden)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#Preview {
|
|
||||||
SettingsView(
|
|
||||||
viewModel: dummyEventViewModel(),
|
|
||||||
settingsModel: dummySettingsViewModel()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -7,44 +7,14 @@
|
|||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* 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 */; };
|
|
||||||
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 */; };
|
A914FA4B2DD26C6800856265 /* HomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A914FA4A2DD26C0F00856265 /* HomeView.swift */; };
|
||||||
A914FA4D2DD2768900856265 /* WhatsNewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A914FA4C2DD2768900856265 /* WhatsNewView.swift */; };
|
A914FA4D2DD2768900856265 /* WhatsNewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A914FA4C2DD2768900856265 /* WhatsNewView.swift */; };
|
||||||
A914FA4F2DD276D200856265 /* AboutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A914FA4E2DD276D200856265 /* AboutView.swift */; };
|
A914FA4F2DD276D200856265 /* AboutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A914FA4E2DD276D200856265 /* AboutView.swift */; };
|
||||||
A91EF8072DFC8B8B00B8463D /* ColorCodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91EF8062DFC8B8B00B8463D /* ColorCodable.swift */; };
|
|
||||||
A91EF8082DFC8B8B00B8463D /* ColorCodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91EF8062DFC8B8B00B8463D /* ColorCodable.swift */; };
|
|
||||||
A91EF8092DFC8B8B00B8463D /* ColorCodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91EF8062DFC8B8B00B8463D /* ColorCodable.swift */; };
|
|
||||||
A91EF80B2DFC910000B8463D /* ViewModifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91EF80A2DFC910000B8463D /* ViewModifiers.swift */; };
|
|
||||||
A91EF80C2DFC910000B8463D /* ViewModifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91EF80A2DFC910000B8463D /* ViewModifiers.swift */; };
|
|
||||||
A91EF80D2DFC910000B8463D /* ViewModifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91EF80A2DFC910000B8463D /* ViewModifiers.swift */; };
|
|
||||||
A91EF80E2DFC9A0C00B8463D /* WhatsNewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A914FA4C2DD2768900856265 /* WhatsNewView.swift */; };
|
|
||||||
A91EF8102DFCB66C00B8463D /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91EF80F2DFCB66C00B8463D /* SettingsView.swift */; };
|
|
||||||
A91EF8132DFCC87D00B8463D /* EditEventView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A949F83D2DCAABE00064DCA0 /* EditEventView.swift */; };
|
|
||||||
A91EF8142DFCC87D00B8463D /* AddEventView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A949F83C2DCAABE00064DCA0 /* AddEventView.swift */; };
|
|
||||||
A91EF8182DFD77BF00B8463D /* SymbolsLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91EF8172DFD77BF00B8463D /* SymbolsLoader.swift */; };
|
|
||||||
A91EF8192DFD77BF00B8463D /* SymbolsLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91EF8172DFD77BF00B8463D /* SymbolsLoader.swift */; };
|
|
||||||
A91EF81A2DFD77BF00B8463D /* SymbolsLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91EF8172DFD77BF00B8463D /* SymbolsLoader.swift */; };
|
|
||||||
A91EF81C2DFD796600B8463D /* SymbolsPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91EF81B2DFD796600B8463D /* SymbolsPicker.swift */; };
|
|
||||||
A91EF81D2DFD796600B8463D /* SymbolsPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91EF81B2DFD796600B8463D /* SymbolsPicker.swift */; };
|
|
||||||
A91EF81E2DFD796600B8463D /* SymbolsPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91EF81B2DFD796600B8463D /* SymbolsPicker.swift */; };
|
|
||||||
A920C2882D24011400E4F9B1 /* NearFutureApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = A920C2872D24011400E4F9B1 /* NearFutureApp.swift */; };
|
A920C2882D24011400E4F9B1 /* NearFutureApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = A920C2872D24011400E4F9B1 /* NearFutureApp.swift */; };
|
||||||
A920C28C2D24011400E4F9B1 /* Events.swift in Sources */ = {isa = PBXBuildFile; fileRef = A920C28B2D24011400E4F9B1 /* Events.swift */; };
|
A920C28C2D24011400E4F9B1 /* Item.swift in Sources */ = {isa = PBXBuildFile; fileRef = A920C28B2D24011400E4F9B1 /* Item.swift */; };
|
||||||
A920C28E2D24011A00E4F9B1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A920C28D2D24011A00E4F9B1 /* Assets.xcassets */; };
|
A920C28E2D24011A00E4F9B1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A920C28D2D24011A00E4F9B1 /* Assets.xcassets */; };
|
||||||
A920C2922D24011A00E4F9B1 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A920C2912D24011A00E4F9B1 /* Preview Assets.xcassets */; };
|
A920C2922D24011A00E4F9B1 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A920C2912D24011A00E4F9B1 /* Preview Assets.xcassets */; };
|
||||||
|
A920C2BE2D24021A00E4F9B1 /* SFSymbolsPicker in Frameworks */ = {isa = PBXBuildFile; productRef = A920C2BD2D24021A00E4F9B1 /* SFSymbolsPicker */; };
|
||||||
A949F8322DCAAA8A0064DCA0 /* NearFutureIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = A949F8312DCAAA8A0064DCA0 /* NearFutureIcon.png */; };
|
A949F8322DCAAA8A0064DCA0 /* NearFutureIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = A949F8312DCAAA8A0064DCA0 /* NearFutureIcon.png */; };
|
||||||
A949F84B2DCAABE00064DCA0 /* ArchiveView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A949F83A2DCAABE00064DCA0 /* ArchiveView.swift */; };
|
A949F84B2DCAABE00064DCA0 /* ArchiveView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A949F83A2DCAABE00064DCA0 /* ArchiveView.swift */; };
|
||||||
A949F84C2DCAABE00064DCA0 /* AddEventView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A949F83C2DCAABE00064DCA0 /* AddEventView.swift */; };
|
A949F84C2DCAABE00064DCA0 /* AddEventView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A949F83C2DCAABE00064DCA0 /* AddEventView.swift */; };
|
||||||
@@ -57,28 +27,16 @@
|
|||||||
A949F8532DCAABE00064DCA0 /* ImportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A949F8452DCAABE00064DCA0 /* ImportView.swift */; };
|
A949F8532DCAABE00064DCA0 /* ImportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A949F8452DCAABE00064DCA0 /* ImportView.swift */; };
|
||||||
A949F8542DCAABE00064DCA0 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A949F8462DCAABE00064DCA0 /* SettingsView.swift */; };
|
A949F8542DCAABE00064DCA0 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A949F8462DCAABE00064DCA0 /* SettingsView.swift */; };
|
||||||
A949F8552DCAABE00064DCA0 /* StatsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A949F8482DCAABE00064DCA0 /* StatsView.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 */; };
|
A949F85F2DCABB420064DCA0 /* Buttons.swift in Sources */ = {isa = PBXBuildFile; fileRef = A949F85D2DCABB420064DCA0 /* Buttons.swift */; };
|
||||||
A95E9ED32DFC703200ED655F /* iCloudSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A949F8442DCAABE00064DCA0 /* iCloudSettingsView.swift */; };
|
A979F6052D270AF00094C0B3 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A979F6042D270AF00094C0B3 /* WidgetKit.framework */; };
|
||||||
A95E9ED82DFC742B00ED655F /* AccentIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = A95E9ED72DFC742B00ED655F /* AccentIcon.swift */; };
|
A979F6072D270AF00094C0B3 /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A979F6062D270AF00094C0B3 /* SwiftUI.framework */; };
|
||||||
A95E9ED92DFC742B00ED655F /* AccentIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = A95E9ED72DFC742B00ED655F /* AccentIcon.swift */; };
|
|
||||||
A95E9EDA2DFC742B00ED655F /* AccentIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = A95E9ED72DFC742B00ED655F /* AccentIcon.swift */; };
|
|
||||||
A95E9EE42DFC77D400ED655F /* ImportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A949F8452DCAABE00064DCA0 /* ImportView.swift */; };
|
|
||||||
A95E9EE52DFC77E200ED655F /* ExportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A949F8432DCAABE00064DCA0 /* ExportView.swift */; };
|
|
||||||
A96609E72DFD800000DBFA78 /* HelpView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A949F8412DCAABE00064DCA0 /* HelpView.swift */; };
|
|
||||||
A979F60A2D270AF00094C0B3 /* NearFutureWidgetsBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = A979F6092D270AF00094C0B3 /* NearFutureWidgetsBundle.swift */; };
|
A979F60A2D270AF00094C0B3 /* NearFutureWidgetsBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = A979F6092D270AF00094C0B3 /* NearFutureWidgetsBundle.swift */; };
|
||||||
A979F60C2D270AF00094C0B3 /* NearFutureWidgetsLiveActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = A979F60B2D270AF00094C0B3 /* NearFutureWidgetsLiveActivity.swift */; };
|
A979F60C2D270AF00094C0B3 /* NearFutureWidgetsLiveActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = A979F60B2D270AF00094C0B3 /* NearFutureWidgetsLiveActivity.swift */; };
|
||||||
A979F6102D270AF90094C0B3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A979F60F2D270AF80094C0B3 /* Assets.xcassets */; };
|
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, ); }; };
|
A979F6142D270AF90094C0B3 /* NearFutureWidgetsExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = A979F6022D270AF00094C0B3 /* NearFutureWidgetsExtension.appex */; platformFilter = ios; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||||
A979F6182D2714310094C0B3 /* Events.swift in Sources */ = {isa = PBXBuildFile; fileRef = A920C28B2D24011400E4F9B1 /* Events.swift */; };
|
A979F6182D2714310094C0B3 /* Item.swift in Sources */ = {isa = PBXBuildFile; fileRef = A920C28B2D24011400E4F9B1 /* Item.swift */; };
|
||||||
A98C20CB2DE730740008D61C /* EventListViewMac.swift in Sources */ = {isa = PBXBuildFile; fileRef = A98C20CA2DE730740008D61C /* EventListViewMac.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 */; };
|
|
||||||
A9C769A22DFDD1FC00082FFF /* SymbolsPicker.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A9C769A02DFDD1FC00082FFF /* SymbolsPicker.storyboard */; };
|
|
||||||
A9C769A32DFDD1FC00082FFF /* SymbolsPicker.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A9C769A02DFDD1FC00082FFF /* SymbolsPicker.storyboard */; };
|
|
||||||
A9C769A52DFDD27500082FFF /* SymbolsPickerStoryboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9C769A42DFDD27500082FFF /* SymbolsPickerStoryboard.swift */; };
|
|
||||||
A9C769A62DFDD27500082FFF /* SymbolsPickerStoryboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9C769A42DFDD27500082FFF /* SymbolsPickerStoryboard.swift */; };
|
|
||||||
A9C769A72DFDD27500082FFF /* SymbolsPickerStoryboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9C769A42DFDD27500082FFF /* SymbolsPickerStoryboard.swift */; };
|
|
||||||
A9FC7EEA2D2823920020D75B /* NearFutureWidgets.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9FC7EE92D28238A0020D75B /* NearFutureWidgets.swift */; };
|
A9FC7EEA2D2823920020D75B /* NearFutureWidgets.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9FC7EE92D28238A0020D75B /* NearFutureWidgets.swift */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
@@ -90,12 +48,12 @@
|
|||||||
remoteGlobalIDString = A979F6012D270AF00094C0B3;
|
remoteGlobalIDString = A979F6012D270AF00094C0B3;
|
||||||
remoteInfo = NearFutureWidgetsExtension;
|
remoteInfo = NearFutureWidgetsExtension;
|
||||||
};
|
};
|
||||||
A98C20D12DE732B10008D61C /* PBXContainerItemProxy */ = {
|
A980FC3B2D93FB2B006A778F /* PBXContainerItemProxy */ = {
|
||||||
isa = PBXContainerItemProxy;
|
isa = PBXContainerItemProxy;
|
||||||
containerPortal = A920C27C2D24011300E4F9B1 /* Project object */;
|
containerPortal = A920C27C2D24011300E4F9B1 /* Project object */;
|
||||||
proxyType = 1;
|
proxyType = 1;
|
||||||
remoteGlobalIDString = A979F6012D270AF00094C0B3;
|
remoteGlobalIDString = A920C2832D24011300E4F9B1;
|
||||||
remoteInfo = NearFutureWidgetsExtension;
|
remoteInfo = NearFuture;
|
||||||
};
|
};
|
||||||
/* End PBXContainerItemProxy section */
|
/* End PBXContainerItemProxy section */
|
||||||
|
|
||||||
@@ -114,29 +72,15 @@
|
|||||||
/* End PBXCopyFilesBuildPhase section */
|
/* End PBXCopyFilesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXFileReference 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>"; };
|
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>"; };
|
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; };
|
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; };
|
A914FA4E2DD276D200856265 /* AboutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AboutView.swift; path = NearFuture/Views/Misc/AboutView.swift; sourceTree = SOURCE_ROOT; };
|
||||||
A91EF8062DFC8B8B00B8463D /* ColorCodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorCodable.swift; sourceTree = "<group>"; };
|
|
||||||
A91EF80A2DFC910000B8463D /* ViewModifiers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewModifiers.swift; sourceTree = "<group>"; };
|
|
||||||
A91EF80F2DFCB66C00B8463D /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
|
|
||||||
A91EF8172DFD77BF00B8463D /* SymbolsLoader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SymbolsLoader.swift; sourceTree = "<group>"; };
|
|
||||||
A91EF81B2DFD796600B8463D /* SymbolsPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SymbolsPicker.swift; sourceTree = "<group>"; };
|
|
||||||
A920C2842D24011400E4F9B1 /* NearFuture.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = NearFuture.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
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>"; };
|
A920C2872D24011400E4F9B1 /* NearFutureApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NearFutureApp.swift; sourceTree = "<group>"; };
|
||||||
A920C28B2D24011400E4F9B1 /* Events.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Events.swift; sourceTree = "<group>"; };
|
A920C28B2D24011400E4F9B1 /* Item.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Item.swift; sourceTree = "<group>"; };
|
||||||
A920C28D2D24011A00E4F9B1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; 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>"; };
|
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>"; };
|
A949F82E2DCAAA640064DCA0 /* NearFutureIcon.pxd */ = {isa = PBXFileReference; lastKnownFileType = file; path = NearFutureIcon.pxd; sourceTree = "<group>"; };
|
||||||
A949F82F2DCAAA640064DCA0 /* NearFutureIconDark.pxd */ = {isa = PBXFileReference; lastKnownFileType = file; path = NearFutureIconDark.pxd; sourceTree = "<group>"; };
|
A949F82F2DCAAA640064DCA0 /* NearFutureIconDark.pxd */ = {isa = PBXFileReference; lastKnownFileType = file; path = NearFutureIconDark.pxd; sourceTree = "<group>"; };
|
||||||
@@ -153,37 +97,46 @@
|
|||||||
A949F8452DCAABE00064DCA0 /* ImportView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImportView.swift; sourceTree = "<group>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
A949F85D2DCABB420064DCA0 /* Buttons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Buttons.swift; sourceTree = "<group>"; };
|
||||||
A95E9ED72DFC742B00ED655F /* AccentIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccentIcon.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; };
|
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>"; };
|
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>"; };
|
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>"; };
|
A979F60F2D270AF80094C0B3 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
A98C20CA2DE730740008D61C /* EventListViewMac.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventListViewMac.swift; sourceTree = "<group>"; };
|
A979F6112D270AF90094C0B3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
A98C20CD2DE7308E0008D61C /* ArchiveView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArchiveView.swift; sourceTree = "<group>"; };
|
A980FC302D920097006A778F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
A98C20CF2DE731BD0008D61C /* HomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeView.swift; sourceTree = "<group>"; };
|
A980FC372D93FB2B006A778F /* NearFutureTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NearFutureTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
A98C20D32DE7339E0008D61C /* AboutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutView.swift; sourceTree = "<group>"; };
|
A9C05E412D2805D7007DC497 /* NearFutureWidgetsExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = NearFutureWidgetsExtension.entitlements; sourceTree = "<group>"; };
|
||||||
A9C769A02DFDD1FC00082FFF /* SymbolsPicker.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = SymbolsPicker.storyboard; sourceTree = "<group>"; };
|
|
||||||
A9C769A42DFDD27500082FFF /* SymbolsPickerStoryboard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SymbolsPickerStoryboard.swift; sourceTree = "<group>"; };
|
|
||||||
A9FC7EE92D28238A0020D75B /* NearFutureWidgets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NearFutureWidgets.swift; sourceTree = "<group>"; };
|
A9FC7EE92D28238A0020D75B /* NearFutureWidgets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NearFutureWidgets.swift; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
A90D49232DDE0FA400781124 /* Frameworks */ = {
|
|
||||||
isa = PBXFrameworksBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
A920C2812D24011300E4F9B1 /* Frameworks */ = {
|
A920C2812D24011300E4F9B1 /* Frameworks */ = {
|
||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
A920C2BE2D24021A00E4F9B1 /* SFSymbolsPicker in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
A979F5FF2D270AF00094C0B3 /* Frameworks */ = {
|
A979F5FF2D270AF00094C0B3 /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
A979F6072D270AF00094C0B3 /* SwiftUI.framework in Frameworks */,
|
||||||
|
A979F6052D270AF00094C0B3 /* WidgetKit.framework in Frameworks */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
A980FC342D93FB2B006A778F /* Frameworks */ = {
|
||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
@@ -193,82 +146,15 @@
|
|||||||
/* End PBXFrameworksBuildPhase section */
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXGroup section */
|
/* Begin PBXGroup section */
|
||||||
A90D49202DDE0A3B00781124 /* Model */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
A920C28B2D24011400E4F9B1 /* Events.swift */,
|
|
||||||
A90D49602DDE626300781124 /* Settings.swift */,
|
|
||||||
A91EF8062DFC8B8B00B8463D /* ColorCodable.swift */,
|
|
||||||
A95E9ED72DFC742B00ED655F /* AccentIcon.swift */,
|
|
||||||
A91EF8162DFD77A500B8463D /* SymbolsPicker */,
|
|
||||||
);
|
|
||||||
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 */,
|
|
||||||
A91EF80F2DFCB66C00B8463D /* SettingsView.swift */,
|
|
||||||
);
|
|
||||||
path = Views;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
A90D49412DDE112700781124 /* Shared */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
A920C2872D24011400E4F9B1 /* NearFutureApp.swift */,
|
|
||||||
A90D49512DDE2D0000781124 /* Extensions.swift */,
|
|
||||||
A90D49202DDE0A3B00781124 /* Model */,
|
|
||||||
A91EF80A2DFC910000B8463D /* ViewModifiers.swift */,
|
|
||||||
);
|
|
||||||
path = Shared;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
A90D49542DDE2D5800781124 /* Frameworks */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
);
|
|
||||||
name = Frameworks;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
A91EF8162DFD77A500B8463D /* SymbolsPicker */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
A91EF8172DFD77BF00B8463D /* SymbolsLoader.swift */,
|
|
||||||
A91EF81B2DFD796600B8463D /* SymbolsPicker.swift */,
|
|
||||||
A9C769A02DFDD1FC00082FFF /* SymbolsPicker.storyboard */,
|
|
||||||
A9C769A42DFDD27500082FFF /* SymbolsPickerStoryboard.swift */,
|
|
||||||
);
|
|
||||||
path = SymbolsPicker;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
A920C27B2D24011300E4F9B1 = {
|
A920C27B2D24011300E4F9B1 = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
A90D491F2DDE08E400781124 /* README.md */,
|
|
||||||
A90FDE222DC0D4310012790C /* Config.xcconfig */,
|
A90FDE222DC0D4310012790C /* Config.xcconfig */,
|
||||||
A90D49412DDE112700781124 /* Shared */,
|
|
||||||
A920C2862D24011400E4F9B1 /* NearFuture */,
|
|
||||||
A90D49362DDE0FAF00781124 /* MacNearFuture */,
|
|
||||||
A949F8002DCAA0340064DCA0 /* Resources */,
|
A949F8002DCAA0340064DCA0 /* Resources */,
|
||||||
|
A920C2862D24011400E4F9B1 /* NearFuture */,
|
||||||
A979F6082D270AF00094C0B3 /* NearFutureWidgets */,
|
A979F6082D270AF00094C0B3 /* NearFutureWidgets */,
|
||||||
A90D49542DDE2D5800781124 /* Frameworks */,
|
A949F8582DCAAD670064DCA0 /* NearFutureTests */,
|
||||||
|
A979F6032D270AF00094C0B3 /* Frameworks */,
|
||||||
A920C2852D24011400E4F9B1 /* Products */,
|
A920C2852D24011400E4F9B1 /* Products */,
|
||||||
);
|
);
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -278,7 +164,7 @@
|
|||||||
children = (
|
children = (
|
||||||
A920C2842D24011400E4F9B1 /* NearFuture.app */,
|
A920C2842D24011400E4F9B1 /* NearFuture.app */,
|
||||||
A979F6022D270AF00094C0B3 /* NearFutureWidgetsExtension.appex */,
|
A979F6022D270AF00094C0B3 /* NearFutureWidgetsExtension.appex */,
|
||||||
A90D49262DDE0FA400781124 /* Near Future.app */,
|
A980FC372D93FB2B006A778F /* NearFutureTests.xctest */,
|
||||||
);
|
);
|
||||||
name = Products;
|
name = Products;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -286,7 +172,11 @@
|
|||||||
A920C2862D24011400E4F9B1 /* NearFuture */ = {
|
A920C2862D24011400E4F9B1 /* NearFuture */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
A920C2872D24011400E4F9B1 /* NearFutureApp.swift */,
|
||||||
|
A920C28B2D24011400E4F9B1 /* Item.swift */,
|
||||||
A949F84A2DCAABE00064DCA0 /* Views */,
|
A949F84A2DCAABE00064DCA0 /* Views */,
|
||||||
|
A980FC302D920097006A778F /* Info.plist */,
|
||||||
|
A920C28F2D24011A00E4F9B1 /* NearFuture.entitlements */,
|
||||||
A920C2902D24011A00E4F9B1 /* Preview Content */,
|
A920C2902D24011A00E4F9B1 /* Preview Content */,
|
||||||
);
|
);
|
||||||
path = NearFuture;
|
path = NearFuture;
|
||||||
@@ -295,6 +185,7 @@
|
|||||||
A920C2902D24011A00E4F9B1 /* Preview Content */ = {
|
A920C2902D24011A00E4F9B1 /* Preview Content */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
A979F58A2D2700680094C0B3 /* NearFutureWidgets */,
|
||||||
A920C2912D24011A00E4F9B1 /* Preview Assets.xcassets */,
|
A920C2912D24011A00E4F9B1 /* Preview Assets.xcassets */,
|
||||||
);
|
);
|
||||||
path = "Preview Content";
|
path = "Preview Content";
|
||||||
@@ -305,7 +196,6 @@
|
|||||||
children = (
|
children = (
|
||||||
A949F8312DCAAA8A0064DCA0 /* NearFutureIcon.png */,
|
A949F8312DCAAA8A0064DCA0 /* NearFutureIcon.png */,
|
||||||
A920C28D2D24011A00E4F9B1 /* Assets.xcassets */,
|
A920C28D2D24011A00E4F9B1 /* Assets.xcassets */,
|
||||||
A90D49432DDE1C1100781124 /* Tints.xcassets */,
|
|
||||||
A949F82E2DCAAA640064DCA0 /* NearFutureIcon.pxd */,
|
A949F82E2DCAAA640064DCA0 /* NearFutureIcon.pxd */,
|
||||||
A949F82F2DCAAA640064DCA0 /* NearFutureIconDark.pxd */,
|
A949F82F2DCAAA640064DCA0 /* NearFutureIconDark.pxd */,
|
||||||
A949F8302DCAAA640064DCA0 /* NearFutureIconTint.pxd */,
|
A949F8302DCAAA640064DCA0 /* NearFutureIconTint.pxd */,
|
||||||
@@ -333,9 +223,10 @@
|
|||||||
A949F8422DCAABE00064DCA0 /* Home */ = {
|
A949F8422DCAABE00064DCA0 /* Home */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
A914FA4A2DD26C0F00856265 /* HomeView.swift */,
|
A949F83F2DCAABE00064DCA0 /* ContentView.swift */,
|
||||||
A949F8402DCAABE00064DCA0 /* EventListView.swift */,
|
A949F8402DCAABE00064DCA0 /* EventListView.swift */,
|
||||||
A949F8412DCAABE00064DCA0 /* HelpView.swift */,
|
A949F8412DCAABE00064DCA0 /* HelpView.swift */,
|
||||||
|
A914FA4A2DD26C0F00856265 /* HomeView.swift */,
|
||||||
);
|
);
|
||||||
path = Home;
|
path = Home;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -363,7 +254,6 @@
|
|||||||
A949F84A2DCAABE00064DCA0 /* Views */ = {
|
A949F84A2DCAABE00064DCA0 /* Views */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
A949F83F2DCAABE00064DCA0 /* ContentView.swift */,
|
|
||||||
A949F8422DCAABE00064DCA0 /* Home */,
|
A949F8422DCAABE00064DCA0 /* Home */,
|
||||||
A949F83E2DCAABE00064DCA0 /* Events */,
|
A949F83E2DCAABE00064DCA0 /* Events */,
|
||||||
A949F83B2DCAABE00064DCA0 /* Archive */,
|
A949F83B2DCAABE00064DCA0 /* Archive */,
|
||||||
@@ -374,6 +264,14 @@
|
|||||||
path = Views;
|
path = Views;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
A949F8582DCAAD670064DCA0 /* NearFutureTests */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
A949F8572DCAAD670064DCA0 /* NearFutureTests.swift */,
|
||||||
|
);
|
||||||
|
path = NearFutureTests;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
A949F85E2DCABB420064DCA0 /* Misc */ = {
|
A949F85E2DCABB420064DCA0 /* Misc */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -383,6 +281,28 @@
|
|||||||
path = Misc;
|
path = Misc;
|
||||||
sourceTree = "<group>";
|
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 */ = {
|
A979F6082D270AF00094C0B3 /* NearFutureWidgets */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -390,7 +310,8 @@
|
|||||||
A979F6092D270AF00094C0B3 /* NearFutureWidgetsBundle.swift */,
|
A979F6092D270AF00094C0B3 /* NearFutureWidgetsBundle.swift */,
|
||||||
A979F60B2D270AF00094C0B3 /* NearFutureWidgetsLiveActivity.swift */,
|
A979F60B2D270AF00094C0B3 /* NearFutureWidgetsLiveActivity.swift */,
|
||||||
A979F60F2D270AF80094C0B3 /* Assets.xcassets */,
|
A979F60F2D270AF80094C0B3 /* Assets.xcassets */,
|
||||||
A90D49652DDE658100781124 /* Info.plist */,
|
A979F6112D270AF90094C0B3 /* Info.plist */,
|
||||||
|
A9C05E412D2805D7007DC497 /* NearFutureWidgetsExtension.entitlements */,
|
||||||
);
|
);
|
||||||
path = NearFutureWidgets;
|
path = NearFutureWidgets;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -398,26 +319,6 @@
|
|||||||
/* End PBXGroup section */
|
/* End PBXGroup section */
|
||||||
|
|
||||||
/* Begin PBXNativeTarget 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 */,
|
|
||||||
);
|
|
||||||
name = MacNearFuture;
|
|
||||||
packageProductDependencies = (
|
|
||||||
);
|
|
||||||
productName = MacNearFuture;
|
|
||||||
productReference = A90D49262DDE0FA400781124 /* Near Future.app */;
|
|
||||||
productType = "com.apple.product-type.application";
|
|
||||||
};
|
|
||||||
A920C2832D24011300E4F9B1 /* NearFuture */ = {
|
A920C2832D24011300E4F9B1 /* NearFuture */ = {
|
||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = A920C2AB2D24011B00E4F9B1 /* Build configuration list for PBXNativeTarget "NearFuture" */;
|
buildConfigurationList = A920C2AB2D24011B00E4F9B1 /* Build configuration list for PBXNativeTarget "NearFuture" */;
|
||||||
@@ -434,6 +335,7 @@
|
|||||||
);
|
);
|
||||||
name = NearFuture;
|
name = NearFuture;
|
||||||
packageProductDependencies = (
|
packageProductDependencies = (
|
||||||
|
A920C2BD2D24021A00E4F9B1 /* SFSymbolsPicker */,
|
||||||
);
|
);
|
||||||
productName = NearFuture;
|
productName = NearFuture;
|
||||||
productReference = A920C2842D24011400E4F9B1 /* NearFuture.app */;
|
productReference = A920C2842D24011400E4F9B1 /* NearFuture.app */;
|
||||||
@@ -456,6 +358,26 @@
|
|||||||
productReference = A979F6022D270AF00094C0B3 /* NearFutureWidgetsExtension.appex */;
|
productReference = A979F6022D270AF00094C0B3 /* NearFutureWidgetsExtension.appex */;
|
||||||
productType = "com.apple.product-type.app-extension";
|
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 */
|
/* End PBXNativeTarget section */
|
||||||
|
|
||||||
/* Begin PBXProject section */
|
/* Begin PBXProject section */
|
||||||
@@ -463,18 +385,19 @@
|
|||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
attributes = {
|
attributes = {
|
||||||
BuildIndependentTargetsInParallel = 1;
|
BuildIndependentTargetsInParallel = 1;
|
||||||
LastSwiftUpdateCheck = 1640;
|
LastSwiftUpdateCheck = 1620;
|
||||||
LastUpgradeCheck = 1630;
|
LastUpgradeCheck = 1630;
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
A90D49252DDE0FA400781124 = {
|
|
||||||
CreatedOnToolsVersion = 16.4;
|
|
||||||
};
|
|
||||||
A920C2832D24011300E4F9B1 = {
|
A920C2832D24011300E4F9B1 = {
|
||||||
CreatedOnToolsVersion = 15.4;
|
CreatedOnToolsVersion = 15.4;
|
||||||
};
|
};
|
||||||
A979F6012D270AF00094C0B3 = {
|
A979F6012D270AF00094C0B3 = {
|
||||||
CreatedOnToolsVersion = 15.4;
|
CreatedOnToolsVersion = 15.4;
|
||||||
};
|
};
|
||||||
|
A980FC362D93FB2B006A778F = {
|
||||||
|
CreatedOnToolsVersion = 16.2;
|
||||||
|
TestTargetID = A920C2832D24011300E4F9B1;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
buildConfigurationList = A920C27F2D24011300E4F9B1 /* Build configuration list for PBXProject "NearFuture" */;
|
buildConfigurationList = A920C27F2D24011300E4F9B1 /* Build configuration list for PBXProject "NearFuture" */;
|
||||||
@@ -487,36 +410,25 @@
|
|||||||
);
|
);
|
||||||
mainGroup = A920C27B2D24011300E4F9B1;
|
mainGroup = A920C27B2D24011300E4F9B1;
|
||||||
packageReferences = (
|
packageReferences = (
|
||||||
|
A920C2BC2D24021900E4F9B1 /* XCRemoteSwiftPackageReference "SFSymbolsPicker" */,
|
||||||
);
|
);
|
||||||
productRefGroup = A920C2852D24011400E4F9B1 /* Products */;
|
productRefGroup = A920C2852D24011400E4F9B1 /* Products */;
|
||||||
projectDirPath = "";
|
projectDirPath = "";
|
||||||
projectRoot = "";
|
projectRoot = "";
|
||||||
targets = (
|
targets = (
|
||||||
A920C2832D24011300E4F9B1 /* NearFuture */,
|
A920C2832D24011300E4F9B1 /* NearFuture */,
|
||||||
A90D49252DDE0FA400781124 /* MacNearFuture */,
|
|
||||||
A979F6012D270AF00094C0B3 /* NearFutureWidgetsExtension */,
|
A979F6012D270AF00094C0B3 /* NearFutureWidgetsExtension */,
|
||||||
|
A980FC362D93FB2B006A778F /* NearFutureTests */,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
/* End PBXProject section */
|
/* End PBXProject section */
|
||||||
|
|
||||||
/* Begin PBXResourcesBuildPhase 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 */ = {
|
A920C2822D24011300E4F9B1 /* Resources */ = {
|
||||||
isa = PBXResourcesBuildPhase;
|
isa = PBXResourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
A90D49442DDE1C7600781124 /* Tints.xcassets in Resources */,
|
|
||||||
A920C2922D24011A00E4F9B1 /* Preview Assets.xcassets in Resources */,
|
A920C2922D24011A00E4F9B1 /* Preview Assets.xcassets in Resources */,
|
||||||
A9C769A22DFDD1FC00082FFF /* SymbolsPicker.storyboard in Resources */,
|
|
||||||
A949F8322DCAAA8A0064DCA0 /* NearFutureIcon.png in Resources */,
|
A949F8322DCAAA8A0064DCA0 /* NearFutureIcon.png in Resources */,
|
||||||
A920C28E2D24011A00E4F9B1 /* Assets.xcassets in Resources */,
|
A920C28E2D24011A00E4F9B1 /* Assets.xcassets in Resources */,
|
||||||
);
|
);
|
||||||
@@ -526,75 +438,40 @@
|
|||||||
isa = PBXResourcesBuildPhase;
|
isa = PBXResourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
A90D49462DDE1C7A00781124 /* Tints.xcassets in Resources */,
|
|
||||||
A9C769A32DFDD1FC00082FFF /* SymbolsPicker.storyboard in Resources */,
|
|
||||||
A979F6102D270AF90094C0B3 /* Assets.xcassets in Resources */,
|
A979F6102D270AF90094C0B3 /* Assets.xcassets in Resources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
A980FC352D93FB2B006A778F /* Resources */ = {
|
||||||
|
isa = PBXResourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
/* End PBXResourcesBuildPhase section */
|
/* End PBXResourcesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXSourcesBuildPhase section */
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
A90D49222DDE0FA400781124 /* Sources */ = {
|
|
||||||
isa = PBXSourcesBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
A9C769A52DFDD27500082FFF /* SymbolsPickerStoryboard.swift in Sources */,
|
|
||||||
A91EF80E2DFC9A0C00B8463D /* WhatsNewView.swift in Sources */,
|
|
||||||
A91EF8192DFD77BF00B8463D /* SymbolsLoader.swift in Sources */,
|
|
||||||
A95E9EE42DFC77D400ED655F /* ImportView.swift in Sources */,
|
|
||||||
A98C20CB2DE730740008D61C /* EventListViewMac.swift in Sources */,
|
|
||||||
A91EF80C2DFC910000B8463D /* ViewModifiers.swift in Sources */,
|
|
||||||
A95E9ED92DFC742B00ED655F /* AccentIcon.swift in Sources */,
|
|
||||||
A91EF8102DFCB66C00B8463D /* SettingsView.swift in Sources */,
|
|
||||||
A90D495E2DDE3C7400781124 /* NFCommands.swift in Sources */,
|
|
||||||
A95E9EE52DFC77E200ED655F /* ExportView.swift in Sources */,
|
|
||||||
A91EF8132DFCC87D00B8463D /* EditEventView.swift in Sources */,
|
|
||||||
A91EF8142DFCC87D00B8463D /* AddEventView.swift in Sources */,
|
|
||||||
A98C20D42DE7339E0008D61C /* AboutView.swift in Sources */,
|
|
||||||
A98C20CE2DE7308E0008D61C /* ArchiveView.swift in Sources */,
|
|
||||||
A98C20D02DE731BD0008D61C /* HomeView.swift in Sources */,
|
|
||||||
A90D495B2DDE2EDB00781124 /* MacNearFutureApp.swift in Sources */,
|
|
||||||
A91EF8082DFC8B8B00B8463D /* ColorCodable.swift in Sources */,
|
|
||||||
A90D49522DDE2D0000781124 /* Extensions.swift in Sources */,
|
|
||||||
A91EF81D2DFD796600B8463D /* SymbolsPicker.swift in Sources */,
|
|
||||||
A90D49422DDE114100781124 /* Events.swift in Sources */,
|
|
||||||
A90D49382DDE0FAF00781124 /* ContentViewMac.swift in Sources */,
|
|
||||||
A90D49622DDE626300781124 /* Settings.swift in Sources */,
|
|
||||||
A95E9ED32DFC703200ED655F /* iCloudSettingsView.swift in Sources */,
|
|
||||||
A96609E72DFD800000DBFA78 /* HelpView.swift in Sources */,
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
A920C2802D24011300E4F9B1 /* Sources */ = {
|
A920C2802D24011300E4F9B1 /* Sources */ = {
|
||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
A920C28C2D24011400E4F9B1 /* Events.swift in Sources */,
|
A920C28C2D24011400E4F9B1 /* Item.swift in Sources */,
|
||||||
A949F84B2DCAABE00064DCA0 /* ArchiveView.swift in Sources */,
|
A949F84B2DCAABE00064DCA0 /* ArchiveView.swift in Sources */,
|
||||||
A914FA4F2DD276D200856265 /* AboutView.swift in Sources */,
|
A914FA4F2DD276D200856265 /* AboutView.swift in Sources */,
|
||||||
A949F84C2DCAABE00064DCA0 /* AddEventView.swift in Sources */,
|
A949F84C2DCAABE00064DCA0 /* AddEventView.swift in Sources */,
|
||||||
A914FA4B2DD26C6800856265 /* HomeView.swift in Sources */,
|
A914FA4B2DD26C6800856265 /* HomeView.swift in Sources */,
|
||||||
A949F84D2DCAABE00064DCA0 /* EditEventView.swift in Sources */,
|
A949F84D2DCAABE00064DCA0 /* EditEventView.swift in Sources */,
|
||||||
A949F84E2DCAABE00064DCA0 /* ContentView.swift in Sources */,
|
A949F84E2DCAABE00064DCA0 /* ContentView.swift in Sources */,
|
||||||
A90D49612DDE626300781124 /* Settings.swift in Sources */,
|
|
||||||
A90D495F2DDE3C7400781124 /* NFCommands.swift in Sources */,
|
|
||||||
A949F84F2DCAABE00064DCA0 /* EventListView.swift in Sources */,
|
A949F84F2DCAABE00064DCA0 /* EventListView.swift in Sources */,
|
||||||
A91EF8092DFC8B8B00B8463D /* ColorCodable.swift in Sources */,
|
|
||||||
A949F8502DCAABE00064DCA0 /* HelpView.swift in Sources */,
|
A949F8502DCAABE00064DCA0 /* HelpView.swift in Sources */,
|
||||||
A949F85F2DCABB420064DCA0 /* Buttons.swift in Sources */,
|
A949F85F2DCABB420064DCA0 /* Buttons.swift in Sources */,
|
||||||
A914FA4D2DD2768900856265 /* WhatsNewView.swift in Sources */,
|
A914FA4D2DD2768900856265 /* WhatsNewView.swift in Sources */,
|
||||||
A91EF80B2DFC910000B8463D /* ViewModifiers.swift in Sources */,
|
|
||||||
A949F8512DCAABE00064DCA0 /* ExportView.swift in Sources */,
|
A949F8512DCAABE00064DCA0 /* ExportView.swift in Sources */,
|
||||||
A95E9ED82DFC742B00ED655F /* AccentIcon.swift in Sources */,
|
|
||||||
A90D49532DDE2D0000781124 /* Extensions.swift in Sources */,
|
|
||||||
A9C769A62DFDD27500082FFF /* SymbolsPickerStoryboard.swift in Sources */,
|
|
||||||
A949F8522DCAABE00064DCA0 /* iCloudSettingsView.swift in Sources */,
|
A949F8522DCAABE00064DCA0 /* iCloudSettingsView.swift in Sources */,
|
||||||
A949F8532DCAABE00064DCA0 /* ImportView.swift in Sources */,
|
A949F8532DCAABE00064DCA0 /* ImportView.swift in Sources */,
|
||||||
A949F8542DCAABE00064DCA0 /* SettingsView.swift in Sources */,
|
A949F8542DCAABE00064DCA0 /* SettingsView.swift in Sources */,
|
||||||
A91EF81E2DFD796600B8463D /* SymbolsPicker.swift in Sources */,
|
|
||||||
A949F8552DCAABE00064DCA0 /* StatsView.swift in Sources */,
|
A949F8552DCAABE00064DCA0 /* StatsView.swift in Sources */,
|
||||||
A91EF81A2DFD77BF00B8463D /* SymbolsLoader.swift in Sources */,
|
|
||||||
A920C2882D24011400E4F9B1 /* NearFutureApp.swift in Sources */,
|
A920C2882D24011400E4F9B1 /* NearFutureApp.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
@@ -603,17 +480,19 @@
|
|||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
A979F6182D2714310094C0B3 /* Events.swift in Sources */,
|
A979F6182D2714310094C0B3 /* Item.swift in Sources */,
|
||||||
A91EF81C2DFD796600B8463D /* SymbolsPicker.swift in Sources */,
|
|
||||||
A979F60A2D270AF00094C0B3 /* NearFutureWidgetsBundle.swift in Sources */,
|
A979F60A2D270AF00094C0B3 /* NearFutureWidgetsBundle.swift in Sources */,
|
||||||
A95E9EDA2DFC742B00ED655F /* AccentIcon.swift in Sources */,
|
|
||||||
A91EF80D2DFC910000B8463D /* ViewModifiers.swift in Sources */,
|
|
||||||
A91EF8182DFD77BF00B8463D /* SymbolsLoader.swift in Sources */,
|
|
||||||
A9C769A72DFDD27500082FFF /* SymbolsPickerStoryboard.swift in Sources */,
|
|
||||||
A91EF8072DFC8B8B00B8463D /* ColorCodable.swift in Sources */,
|
|
||||||
A9FC7EEA2D2823920020D75B /* NearFutureWidgets.swift in Sources */,
|
A9FC7EEA2D2823920020D75B /* NearFutureWidgets.swift in Sources */,
|
||||||
A979F60C2D270AF00094C0B3 /* NearFutureWidgetsLiveActivity.swift in Sources */,
|
A979F60C2D270AF00094C0B3 /* NearFutureWidgetsLiveActivity.swift in Sources */,
|
||||||
A90D49632DDE626300781124 /* Settings.swift in Sources */,
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
A980FC332D93FB2B006A778F /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
A949F8592DCAAD670064DCA0 /* NearFutureTests.swift in Sources */,
|
||||||
|
A949F8562DCAABE00064DCA0 /* ExportView.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@@ -626,76 +505,14 @@
|
|||||||
target = A979F6012D270AF00094C0B3 /* NearFutureWidgetsExtension */;
|
target = A979F6012D270AF00094C0B3 /* NearFutureWidgetsExtension */;
|
||||||
targetProxy = A979F6122D270AF90094C0B3 /* PBXContainerItemProxy */;
|
targetProxy = A979F6122D270AF90094C0B3 /* PBXContainerItemProxy */;
|
||||||
};
|
};
|
||||||
A98C20D22DE732B10008D61C /* PBXTargetDependency */ = {
|
A980FC3C2D93FB2B006A778F /* PBXTargetDependency */ = {
|
||||||
isa = PBXTargetDependency;
|
isa = PBXTargetDependency;
|
||||||
target = A979F6012D270AF00094C0B3 /* NearFutureWidgetsExtension */;
|
target = A920C2832D24011300E4F9B1 /* NearFuture */;
|
||||||
targetProxy = A98C20D12DE732B10008D61C /* PBXContainerItemProxy */;
|
targetProxy = A980FC3B2D93FB2B006A778F /* PBXContainerItemProxy */;
|
||||||
};
|
};
|
||||||
/* End PBXTargetDependency section */
|
/* End PBXTargetDependency section */
|
||||||
|
|
||||||
/* Begin XCBuildConfiguration 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 */ = {
|
A920C2A92D24011B00E4F9B1 /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
@@ -843,7 +660,8 @@
|
|||||||
ENABLE_HARDENED_RUNTIME = NO;
|
ENABLE_HARDENED_RUNTIME = NO;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = "Near Future";
|
INFOPLIST_FILE = NearFuture/Info.plist;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = "$(NAME)";
|
||||||
INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO;
|
INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO;
|
||||||
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES;
|
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES;
|
||||||
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES;
|
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES;
|
||||||
@@ -869,8 +687,8 @@
|
|||||||
REGISTER_APP_GROUPS = YES;
|
REGISTER_APP_GROUPS = YES;
|
||||||
SDKROOT = auto;
|
SDKROOT = auto;
|
||||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||||
SUPPORTS_MACCATALYST = NO;
|
SUPPORTS_MACCATALYST = YES;
|
||||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
|
||||||
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = YES;
|
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = YES;
|
||||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
@@ -895,7 +713,8 @@
|
|||||||
ENABLE_HARDENED_RUNTIME = NO;
|
ENABLE_HARDENED_RUNTIME = NO;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = "Near Future";
|
INFOPLIST_FILE = NearFuture/Info.plist;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = "$(NAME)";
|
||||||
INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO;
|
INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO;
|
||||||
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES;
|
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES;
|
||||||
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES;
|
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES;
|
||||||
@@ -918,8 +737,8 @@
|
|||||||
REGISTER_APP_GROUPS = YES;
|
REGISTER_APP_GROUPS = YES;
|
||||||
SDKROOT = auto;
|
SDKROOT = auto;
|
||||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||||
SUPPORTS_MACCATALYST = NO;
|
SUPPORTS_MACCATALYST = YES;
|
||||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
|
||||||
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = YES;
|
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = YES;
|
||||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
@@ -939,7 +758,7 @@
|
|||||||
CURRENT_PROJECT_VERSION = "$(BUILD_NUMBER)";
|
CURRENT_PROJECT_VERSION = "$(BUILD_NUMBER)";
|
||||||
DEVELOPMENT_TEAM = "$(TEAM_ID)";
|
DEVELOPMENT_TEAM = "$(TEAM_ID)";
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
INFOPLIST_FILE = "$(SRCROOT)/NearFutureWidgets/Info.plist";
|
INFOPLIST_FILE = NearFutureWidgets/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = NearFutureWidgets;
|
INFOPLIST_KEY_CFBundleDisplayName = NearFutureWidgets;
|
||||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 17;
|
IPHONEOS_DEPLOYMENT_TARGET = 17;
|
||||||
@@ -959,9 +778,8 @@
|
|||||||
REGISTER_APP_GROUPS = YES;
|
REGISTER_APP_GROUPS = YES;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
|
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||||
SUPPORTS_MACCATALYST = NO;
|
SUPPORTS_MACCATALYST = YES;
|
||||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
|
||||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
@@ -981,7 +799,7 @@
|
|||||||
CURRENT_PROJECT_VERSION = "$(BUILD_NUMBER)";
|
CURRENT_PROJECT_VERSION = "$(BUILD_NUMBER)";
|
||||||
DEVELOPMENT_TEAM = "$(TEAM_ID)";
|
DEVELOPMENT_TEAM = "$(TEAM_ID)";
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
INFOPLIST_FILE = "$(SRCROOT)/NearFutureWidgets/Info.plist";
|
INFOPLIST_FILE = NearFutureWidgets/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = NearFutureWidgets;
|
INFOPLIST_KEY_CFBundleDisplayName = NearFutureWidgets;
|
||||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 17;
|
IPHONEOS_DEPLOYMENT_TARGET = 17;
|
||||||
@@ -997,9 +815,8 @@
|
|||||||
REGISTER_APP_GROUPS = YES;
|
REGISTER_APP_GROUPS = YES;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
|
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||||
SUPPORTS_MACCATALYST = NO;
|
SUPPORTS_MACCATALYST = YES;
|
||||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
|
||||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
@@ -1008,18 +825,61 @@
|
|||||||
};
|
};
|
||||||
name = Release;
|
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 */
|
/* End XCBuildConfiguration section */
|
||||||
|
|
||||||
/* Begin XCConfigurationList 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" */ = {
|
A920C27F2D24011300E4F9B1 /* Build configuration list for PBXProject "NearFuture" */ = {
|
||||||
isa = XCConfigurationList;
|
isa = XCConfigurationList;
|
||||||
buildConfigurations = (
|
buildConfigurations = (
|
||||||
@@ -1047,7 +907,35 @@
|
|||||||
defaultConfigurationIsVisible = 0;
|
defaultConfigurationIsVisible = 0;
|
||||||
defaultConfigurationName = Release;
|
defaultConfigurationName = Release;
|
||||||
};
|
};
|
||||||
|
A980FC3D2D93FB2B006A778F /* Build configuration list for PBXNativeTarget "NearFutureTests" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
A980FC3E2D93FB2B006A778F /* Debug */,
|
||||||
|
A980FC3F2D93FB2B006A778F /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
/* End XCConfigurationList section */
|
/* End XCConfigurationList section */
|
||||||
|
|
||||||
|
/* Begin XCRemoteSwiftPackageReference section */
|
||||||
|
A920C2BC2D24021900E4F9B1 /* XCRemoteSwiftPackageReference "SFSymbolsPicker" */ = {
|
||||||
|
isa = XCRemoteSwiftPackageReference;
|
||||||
|
repositoryURL = "https://github.com/alessiorubicini/SFSymbolsPicker";
|
||||||
|
requirement = {
|
||||||
|
kind = upToNextMajorVersion;
|
||||||
|
minimumVersion = 1.0.6;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/* End XCRemoteSwiftPackageReference section */
|
||||||
|
|
||||||
|
/* Begin XCSwiftPackageProductDependency section */
|
||||||
|
A920C2BD2D24021A00E4F9B1 /* SFSymbolsPicker */ = {
|
||||||
|
isa = XCSwiftPackageProductDependency;
|
||||||
|
package = A920C2BC2D24021900E4F9B1 /* XCRemoteSwiftPackageReference "SFSymbolsPicker" */;
|
||||||
|
productName = SFSymbolsPicker;
|
||||||
|
};
|
||||||
|
/* End XCSwiftPackageProductDependency section */
|
||||||
};
|
};
|
||||||
rootObject = A920C27C2D24011300E4F9B1 /* Project object */;
|
rootObject = A920C27C2D24011300E4F9B1 /* Project object */;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"originHash" : "19df39f99b22f4ef95b73ed292ffb0c8d7694dd4c9db2b96ea73b091b7b1a026",
|
||||||
|
"pins" : [
|
||||||
|
{
|
||||||
|
"identity" : "sfsymbolspicker",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/alessiorubicini/SFSymbolsPicker",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "73c909b8a7fc77a30dd04208e33f759f8b52c4c8",
|
||||||
|
"version" : "1.0.6"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version" : 3
|
||||||
|
}
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
<?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>
|
|
||||||
@@ -4,29 +4,19 @@
|
|||||||
<dict>
|
<dict>
|
||||||
<key>SchemeUserState</key>
|
<key>SchemeUserState</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>MacNearFuture.xcscheme_^#shared#^_</key>
|
<key>NearFuture.xcscheme_^#shared#^_</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>orderHint</key>
|
<key>orderHint</key>
|
||||||
<integer>1</integer>
|
<integer>1</integer>
|
||||||
</dict>
|
</dict>
|
||||||
<key>NearFuture.xcscheme_^#shared#^_</key>
|
<key>NearFutureWidgetsExtension.xcscheme_^#shared#^_</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>orderHint</key>
|
<key>orderHint</key>
|
||||||
<integer>0</integer>
|
<integer>0</integer>
|
||||||
</dict>
|
</dict>
|
||||||
<key>NearFutureWidgetsExtension.xcscheme_^#shared#^_</key>
|
|
||||||
<dict>
|
|
||||||
<key>orderHint</key>
|
|
||||||
<integer>2</integer>
|
|
||||||
</dict>
|
|
||||||
</dict>
|
</dict>
|
||||||
<key>SuppressBuildableAutocreation</key>
|
<key>SuppressBuildableAutocreation</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>A90D49252DDE0FA400781124</key>
|
|
||||||
<dict>
|
|
||||||
<key>primary</key>
|
|
||||||
<true/>
|
|
||||||
</dict>
|
|
||||||
<key>A920C2832D24011300E4F9B1</key>
|
<key>A920C2832D24011300E4F9B1</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>primary</key>
|
<key>primary</key>
|
||||||
|
|||||||
170
NearFuture/Home/EventListView.swift
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
//
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
10
NearFuture/Info.plist
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?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>
|
||||||
@@ -11,9 +11,6 @@ import SwiftUI
|
|||||||
import WidgetKit
|
import WidgetKit
|
||||||
import UserNotifications
|
import UserNotifications
|
||||||
import AppIntents
|
import AppIntents
|
||||||
#if canImport(AppKit)
|
|
||||||
import AppKit
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//@Model
|
//@Model
|
||||||
//final class Item {
|
//final class Item {
|
||||||
@@ -24,7 +21,7 @@ import AppKit
|
|||||||
// }
|
// }
|
||||||
//}
|
//}
|
||||||
|
|
||||||
struct Event: Identifiable, Codable, Equatable, Animatable, Hashable {
|
struct Event: Identifiable, Codable, Equatable, Animatable {
|
||||||
var id = UUID()
|
var id = UUID()
|
||||||
var name: String
|
var name: String
|
||||||
var complete: Bool
|
var complete: Bool
|
||||||
@@ -40,6 +37,52 @@ struct Event: Identifiable, Codable, Equatable, Animatable, Hashable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
self.red = Double(r)
|
||||||
|
self.green = Double(g)
|
||||||
|
self.blue = Double(b)
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
init(red: Double, green: Double, blue: Double) {
|
||||||
|
self.red = red
|
||||||
|
self.green = green
|
||||||
|
self.blue = blue
|
||||||
|
}
|
||||||
|
|
||||||
|
var red: Double
|
||||||
|
var green: Double
|
||||||
|
var blue: Double
|
||||||
|
|
||||||
|
var color: Color {
|
||||||
|
Color(red: red, green: green, blue: blue)
|
||||||
|
}
|
||||||
|
var colorBind: Color {
|
||||||
|
get {
|
||||||
|
return Color(
|
||||||
|
red: red,
|
||||||
|
green: green,
|
||||||
|
blue: blue
|
||||||
|
)
|
||||||
|
} set {
|
||||||
|
let cc = ColorCodable(newValue)
|
||||||
|
self.red = cc.red
|
||||||
|
self.green = cc.green
|
||||||
|
self.blue = cc.blue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func daysUntilEvent(_ eventDate: Date) -> (long: String, short: String) {
|
func daysUntilEvent(_ eventDate: Date) -> (long: String, short: String) {
|
||||||
let calendar = Calendar.current
|
let calendar = Calendar.current
|
||||||
let startOfDayNow = calendar.startOfDay(for: Date())
|
let startOfDayNow = calendar.startOfDay(for: Date())
|
||||||
@@ -50,18 +93,114 @@ func daysUntilEvent(_ eventDate: Date) -> (long: String, short: String) {
|
|||||||
if days < 0 {
|
if days < 0 {
|
||||||
//past
|
//past
|
||||||
return (
|
return (
|
||||||
"\(-days)\nday\(plu(days)) ago",
|
"\(-days) day\(plu(days)) ago",
|
||||||
"\(days)d"
|
"\(days)d"
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
//future
|
//future
|
||||||
return (
|
return (
|
||||||
"\(days)\nday\(plu(days))",
|
"\(days) day\(plu(days))",
|
||||||
"\(days)d"
|
"\(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 {
|
class EventViewModel: ObservableObject, @unchecked Sendable {
|
||||||
@Published var events: [Event] = []
|
@Published var events: [Event] = []
|
||||||
@Published var icloudData: [Event] = []
|
@Published var icloudData: [Event] = []
|
||||||
@@ -93,31 +232,11 @@ class EventViewModel: ObservableObject, @unchecked Sendable {
|
|||||||
@Published var localEventCount: Int = 0
|
@Published var localEventCount: Int = 0
|
||||||
@Published var syncStatus: String = "Not Synced"
|
@Published var syncStatus: String = "Not Synced"
|
||||||
|
|
||||||
@Published var hasUbiquitous: Bool = false
|
|
||||||
@Published var lastSyncWasSuccessful: Bool = false
|
|
||||||
@Published var lastSyncWasNormalAgo: Bool = false
|
|
||||||
@Published var localCountEqualToiCloud: Bool = false
|
|
||||||
@Published var icloudCountEqualToLocal: Bool = false
|
|
||||||
|
|
||||||
var iCloudStatusColor: Color {
|
|
||||||
let allTrue = hasUbiquitous && lastSyncWasSuccessful && lastSyncWasNormalAgo && localCountEqualToiCloud && icloudCountEqualToLocal
|
|
||||||
let someTrue = hasUbiquitous || lastSyncWasSuccessful || lastSyncWasNormalAgo || localCountEqualToiCloud || icloudCountEqualToLocal
|
|
||||||
|
|
||||||
if allTrue {
|
|
||||||
return .green
|
|
||||||
} else if someTrue {
|
|
||||||
return .orange
|
|
||||||
} else {
|
|
||||||
return .red
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
init(load: Bool = true) {
|
init(load: Bool = true) {
|
||||||
self.editableTemplate = template
|
self.editableTemplate = template
|
||||||
if load {
|
if load {
|
||||||
loadEvents()
|
loadEvents()
|
||||||
}
|
}
|
||||||
// AudioServicesPlaySystemSound(kSystemSoundID_Vibrate)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//appgroup or regular userdefaults
|
//appgroup or regular userdefaults
|
||||||
@@ -196,8 +315,8 @@ class EventViewModel: ObservableObject, @unchecked Sendable {
|
|||||||
|
|
||||||
updateSyncStatus()
|
updateSyncStatus()
|
||||||
loadEvents()
|
loadEvents()
|
||||||
Task.detached {
|
Task {
|
||||||
await self.checkPendingNotifs(self.getNotifs())
|
await checkPendingNotifs(getNotifs())
|
||||||
}
|
}
|
||||||
WidgetCenter.shared.reloadAllTimelines()//reload all widgets when saving events
|
WidgetCenter.shared.reloadAllTimelines()//reload all widgets when saving events
|
||||||
objectWillChange.send()
|
objectWillChange.send()
|
||||||
@@ -273,32 +392,20 @@ class EventViewModel: ObservableObject, @unchecked Sendable {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func importEvents(_ imported: String, replace: Bool) throws {
|
func importEvents(_ imported: String) throws {
|
||||||
guard let data = Data(base64Encoded: imported) else {
|
guard let data = Data(base64Encoded: imported) else {
|
||||||
throw importError.invalidB64
|
throw importError.invalidB64
|
||||||
}
|
}
|
||||||
let decoder = JSONDecoder()
|
let decoder = JSONDecoder()
|
||||||
do {
|
do {
|
||||||
let decoded = try decoder.decode([Event].self, from: data)
|
let decoded = try decoder.decode([Event].self, from: data)
|
||||||
if replace {
|
|
||||||
self.events = decoded
|
self.events = decoded
|
||||||
} else {
|
|
||||||
self.events = self.events + decoded
|
|
||||||
}
|
|
||||||
saveEvents()
|
saveEvents()
|
||||||
} catch {
|
} catch {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateiCStatus() {
|
|
||||||
hasUbiquitous = hasUbiquitousKeyValueStore()
|
|
||||||
lastSyncWasSuccessful = syncStatus.contains("Success")
|
|
||||||
lastSyncWasNormalAgo = lastSync?.timeIntervalSinceNow.isNormal ?? false
|
|
||||||
localCountEqualToiCloud = localEventCount == icloudEventCount
|
|
||||||
icloudCountEqualToLocal = icloudEventCount == localEventCount
|
|
||||||
}
|
|
||||||
|
|
||||||
//MARK: Danger Zone
|
//MARK: Danger Zone
|
||||||
func dangerClearLocalData() {
|
func dangerClearLocalData() {
|
||||||
UserDefaults.standard.removeObject(forKey: "events")
|
UserDefaults.standard.removeObject(forKey: "events")
|
||||||
@@ -344,7 +451,7 @@ class EventViewModel: ObservableObject, @unchecked Sendable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class dummyEventViewModel: EventViewModel, @unchecked Sendable{
|
class dummyEventViewModel: EventViewModel, @unchecked Sendable {
|
||||||
var template2: Event
|
var template2: Event
|
||||||
override init(load: Bool = false) {
|
override init(load: Bool = false) {
|
||||||
self.template2 = Event(
|
self.template2 = Event(
|
||||||
@@ -473,7 +580,6 @@ func getBuildID() -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getDevice() -> (sf: String, label: String) {
|
func getDevice() -> (sf: String, label: String) {
|
||||||
#if canImport(UIKit)
|
|
||||||
let asi = ProcessInfo().isiOSAppOnMac
|
let asi = ProcessInfo().isiOSAppOnMac
|
||||||
let model = UIDevice().model
|
let model = UIDevice().model
|
||||||
if asi {
|
if asi {
|
||||||
@@ -484,10 +590,6 @@ func getDevice() -> (sf: String, label: String) {
|
|||||||
return (sf: model.lowercased(), label: model)
|
return (sf: model.lowercased(), label: model)
|
||||||
}
|
}
|
||||||
return (sf: "iphone", label: "iPhone")
|
return (sf: "iphone", label: "iPhone")
|
||||||
#elseif canImport(AppKit)
|
|
||||||
|
|
||||||
return (sf: "desktopcomputer", label: "Mac")
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Event: AppEntity {
|
extension Event: AppEntity {
|
||||||
112
NearFuture/Misc/HelpView.swift
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
//
|
||||||
|
// 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))
|
||||||
|
}
|
||||||
@@ -2,6 +2,10 @@
|
|||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<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>
|
<key>com.apple.developer.icloud-container-identifiers</key>
|
||||||
<array/>
|
<array/>
|
||||||
<key>com.apple.developer.ubiquity-kvstore-identifier</key>
|
<key>com.apple.developer.ubiquity-kvstore-identifier</key>
|
||||||
|
|||||||
36
NearFuture/NearFutureApp.swift
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
//
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
18
NearFuture/Preview Content/NearFutureWidgets/AppIntent.swift
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
//
|
||||||
|
// 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
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"size" : "1024x1024"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
11
NearFuture/Preview Content/NearFutureWidgets/Info.plist
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<?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>
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
//
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
//
|
||||||
|
// NearFutureWidgetsBundle.swift
|
||||||
|
// NearFutureWidgets
|
||||||
|
//
|
||||||
|
// Created by neon443 on 02/01/2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
import WidgetKit
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
@main
|
||||||
|
struct NearFutureWidgetsBundle: WidgetBundle {
|
||||||
|
var body: some Widget {
|
||||||
|
NearFutureWidgets()
|
||||||
|
NearFutureWidgetsLiveActivity()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
//
|
||||||
|
// 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
|
||||||
|
}
|
||||||
@@ -11,8 +11,7 @@ struct ArchiveView: View {
|
|||||||
@ObservedObject var viewModel: EventViewModel
|
@ObservedObject var viewModel: EventViewModel
|
||||||
@State var showAddEvent: Bool = false
|
@State var showAddEvent: Bool = false
|
||||||
var filteredEvents: [Event] {
|
var filteredEvents: [Event] {
|
||||||
let filteredEvents = viewModel.events.filter({$0.complete})
|
return viewModel.events.filter() {$0.complete}
|
||||||
return filteredEvents.reversed()
|
|
||||||
}
|
}
|
||||||
var body: some View {
|
var body: some View {
|
||||||
NavigationStack {
|
NavigationStack {
|
||||||
@@ -39,12 +38,25 @@ struct ArchiveView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.navigationTitle("Archive")
|
.navigationTitle("Archive")
|
||||||
.modifier(navigationInlineLarge())
|
.apply {
|
||||||
|
if #available(iOS 17, *) {
|
||||||
|
$0.toolbarTitleDisplayMode(.inlineLarge)
|
||||||
|
} else {
|
||||||
|
$0.navigationBarTitleDisplayMode(.inline)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.sheet(isPresented: $showAddEvent) {
|
.sheet(isPresented: $showAddEvent) {
|
||||||
AddEventView(
|
AddEventView(
|
||||||
viewModel: viewModel,
|
viewModel: viewModel,
|
||||||
event: $viewModel.editableTemplate,
|
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,
|
||||||
adding: true
|
adding: true
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,15 +6,23 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
import SFSymbolsPicker
|
||||||
|
|
||||||
struct AddEventView: View {
|
struct AddEventView: View {
|
||||||
@ObservedObject var viewModel: EventViewModel
|
@ObservedObject var viewModel: EventViewModel
|
||||||
|
|
||||||
@Binding var event: Event
|
@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
|
||||||
|
|
||||||
@State var adding: Bool
|
@State var adding: Bool
|
||||||
@State var showNeedsNameAlert: Bool = false
|
@State var showNeedsNameAlert: Bool = false
|
||||||
@State var isSymbolPickerPresented: Bool = false
|
@State var isSymbolPickerPresented = false
|
||||||
|
|
||||||
@State private var bye: Bool = false
|
@State private var bye: Bool = false
|
||||||
|
|
||||||
@@ -31,7 +39,7 @@ struct AddEventView: View {
|
|||||||
backgroundGradient
|
backgroundGradient
|
||||||
}
|
}
|
||||||
NavigationStack {
|
NavigationStack {
|
||||||
List {
|
Form {
|
||||||
Section(
|
Section(
|
||||||
header:
|
header:
|
||||||
Text("Event Details")
|
Text("Event Details")
|
||||||
@@ -43,49 +51,66 @@ struct AddEventView: View {
|
|||||||
Button() {
|
Button() {
|
||||||
isSymbolPickerPresented.toggle()
|
isSymbolPickerPresented.toggle()
|
||||||
} label: {
|
} label: {
|
||||||
Image(systemName: event.symbol)
|
Image(systemName: eventSymbol)
|
||||||
.resizable()
|
.resizable()
|
||||||
.scaledToFit()
|
.scaledToFit()
|
||||||
.frame(width: 20, height: 20)
|
.frame(width: 20, height: 20)
|
||||||
.foregroundStyle(event.color.color)
|
.foregroundStyle(eventColor)
|
||||||
}
|
}
|
||||||
.frame(width: 20)
|
.frame(width: 20)
|
||||||
.buttonStyle(.borderless)
|
.buttonStyle(.borderless)
|
||||||
.sheet(isPresented: $isSymbolPickerPresented) {
|
.sheet(isPresented: $isSymbolPickerPresented) {
|
||||||
SymbolsPicker(
|
SymbolsPicker(
|
||||||
selection: $event.symbol
|
selection: $eventSymbol,
|
||||||
)
|
title: "Choose a Symbol",
|
||||||
|
searchLabel: "Search...",
|
||||||
|
autoDismiss: true)
|
||||||
.presentationDetents([.medium])
|
.presentationDetents([.medium])
|
||||||
.modifier(presentationSizeForm())
|
.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)
|
||||||
}
|
}
|
||||||
TextField("Event Name", text: $event.name)
|
|
||||||
.textFieldStyle(.roundedBorder)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// dscription
|
// dscription
|
||||||
ZStack {
|
ZStack {
|
||||||
TextField("Event Notes", text: $event.notes)
|
TextField("Event Notes", text: $eventNotes)
|
||||||
.textFieldStyle(RoundedBorderTextFieldStyle())
|
.textFieldStyle(RoundedBorderTextFieldStyle())
|
||||||
.padding(.trailing, event.notes.isEmpty ? 0 : 30)
|
.padding(.trailing, eventNotes.isEmpty ? 0 : 30)
|
||||||
.animation(.spring, value: event.notes)
|
.animation(.spring, value: eventNotes)
|
||||||
.focused($focusedField, equals: Field.Notes)
|
.focused($focusedField, equals: Field.Notes)
|
||||||
.submitLabel(.done)
|
.submitLabel(.done)
|
||||||
.onSubmit {
|
.onSubmit {
|
||||||
focusedField = nil
|
focusedField = nil
|
||||||
}
|
}
|
||||||
|
MagicClearButton(text: $eventNotes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// date picker
|
// date picker
|
||||||
HStack {
|
HStack {
|
||||||
Spacer()
|
Spacer()
|
||||||
DatePicker("", selection: $event.date, displayedComponents: .date)
|
DatePicker("", selection: $eventDate, displayedComponents: .date)
|
||||||
#if os(iOS)
|
.datePickerStyle(WheelDatePickerStyle())
|
||||||
.datePickerStyle(.wheel)
|
|
||||||
#endif
|
|
||||||
Spacer()
|
Spacer()
|
||||||
Button() {
|
Button() {
|
||||||
event.date = Date()
|
eventDate = Date()
|
||||||
} label: {
|
} label: {
|
||||||
Image(systemName: "arrow.uturn.left")
|
Image(systemName: "arrow.uturn.left")
|
||||||
.resizable()
|
.resizable()
|
||||||
@@ -97,12 +122,12 @@ struct AddEventView: View {
|
|||||||
|
|
||||||
DatePicker(
|
DatePicker(
|
||||||
"",
|
"",
|
||||||
selection: $event.date,
|
selection: $eventDate,
|
||||||
displayedComponents: .hourAndMinute
|
displayedComponents: .hourAndMinute
|
||||||
)
|
)
|
||||||
|
|
||||||
// re-ocurrence Picker
|
// re-ocurrence Picker
|
||||||
Picker("Recurrence", selection: $event.recurrence) {
|
Picker("Recurrence", selection: $eventRecurrence) {
|
||||||
ForEach(Event.RecurrenceType.allCases, id: \.self) { recurrence in
|
ForEach(Event.RecurrenceType.allCases, id: \.self) { recurrence in
|
||||||
Text(recurrence.rawValue.capitalized)
|
Text(recurrence.rawValue.capitalized)
|
||||||
}
|
}
|
||||||
@@ -110,33 +135,44 @@ struct AddEventView: View {
|
|||||||
.pickerStyle(SegmentedPickerStyle())
|
.pickerStyle(SegmentedPickerStyle())
|
||||||
Text(
|
Text(
|
||||||
describeOccurrence(
|
describeOccurrence(
|
||||||
date: event.date,
|
date: eventDate,
|
||||||
recurrence: event.recurrence
|
recurrence: eventRecurrence
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.scrollContentBackground(.hidden)
|
||||||
.navigationTitle("\(adding ? "Add Event" : "")")
|
.navigationTitle("\(adding ? "Add Event" : "")")
|
||||||
.modifier(navigationInlineLarge())
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
.toolbar {
|
.toolbar {
|
||||||
ToolbarItem(placement: .cancellationAction) {
|
ToolbarItem(placement: .topBarLeading) {
|
||||||
if adding {
|
if adding {
|
||||||
Button() {
|
Button() {
|
||||||
resetAddEventView()
|
resetAddEventView()
|
||||||
dismiss()
|
dismiss()
|
||||||
} label: {
|
} label: {
|
||||||
Image(systemName: "xmark")
|
Image(systemName: "xmark.circle.fill")
|
||||||
|
.symbolRenderingMode(.hierarchical)
|
||||||
.resizable()
|
.resizable()
|
||||||
.scaledToFit()
|
.scaledToFit()
|
||||||
.tint(.one)
|
.frame(width: 30)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ToolbarItem() {
|
ToolbarItem(placement: .topBarTrailing) {
|
||||||
if adding {
|
if adding {
|
||||||
Button {
|
Button {
|
||||||
viewModel.addEvent(
|
viewModel.addEvent(
|
||||||
newEvent: event
|
newEvent: Event(
|
||||||
|
name: eventName,
|
||||||
|
complete: eventComplete,
|
||||||
|
completeDesc: eventCompleteDesc,
|
||||||
|
symbol: eventSymbol,
|
||||||
|
color: ColorCodable(eventColor),
|
||||||
|
notes: eventNotes,
|
||||||
|
date: eventDate,
|
||||||
|
recurrence: eventRecurrence
|
||||||
|
)
|
||||||
)
|
)
|
||||||
bye.toggle()
|
bye.toggle()
|
||||||
resetAddEventView()
|
resetAddEventView()
|
||||||
@@ -146,11 +182,14 @@ struct AddEventView: View {
|
|||||||
.cornerRadius(10)
|
.cornerRadius(10)
|
||||||
.buttonStyle(BorderedProminentButtonStyle())
|
.buttonStyle(BorderedProminentButtonStyle())
|
||||||
}
|
}
|
||||||
.tint(.accent)
|
.apply {
|
||||||
.modifier(hapticSuccess(trigger: bye))
|
if #available(iOS 17, *) {
|
||||||
.disabled(event.name.isEmpty)
|
$0.sensoryFeedback(.success, trigger: bye)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.disabled(eventName.isEmpty)
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
if event.name.isEmpty {
|
if eventName.isEmpty {
|
||||||
showNeedsNameAlert.toggle()
|
showNeedsNameAlert.toggle()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -162,17 +201,36 @@ struct AddEventView: View {
|
|||||||
} message: {
|
} message: {
|
||||||
Text("Give your Event a name before saving.")
|
Text("Give your Event a name before saving.")
|
||||||
}
|
}
|
||||||
|
if eventName.isEmpty {
|
||||||
|
HStack {
|
||||||
|
Image(systemName: "exclamationmark")
|
||||||
|
.foregroundStyle(.red)
|
||||||
|
Text("Give your event a name.")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.scrollContentBackground(.hidden)
|
|
||||||
.presentationDragIndicator(.visible)
|
.presentationDragIndicator(.visible)
|
||||||
|
.scrollContentBackground(.hidden)
|
||||||
|
}
|
||||||
|
.apply {
|
||||||
|
if #available(iOS 16.4, *) {
|
||||||
|
$0.presentationBackground(.ultraThinMaterial)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func resetAddEventView() {
|
func resetAddEventView() {
|
||||||
//reset addeventView
|
//reset addeventView
|
||||||
event = viewModel.template
|
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
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,7 +243,14 @@ struct AddEventView: View {
|
|||||||
.sheet(isPresented: .constant(true)) {
|
.sheet(isPresented: .constant(true)) {
|
||||||
AddEventView(
|
AddEventView(
|
||||||
viewModel: vm,
|
viewModel: vm,
|
||||||
event: .constant(vm.template),
|
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),
|
||||||
adding: true
|
adding: true
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,12 +28,19 @@ struct EditEventView: View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
AddEventView(
|
AddEventView(
|
||||||
viewModel: viewModel,
|
viewModel: viewModel,
|
||||||
event: $event,
|
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,
|
||||||
adding: false //bc we editing existing event
|
adding: false //bc we editing existing event
|
||||||
)
|
)
|
||||||
.navigationTitle("Edit Event")
|
.navigationTitle("Edit Event")
|
||||||
.toolbar {
|
.toolbar {
|
||||||
ToolbarItem(/*placement: .topBarTrailing*/) {
|
ToolbarItem(placement: .topBarTrailing) {
|
||||||
Button() {
|
Button() {
|
||||||
saveEdits()
|
saveEdits()
|
||||||
} label: {
|
} label: {
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ import SwiftUI
|
|||||||
import UserNotifications
|
import UserNotifications
|
||||||
import SwiftData
|
import SwiftData
|
||||||
|
|
||||||
|
enum Field {
|
||||||
|
case Search
|
||||||
|
}
|
||||||
enum Tab {
|
enum Tab {
|
||||||
case home
|
case home
|
||||||
case archive
|
case archive
|
||||||
@@ -19,10 +22,10 @@ enum Tab {
|
|||||||
struct ContentView: View {
|
struct ContentView: View {
|
||||||
@StateObject var viewModel: EventViewModel
|
@StateObject var viewModel: EventViewModel
|
||||||
@StateObject var settingsModel: SettingsViewModel
|
@StateObject var settingsModel: SettingsViewModel
|
||||||
@State var tabSelection: Tab = .home
|
@State var selection: Tab = .home
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
TabView(selection: $tabSelection) {
|
TabView(selection: $selection) {
|
||||||
HomeView(viewModel: viewModel, settingsModel: settingsModel)
|
HomeView(viewModel: viewModel, settingsModel: settingsModel)
|
||||||
.tabItem {
|
.tabItem {
|
||||||
Label("Home", systemImage: "house")
|
Label("Home", systemImage: "house")
|
||||||
@@ -34,7 +37,6 @@ struct ContentView: View {
|
|||||||
}
|
}
|
||||||
.tag(Tab.archive)
|
.tag(Tab.archive)
|
||||||
StatsView(viewModel: viewModel)
|
StatsView(viewModel: viewModel)
|
||||||
// SymbolsPickerStoryboardUIViewRepresentable()
|
|
||||||
.tabItem {
|
.tabItem {
|
||||||
Label("Statistics", systemImage: "chart.pie")
|
Label("Statistics", systemImage: "chart.pie")
|
||||||
}
|
}
|
||||||
@@ -45,7 +47,11 @@ struct ContentView: View {
|
|||||||
}
|
}
|
||||||
.tag(Tab.settings)
|
.tag(Tab.settings)
|
||||||
}
|
}
|
||||||
.modifier(hapticHeavy(trigger: tabSelection))
|
.apply {
|
||||||
|
if #available(iOS 17, *) {
|
||||||
|
$0.sensoryFeedback(.impact(weight: .heavy, intensity: 1), trigger: selection)
|
||||||
|
}
|
||||||
|
}
|
||||||
.sheet(isPresented: $settingsModel.settings.showWhatsNew) {
|
.sheet(isPresented: $settingsModel.settings.showWhatsNew) {
|
||||||
WhatsNewView(settingsModel: settingsModel)
|
WhatsNewView(settingsModel: settingsModel)
|
||||||
}
|
}
|
||||||
@@ -58,3 +64,33 @@ struct ContentView: View {
|
|||||||
settingsModel: dummySettingsViewModel()
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -76,7 +76,6 @@ struct EventListView: View {
|
|||||||
Text("\(daysUntilEvent(event.date).long)")
|
Text("\(daysUntilEvent(event.date).long)")
|
||||||
.font(.subheadline)
|
.font(.subheadline)
|
||||||
.foregroundStyle(event.date.timeIntervalSinceNow < 0 ? .red : .one)
|
.foregroundStyle(event.date.timeIntervalSinceNow < 0 ? .red : .one)
|
||||||
.multilineTextAlignment(.trailing)
|
|
||||||
}
|
}
|
||||||
Button() {
|
Button() {
|
||||||
withAnimation {
|
withAnimation {
|
||||||
@@ -112,10 +111,15 @@ struct EventListView: View {
|
|||||||
.frame(maxWidth: 25, maxHeight: 25)
|
.frame(maxWidth: 25, maxHeight: 25)
|
||||||
.shadow(radius: 5)
|
.shadow(radius: 5)
|
||||||
.padding(.trailing, 5)
|
.padding(.trailing, 5)
|
||||||
.modifier(hapticSuccess(trigger: event.complete))
|
.apply {
|
||||||
|
if #available(iOS 17, *) {
|
||||||
|
$0.sensoryFeedback(.success, trigger: event.complete)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.transition(.opacity)
|
.transition(.opacity)
|
||||||
.padding(.vertical, 5)
|
.padding(.vertical, 5)
|
||||||
|
.background(.ultraThinMaterial)
|
||||||
.overlay(
|
.overlay(
|
||||||
RoundedRectangle(cornerRadius: 10)
|
RoundedRectangle(cornerRadius: 10)
|
||||||
.stroke(
|
.stroke(
|
||||||
|
|||||||
@@ -13,10 +13,6 @@ enum HelpType {
|
|||||||
case Archive
|
case Archive
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Field {
|
|
||||||
case Search
|
|
||||||
}
|
|
||||||
|
|
||||||
struct HelpView: View {
|
struct HelpView: View {
|
||||||
/// initialises a Search HelpView
|
/// initialises a Search HelpView
|
||||||
///
|
///
|
||||||
@@ -78,7 +74,7 @@ struct HelpView: View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
List {
|
List {
|
||||||
ZStack {
|
ZStack {
|
||||||
Color(.accent)
|
Color(.tintColor)
|
||||||
.opacity(0.4)
|
.opacity(0.4)
|
||||||
.padding(.horizontal, -15)
|
.padding(.horizontal, -15)
|
||||||
.blur(radius: 5)
|
.blur(radius: 5)
|
||||||
|
|||||||
@@ -5,15 +5,20 @@
|
|||||||
// Created by neon443 on 12/05/2025.
|
// Created by neon443 on 12/05/2025.
|
||||||
//
|
//
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI;import AppIntents
|
||||||
import AppIntents
|
|
||||||
|
|
||||||
struct HomeView: View {
|
struct HomeView: View {
|
||||||
@ObservedObject var viewModel: EventViewModel
|
@ObservedObject var viewModel: EventViewModel
|
||||||
@ObservedObject var settingsModel: SettingsViewModel
|
@ObservedObject var settingsModel: SettingsViewModel
|
||||||
|
@State private var eventName = ""
|
||||||
@State private var event: Event = dummyEventViewModel().template
|
@State private var eventComplete = false
|
||||||
@State private var showingAddEventView: Bool = 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 searchInput: String = ""
|
@State private var searchInput: String = ""
|
||||||
@Environment(\.colorScheme) var appearance
|
@Environment(\.colorScheme) var appearance
|
||||||
var darkMode: Bool {
|
var darkMode: Bool {
|
||||||
@@ -42,18 +47,36 @@ struct HomeView: View {
|
|||||||
ZStack {
|
ZStack {
|
||||||
backgroundGradient
|
backgroundGradient
|
||||||
VStack {
|
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 {
|
if filteredEvents.isEmpty && !searchInput.isEmpty {
|
||||||
HelpView(searchInput: $searchInput, focusedField: focusedField)
|
HelpView(searchInput: $searchInput, focusedField: focusedField)
|
||||||
} else {
|
} else {
|
||||||
ScrollView {
|
ScrollView {
|
||||||
// LazyVStack {
|
|
||||||
ForEach(filteredEvents) { event in
|
ForEach(filteredEvents) { event in
|
||||||
EventListView(viewModel: viewModel, event: event)
|
EventListView(viewModel: viewModel, event: event)
|
||||||
.transition(.moveAndFade)
|
.transition(.moveAndFade)
|
||||||
.id(event.complete)
|
.id(event.complete)
|
||||||
}
|
}
|
||||||
.padding(.horizontal)
|
.padding(.horizontal)
|
||||||
// }
|
|
||||||
if filteredEvents.isEmpty {
|
if filteredEvents.isEmpty {
|
||||||
HelpView(
|
HelpView(
|
||||||
searchInput: $searchInput,
|
searchInput: $searchInput,
|
||||||
@@ -65,13 +88,25 @@ struct HomeView: View {
|
|||||||
.animation(.default, value: filteredEvents)
|
.animation(.default, value: filteredEvents)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.searchable(text: $searchInput)
|
|
||||||
.navigationTitle("Near Future")
|
.navigationTitle("Near Future")
|
||||||
.modifier(navigationInlineLarge())
|
.apply {
|
||||||
|
if #available(iOS 17, *) {
|
||||||
|
$0.toolbarTitleDisplayMode(.inlineLarge)
|
||||||
|
} else {
|
||||||
|
$0.navigationBarTitleDisplayMode(.inline)
|
||||||
|
}
|
||||||
|
}
|
||||||
.sheet(isPresented: $showingAddEventView) {
|
.sheet(isPresented: $showingAddEventView) {
|
||||||
AddEventView(
|
AddEventView(
|
||||||
viewModel: viewModel,
|
viewModel: viewModel,
|
||||||
event: $event,
|
eventName: $eventName,
|
||||||
|
eventComplete: $eventComplete,
|
||||||
|
eventCompleteDesc: $eventCompleteDesc,
|
||||||
|
eventSymbol: $eventSymbol,
|
||||||
|
eventColor: $eventColor,
|
||||||
|
eventNotes: $eventNotes,
|
||||||
|
eventDate: $eventDate,
|
||||||
|
eventRecurrence: $eventRecurrence,
|
||||||
adding: true //adding event
|
adding: true //adding event
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,12 +34,17 @@ struct AddEventButton: View {
|
|||||||
Button() {
|
Button() {
|
||||||
showingAddEventView.toggle()
|
showingAddEventView.toggle()
|
||||||
} label: {
|
} label: {
|
||||||
|
ZStack {
|
||||||
|
Circle()
|
||||||
|
.frame(width: 33)
|
||||||
|
.foregroundStyle(.one)
|
||||||
Image(systemName: "plus")
|
Image(systemName: "plus")
|
||||||
.resizable()
|
.resizable()
|
||||||
.scaledToFit()
|
.scaledToFit()
|
||||||
.frame(width: 15)
|
.frame(width: 15)
|
||||||
.bold()
|
.bold()
|
||||||
.foregroundStyle(.one)
|
.foregroundStyle(.two)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,11 +12,7 @@ struct ExportView: View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
List {
|
List {
|
||||||
Button() {
|
Button() {
|
||||||
#if canImport(UIKit)
|
|
||||||
UIPasteboard.general.string = viewModel.exportEvents()
|
UIPasteboard.general.string = viewModel.exportEvents()
|
||||||
#else
|
|
||||||
NSPasteboard.general.setString(viewModel.exportEvents(), forType: .string)
|
|
||||||
#endif
|
|
||||||
} label: {
|
} label: {
|
||||||
Label("Copy Events", systemImage: "document.on.clipboard")
|
Label("Copy Events", systemImage: "document.on.clipboard")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,13 +15,17 @@ struct ImportView: View {
|
|||||||
@State private var text: String = "Ready..."
|
@State private var text: String = "Ready..."
|
||||||
@State private var fgColor: Color = .yellow
|
@State private var fgColor: Color = .yellow
|
||||||
|
|
||||||
@State private var showAlert: Bool = false
|
var body: some View {
|
||||||
|
List {
|
||||||
@State private var replaceCurrentEvents: Bool = false
|
Section("Status") {
|
||||||
|
Label(text, systemImage: image)
|
||||||
fileprivate func importEvents() {
|
.contentTransition(.numericText())
|
||||||
|
.foregroundStyle(fgColor)
|
||||||
|
}
|
||||||
|
TextField("", text: $importStr)
|
||||||
|
Button() {
|
||||||
do throws {
|
do throws {
|
||||||
try viewModel.importEvents(importStr, replace: replaceCurrentEvents)
|
try viewModel.importEvents(importStr)
|
||||||
withAnimation {
|
withAnimation {
|
||||||
image = "checkmark.circle.fill"
|
image = "checkmark.circle.fill"
|
||||||
text = "Complete"
|
text = "Complete"
|
||||||
@@ -40,21 +44,6 @@ struct ImportView: View {
|
|||||||
fgColor = .red
|
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: {
|
||||||
Label("Import", systemImage: "tray.and.arrow.down.fill")
|
Label("Import", systemImage: "tray.and.arrow.down.fill")
|
||||||
}
|
}
|
||||||
@@ -66,66 +55,7 @@ struct ImportView: View {
|
|||||||
fgColor = .yellow
|
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,20 +11,47 @@ struct SettingsView: View {
|
|||||||
@ObservedObject var viewModel: EventViewModel
|
@ObservedObject var viewModel: EventViewModel
|
||||||
@ObservedObject var settingsModel: SettingsViewModel
|
@ObservedObject var settingsModel: SettingsViewModel
|
||||||
|
|
||||||
|
@State private var hasUbiquitous: Bool = false
|
||||||
|
@State private var lastSyncWasSuccessful: Bool = false
|
||||||
|
@State private var lastSyncWasNormalAgo: Bool = false
|
||||||
|
@State private var localCountEqualToiCloud: Bool = false
|
||||||
|
@State private var icloudCountEqualToLocal: Bool = false
|
||||||
@State private var importStr: String = ""
|
@State private var importStr: String = ""
|
||||||
|
|
||||||
func changeIcon(to toIcon: String) {
|
func updateStatus() {
|
||||||
|
let vm = viewModel
|
||||||
|
hasUbiquitous = vm.hasUbiquitousKeyValueStore()
|
||||||
|
lastSyncWasSuccessful = vm.syncStatus.contains("Success")
|
||||||
|
lastSyncWasNormalAgo = vm.lastSync?.timeIntervalSinceNow.isNormal ?? false
|
||||||
|
localCountEqualToiCloud = vm.localEventCount == vm.icloudEventCount
|
||||||
|
icloudCountEqualToLocal = vm.icloudEventCount == vm.localEventCount
|
||||||
|
}
|
||||||
|
|
||||||
|
var iCloudStatusColor: Color {
|
||||||
|
let allTrue = hasUbiquitous && lastSyncWasSuccessful && lastSyncWasNormalAgo && localCountEqualToiCloud && icloudCountEqualToLocal
|
||||||
|
let someTrue = hasUbiquitous || lastSyncWasSuccessful || lastSyncWasNormalAgo || localCountEqualToiCloud || icloudCountEqualToLocal
|
||||||
|
|
||||||
|
if allTrue {
|
||||||
|
return .green
|
||||||
|
} else if someTrue {
|
||||||
|
return .orange
|
||||||
|
} else {
|
||||||
|
return .red
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func changeIcon(to: String) {
|
||||||
guard UIApplication.shared.supportsAlternateIcons else {
|
guard UIApplication.shared.supportsAlternateIcons else {
|
||||||
print("doesnt tsupport alternate icons")
|
print("doesnt tsupport alternate icons")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
guard toIcon != "orange" else {
|
guard to != "orange" else {
|
||||||
UIApplication.shared.setAlternateIconName(nil) { error in
|
UIApplication.shared.setAlternateIconName(nil) { error in
|
||||||
print(error as Any)
|
print(error as Any)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
UIApplication.shared.setAlternateIconName(toIcon) { error in
|
UIApplication.shared.setAlternateIconName(to) { error in
|
||||||
print(error as Any)
|
print(error as Any)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -47,7 +74,6 @@ struct SettingsView: View {
|
|||||||
.foregroundStyle(color)
|
.foregroundStyle(color)
|
||||||
.frame(width: 30)
|
.frame(width: 30)
|
||||||
}
|
}
|
||||||
.buttonStyle(.plain)
|
|
||||||
if ColorCodable(color) == settingsModel.settings.tint {
|
if ColorCodable(color) == settingsModel.settings.tint {
|
||||||
let needContrast: Bool = ColorCodable(color) == settingsModel.settings.tint
|
let needContrast: Bool = ColorCodable(color) == settingsModel.settings.tint
|
||||||
Circle()
|
Circle()
|
||||||
@@ -68,16 +94,13 @@ struct SettingsView: View {
|
|||||||
NavigationLink() {
|
NavigationLink() {
|
||||||
List {
|
List {
|
||||||
if !settingsModel.notifsGranted {
|
if !settingsModel.notifsGranted {
|
||||||
|
Button("Request Notifications") {
|
||||||
|
Task {
|
||||||
|
settingsModel.notifsGranted = await requestNotifs()
|
||||||
|
}
|
||||||
|
}
|
||||||
Text("\(Image(systemName: "xmark")) Notifications disabled for Near Future")
|
Text("\(Image(systemName: "xmark")) Notifications disabled for Near Future")
|
||||||
.foregroundStyle(.red)
|
.foregroundStyle(.red)
|
||||||
Button("Request Notifications") {
|
|
||||||
Task.detached {
|
|
||||||
let requestNotifsResult = await requestNotifs()
|
|
||||||
await MainActor.run {
|
|
||||||
settingsModel.notifsGranted = requestNotifsResult
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
Text("\(Image(systemName: "checkmark")) Notifications enabled for Near Future")
|
Text("\(Image(systemName: "checkmark")) Notifications enabled for Near Future")
|
||||||
.foregroundStyle(.green)
|
.foregroundStyle(.green)
|
||||||
@@ -90,7 +113,13 @@ struct SettingsView: View {
|
|||||||
NavigationLink() {
|
NavigationLink() {
|
||||||
iCloudSettingsView(
|
iCloudSettingsView(
|
||||||
viewModel: viewModel,
|
viewModel: viewModel,
|
||||||
settingsModel: settingsModel
|
settingsModel: settingsModel,
|
||||||
|
hasUbiquitous: $hasUbiquitous,
|
||||||
|
lastSyncWasSuccessful: $lastSyncWasSuccessful,
|
||||||
|
lastSyncWasNormalAgo: $lastSyncWasNormalAgo,
|
||||||
|
localCountEqualToiCloud: $localCountEqualToiCloud,
|
||||||
|
icloudCountEqualToLocal: $icloudCountEqualToLocal,
|
||||||
|
updateStatus: updateStatus
|
||||||
)
|
)
|
||||||
} label: {
|
} label: {
|
||||||
HStack {
|
HStack {
|
||||||
@@ -99,12 +128,12 @@ struct SettingsView: View {
|
|||||||
Spacer()
|
Spacer()
|
||||||
Circle()
|
Circle()
|
||||||
.frame(width: 20, height: 20)
|
.frame(width: 20, height: 20)
|
||||||
.foregroundStyle(viewModel.iCloudStatusColor)
|
.foregroundStyle(iCloudStatusColor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onAppear {
|
.onAppear {
|
||||||
viewModel.sync()
|
viewModel.sync()
|
||||||
viewModel.updateiCStatus()
|
updateStatus()
|
||||||
}
|
}
|
||||||
NavigationLink() {
|
NavigationLink() {
|
||||||
ImportView(viewModel: viewModel, importStr: $importStr)
|
ImportView(viewModel: viewModel, importStr: $importStr)
|
||||||
@@ -148,9 +177,15 @@ struct SettingsView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.navigationTitle("Settings")
|
|
||||||
.modifier(navigationInlineLarge())
|
|
||||||
.scrollContentBackground(.hidden)
|
.scrollContentBackground(.hidden)
|
||||||
|
.navigationTitle("Settings")
|
||||||
|
.apply {
|
||||||
|
if #available(iOS 17, *) {
|
||||||
|
$0.toolbarTitleDisplayMode(.inlineLarge)
|
||||||
|
} else {
|
||||||
|
$0.navigationBarTitleDisplayMode(.inline)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,14 +16,9 @@ struct WhatsNewView: View {
|
|||||||
var title: String
|
var title: String
|
||||||
var subtitle: String
|
var subtitle: String
|
||||||
}
|
}
|
||||||
@State var bye: Bool = false
|
@State var bye = false
|
||||||
var whatsNewChunks: [WhatsNewChunk] {
|
var whatsNewChunks: [WhatsNewChunk] {
|
||||||
return [
|
return [
|
||||||
WhatsNewChunk(
|
|
||||||
symbol: "desktopcomputer",
|
|
||||||
title: "Mac Native App",
|
|
||||||
subtitle: "New Mac native app (Intel too!)"
|
|
||||||
),
|
|
||||||
WhatsNewChunk(
|
WhatsNewChunk(
|
||||||
symbol: "iphone.radiowaves.left.and.right",
|
symbol: "iphone.radiowaves.left.and.right",
|
||||||
title: "Haptic Feedback",
|
title: "Haptic Feedback",
|
||||||
@@ -58,11 +53,13 @@ struct WhatsNewView: View {
|
|||||||
}
|
}
|
||||||
var body: some View {
|
var body: some View {
|
||||||
NavigationStack {
|
NavigationStack {
|
||||||
ScrollView {
|
List {
|
||||||
|
VStack {
|
||||||
Text("What's New")
|
Text("What's New")
|
||||||
.font(.largeTitle)
|
.font(.largeTitle)
|
||||||
.bold()
|
.bold()
|
||||||
.padding(.vertical)
|
AboutView()
|
||||||
|
Divider()
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
ForEach(whatsNewChunks) { new in
|
ForEach(whatsNewChunks) { new in
|
||||||
WhatsNewChunkView(
|
WhatsNewChunkView(
|
||||||
@@ -71,9 +68,8 @@ struct WhatsNewView: View {
|
|||||||
subtitle: new.subtitle
|
subtitle: new.subtitle
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Spacer()
|
|
||||||
}
|
}
|
||||||
.padding(.horizontal, 10)
|
}
|
||||||
}
|
}
|
||||||
Button() {
|
Button() {
|
||||||
bye.toggle()
|
bye.toggle()
|
||||||
@@ -83,14 +79,24 @@ struct WhatsNewView: View {
|
|||||||
.font(.headline)
|
.font(.headline)
|
||||||
.frame(height: 40)
|
.frame(height: 40)
|
||||||
.bold()
|
.bold()
|
||||||
// .frame(maxWidth: .infinity)
|
.frame(maxWidth: .infinity)
|
||||||
|
}
|
||||||
|
.buttonStyle(BorderedProminentButtonStyle())
|
||||||
|
.clipShape(RoundedRectangle(cornerRadius: 15))
|
||||||
|
.padding().padding()
|
||||||
|
.apply {
|
||||||
|
if #available(iOS 17, *) {
|
||||||
|
$0.sensoryFeedback(.impact(weight: .heavy, intensity: 1), trigger: bye)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.foregroundStyle(.orange)
|
|
||||||
.modifier(glassButton())
|
|
||||||
.modifier(hapticHeavy(trigger: bye))
|
|
||||||
}
|
}
|
||||||
.scrollContentBackground(.hidden)
|
.scrollContentBackground(.hidden)
|
||||||
.presentationDragIndicator(.visible)
|
.presentationDragIndicator(.visible)
|
||||||
|
.apply {
|
||||||
|
if #available(iOS 16.4, *) {
|
||||||
|
$0.presentationBackground(.ultraThinMaterial)
|
||||||
|
}
|
||||||
|
}
|
||||||
.onDisappear {
|
.onDisappear {
|
||||||
settingsModel.settings.prevAppVersion = getVersion()+getBuildID()
|
settingsModel.settings.prevAppVersion = getVersion()+getBuildID()
|
||||||
settingsModel.saveSettings()
|
settingsModel.saveSettings()
|
||||||
@@ -116,7 +122,7 @@ struct WhatsNewChunkView: View {
|
|||||||
.resizable()
|
.resizable()
|
||||||
.scaledToFit()
|
.scaledToFit()
|
||||||
.frame(width: 30, height: 30)
|
.frame(width: 30, height: 30)
|
||||||
.foregroundStyle(Color.orange)
|
.foregroundStyle(Color.accentColor)
|
||||||
.padding(.trailing, 15)
|
.padding(.trailing, 15)
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
Text(title)
|
Text(title)
|
||||||
|
|||||||
@@ -13,13 +13,13 @@ struct iCloudSettingsView: View {
|
|||||||
@State var showPushAlert: Bool = false
|
@State var showPushAlert: Bool = false
|
||||||
@State var showPullAlert: Bool = false
|
@State var showPullAlert: Bool = false
|
||||||
|
|
||||||
// @Binding var hasUbiquitous: Bool
|
@Binding var hasUbiquitous: Bool
|
||||||
// @Binding var lastSyncWasSuccessful: Bool
|
@Binding var lastSyncWasSuccessful: Bool
|
||||||
// @Binding var lastSyncWasNormalAgo: Bool
|
@Binding var lastSyncWasNormalAgo: Bool
|
||||||
// @Binding var localCountEqualToiCloud: Bool
|
@Binding var localCountEqualToiCloud: Bool
|
||||||
// @Binding var icloudCountEqualToLocal: Bool
|
@Binding var icloudCountEqualToLocal: Bool
|
||||||
//
|
|
||||||
// var updateStatus: () -> Void
|
var updateStatus: () -> Void
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack {
|
ZStack {
|
||||||
@@ -55,7 +55,7 @@ struct iCloudSettingsView: View {
|
|||||||
Button("OK", role: .destructive) {
|
Button("OK", role: .destructive) {
|
||||||
viewModel.replaceiCloudWithLocalData()
|
viewModel.replaceiCloudWithLocalData()
|
||||||
viewModel.sync()
|
viewModel.sync()
|
||||||
viewModel.updateiCStatus()
|
updateStatus()
|
||||||
}
|
}
|
||||||
Button("Cancel", role: .cancel) {}
|
Button("Cancel", role: .cancel) {}
|
||||||
} message: {
|
} message: {
|
||||||
@@ -64,7 +64,7 @@ struct iCloudSettingsView: View {
|
|||||||
|
|
||||||
Button() {
|
Button() {
|
||||||
viewModel.sync()
|
viewModel.sync()
|
||||||
viewModel.updateiCStatus()
|
updateStatus()
|
||||||
} label: {
|
} label: {
|
||||||
Image(systemName: "arrow.triangle.2.circlepath")
|
Image(systemName: "arrow.triangle.2.circlepath")
|
||||||
.resizable()
|
.resizable()
|
||||||
@@ -87,7 +87,7 @@ struct iCloudSettingsView: View {
|
|||||||
Button("OK", role: .destructive) {
|
Button("OK", role: .destructive) {
|
||||||
viewModel.replaceLocalWithiCloudData()
|
viewModel.replaceLocalWithiCloudData()
|
||||||
viewModel.sync()
|
viewModel.sync()
|
||||||
viewModel.updateiCStatus()
|
updateStatus()
|
||||||
}
|
}
|
||||||
Button("Cancel", role: .cancel) {}
|
Button("Cancel", role: .cancel) {}
|
||||||
} message: {
|
} message: {
|
||||||
@@ -112,23 +112,23 @@ struct iCloudSettingsView: View {
|
|||||||
.listRowSeparator(.hidden)
|
.listRowSeparator(.hidden)
|
||||||
.onAppear {
|
.onAppear {
|
||||||
viewModel.sync()
|
viewModel.sync()
|
||||||
viewModel.updateiCStatus()
|
updateStatus()
|
||||||
}
|
}
|
||||||
|
|
||||||
HStack {
|
HStack {
|
||||||
Circle()
|
Circle()
|
||||||
.frame(width: 20, height: 20)
|
.frame(width: 20, height: 20)
|
||||||
.foregroundStyle(viewModel.hasUbiquitous ? .green : .red)
|
.foregroundStyle(hasUbiquitous ? .green : .red)
|
||||||
Text("iCloud")
|
Text("iCloud")
|
||||||
Spacer()
|
Spacer()
|
||||||
Text("\(viewModel.hasUbiquitous ? "" : "Not ")Working")
|
Text("\(hasUbiquitous ? "" : "Not ")Working")
|
||||||
.bold()
|
.bold()
|
||||||
}
|
}
|
||||||
|
|
||||||
HStack {
|
HStack {
|
||||||
Circle()
|
Circle()
|
||||||
.frame(width: 20, height: 20)
|
.frame(width: 20, height: 20)
|
||||||
.foregroundStyle(viewModel.lastSyncWasSuccessful ? .green : .red)
|
.foregroundStyle(lastSyncWasSuccessful ? .green : .red)
|
||||||
Text("Sync Status")
|
Text("Sync Status")
|
||||||
Spacer()
|
Spacer()
|
||||||
Text("\(viewModel.syncStatus)")
|
Text("\(viewModel.syncStatus)")
|
||||||
@@ -138,7 +138,7 @@ struct iCloudSettingsView: View {
|
|||||||
HStack {
|
HStack {
|
||||||
Circle()
|
Circle()
|
||||||
.frame(width: 20, height: 20)
|
.frame(width: 20, height: 20)
|
||||||
.foregroundStyle(viewModel.lastSyncWasNormalAgo ? .green : .red)
|
.foregroundStyle(lastSyncWasNormalAgo ? .green : .red)
|
||||||
Text("Last Sync")
|
Text("Last Sync")
|
||||||
Spacer()
|
Spacer()
|
||||||
Text("\(viewModel.lastSync?.formatted(date: .long, time: .standard) ?? "Never")")
|
Text("\(viewModel.lastSync?.formatted(date: .long, time: .standard) ?? "Never")")
|
||||||
@@ -148,7 +148,7 @@ struct iCloudSettingsView: View {
|
|||||||
HStack {
|
HStack {
|
||||||
Circle()
|
Circle()
|
||||||
.frame(width: 20, height: 20)
|
.frame(width: 20, height: 20)
|
||||||
.foregroundStyle(viewModel.localCountEqualToiCloud ? .green : .red)
|
.foregroundStyle(localCountEqualToiCloud ? .green : .red)
|
||||||
Text("Local Events")
|
Text("Local Events")
|
||||||
Spacer()
|
Spacer()
|
||||||
Text("\(viewModel.localEventCount)")
|
Text("\(viewModel.localEventCount)")
|
||||||
@@ -158,7 +158,7 @@ struct iCloudSettingsView: View {
|
|||||||
HStack {
|
HStack {
|
||||||
Circle()
|
Circle()
|
||||||
.frame(width: 20, height: 20)
|
.frame(width: 20, height: 20)
|
||||||
.foregroundStyle(viewModel.icloudCountEqualToLocal ? .green : .red)
|
.foregroundStyle(icloudCountEqualToLocal ? .green : .red)
|
||||||
Text("Events in iCloud")
|
Text("Events in iCloud")
|
||||||
Spacer()
|
Spacer()
|
||||||
Text("\(viewModel.icloudEventCount)")
|
Text("\(viewModel.icloudEventCount)")
|
||||||
@@ -172,10 +172,11 @@ struct iCloudSettingsView: View {
|
|||||||
}
|
}
|
||||||
.refreshable {
|
.refreshable {
|
||||||
viewModel.sync()
|
viewModel.sync()
|
||||||
viewModel.updateiCStatus()
|
updateStatus()
|
||||||
}
|
}
|
||||||
.scrollContentBackground(.hidden)
|
.scrollContentBackground(.hidden)
|
||||||
.navigationTitle("iCloud")
|
.navigationTitle("iCloud")
|
||||||
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -183,6 +184,12 @@ struct iCloudSettingsView: View {
|
|||||||
#Preview("iCloudSettingsView") {
|
#Preview("iCloudSettingsView") {
|
||||||
iCloudSettingsView(
|
iCloudSettingsView(
|
||||||
viewModel: dummyEventViewModel(),
|
viewModel: dummyEventViewModel(),
|
||||||
settingsModel: dummySettingsViewModel()
|
settingsModel: dummySettingsViewModel(),
|
||||||
|
hasUbiquitous: .constant(true),
|
||||||
|
lastSyncWasSuccessful: .constant(true),
|
||||||
|
lastSyncWasNormalAgo: .constant(true),
|
||||||
|
localCountEqualToiCloud: .constant(true),
|
||||||
|
icloudCountEqualToLocal: .constant(true),
|
||||||
|
updateStatus: {}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,7 +58,13 @@ struct StatsView: View {
|
|||||||
}
|
}
|
||||||
.scrollContentBackground(.hidden)
|
.scrollContentBackground(.hidden)
|
||||||
.navigationTitle("Statistics")
|
.navigationTitle("Statistics")
|
||||||
.modifier(navigationInlineLarge())
|
.apply {
|
||||||
|
if #available(iOS 17, *) {
|
||||||
|
$0.toolbarTitleDisplayMode(.inlineLarge)
|
||||||
|
} else {
|
||||||
|
$0.navigationBarTitleDisplayMode(.inline)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
16
NearFutureTests/NearFutureTests.swift
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
//
|
||||||
|
// 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.
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -11,18 +11,17 @@
|
|||||||
- [x] Event colors
|
- [x] Event colors
|
||||||
- [x] Recurrence
|
- [x] Recurrence
|
||||||
- [x] Search
|
- [x] Search
|
||||||
- [x] Notifications
|
- [ ] Notifications
|
||||||
- [ ] Mac App
|
|
||||||
- [ ] Apple Watch App
|
- [ ] Apple Watch App
|
||||||
- [x] Home Screen Widgets
|
- [x] Home Screen Widgets
|
||||||
- [ ] Lock Screen Widgets
|
- [ ] Lock Screen Widgets
|
||||||
- [ ] Later Box
|
- [ ] Later Box
|
||||||
- [ ] Sort by
|
- [ ] Sort by
|
||||||
- [ ] Reorder Events
|
- [ ] Reorder Events
|
||||||
- [x] Archive
|
- [ ] Archive
|
||||||
- [ ] Collaboration
|
- [ ] Collaboration
|
||||||
- [ ] Autocomplete tasks
|
- [ ] Autocomplete tasks
|
||||||
- [x] Settings
|
- [ ] Settings
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
- **Event Creation**: Create events with a name, description, date, recurrence, and an icon
|
- **Event Creation**: Create events with a name, description, date, recurrence, and an icon
|
||||||
|
|||||||
@@ -31,70 +31,54 @@
|
|||||||
"size" : "1024x1024"
|
"size" : "1024x1024"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filename" : "MacNearFutureIcon16.png",
|
|
||||||
"idiom" : "mac",
|
"idiom" : "mac",
|
||||||
"scale" : "1x",
|
"scale" : "1x",
|
||||||
"size" : "16x16"
|
"size" : "16x16"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filename" : "MacNearFutureIcon32.png",
|
|
||||||
"idiom" : "mac",
|
"idiom" : "mac",
|
||||||
"scale" : "2x",
|
"scale" : "2x",
|
||||||
"size" : "16x16"
|
"size" : "16x16"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filename" : "MacNearFutureIcon32.png",
|
|
||||||
"idiom" : "mac",
|
"idiom" : "mac",
|
||||||
"scale" : "1x",
|
"scale" : "1x",
|
||||||
"size" : "32x32"
|
"size" : "32x32"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filename" : "MacNearFutureIcon64.png",
|
|
||||||
"idiom" : "mac",
|
"idiom" : "mac",
|
||||||
"scale" : "2x",
|
"scale" : "2x",
|
||||||
"size" : "32x32"
|
"size" : "32x32"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filename" : "MacNearFutureIcon128.png",
|
|
||||||
"idiom" : "mac",
|
"idiom" : "mac",
|
||||||
"scale" : "1x",
|
"scale" : "1x",
|
||||||
"size" : "128x128"
|
"size" : "128x128"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filename" : "MacNearFutureIcon256.png",
|
|
||||||
"idiom" : "mac",
|
"idiom" : "mac",
|
||||||
"scale" : "2x",
|
"scale" : "2x",
|
||||||
"size" : "128x128"
|
"size" : "128x128"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filename" : "MacNearFutureIcon256.png",
|
|
||||||
"idiom" : "mac",
|
"idiom" : "mac",
|
||||||
"scale" : "1x",
|
"scale" : "1x",
|
||||||
"size" : "256x256"
|
"size" : "256x256"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filename" : "MacNearFutureIcon512.png",
|
|
||||||
"idiom" : "mac",
|
"idiom" : "mac",
|
||||||
"scale" : "2x",
|
"scale" : "2x",
|
||||||
"size" : "256x256"
|
"size" : "256x256"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filename" : "MacNearFutureIcon512.png",
|
|
||||||
"idiom" : "mac",
|
"idiom" : "mac",
|
||||||
"scale" : "1x",
|
"scale" : "1x",
|
||||||
"size" : "512x512"
|
"size" : "512x512"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filename" : "MacNearFutureIcon.png",
|
|
||||||
"idiom" : "mac",
|
"idiom" : "mac",
|
||||||
"scale" : "2x",
|
"scale" : "2x",
|
||||||
"size" : "512x512"
|
"size" : "512x512"
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "NearFutureIcon.png",
|
|
||||||
"idiom" : "universal",
|
|
||||||
"platform" : "watchos",
|
|
||||||
"size" : "1024x1024"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"info" : {
|
"info" : {
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 893 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 197 KiB |
|
Before Width: | Height: | Size: 5.8 KiB |
@@ -29,12 +29,6 @@
|
|||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"platform" : "ios",
|
"platform" : "ios",
|
||||||
"size" : "1024x1024"
|
"size" : "1024x1024"
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "bloo.png",
|
|
||||||
"idiom" : "universal",
|
|
||||||
"platform" : "watchos",
|
|
||||||
"size" : "1024x1024"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"info" : {
|
"info" : {
|
||||||
|
|||||||
@@ -29,12 +29,6 @@
|
|||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"platform" : "ios",
|
"platform" : "ios",
|
||||||
"size" : "1024x1024"
|
"size" : "1024x1024"
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "blue.png",
|
|
||||||
"idiom" : "universal",
|
|
||||||
"platform" : "watchos",
|
|
||||||
"size" : "1024x1024"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"info" : {
|
"info" : {
|
||||||
|
|||||||
@@ -29,12 +29,6 @@
|
|||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"platform" : "ios",
|
"platform" : "ios",
|
||||||
"size" : "1024x1024"
|
"size" : "1024x1024"
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "green.png",
|
|
||||||
"idiom" : "universal",
|
|
||||||
"platform" : "watchos",
|
|
||||||
"size" : "1024x1024"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"info" : {
|
"info" : {
|
||||||
|
|||||||
@@ -29,12 +29,6 @@
|
|||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"platform" : "ios",
|
"platform" : "ios",
|
||||||
"size" : "1024x1024"
|
"size" : "1024x1024"
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "pink.png",
|
|
||||||
"idiom" : "universal",
|
|
||||||
"platform" : "watchos",
|
|
||||||
"size" : "1024x1024"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"info" : {
|
"info" : {
|
||||||
|
|||||||
@@ -29,12 +29,6 @@
|
|||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"platform" : "ios",
|
"platform" : "ios",
|
||||||
"size" : "1024x1024"
|
"size" : "1024x1024"
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "purple.png",
|
|
||||||
"idiom" : "universal",
|
|
||||||
"platform" : "watchos",
|
|
||||||
"size" : "1024x1024"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"info" : {
|
"info" : {
|
||||||
|
|||||||
@@ -29,12 +29,6 @@
|
|||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"platform" : "ios",
|
"platform" : "ios",
|
||||||
"size" : "1024x1024"
|
"size" : "1024x1024"
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "red.png",
|
|
||||||
"idiom" : "universal",
|
|
||||||
"platform" : "watchos",
|
|
||||||
"size" : "1024x1024"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"info" : {
|
"info" : {
|
||||||
|
|||||||
@@ -29,12 +29,6 @@
|
|||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"platform" : "ios",
|
"platform" : "ios",
|
||||||
"size" : "1024x1024"
|
"size" : "1024x1024"
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "yellow.png",
|
|
||||||
"idiom" : "universal",
|
|
||||||
"platform" : "watchos",
|
|
||||||
"size" : "1024x1024"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"info" : {
|
"info" : {
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 551 KiB |
|
Before Width: | Height: | Size: 126 KiB |
@@ -1,50 +0,0 @@
|
|||||||
{
|
|
||||||
"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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
//
|
|
||||||
// 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
//
|
|
||||||
// AccentIcon.swift
|
|
||||||
// NearFuture
|
|
||||||
//
|
|
||||||
// Created by neon443 on 13/06/2025.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import SwiftUI
|
|
||||||
#if canImport(AppKit)
|
|
||||||
import AppKit
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
//
|
|
||||||
// ColorCodable.swift
|
|
||||||
// NearFuture
|
|
||||||
//
|
|
||||||
// Created by neon443 on 13/06/2025.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import SwiftUI
|
|
||||||
#if canImport(UIKit)
|
|
||||||
import UIKit
|
|
||||||
#else
|
|
||||||
import AppKit
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct ColorCodable: Codable, Equatable, Hashable {
|
|
||||||
init(_ color: Color) {
|
|
||||||
var r: CGFloat = 0, g: CGFloat = 0, b: CGFloat = 0, a: CGFloat = 1
|
|
||||||
|
|
||||||
#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 = 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
|
|
||||||
self.blue = blue
|
|
||||||
}
|
|
||||||
|
|
||||||
var red: Double
|
|
||||||
var green: Double
|
|
||||||
var blue: Double
|
|
||||||
|
|
||||||
var color: Color {
|
|
||||||
Color(red: red, green: green, blue: blue)
|
|
||||||
}
|
|
||||||
var colorBind: Color {
|
|
||||||
get {
|
|
||||||
return Color(
|
|
||||||
red: red,
|
|
||||||
green: green,
|
|
||||||
blue: blue
|
|
||||||
)
|
|
||||||
} set {
|
|
||||||
let cc = ColorCodable(newValue)
|
|
||||||
self.red = cc.red
|
|
||||||
self.green = cc.green
|
|
||||||
self.blue = cc.blue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
//
|
|
||||||
// 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 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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
//
|
|
||||||
// SymbolsLoader.swift
|
|
||||||
// NearFuture
|
|
||||||
//
|
|
||||||
// Created by neon443 on 14/06/2025.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
class SymbolsLoader: ObservableObject {
|
|
||||||
@Published var allSymbols: [String] = []
|
|
||||||
|
|
||||||
init() {
|
|
||||||
self.allSymbols = getAllSymbols()
|
|
||||||
}
|
|
||||||
|
|
||||||
func getSymbols(_ searched: String) -> [String] {
|
|
||||||
if searched.isEmpty {
|
|
||||||
return allSymbols
|
|
||||||
} else {
|
|
||||||
return allSymbols.filter() { $0.localizedCaseInsensitiveContains(searched) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getAllSymbols() -> [String] {
|
|
||||||
var allSymbols = [String]()
|
|
||||||
if let bundle = Bundle(identifier: "com.apple.CoreGlyphs"),
|
|
||||||
let resPath = bundle.path(forResource: "name_availability", ofType: "plist"),
|
|
||||||
let plist = try? NSDictionary(contentsOf: URL(fileURLWithPath: resPath), error: ()),
|
|
||||||
let plistSymbols = plist["symbols"] as? [String: String]
|
|
||||||
{
|
|
||||||
allSymbols = Array(plistSymbols.keys)
|
|
||||||
}
|
|
||||||
return allSymbols
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="24093.7" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
|
||||||
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
|
||||||
<dependencies>
|
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="24053.1"/>
|
|
||||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
|
||||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
|
||||||
<capability name="collection view cell content view" minToolsVersion="11.0"/>
|
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
|
||||||
</dependencies>
|
|
||||||
<scenes>
|
|
||||||
<!--View Controller-->
|
|
||||||
<scene sceneID="s0d-6b-0kx">
|
|
||||||
<objects>
|
|
||||||
<viewController storyboardIdentifier="ViewController" id="Y6W-OH-hqX" customClass="ViewController" customModule="NearFuture" customModuleProvider="target" sceneMemberID="viewController">
|
|
||||||
<view key="view" contentMode="scaleToFill" id="5EZ-qb-Rvc">
|
|
||||||
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
|
||||||
<subviews>
|
|
||||||
<collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" fixedFrame="YES" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="xBf-3w-4Ao">
|
|
||||||
<rect key="frame" x="0.0" y="63" width="393" height="666"/>
|
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
|
||||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
|
||||||
<collectionViewFlowLayout key="collectionViewLayout" automaticEstimatedItemSize="YES" minimumLineSpacing="10" minimumInteritemSpacing="10" id="d2N-B5-D5N">
|
|
||||||
<size key="itemSize" width="100" height="100"/>
|
|
||||||
<size key="headerReferenceSize" width="0.0" height="0.0"/>
|
|
||||||
<size key="footerReferenceSize" width="0.0" height="0.0"/>
|
|
||||||
<inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
|
|
||||||
</collectionViewFlowLayout>
|
|
||||||
<cells>
|
|
||||||
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="symbolCell" id="nKx-2O-Nq5" customClass="SymbolCell" customModule="NearFuture" customModuleProvider="target">
|
|
||||||
<rect key="frame" x="0.0" y="0.0" width="100" height="100"/>
|
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
|
||||||
<collectionViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" id="3DG-aV-ZH4">
|
|
||||||
<rect key="frame" x="0.0" y="0.0" width="100" height="100"/>
|
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
|
||||||
<subviews>
|
|
||||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="AaY-Po-OoS">
|
|
||||||
<rect key="frame" x="0.0" y="0.0" width="100" height="100"/>
|
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
|
||||||
</imageView>
|
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="gGM-kQ-cA7">
|
|
||||||
<rect key="frame" x="29" y="79" width="42" height="21"/>
|
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
|
||||||
<nil key="textColor"/>
|
|
||||||
<nil key="highlightedColor"/>
|
|
||||||
</label>
|
|
||||||
</subviews>
|
|
||||||
</collectionViewCellContentView>
|
|
||||||
<connections>
|
|
||||||
<outlet property="imageView" destination="AaY-Po-OoS" id="Swa-vO-Mtz"/>
|
|
||||||
<outlet property="textLabel" destination="gGM-kQ-cA7" id="Qei-Qd-rn5"/>
|
|
||||||
</connections>
|
|
||||||
</collectionViewCell>
|
|
||||||
</cells>
|
|
||||||
</collectionView>
|
|
||||||
</subviews>
|
|
||||||
<viewLayoutGuide key="safeArea" id="vDu-zF-Fre"/>
|
|
||||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
|
||||||
</view>
|
|
||||||
<connections>
|
|
||||||
<outlet property="collectionView" destination="xBf-3w-4Ao" id="c9h-Ew-aOX"/>
|
|
||||||
</connections>
|
|
||||||
</viewController>
|
|
||||||
<placeholder placeholderIdentifier="IBFirstResponder" id="Ief-a0-LHa" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
|
|
||||||
</objects>
|
|
||||||
<point key="canvasLocation" x="139.69465648854961" y="65.492957746478879"/>
|
|
||||||
</scene>
|
|
||||||
</scenes>
|
|
||||||
<resources>
|
|
||||||
<systemColor name="systemBackgroundColor">
|
|
||||||
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
|
||||||
</systemColor>
|
|
||||||
</resources>
|
|
||||||
</document>
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
//
|
|
||||||
// SymbolsPicker.swift
|
|
||||||
// NearFuture
|
|
||||||
//
|
|
||||||
// Created by neon443 on 14/06/2025.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
struct SymbolsPicker: View {
|
|
||||||
@StateObject private var symbolsLoader = SymbolsLoader()
|
|
||||||
@Binding var selection: String
|
|
||||||
|
|
||||||
@FocusState var searchfocuesd: Bool
|
|
||||||
|
|
||||||
@State var searchInput: String = ""
|
|
||||||
|
|
||||||
var symbols: [String] {
|
|
||||||
return symbolsLoader.getSymbols(searchInput)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func gridLayout(forWidth geoSizeWidth: CGFloat) -> [GridItem] {
|
|
||||||
let gridItem = GridItem(.fixed(80), spacing: 20, alignment: .center)
|
|
||||||
let columns = Int(geoSizeWidth/100.rounded(.up))
|
|
||||||
return Array(repeating: gridItem, count: columns)
|
|
||||||
}
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
NavigationStack {
|
|
||||||
GeometryReader { geo in
|
|
||||||
ScrollView {
|
|
||||||
if symbols.isEmpty {
|
|
||||||
HStack {
|
|
||||||
Image(systemName: "magnifyingglass")
|
|
||||||
.resizable().scaledToFit()
|
|
||||||
.frame(width: 30)
|
|
||||||
Text("You look lost")
|
|
||||||
.font(.title)
|
|
||||||
.bold()
|
|
||||||
}
|
|
||||||
.padding()
|
|
||||||
Text("The symbol picker search only works with exact matches, try a different search term.")
|
|
||||||
}
|
|
||||||
LazyVGrid(columns: gridLayout(forWidth: geo.size.width)) {
|
|
||||||
ForEach(symbols, id: \.self) { symbol in
|
|
||||||
Button() {
|
|
||||||
selection = symbol
|
|
||||||
} label: {
|
|
||||||
VStack {
|
|
||||||
Image(systemName: symbol)
|
|
||||||
.resizable()
|
|
||||||
.scaledToFit()
|
|
||||||
.symbolRenderingMode(.palette)
|
|
||||||
.foregroundStyle(.blue, .gray, .black)
|
|
||||||
Text(symbol)
|
|
||||||
.truncationMode(.middle)
|
|
||||||
.font(.footnote)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.frame(maxWidth: 80, maxHeight: 80)
|
|
||||||
.buttonStyle(.plain)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.searchable(text: $searchInput)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#Preview {
|
|
||||||
SymbolsPicker(selection: .constant(""))
|
|
||||||
}
|
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
//
|
|
||||||
// SymbolsPickerStoryboard.swift
|
|
||||||
// NearFuture
|
|
||||||
//
|
|
||||||
// Created by neon443 on 14/06/2025.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import SwiftUI
|
|
||||||
#if canImport(UIKit)
|
|
||||||
import UIKit
|
|
||||||
#else
|
|
||||||
import AppKit
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class ViewController: UIViewController {
|
|
||||||
@IBOutlet weak var collectionView: UICollectionView!
|
|
||||||
var symbolLoader: SymbolsLoader = SymbolsLoader()
|
|
||||||
|
|
||||||
override func viewDidLayoutSubviews() {
|
|
||||||
super.viewDidLayoutSubviews()
|
|
||||||
|
|
||||||
if let flowLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
|
|
||||||
flowLayout.itemSize = CGSize(
|
|
||||||
width: 100,
|
|
||||||
height: 100
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override func viewDidLoad() {
|
|
||||||
super.viewDidLoad()
|
|
||||||
collectionView.delegate = self
|
|
||||||
collectionView.dataSource = self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension ViewController: UICollectionViewDataSource {
|
|
||||||
func numberOfSections(in collectionView: UICollectionView) -> Int {
|
|
||||||
symbolLoader.allSymbols.count
|
|
||||||
}
|
|
||||||
|
|
||||||
func collectionView(
|
|
||||||
_ collectionView: UICollectionView,
|
|
||||||
numberOfItemsInSection section: Int
|
|
||||||
) -> Int {
|
|
||||||
section
|
|
||||||
}
|
|
||||||
|
|
||||||
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
|
||||||
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "symbolCell", for: indexPath) as! SymbolCell
|
|
||||||
|
|
||||||
let imageView = cell.imageView
|
|
||||||
imageView?.image = UIImage(systemName: symbolLoader.allSymbols[indexPath.item])!
|
|
||||||
cell.textLabel?.text = "hi\(indexPath.row)"
|
|
||||||
return cell
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension ViewController: UICollectionViewDelegate {
|
|
||||||
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
|
||||||
print(indexPath.item)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class SymbolCell: UICollectionViewCell {
|
|
||||||
@IBOutlet weak var imageView: UIImageView!
|
|
||||||
@IBOutlet weak var textLabel: UILabel!
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
struct SymbolsPickerStoryboardUIViewRepresentable: UIViewRepresentable {
|
|
||||||
class Coordinator {
|
|
||||||
var viewController: ViewController?
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeCoordinator() -> Coordinator {
|
|
||||||
Coordinator()
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeUIView(context: Context) -> some UIView {
|
|
||||||
let storyboard = UIStoryboard(name: "SymbolsPicker", bundle: nil)
|
|
||||||
let viewController = storyboard.instantiateViewController(withIdentifier: "ViewController") as! ViewController
|
|
||||||
context.coordinator.viewController = viewController
|
|
||||||
return viewController.view
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateUIView(_ uiView: UIViewType, context: Context) {
|
|
||||||
print()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
//
|
|
||||||
// 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
//
|
|
||||||
// ViewModifiers.swift
|
|
||||||
// NearFuture
|
|
||||||
//
|
|
||||||
// Created by neon443 on 13/06/2025.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
struct hapticHeavy: ViewModifier {
|
|
||||||
var trigger: any Equatable
|
|
||||||
|
|
||||||
init(trigger: any Equatable) {
|
|
||||||
self.trigger = trigger
|
|
||||||
}
|
|
||||||
|
|
||||||
func body(content: Content) -> some View {
|
|
||||||
if #available(iOS 17, *) {
|
|
||||||
content
|
|
||||||
.sensoryFeedback(.impact(weight: .heavy, intensity: 1), trigger: trigger)
|
|
||||||
} else {
|
|
||||||
content
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct glassButton: ViewModifier {
|
|
||||||
func body(content: Content) -> some View {
|
|
||||||
if #available(iOS 19, macOS 16, *) {
|
|
||||||
content.buttonStyle(.glass)
|
|
||||||
} else {
|
|
||||||
content.buttonStyle(.borderedProminent)
|
|
||||||
.clipShape(RoundedRectangle(cornerRadius: 15))
|
|
||||||
.tint(.two)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct hapticSuccess: ViewModifier {
|
|
||||||
var trigger: any Equatable
|
|
||||||
|
|
||||||
init(trigger: any Equatable) {
|
|
||||||
self.trigger = trigger
|
|
||||||
}
|
|
||||||
|
|
||||||
func body(content: Content) -> some View {
|
|
||||||
if #available(iOS 17, *) {
|
|
||||||
content.sensoryFeedback(.success, trigger: trigger)
|
|
||||||
} else {
|
|
||||||
content
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct navigationInlineLarge: ViewModifier {
|
|
||||||
func body(content: Content) -> some View {
|
|
||||||
#if os(macOS)
|
|
||||||
content
|
|
||||||
.toolbarTitleDisplayMode(.inlineLarge)
|
|
||||||
#else
|
|
||||||
content
|
|
||||||
.navigationBarTitleDisplayMode(.inline)
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct presentationSizeForm: ViewModifier {
|
|
||||||
func body(content: Content) -> some View {
|
|
||||||
if #available(iOS 18, macOS 15, *) {
|
|
||||||
content.presentationSizing(.form)
|
|
||||||
} else {
|
|
||||||
content
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||