Shortcut test + fixes

release
Laurent 3 years ago
parent 78d1fc0b73
commit 88d85ed49c
  1. 10
      LeCountdown.xcodeproj/project.pbxproj
  2. 8
      LeCountdown.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
  3. 1
      LeCountdown/Info.plist
  4. 7
      LeCountdown/LeCountdownApp.swift
  5. 56
      LeCountdown/Utils/Shortcut.swift
  6. 20
      LeCountdown/Utils/UIDevice+Extensions.swift
  7. 6
      LeCountdown/Views/ContentView.swift
  8. 8
      LeCountdown/Views/Countdown/NewCountdownView.swift
  9. 7
      LeCountdown/Views/HomeView.swift
  10. 6
      LeCountdown/Views/LiveTimerListView.swift
  11. 6
      LeCountdown/Views/PresetsView.swift
  12. 10
      LeCountdown/Views/Stats/ActivityView.swift
  13. 24
      LeCountdown/Views/Stats/RecordsView.swift

@ -128,6 +128,8 @@
C4BA2B6829A3C4AC00CB4FBA /* Context+Calculations.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BA2B6729A3C4AC00CB4FBA /* Context+Calculations.swift */; };
C4BA2B6A29A4BE1800CB4FBA /* Date+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BA2B6929A4BE1800CB4FBA /* Date+Extensions.swift */; };
C4BA2B7129A51CA000CB4FBA /* SiriIntents.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = C4BA2B7029A51CA000CB4FBA /* SiriIntents.intentdefinition */; };
C4BA2B7329A60CF000CB4FBA /* Shortcut.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BA2B7229A60CF000CB4FBA /* Shortcut.swift */; };
C4BA2B7929A65C1400CB4FBA /* UIDevice+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BA2B7829A65C1400CB4FBA /* UIDevice+Extensions.swift */; };
C4F8B1532987FE6F005C86A5 /* LaunchWidgetLiveActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = C438C7D72981216200BF3EF9 /* LaunchWidgetLiveActivity.swift */; };
C4F8B15729891271005C86A5 /* Conductor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4F8B15629891271005C86A5 /* Conductor.swift */; };
C4F8B15929891528005C86A5 /* forest_stream.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = C4F8B15829891528005C86A5 /* forest_stream.mp3 */; };
@ -325,6 +327,8 @@
C4BA2B6929A4BE1800CB4FBA /* Date+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+Extensions.swift"; sourceTree = "<group>"; };
C4BA2B6B29A4C47100CB4FBA /* LeCountdown.0.6.2.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = LeCountdown.0.6.2.xcdatamodel; sourceTree = "<group>"; };
C4BA2B7029A51CA000CB4FBA /* SiriIntents.intentdefinition */ = {isa = PBXFileReference; lastKnownFileType = file.intentdefinition; path = SiriIntents.intentdefinition; sourceTree = "<group>"; };
C4BA2B7229A60CF000CB4FBA /* Shortcut.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Shortcut.swift; sourceTree = "<group>"; };
C4BA2B7829A65C1400CB4FBA /* UIDevice+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIDevice+Extensions.swift"; sourceTree = "<group>"; };
C4F8B15629891271005C86A5 /* Conductor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Conductor.swift; sourceTree = "<group>"; };
C4F8B15829891528005C86A5 /* forest_stream.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = forest_stream.mp3; sourceTree = "<group>"; };
C4F8B15E298961A7005C86A5 /* ReorderableForEach.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReorderableForEach.swift; sourceTree = "<group>"; };
@ -541,6 +545,8 @@
C438C81029829EAF00BF3EF9 /* PropertyWrappers.swift */,
C40FDB612992985C0042A390 /* TextToSpeechRecorder.swift */,
C4060DF4297AE9A7003FAB80 /* TimeInterval+Extensions.swift */,
C4BA2B7229A60CF000CB4FBA /* Shortcut.swift */,
C4BA2B7829A65C1400CB4FBA /* UIDevice+Extensions.swift */,
);
path = Utils;
sourceTree = "<group>";
@ -901,6 +907,7 @@
buildActionMask = 2147483647;
files = (
C4F8B1D2298BF646005C86A5 /* PermissionAlertView.swift in Sources */,
C4BA2B7329A60CF000CB4FBA /* Shortcut.swift in Sources */,
C4060DC9297AE73D003FAB80 /* Persistence.swift in Sources */,
C4BA2B36299F82FB00CB4FBA /* Fakes.swift in Sources */,
C498E5A1298D543900E90DE0 /* LiveTimer.swift in Sources */,
@ -915,6 +922,7 @@
C4BA2B57299FFA4F00CB4FBA /* AppGuard.swift in Sources */,
C4F8B15729891271005C86A5 /* Conductor.swift in Sources */,
C4BA2B5F299FFC8400CB4FBA /* StoreView.swift in Sources */,
C4BA2B7929A65C1400CB4FBA /* UIDevice+Extensions.swift in Sources */,
C4F8B17E298AC234005C86A5 /* Alarm+CoreDataClass.swift in Sources */,
C438C81129829EAF00BF3EF9 /* PropertyWrappers.swift in Sources */,
C4F8B1BF298ACA0B005C86A5 /* StopwatchDialView.swift in Sources */,
@ -1433,6 +1441,7 @@
INFOPLIST_FILE = LaunchIntents/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = LaunchIntents;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 16.2;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@ -1459,6 +1468,7 @@
INFOPLIST_FILE = LaunchIntents/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = LaunchIntents;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 16.2;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",

@ -0,0 +1,8 @@
<?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>PreviewsEnabled</key>
<false/>
</dict>
</plist>

@ -8,6 +8,7 @@
</array>
<key>NSUserActivityTypes</key>
<array>
<string>app.kikai.NewCountdown</string>
<string>LaunchTimerIntent</string>
<string>SelectTimerIntent</string>
</array>

@ -32,16 +32,13 @@ struct LeCountdownApp: App {
@Environment(\.scenePhase) var scenePhase
#if os(iOS)
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
#endif
var body: some Scene {
WindowGroup {
Group {
#if os(iOS)
if horizontalSizeClass == .compact {
if UIDevice.isPhoneIdiom {
CompactHomeView()
.environment(\.managedObjectContext, persistenceController.container.viewContext)
} else {

@ -0,0 +1,56 @@
//
// Shortcut.swift
// LeCountdown
//
// Created by Laurent Morvillier on 22/02/2023.
//
import Foundation
import UIKit
import CoreServices
import CoreSpotlight
import UniformTypeIdentifiers
enum Shortcut: String {
case newCountdown = "app.kikai.NewCountdown"
var userActivity: NSUserActivity {
let activity = NSUserActivity(activityType: self.rawValue)
activity.persistentIdentifier = NSUserActivityPersistentIdentifier(self.rawValue)
activity.title = self.title
activity.suggestedInvocationPhrase = self.suggestedInvocationPhrase
activity.isEligibleForSearch = true
activity.isEligibleForPrediction = true
let attributes = CSSearchableItemAttributeSet(contentType: UTType.item)
attributes.contentDescription = self.contentDescription
attributes.thumbnailData = self.image?.jpegData(compressionQuality: 1.0)
activity.contentAttributeSet = attributes
return activity
}
var title: String {
switch self {
case .newCountdown: return NSLocalizedString("New countdown", comment: "")
}
}
var suggestedInvocationPhrase: String {
switch self {
case .newCountdown: return NSLocalizedString("Create countdown", comment: "")
}
}
var contentDescription: String {
switch self {
case .newCountdown: return NSLocalizedString("Create a new countdown", comment: "")
}
}
var image: UIImage? {
return UIImage(named: "pic1")
}
}

@ -0,0 +1,20 @@
//
// UIDevice+Extensions.swift
// LeCountdown
//
// Created by Laurent Morvillier on 22/02/2023.
//
import Foundation
import UIKit
extension UIDevice {
@objc static var isPadIdiom: Bool {
return UIDevice.current.userInterfaceIdiom == .pad
}
@objc static var isPhoneIdiom: Bool {
return UIDevice.current.userInterfaceIdiom == .phone
}
}

@ -55,10 +55,6 @@ struct ContentView<T : AbstractTimer>: View {
@Environment(\.managedObjectContext) private var viewContext
#if os(iOS)
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
#endif
@FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \T.order, ascending: true)],
animation: .default)
@ -168,7 +164,7 @@ struct ContentView<T : AbstractTimer>: View {
fileprivate func _columnCount() -> Int {
#if os(iOS)
if horizontalSizeClass == .compact {
if UIDevice.isPhoneIdiom {
return 2
} else {
return 3

@ -15,16 +15,24 @@ struct NewCountdownView : View {
@Binding var isPresented: Bool
var tabSelection: Binding<Int>
var userActivity: NSUserActivity
init(isPresented: Binding<Bool>, tabSelection: Binding<Int>) {
_isPresented = isPresented
self.tabSelection = tabSelection
self.userActivity = Shortcut.newCountdown.userActivity
}
var body: some View {
CountdownEditView(isPresented: $isPresented, tabSelection: self.tabSelection)
.environment(\.managedObjectContext, viewContext)
.navigationTitle("New countdown")
.onAppear {
self.userActivity.becomeCurrent()
}
.onDisappear {
self.userActivity.resignCurrent()
}
}
}

@ -6,6 +6,7 @@
//
import SwiftUI
import CoreSpotlight
struct CompactHomeView: View {
@ -80,12 +81,16 @@ struct RegularHomeView: View {
.tag(2)
}.tabViewStyle(.page(indexDisplayMode: .never))
}
.onContinueUserActivity(Shortcut.newCountdown.rawValue, perform: _handleNewCountdown)
.onOpenURL { _ in
self.tabSelection = 1
}
}
fileprivate func _handleNewCountdown(_ userActivity: NSUserActivity) {
print(">>> new countdown")
}
}
struct CompactHomeView_Previews: PreviewProvider {

@ -197,10 +197,6 @@ struct LiveTimerListView: View {
@Environment(\.managedObjectContext) private var viewContext
@EnvironmentObject var conductor: Conductor
#if os(iOS)
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
#endif
var body: some View {
// ScrollView {
@ -234,7 +230,7 @@ struct LiveTimerListView: View {
fileprivate func _columnCount() -> Int {
#if os(iOS)
if horizontalSizeClass == .compact {
if UIDevice.isPhoneIdiom {
return 2
} else {
return 3

@ -145,10 +145,6 @@ struct PresetsView: View {
@Environment(\.managedObjectContext) private var viewContext
#if os(iOS)
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
#endif
@StateObject var model: PresetModel = PresetModel()
@State var isPresented: Bool = false
@ -160,7 +156,7 @@ struct PresetsView: View {
fileprivate func _columnCount() -> Int {
#if os(iOS)
if horizontalSizeClass == .compact {
if UIDevice.isPhoneIdiom {
return 2
} else {
return 3

@ -12,7 +12,7 @@ struct ActivityView: View {
@Environment(\.managedObjectContext) private var viewContext
var activity: Activity
let activity: Activity
@State var selectedTimeFrame: TimeFrame = .all
@ -36,8 +36,10 @@ struct ActivityView: View {
// }
// Section {
RecordsView(activity: self.activity,
timeFrame: self.selectedTimeFrame)
let filters = self.selectedTimeFrame.filters(context: viewContext)
RecordsView(activity: self.activity, filters: filters)
.environment(\.managedObjectContext, viewContext)
// }
// }
@ -106,6 +108,6 @@ enum TimeFrame: Int, Identifiable, CaseIterable {
struct ActivityView_Previews: PreviewProvider {
static var previews: some View {
ActivityView(activity: Activity.fake(context: PersistenceController.preview.container.viewContext))
ActivityView(activity: Activity.fake(context: PersistenceController.preview.container.viewContext), selectedTimeFrame: .all)
}
}

@ -22,11 +22,17 @@ struct RecordsView: View {
@Environment(\.managedObjectContext) private var viewContext
var activity: Activity
let activity: Activity
let filters: [Filter]
var timeFrame: TimeFrame
// let timeFrame: TimeFrame {
// didSet {
// self._loadFilters()
// }
// }
@StateObject var model: RecordsModel = RecordsModel()
// @StateObject var model: RecordsModel = RecordsModel()
// var request: FetchRequest<Record>
@ -38,18 +44,16 @@ struct RecordsView: View {
var body: some View {
List {
ForEach(self.model.filters) { filter in
ForEach(self.filters) { filter in
RecordsSectionView(activity: self.activity, filter: filter)
.environment(\.managedObjectContext, viewContext)
}
}.onChange(of: self.timeFrame) { newValue in
self._loadFilters()
}
}
fileprivate func _loadFilters() {
self.model.loadFilters(activity: self.activity, timeFrame: self.timeFrame, context: self.viewContext)
}
// fileprivate func _loadFilters() {
// self.model.loadFilters(activity: self.activity, timeFrame: self.timeFrame, context: self.viewContext)
// }
}
@ -131,6 +135,6 @@ struct RecordsView_Previews: PreviewProvider {
static var previews: some View {
RecordsView(activity:
Activity.fake(context: PersistenceController.preview.container.viewContext),
timeFrame: .all)
filters: [])
}
}

Loading…
Cancel
Save