From 89fdb849e4158926d40c0dc1fd5638683902fb9a Mon Sep 17 00:00:00 2001 From: Laurent Date: Sat, 25 Feb 2023 12:44:58 +0100 Subject: [PATCH] various improvements --- LaunchIntents/Info.plist | 1 + LaunchIntents/IntentHandler.swift | 31 +- LaunchIntents/fr.lproj/Localizable.strings | 15 + LaunchWidget/LaunchWidgetLiveActivity.swift | 13 - .../LaunchWidget.intentdefinition | 0 .../fr.lproj/LaunchWidget.intentdefinition | 264 +++++++ LaunchWidget/fr.lproj/Localizable.strings | 18 + LeCountdown.xcodeproj/project.pbxproj | 127 +++- LeCountdown/AppDelegate.swift | 12 + LeCountdown/Conductor.swift | 78 ++- LeCountdown/CountdownScheduler.swift | 9 +- LeCountdown/Info.plist | 2 +- LeCountdown/LeCountdownApp.swift | 22 +- .../en.xcloc/Localized Contents/en.xliff | 647 ++++++++++++++++++ .../LaunchIntents/en.lproj/InfoPlist.strings | 6 + .../en.lproj/Localizable.strings | Bin 0 -> 1384 bytes .../LaunchWidget/en.lproj/InfoPlist.strings | 6 + .../LaunchWidget/en.lproj/Localizable.strings | 27 + .../LeCountdown/en.lproj/InfoPlist.strings | 4 + .../LeCountdown/en.lproj/Localizable.strings | Bin 0 -> 5018 bytes .../Localizations/en.xcloc/contents.json | 12 + .../fr.xcloc/Localized Contents/fr.xliff | 617 +++++++++++++++++ .../LaunchIntents/en.lproj/InfoPlist.strings | 6 + .../en.lproj/Localizable.strings | Bin 0 -> 1384 bytes .../LaunchWidget/en.lproj/InfoPlist.strings | 6 + .../LaunchWidget/en.lproj/Localizable.strings | 27 + .../LeCountdown/en.lproj/InfoPlist.strings | 4 + .../LeCountdown/en.lproj/Localizable.strings | Bin 0 -> 5018 bytes .../Localizations/fr.xcloc/contents.json | 12 + LeCountdown/Model/Model+Extensions.swift | 16 - LeCountdown/Stats/Context+Calculations.swift | 17 + LeCountdown/TimerRouter.swift | 40 +- LeCountdown/Views/ContentView.swift | 97 +-- .../Views/Countdown/NewCountdownView.swift | 8 +- LeCountdown/Views/DialView.swift | 2 +- LeCountdown/Views/HomeView.swift | 41 +- .../Views/Stopwatch/NewStopwatchView.swift | 6 +- .../Widget/LaunchWidgetAttributes.swift | 22 + .../SiriIntents.intentdefinition | 36 +- LeCountdown/fr.lproj/Localizable.strings | 241 +++++++ .../fr.lproj/SiriIntents.intentdefinition | 214 ++++++ 41 files changed, 2476 insertions(+), 230 deletions(-) create mode 100644 LaunchIntents/fr.lproj/Localizable.strings rename LaunchWidget/{ => en.lproj}/LaunchWidget.intentdefinition (100%) create mode 100644 LaunchWidget/fr.lproj/LaunchWidget.intentdefinition create mode 100644 LaunchWidget/fr.lproj/Localizable.strings create mode 100644 LeCountdown/Localizations/en.xcloc/Localized Contents/en.xliff create mode 100644 LeCountdown/Localizations/en.xcloc/Source Contents/LaunchIntents/en.lproj/InfoPlist.strings create mode 100644 LeCountdown/Localizations/en.xcloc/Source Contents/LaunchIntents/en.lproj/Localizable.strings create mode 100644 LeCountdown/Localizations/en.xcloc/Source Contents/LaunchWidget/en.lproj/InfoPlist.strings create mode 100644 LeCountdown/Localizations/en.xcloc/Source Contents/LaunchWidget/en.lproj/Localizable.strings create mode 100644 LeCountdown/Localizations/en.xcloc/Source Contents/LeCountdown/en.lproj/InfoPlist.strings create mode 100644 LeCountdown/Localizations/en.xcloc/Source Contents/LeCountdown/en.lproj/Localizable.strings create mode 100644 LeCountdown/Localizations/en.xcloc/contents.json create mode 100644 LeCountdown/Localizations/fr.xcloc/Localized Contents/fr.xliff create mode 100644 LeCountdown/Localizations/fr.xcloc/Source Contents/LaunchIntents/en.lproj/InfoPlist.strings create mode 100644 LeCountdown/Localizations/fr.xcloc/Source Contents/LaunchIntents/en.lproj/Localizable.strings create mode 100644 LeCountdown/Localizations/fr.xcloc/Source Contents/LaunchWidget/en.lproj/InfoPlist.strings create mode 100644 LeCountdown/Localizations/fr.xcloc/Source Contents/LaunchWidget/en.lproj/Localizable.strings create mode 100644 LeCountdown/Localizations/fr.xcloc/Source Contents/LeCountdown/en.lproj/InfoPlist.strings create mode 100644 LeCountdown/Localizations/fr.xcloc/Source Contents/LeCountdown/en.lproj/Localizable.strings create mode 100644 LeCountdown/Localizations/fr.xcloc/contents.json create mode 100644 LeCountdown/Widget/LaunchWidgetAttributes.swift rename LeCountdown/{ => en.lproj}/SiriIntents.intentdefinition (88%) create mode 100644 LeCountdown/fr.lproj/Localizable.strings create mode 100644 LeCountdown/fr.lproj/SiriIntents.intentdefinition diff --git a/LaunchIntents/Info.plist b/LaunchIntents/Info.plist index 6e03edf..bd524a4 100644 --- a/LaunchIntents/Info.plist +++ b/LaunchIntents/Info.plist @@ -12,6 +12,7 @@ IntentsSupported + LaunchTimerIntent SelectTimerIntent diff --git a/LaunchIntents/IntentHandler.swift b/LaunchIntents/IntentHandler.swift index 69b21dc..c35f7c7 100644 --- a/LaunchIntents/IntentHandler.swift +++ b/LaunchIntents/IntentHandler.swift @@ -7,7 +7,36 @@ import Intents -class IntentHandler: INExtension, SelectTimerIntentHandling { +class IntentHandler: INExtension, SelectTimerIntentHandling, LaunchTimerIntentHandling { + + // MARK: - SelectTimerIntentHandling + + func resolveTimer(for intent: LaunchTimerIntent) async -> TimerIdentifierResolutionResult { + if let timer = intent.timer { + print("resolveTimer(for intent: LaunchTimerIntent) success !") + return .success(with: timer) + } + print("resolveTimer(for intent: LaunchTimerIntent) needsValue") + return .needsValue() + } + + func handle(intent: LaunchTimerIntent) async -> LaunchTimerIntentResponse { + if let timerIdentifier = intent.timer, + let timerId = timerIdentifier.identifier, + let timer = IntentDataProvider.main.timer(id: timerId) { + do { + let _ = try await TimerRouter.performAction(timer: timer) + print("handle(intent: LaunchTimerIntent) success !") + return .success(timer: timerIdentifier) + } catch { + return LaunchTimerIntentResponse(code: LaunchTimerIntentResponseCode(rawValue: 1)!, userActivity: nil) + } + } + print("handle(intent: LaunchTimerIntent) no timer") + return LaunchTimerIntentResponse(code: LaunchTimerIntentResponseCode(rawValue: 1)!, userActivity: nil) + } + + // MARK: - SelectTimerIntentHandling func resolveTimer(for intent: SelectTimerIntent) async -> [TimerPropertiesResolutionResult] { print("***resolveCountdown") diff --git a/LaunchIntents/fr.lproj/Localizable.strings b/LaunchIntents/fr.lproj/Localizable.strings new file mode 100644 index 0000000..4216c7e --- /dev/null +++ b/LaunchIntents/fr.lproj/Localizable.strings @@ -0,0 +1,15 @@ +/* No comment provided by engineer. */ +"Custom" = "Personnalisé"; + +/* No comment provided by engineer. */ +"It's time!" = "C'est l'heure !"; + +/* No comment provided by engineer. */ +"Nature" = "Nature"; + +/* No comment provided by engineer. */ +"Time's up for (name)!" = "C'est l'heure pour (name) !"; + +/* No comment provided by engineer. */ +"Your (duration.minuteSecond) countdown is over!" = "Votre minuteur de (duration.minuteSecond) est terminé !"; + diff --git a/LaunchWidget/LaunchWidgetLiveActivity.swift b/LaunchWidget/LaunchWidgetLiveActivity.swift index 46d62cb..6aec846 100644 --- a/LaunchWidget/LaunchWidgetLiveActivity.swift +++ b/LaunchWidget/LaunchWidgetLiveActivity.swift @@ -9,19 +9,6 @@ import ActivityKit import WidgetKit import SwiftUI -struct LaunchWidgetAttributes: ActivityAttributes { - public struct ContentState: Codable, Hashable { - // Dynamic stateful properties about your activity go here! - var ended: Bool - } - - // Fixed non-changing properties about your activity go here! - var id: String - var name: String - var date: Date - -} - struct LiveActivityView: View { var name: String diff --git a/LaunchWidget/LaunchWidget.intentdefinition b/LaunchWidget/en.lproj/LaunchWidget.intentdefinition similarity index 100% rename from LaunchWidget/LaunchWidget.intentdefinition rename to LaunchWidget/en.lproj/LaunchWidget.intentdefinition diff --git a/LaunchWidget/fr.lproj/LaunchWidget.intentdefinition b/LaunchWidget/fr.lproj/LaunchWidget.intentdefinition new file mode 100644 index 0000000..0eb2c8e --- /dev/null +++ b/LaunchWidget/fr.lproj/LaunchWidget.intentdefinition @@ -0,0 +1,264 @@ + + + + + INEnums + + INIntentDefinitionModelVersion + 1.2 + INIntentDefinitionNamespace + 88xZPY + INIntentDefinitionSystemVersion + 22A400 + INIntentDefinitionToolsBuildVersion + 14C18 + INIntentDefinitionToolsVersion + 14.2 + INIntents + + + INIntentCategory + information + INIntentDescriptionID + dIYBJB + INIntentEligibleForWidgets + + INIntentIneligibleForSuggestions + + INIntentLastParameterTag + 3 + INIntentName + SelectTimer + INIntentParameters + + + INIntentParameterArraySizes + + + INIntentParameterArraySizeSize + 1 + INIntentParameterArraySizeSizeClass + Small + + + INIntentParameterArraySizeSize + 4 + INIntentParameterArraySizeSizeClass + Medium + + + INIntentParameterArraySizeSize + 8 + INIntentParameterArraySizeSizeClass + Large + + + INIntentParameterArraySizeSize + 12 + INIntentParameterArraySizeSizeClass + ExtraLarge + + + INIntentParameterArraySizeSize + 1 + INIntentParameterArraySizeSizeClass + AccessoryInline + + + INIntentParameterArraySizeSize + 1 + INIntentParameterArraySizeSizeClass + AccessoryCorner + + + INIntentParameterArraySizeSize + 1 + INIntentParameterArraySizeSizeClass + AccessoryCircular + + + INIntentParameterArraySizeSize + 1 + INIntentParameterArraySizeSizeClass + AccessoryRectangular + + + INIntentParameterConfigurable + + INIntentParameterCustomDisambiguation + + INIntentParameterDisplayName + Compteur + INIntentParameterDisplayNameID + lE8mOk + INIntentParameterDisplayPriority + 1 + INIntentParameterFixedSizeArray + 1 + INIntentParameterName + timer + INIntentParameterObjectType + TimerProperties + INIntentParameterObjectTypeNamespace + 88xZPY + INIntentParameterPromptDialogs + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogType + Configuration + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogType + Primary + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogFormatString + Il y a ${count} options correspondant à ‘${timer}’. + INIntentParameterPromptDialogFormatStringID + gtJyOP + INIntentParameterPromptDialogType + DisambiguationIntroduction + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogFormatString + Merci de confirmer, vous souhaitez ‘${timer}’? + INIntentParameterPromptDialogFormatStringID + nntWsg + INIntentParameterPromptDialogType + Confirmation + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogFormatString + Laquelle ? + INIntentParameterPromptDialogFormatStringID + tTDiOr + INIntentParameterPromptDialogType + DisambiguationSelection + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogFormatString + Nous avons aussi, + INIntentParameterPromptDialogFormatStringID + VvsWeN + INIntentParameterPromptDialogType + SubsequentIntroduction + + + INIntentParameterSupportsDynamicEnumeration + + INIntentParameterSupportsMultipleValues + + INIntentParameterSupportsResolution + + INIntentParameterTag + 3 + INIntentParameterType + Object + + + INIntentResponse + + INIntentResponseCodes + + + INIntentResponseCodeName + success + INIntentResponseCodeSuccess + + + + INIntentResponseCodeName + failure + + + + INIntentTitle + Choisissez un compteur + INIntentTitleID + Dm6sPw + INIntentType + Custom + INIntentVerb + View + + + INTypes + + + INTypeDisplayName + TimerProperties + INTypeDisplayNameID + ZTfW1g + INTypeLastPropertyTag + 102 + INTypeName + TimerProperties + INTypeProperties + + + INTypePropertyDefault + + INTypePropertyDisplayPriority + 1 + INTypePropertyName + identifier + INTypePropertyTag + 1 + INTypePropertyType + String + + + INTypePropertyDefault + + INTypePropertyDisplayPriority + 2 + INTypePropertyName + displayString + INTypePropertyTag + 2 + INTypePropertyType + String + + + INTypePropertyDefault + + INTypePropertyDisplayPriority + 3 + INTypePropertyName + pronunciationHint + INTypePropertyTag + 3 + INTypePropertyType + String + + + INTypePropertyDefault + + INTypePropertyDisplayPriority + 4 + INTypePropertyName + alternativeSpeakableMatches + INTypePropertySupportsMultipleValues + + INTypePropertyTag + 4 + INTypePropertyType + SpeakableString + + + + + + diff --git a/LaunchWidget/fr.lproj/Localizable.strings b/LaunchWidget/fr.lproj/Localizable.strings new file mode 100644 index 0000000..0418c89 --- /dev/null +++ b/LaunchWidget/fr.lproj/Localizable.strings @@ -0,0 +1,18 @@ +/* No comment provided by engineer. */ +"Configure me!" = "Configurez moi !"; + +/* No comment provided by engineer. */ +"Configure me!\n" = "Configurez moi !"; + +/* No comment provided by engineer. */ +"Launch Widget" = "Widget de lancement"; + +/* No comment provided by engineer. */ +"Min" = "Min"; + +/* No comment provided by engineer. */ +"Select and launch your timers" = "Sélectionnez et lancer vos minuteurs"; + +/* No comment provided by engineer. */ +"Stop" = "Arrêter"; + diff --git a/LeCountdown.xcodeproj/project.pbxproj b/LeCountdown.xcodeproj/project.pbxproj index 211d254..40c38a5 100644 --- a/LeCountdown.xcodeproj/project.pbxproj +++ b/LeCountdown.xcodeproj/project.pbxproj @@ -28,15 +28,12 @@ C438C7D82981216200BF3EF9 /* LaunchWidgetLiveActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = C438C7D72981216200BF3EF9 /* LaunchWidgetLiveActivity.swift */; }; C438C7DA2981216200BF3EF9 /* LaunchWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = C438C7D92981216200BF3EF9 /* LaunchWidget.swift */; }; C438C7DD2981216300BF3EF9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C438C7DC2981216300BF3EF9 /* Assets.xcassets */; }; - C438C7DF2981216300BF3EF9 /* LaunchWidget.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = C438C7DB2981216200BF3EF9 /* LaunchWidget.intentdefinition */; }; - C438C7E02981216300BF3EF9 /* LaunchWidget.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = C438C7DB2981216200BF3EF9 /* LaunchWidget.intentdefinition */; }; C438C7E32981216300BF3EF9 /* LaunchWidgetExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = C438C7CE2981216200BF3EF9 /* LaunchWidgetExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; C438C7E82981255D00BF3EF9 /* TimeInterval+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4060DF4297AE9A7003FAB80 /* TimeInterval+Extensions.swift */; }; C438C7EB2981266F00BF3EF9 /* SingleTimerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C438C7E92981260D00BF3EF9 /* SingleTimerView.swift */; }; C438C7F229812BB200BF3EF9 /* Intents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C438C7F129812BB200BF3EF9 /* Intents.framework */; }; C438C7F529812BB200BF3EF9 /* IntentHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C438C7F429812BB200BF3EF9 /* IntentHandler.swift */; }; C438C7F929812BB200BF3EF9 /* LaunchIntents.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = C438C7F029812BB200BF3EF9 /* LaunchIntents.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; - C438C7FD29812BF700BF3EF9 /* LaunchWidget.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = C438C7DB2981216200BF3EF9 /* LaunchWidget.intentdefinition */; }; C438C7FF2981300500BF3EF9 /* IntentDataProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = C438C7FE2981300500BF3EF9 /* IntentDataProvider.swift */; }; C438C800298130E900BF3EF9 /* IntentDataProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = C438C7FE2981300500BF3EF9 /* IntentDataProvider.swift */; }; C438C8012981327600BF3EF9 /* Persistence.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4060DC8297AE73D003FAB80 /* Persistence.swift */; }; @@ -57,6 +54,33 @@ C445FA8F2987B83B0054D761 /* SoundPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C445FA8E2987B83B0054D761 /* SoundPlayer.swift */; }; C445FA922987CC8A0054D761 /* Sound.swift in Sources */ = {isa = PBXBuildFile; fileRef = C445FA912987CC8A0054D761 /* Sound.swift */; }; C445FA952987D01C0054D761 /* train_horn.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = C445FA942987D01C0054D761 /* train_horn.mp3 */; }; + C473C2F029A8CFFC0056B38A /* TimerRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4F8B1D7298C0727005C86A5 /* TimerRouter.swift */; }; + C473C2F129A8DA0B0056B38A /* Conductor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4F8B15629891271005C86A5 /* Conductor.swift */; }; + C473C2F229A8DA1F0056B38A /* CountdownScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C438C7C02980228B00BF3EF9 /* CountdownScheduler.swift */; }; + C473C2F329A8DA6F0056B38A /* LiveTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C498E5A0298D543900E90DE0 /* LiveTimer.swift */; }; + C473C2F429A8DAE70056B38A /* Model+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C438C806298195E600BF3EF9 /* Model+Extensions.swift */; }; + C473C2F529A8DAF30056B38A /* PropertyWrappers.swift in Sources */ = {isa = PBXBuildFile; fileRef = C438C81029829EAF00BF3EF9 /* PropertyWrappers.swift */; }; + C473C2F629A8DB1D0056B38A /* Sound.swift in Sources */ = {isa = PBXBuildFile; fileRef = C445FA912987CC8A0054D761 /* Sound.swift */; }; + C473C2F729A8DB6F0056B38A /* Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BA2B2C299E2DEE00CB4FBA /* Preferences.swift */; }; + C473C2F929A8DC0A0056B38A /* LaunchWidgetAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = C473C2F829A8DC0A0056B38A /* LaunchWidgetAttributes.swift */; }; + C473C2FA29A8DC1E0056B38A /* LaunchWidgetAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = C473C2F829A8DC0A0056B38A /* LaunchWidgetAttributes.swift */; }; + C473C2FB29A8DC3A0056B38A /* LaunchWidgetAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = C473C2F829A8DC0A0056B38A /* LaunchWidgetAttributes.swift */; }; + C473C2FC29A8DC4B0056B38A /* Date+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BA2B6929A4BE1800CB4FBA /* Date+Extensions.swift */; }; + C473C2FD29A8DC690056B38A /* CoreDataRequests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C438C80C2982847300BF3EF9 /* CoreDataRequests.swift */; }; + C473C30329A91BB90056B38A /* en.xcloc in Resources */ = {isa = PBXBuildFile; fileRef = C473C30229A91BB90056B38A /* en.xcloc */; }; + C473C30429A91BB90056B38A /* en.xcloc in Resources */ = {isa = PBXBuildFile; fileRef = C473C30229A91BB90056B38A /* en.xcloc */; }; + C473C30529A91BB90056B38A /* en.xcloc in Resources */ = {isa = PBXBuildFile; fileRef = C473C30229A91BB90056B38A /* en.xcloc */; }; + C473C30729A91BCC0056B38A /* fr.xcloc in Resources */ = {isa = PBXBuildFile; fileRef = C473C30629A91BCB0056B38A /* fr.xcloc */; }; + C473C30829A91BCC0056B38A /* fr.xcloc in Resources */ = {isa = PBXBuildFile; fileRef = C473C30629A91BCB0056B38A /* fr.xcloc */; }; + C473C30929A91BCC0056B38A /* fr.xcloc in Resources */ = {isa = PBXBuildFile; fileRef = C473C30629A91BCB0056B38A /* fr.xcloc */; }; + C473C30C29A9212E0056B38A /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = C473C30A29A9212E0056B38A /* Localizable.strings */; }; + C473C30F29A9212E0056B38A /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = C473C30D29A9212E0056B38A /* Localizable.strings */; }; + C473C31229A9212E0056B38A /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = C473C31029A9212E0056B38A /* Localizable.strings */; }; + C473C31329A925D50056B38A /* SiriIntents.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = C473C31629A925D50056B38A /* SiriIntents.intentdefinition */; }; + C473C31429A925D50056B38A /* SiriIntents.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = C473C31629A925D50056B38A /* SiriIntents.intentdefinition */; }; + C473C31829A926F50056B38A /* LaunchWidget.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = C473C31C29A926F50056B38A /* LaunchWidget.intentdefinition */; }; + C473C31929A926F50056B38A /* LaunchWidget.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = C473C31C29A926F50056B38A /* LaunchWidget.intentdefinition */; }; + C473C31A29A926F50056B38A /* LaunchWidget.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = C473C31C29A926F50056B38A /* LaunchWidget.intentdefinition */; }; C4742B5729840F6400D5D950 /* CoolPic.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4742B5629840F6400D5D950 /* CoolPic.swift */; }; C4742B59298411E800D5D950 /* CountdownFormView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4742B58298411E800D5D950 /* CountdownFormView.swift */; }; C4742B5B298414B000D5D950 /* ImageSelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4742B5A298414B000D5D950 /* ImageSelectionView.swift */; }; @@ -127,7 +151,6 @@ C4BA2B6529A3C37D00CB4FBA /* Filter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BA2B6429A3C37D00CB4FBA /* Filter.swift */; }; 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 */; }; @@ -256,7 +279,6 @@ C438C7D52981216200BF3EF9 /* LaunchWidgetBundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LaunchWidgetBundle.swift; sourceTree = ""; }; C438C7D72981216200BF3EF9 /* LaunchWidgetLiveActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LaunchWidgetLiveActivity.swift; sourceTree = ""; }; C438C7D92981216200BF3EF9 /* LaunchWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LaunchWidget.swift; sourceTree = ""; }; - C438C7DB2981216200BF3EF9 /* LaunchWidget.intentdefinition */ = {isa = PBXFileReference; lastKnownFileType = file.intentdefinition; path = LaunchWidget.intentdefinition; sourceTree = ""; }; C438C7DC2981216300BF3EF9 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; C438C7DE2981216300BF3EF9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; C438C7E92981260D00BF3EF9 /* SingleTimerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SingleTimerView.swift; sourceTree = ""; }; @@ -275,6 +297,14 @@ C445FA902987C0CF0054D761 /* LeCountdown.0.2.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = LeCountdown.0.2.xcdatamodel; sourceTree = ""; }; C445FA912987CC8A0054D761 /* Sound.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sound.swift; sourceTree = ""; }; C445FA942987D01C0054D761 /* train_horn.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = train_horn.mp3; sourceTree = ""; }; + C473C2F829A8DC0A0056B38A /* LaunchWidgetAttributes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LaunchWidgetAttributes.swift; sourceTree = ""; }; + C473C30229A91BB90056B38A /* en.xcloc */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = en.xcloc; path = Localizations/en.xcloc; sourceTree = ""; }; + C473C30629A91BCB0056B38A /* fr.xcloc */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = fr.xcloc; path = Localizations/fr.xcloc; sourceTree = ""; }; + C473C30B29A9212E0056B38A /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = ""; }; + C473C30E29A9212E0056B38A /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = ""; }; + C473C31129A9212E0056B38A /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = ""; }; + C473C31729A9262A0056B38A /* en */ = {isa = PBXFileReference; lastKnownFileType = file.intentdefinition; name = en; path = en.lproj/SiriIntents.intentdefinition; sourceTree = ""; }; + C473C31D29A926F80056B38A /* en */ = {isa = PBXFileReference; lastKnownFileType = file.intentdefinition; name = en; path = en.lproj/LaunchWidget.intentdefinition; sourceTree = ""; }; C4742B5629840F6400D5D950 /* CoolPic.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoolPic.swift; sourceTree = ""; }; C4742B58298411E800D5D950 /* CountdownFormView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CountdownFormView.swift; sourceTree = ""; }; C4742B5A298414B000D5D950 /* ImageSelectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageSelectionView.swift; sourceTree = ""; }; @@ -326,7 +356,6 @@ C4BA2B6729A3C4AC00CB4FBA /* Context+Calculations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Context+Calculations.swift"; sourceTree = ""; }; C4BA2B6929A4BE1800CB4FBA /* Date+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+Extensions.swift"; sourceTree = ""; }; C4BA2B6B29A4C47100CB4FBA /* LeCountdown.0.6.2.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = LeCountdown.0.6.2.xcdatamodel; sourceTree = ""; }; - C4BA2B7029A51CA000CB4FBA /* SiriIntents.intentdefinition */ = {isa = PBXFileReference; lastKnownFileType = file.intentdefinition; path = SiriIntents.intentdefinition; sourceTree = ""; }; C4BA2B7229A60CF000CB4FBA /* Shortcut.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Shortcut.swift; sourceTree = ""; }; C4BA2B7829A65C1400CB4FBA /* UIDevice+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIDevice+Extensions.swift"; sourceTree = ""; }; C4F8B15629891271005C86A5 /* Conductor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Conductor.swift; sourceTree = ""; }; @@ -442,8 +471,11 @@ C4BA2B55299FFA3700CB4FBA /* Subscription */, C4060DC3297AE73D003FAB80 /* Assets.xcassets */, C438C80429813B3100BF3EF9 /* LeCountdown.entitlements */, - C4BA2B7029A51CA000CB4FBA /* SiriIntents.intentdefinition */, + C473C30229A91BB90056B38A /* en.xcloc */, + C473C30629A91BCB0056B38A /* fr.xcloc */, + C473C31629A925D50056B38A /* SiriIntents.intentdefinition */, C4060DCD297AE73D003FAB80 /* Info.plist */, + C473C31029A9212E0056B38A /* Localizable.strings */, C4060DC5297AE73D003FAB80 /* Preview Content */, ); path = LeCountdown; @@ -493,9 +525,10 @@ C438C7D92981216200BF3EF9 /* LaunchWidget.swift */, C438C7E92981260D00BF3EF9 /* SingleTimerView.swift */, C4BA2B30299F759700CB4FBA /* DefaultView.swift */, - C438C7DB2981216200BF3EF9 /* LaunchWidget.intentdefinition */, + C473C31C29A926F50056B38A /* LaunchWidget.intentdefinition */, C438C7DC2981216300BF3EF9 /* Assets.xcassets */, C438C7DE2981216300BF3EF9 /* Info.plist */, + C473C30D29A9212E0056B38A /* Localizable.strings */, ); path = LaunchWidget; sourceTree = ""; @@ -506,6 +539,7 @@ C438C7F429812BB200BF3EF9 /* IntentHandler.swift */, C438C80329813B2500BF3EF9 /* LaunchIntents.entitlements */, C438C7F629812BB200BF3EF9 /* Info.plist */, + C473C30A29A9212E0056B38A /* Localizable.strings */, ); path = LaunchIntents; sourceTree = ""; @@ -514,6 +548,7 @@ isa = PBXGroup; children = ( C438C7FE2981300500BF3EF9 /* IntentDataProvider.swift */, + C473C2F829A8DC0A0056B38A /* LaunchWidgetAttributes.swift */, ); path = Widget; sourceTree = ""; @@ -834,7 +869,7 @@ hasScannedForEncodings = 0; knownRegions = ( en, - Base, + fr, ); mainGroup = C4060DB3297AE73B003FAB80; productRefGroup = C4060DBD297AE73B003FAB80 /* Products */; @@ -856,7 +891,9 @@ buildActionMask = 2147483647; files = ( C4060DC7297AE73D003FAB80 /* Preview Assets.xcassets in Resources */, + C473C30729A91BCC0056B38A /* fr.xcloc in Resources */, C4BA2AEA2995AD1C00CB4FBA /* SEM_Synths_Loop4_Nothing_Like_You.wav in Resources */, + C473C31229A9212E0056B38A /* Localizable.strings in Resources */, C4BA2AE42995AC0D00CB4FBA /* Arpeggio_Loop_River.wav in Resources */, C4F8B15929891528005C86A5 /* forest_stream.mp3 in Resources */, C4BA2AE22995ABE700CB4FBA /* SquareArp_Loop_River.wav in Resources */, @@ -865,6 +902,7 @@ C445FA952987D01C0054D761 /* train_horn.mp3 in Resources */, C4BA2AE02995ABD200CB4FBA /* HighChords_Loop_River.wav in Resources */, C4060DC4297AE73D003FAB80 /* Assets.xcassets in Resources */, + C473C30329A91BB90056B38A /* en.xcloc in Resources */, C4BA2AE62995AC3F00CB4FBA /* Loop_ToneSD_Boavista.wav in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -887,8 +925,11 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + C473C30F29A9212E0056B38A /* Localizable.strings in Resources */, C445FA882984487F0054D761 /* Assets.xcassets in Resources */, + C473C30429A91BB90056B38A /* en.xcloc in Resources */, C438C7DD2981216300BF3EF9 /* Assets.xcassets in Resources */, + C473C30829A91BCC0056B38A /* fr.xcloc in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -896,6 +937,9 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + C473C30529A91BB90056B38A /* en.xcloc in Resources */, + C473C30C29A9212E0056B38A /* Localizable.strings in Resources */, + C473C30929A91BCC0056B38A /* fr.xcloc in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -935,6 +979,7 @@ C498E5A5299152B400E90DE0 /* GreenCheckmarkView.swift in Sources */, C4BA2B3E299FC86800CB4FBA /* StatsView.swift in Sources */, C4F8B1B8298AC81D005C86A5 /* CountdownDialView.swift in Sources */, + C473C2F929A8DC0A0056B38A /* LaunchWidgetAttributes.swift in Sources */, C445FA922987CC8A0054D761 /* Sound.swift in Sources */, C4F8B1D0298BF2E2005C86A5 /* DialView.swift in Sources */, C4BA2B11299BE61E00CB4FBA /* IntervalGroup+CoreDataClass.swift in Sources */, @@ -948,7 +993,7 @@ C438C7C12980228B00BF3EF9 /* CountdownScheduler.swift in Sources */, C498E5A3298D720600E90DE0 /* TestView.swift in Sources */, C4BA2B06299A8F8D00CB4FBA /* PresetsView.swift in Sources */, - C4BA2B7129A51CA000CB4FBA /* SiriIntents.intentdefinition in Sources */, + C473C31329A925D50056B38A /* SiriIntents.intentdefinition in Sources */, C445FA8F2987B83B0054D761 /* SoundPlayer.swift in Sources */, C4F8B1A7298AC2FC005C86A5 /* AbstractSoundTimer+CoreDataClass.swift in Sources */, C438C7C929803CA000BF3EF9 /* AppDelegate.swift in Sources */, @@ -987,7 +1032,7 @@ C4F8B1AC298AC3A0005C86A5 /* Alarm+CoreDataProperties.swift in Sources */, C498E59F298D4DEA00E90DE0 /* LiveTimerListView.swift in Sources */, C4060DC0297AE73B003FAB80 /* LeCountdownApp.swift in Sources */, - C438C7E02981216300BF3EF9 /* LaunchWidget.intentdefinition in Sources */, + C473C31829A926F50056B38A /* LaunchWidget.intentdefinition in Sources */, C4742B5729840F6400D5D950 /* CoolPic.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1031,9 +1076,10 @@ C4BA2B4D299FCE0C00CB4FBA /* Stopwatch+CoreDataProperties.swift in Sources */, C4F8B194298AC288005C86A5 /* Record+CoreDataProperties.swift in Sources */, C438C8152982BD9000BF3EF9 /* IntentDataProvider.swift in Sources */, - C438C7DF2981216300BF3EF9 /* LaunchWidget.intentdefinition in Sources */, + C473C31929A926F50056B38A /* LaunchWidget.intentdefinition in Sources */, C4F8B15B29892D40005C86A5 /* SoundPlayer.swift in Sources */, C4BA2B5C299FFAB000CB4FBA /* Logger.swift in Sources */, + C473C2FA29A8DC1E0056B38A /* LaunchWidgetAttributes.swift in Sources */, C438C7E82981255D00BF3EF9 /* TimeInterval+Extensions.swift in Sources */, C4BA2B37299F82FF00CB4FBA /* Fakes.swift in Sources */, C4F8B18F298AC288005C86A5 /* AbstractTimer+CoreDataClass.swift in Sources */, @@ -1057,11 +1103,15 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + C473C2FD29A8DC690056B38A /* CoreDataRequests.swift in Sources */, + C473C2F329A8DA6F0056B38A /* LiveTimer.swift in Sources */, C4F8B1C6298ACC1F005C86A5 /* SoundPlayer.swift in Sources */, C4F8B1A2298AC288005C86A5 /* Record+CoreDataProperties.swift in Sources */, C4F8B1B2298AC451005C86A5 /* Alarm+CoreDataProperties.swift in Sources */, + C473C2F229A8DA1F0056B38A /* CountdownScheduler.swift in Sources */, C4BA2AF92996A4F000CB4FBA /* CustomSound+CoreDataClass.swift in Sources */, C4F8B1A1298AC288005C86A5 /* Countdown+CoreDataClass.swift in Sources */, + C473C2F729A8DB6F0056B38A /* Preferences.swift in Sources */, C4BA2B38299F82FF00CB4FBA /* Fakes.swift in Sources */, C438C7F529812BB200BF3EF9 /* IntentHandler.swift in Sources */, C4F8B19C298AC288005C86A5 /* AbstractTimer+CoreDataProperties.swift in Sources */, @@ -1070,6 +1120,7 @@ C4F8B1A3298AC288005C86A5 /* Activity+CoreDataClass.swift in Sources */, C4F8B19A298AC288005C86A5 /* Alarm+CoreDataClass.swift in Sources */, C438C80529813FB400BF3EF9 /* TimeInterval+Extensions.swift in Sources */, + C473C2F629A8DB1D0056B38A /* Sound.swift in Sources */, C4BA2B1B299BE6A100CB4FBA /* Interval+CoreDataProperties.swift in Sources */, C438C802298132B900BF3EF9 /* LeCountdown.xcdatamodeld in Sources */, C4F8B19B298AC288005C86A5 /* Stopwatch+CoreDataClass.swift in Sources */, @@ -1080,14 +1131,21 @@ C4BA2AF82996A4F000CB4FBA /* CustomSound+CoreDataProperties.swift in Sources */, C4F8B199298AC288005C86A5 /* Record+CoreDataClass.swift in Sources */, C438C8012981327600BF3EF9 /* Persistence.swift in Sources */, - C438C7FD29812BF700BF3EF9 /* LaunchWidget.intentdefinition in Sources */, + C473C31A29A926F50056B38A /* LaunchWidget.intentdefinition in Sources */, C4BA2B5D299FFAB000CB4FBA /* Logger.swift in Sources */, + C473C2FB29A8DC3A0056B38A /* LaunchWidgetAttributes.swift in Sources */, C4BA2B4B299FCE0C00CB4FBA /* IntervalGroup+CoreDataProperties.swift in Sources */, C4F8B1B1298AC451005C86A5 /* AbstractSoundTimer+CoreDataClass.swift in Sources */, + C473C2F129A8DA0B0056B38A /* Conductor.swift in Sources */, C4BA2B1E299BE6A100CB4FBA /* Interval+CoreDataClass.swift in Sources */, + C473C2FC29A8DC4B0056B38A /* Date+Extensions.swift in Sources */, + C473C2F429A8DAE70056B38A /* Model+Extensions.swift in Sources */, + C473C31429A925D50056B38A /* SiriIntents.intentdefinition in Sources */, C445FA86298448720054D761 /* CoolPic.swift in Sources */, C4BA2B4E299FCE0C00CB4FBA /* Stopwatch+CoreDataProperties.swift in Sources */, C4BA2B23299BE82E00CB4FBA /* AbstractSoundTimer+CoreDataProperties.swift in Sources */, + C473C2F529A8DAF30056B38A /* PropertyWrappers.swift in Sources */, + C473C2F029A8CFFC0056B38A /* TimerRouter.swift in Sources */, C438C800298130E900BF3EF9 /* IntentDataProvider.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1117,6 +1175,49 @@ }; /* End PBXTargetDependency section */ +/* Begin PBXVariantGroup section */ + C473C30A29A9212E0056B38A /* Localizable.strings */ = { + isa = PBXVariantGroup; + children = ( + C473C30B29A9212E0056B38A /* fr */, + ); + name = Localizable.strings; + sourceTree = ""; + }; + C473C30D29A9212E0056B38A /* Localizable.strings */ = { + isa = PBXVariantGroup; + children = ( + C473C30E29A9212E0056B38A /* fr */, + ); + name = Localizable.strings; + sourceTree = ""; + }; + C473C31029A9212E0056B38A /* Localizable.strings */ = { + isa = PBXVariantGroup; + children = ( + C473C31129A9212E0056B38A /* fr */, + ); + name = Localizable.strings; + sourceTree = ""; + }; + C473C31629A925D50056B38A /* SiriIntents.intentdefinition */ = { + isa = PBXVariantGroup; + children = ( + C473C31729A9262A0056B38A /* en */, + ); + name = SiriIntents.intentdefinition; + sourceTree = ""; + }; + C473C31C29A926F50056B38A /* LaunchWidget.intentdefinition */ = { + isa = PBXVariantGroup; + children = ( + C473C31D29A926F80056B38A /* en */, + ); + name = LaunchWidget.intentdefinition; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + /* Begin XCBuildConfiguration section */ C4060DE4297AE73D003FAB80 /* Debug */ = { isa = XCBuildConfiguration; diff --git a/LeCountdown/AppDelegate.swift b/LeCountdown/AppDelegate.swift index eba54b4..a2db5ed 100644 --- a/LeCountdown/AppDelegate.swift +++ b/LeCountdown/AppDelegate.swift @@ -12,11 +12,23 @@ class AppDelegate : NSObject, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { + Logger.log("didfinish > countdowns count = \(Conductor.maestro.currentCountdowns.count)") + UNUserNotificationCenter.current().delegate = self Conductor.maestro.cleanup() return true } + func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool { + + if userActivity.interaction == nil { + + Logger.log("restorationHandler called! interaction is nil") + return false + } + return true + } + } extension AppDelegate: UNUserNotificationCenterDelegate { diff --git a/LeCountdown/Conductor.swift b/LeCountdown/Conductor.swift index da16b08..31e40ef 100644 --- a/LeCountdown/Conductor.swift +++ b/LeCountdown/Conductor.swift @@ -9,7 +9,11 @@ import Foundation import ActivityKit import BackgroundTasks import SwiftUI -//import Intents +import Intents + +enum BGTaskIdentifier : String { + case refresh = "com.staxriver.lecountdown.refresh" +} class Conductor: ObservableObject { @@ -32,6 +36,7 @@ class Conductor: ObservableObject { @Published var currentCountdowns: [String : DateInterval] = [:] { didSet { Conductor.savedCountdowns = currentCountdowns + Logger.log("**** currentCountdowns didSet, count = \(currentCountdowns.count)") withAnimation { self._buildLiveTimers() } @@ -46,8 +51,6 @@ class Conductor: ObservableObject { } } } - - fileprivate var _cleanupTimers: [String : Timer] = [:] func removeLiveTimer(id: String) { self.liveTimers.removeAll(where: { $0.id == id }) @@ -56,6 +59,8 @@ class Conductor: ObservableObject { fileprivate func _buildLiveTimers() { + Logger.log("_buildLiveTimers") + let liveCountdowns = self.currentCountdowns.map { return LiveTimer(id: $0, date: $1.end) } @@ -105,15 +110,25 @@ class Conductor: ObservableObject { // MARK: - Countdown func startCountdown(_ date: Date, countdown: Countdown) { - DispatchQueue.main.async { +// DispatchQueue.main.async { + + Logger.log("Starts countdown: \(countdown.displayName)") + + // cleanup existing countdowns + self.removeLiveTimer(id: countdown.stringId) + +// self._cleanupTimers.removeValue(forKey: countdown.stringId) + let dateInterval = DateInterval(start: Date(), end: date) self.currentCountdowns[countdown.stringId] = dateInterval // self._launchLiveActivity(countdown: countdown, endDate: date) - self._cleanupTimers.removeValue(forKey: countdown.stringId) + self._createTimerIntent(countdown) - } + Logger.log("countdowns count = \(self.currentCountdowns.count)") + +// } } func cancelCountdown(id: String) { @@ -129,26 +144,6 @@ class Conductor: ObservableObject { self._recordActivity(countdownId: countdownId) } self.currentCountdowns.removeValue(forKey: countdownId) - -// if self.currentCountdowns.removeValue(forKey: countdownId) != nil { -// self._endLiveActivity(countdownId: countdownId) -// } - -// self.removeLiveTimer(id: countdownId) - } - } - - func cleanup() { - self._cleanupCountdowns() - self._buildLiveTimers() - } - - fileprivate func _cleanupCountdowns() { - let now = Date() - for (key, value) in self.currentCountdowns { - if value.end < now { - self._endCountdown(countdownId: key, cancel: false) - } } } @@ -160,7 +155,8 @@ class Conductor: ObservableObject { Conductor.maestro.currentStopwatches[stopwatch.stringId] = now self._launchLiveActivity(stopwatch: stopwatch, start: now) -// LaunchTim + self._createTimerIntent(stopwatch) + } } @@ -176,6 +172,22 @@ class Conductor: ObservableObject { } } + // MARK: - Cleanup + + func cleanup() { + self._cleanupCountdowns() + self._buildLiveTimers() + } + + fileprivate func _cleanupCountdowns() { + let now = Date() + for (key, value) in self.currentCountdowns { + if value.end < now { + self._endCountdown(countdownId: key, cancel: false) + } + } + } + // MARK: - Sound fileprivate func _playSound(timerId: String) { @@ -217,6 +229,18 @@ class Conductor: ObservableObject { self.soundPlayer = nil } + // MARK: - Intent + + fileprivate func _createTimerIntent(_ timer: AbstractTimer) { + let intent = LaunchTimerIntent() + intent.suggestedInvocationPhrase = "\(NSLocalizedString("Launch", comment: "")) \(timer.displayName)" + + intent.timer = TimerIdentifier(identifier: timer.stringId, display: timer.displayName) + + let interaction = INInteraction(intent: intent, response: nil) + interaction.donate() + } + // MARK: - Live Activity fileprivate func _launchLiveActivity(stopwatch: Stopwatch, start: Date) { diff --git a/LeCountdown/CountdownScheduler.swift b/LeCountdown/CountdownScheduler.swift index 88735cf..680d37f 100644 --- a/LeCountdown/CountdownScheduler.swift +++ b/LeCountdown/CountdownScheduler.swift @@ -78,11 +78,11 @@ class CountdownScheduler { handler(.failure(error)) print("Scheduling error = \(error)") } else { - + if offset == 0.0 { if let triggerDate = trigger.nextTriggerDate() { Conductor.maestro.startCountdown(triggerDate, countdown: countdown) - handler(.success(trigger.nextTriggerDate())) + handler(.success(triggerDate)) } else { let backupDate = Date().addingTimeInterval(duration) Conductor.maestro.startCountdown(backupDate, countdown: countdown) @@ -92,6 +92,11 @@ class CountdownScheduler { } } +// DispatchQueue.main.async { +// let d = countdown.duration + offset +// let td = Date().addingTimeInterval(d) +// Conductor.maestro.startCountdown(td, countdown: countdown) +// } } } diff --git a/LeCountdown/Info.plist b/LeCountdown/Info.plist index 2c97560..40adea8 100644 --- a/LeCountdown/Info.plist +++ b/LeCountdown/Info.plist @@ -8,9 +8,9 @@ NSUserActivityTypes - app.kikai.NewCountdown LaunchTimerIntent SelectTimerIntent + app.kikai.NewCountdown UIApplicationSceneManifest diff --git a/LeCountdown/LeCountdownApp.swift b/LeCountdown/LeCountdownApp.swift index 275cdf4..9e66ae0 100644 --- a/LeCountdown/LeCountdownApp.swift +++ b/LeCountdown/LeCountdownApp.swift @@ -10,10 +10,6 @@ import CoreData import BackgroundTasks import AVFoundation -enum BGTaskIdentifier : String { - case refresh = "com.staxriver.lecountdown.refresh" -} - @main struct LeCountdownApp: App { @@ -50,9 +46,9 @@ struct LeCountdownApp: App { .environment(\.managedObjectContext, persistenceController.container.viewContext) #endif } - .onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in - self._willEnterForegroundNotification() - } +// .onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in +// self._willEnterForegroundNotification() +// } .onAppear { self._onAppear() } @@ -60,6 +56,10 @@ struct LeCountdownApp: App { switch newPhase { case .inactive: Conductor.maestro.stopSoundIfPossible() + case .active: + Logger.log("onChange(of: scenePhase) active") + Logger.log(Conductor.maestro.currentCountdowns.count) + Conductor.maestro.cleanup() default: break } @@ -68,12 +68,14 @@ struct LeCountdownApp: App { } - fileprivate func _willEnterForegroundNotification() { - Conductor.maestro.cleanup() - } +// fileprivate func _willEnterForegroundNotification() { +// Conductor.maestro.cleanup() +// } fileprivate func _onAppear() { + Logger.log("Locale = \(Locale.preferredLanguages.first)") + Sound.computeSoundDurationsIfNecessary() self._patch() diff --git a/LeCountdown/Localizations/en.xcloc/Localized Contents/en.xliff b/LeCountdown/Localizations/en.xcloc/Localized Contents/en.xliff new file mode 100644 index 0000000..8d989fa --- /dev/null +++ b/LeCountdown/Localizations/en.xcloc/Localized Contents/en.xliff @@ -0,0 +1,647 @@ + + + +
+ +
+ + + LaunchIntents + LaunchIntents + Bundle display name + + + LaunchIntents + LaunchIntents + Bundle name + + + + + Copyright (human-readable) + + +
+ +
+ +
+ + + Custom + Custom + No comment provided by engineer. + + + Démarre + Démarre + No comment provided by engineer. + + + Forest stream + Forest stream + No comment provided by engineer. + + + Fun + Fun + No comment provided by engineer. + + + It's time! + It's time! + No comment provided by engineer. + + + Nature + Nature + No comment provided by engineer. + + + Time's up for (name)! + Time's up for (name)! + No comment provided by engineer. + + + Train horn + Train horn + No comment provided by engineer. + + + Your (duration.minuteSecond) countdown is over! + Your (duration.minuteSecond) countdown is over! + No comment provided by engineer. + + +
+ +
+ +
+ + + LaunchWidget + LaunchWidget + Bundle display name + + + LaunchWidgetExtension + LaunchWidgetExtension + Bundle name + + + + + Copyright (human-readable) + + +
+ +
+ +
+ + + 4:00 + 4:00 + No comment provided by engineer. + + + Configure me! + Configure me! + No comment provided by engineer. + + + Configure me! + + Configure me! + + No comment provided by engineer. + + + L + L + No comment provided by engineer. + + + Launch Widget + Launch Widget + No comment provided by engineer. + + + Min + Min + No comment provided by engineer. + + + Select and launch your timers + Select and launch your timers + No comment provided by engineer. + + + Stop + Stop + No comment provided by engineer. + + + T + T + No comment provided by engineer. + + +
+ +
+ +
+ + + LeCountdown + LeCountdown + Bundle name + + + NSAppleMusicUsageDescription + NSAppleMusicUsageDescription + Privacy - Media Library Usage Description + + +
+ +
+ +
+ + + %d + %d + No comment provided by engineer. + + + .create countdown + .create countdown + No comment provided by engineer. + + + .create stopwatch + .create stopwatch + No comment provided by engineer. + + + Activities + Activities + No comment provided by engineer. + + + All + All + No comment provided by engineer. + + + Average duration + Average duration + No comment provided by engineer. + + + Background + Background + No comment provided by engineer. + + + Black tea + Black tea + No comment provided by engineer. + + + Cancel + Cancel + No comment provided by engineer. + + + Cancelled + Cancelled + No comment provided by engineer. + + + Chill + Chill + No comment provided by engineer. + + + Cooking + Cooking + No comment provided by engineer. + + + Coundown + Coundown + No comment provided by engineer. + + + Count + Count + No comment provided by engineer. + + + Create + Create + No comment provided by engineer. + + + Create a new countdown + Create a new countdown + No comment provided by engineer. + + + Create countdown + Create countdown + No comment provided by engineer. + + + Custom + Custom + No comment provided by engineer. + + + Démarre + Démarre + No comment provided by engineer. + + + Do you really want to delete? + Do you really want to delete? + No comment provided by engineer. + + + Do you wish to rename or create a new activity + Do you wish to rename or create a new activity + No comment provided by engineer. + + + Don't show this again + Don't show this again + No comment provided by engineer. + + + Done + Done + No comment provided by engineer. + + + Duration + Duration + No comment provided by engineer. + + + Edit + Edit + No comment provided by engineer. + + + Edit alarm + Edit alarm + No comment provided by engineer. + + + Edit countdown + Edit countdown + No comment provided by engineer. + + + Edit stopwatch + Edit stopwatch + No comment provided by engineer. + + + Forest stream + Forest stream + No comment provided by engineer. + + + Fun + Fun + No comment provided by engineer. + + + Green tea + Green tea + No comment provided by engineer. + + + Hard boiled eggs + Hard boiled eggs + No comment provided by engineer. + + + Hello Store! + Hello Store! + No comment provided by engineer. + + + Home + Home + No comment provided by engineer. + + + It's time! + It's time! + No comment provided by engineer. + + + L + L + No comment provided by engineer. + + + Make sure your device is not on silent mode + Make sure your device is not on silent mode + No comment provided by engineer. + + + Meditation + Meditation + No comment provided by engineer. + + + Medium boiled eggs + Medium boiled eggs + No comment provided by engineer. + + + Min + Min + No comment provided by engineer. + + + Minutes + Minutes + No comment provided by engineer. + + + Month + Month + No comment provided by engineer. + + + Name (activates tracking) + Name (activates tracking) + No comment provided by engineer. + + + Name for tracking the activity + Name for tracking the activity + No comment provided by engineer. + + + Nap + Nap + No comment provided by engineer. + + + Nature + Nature + No comment provided by engineer. + + + New activity + New activity + No comment provided by engineer. + + + New alarm + New alarm + No comment provided by engineer. + + + New countdown + New countdown + No comment provided by engineer. + + + New stopwatch + New stopwatch + No comment provided by engineer. + + + No + No + No comment provided by engineer. + + + OK + OK + No comment provided by engineer. + + + Other + Other + No comment provided by engineer. + + + Play sound on end + Play sound on end + No comment provided by engineer. + + + Presets + Presets + No comment provided by engineer. + + + Properties + Properties + No comment provided by engineer. + + + Rename + Rename + No comment provided by engineer. + + + Repeat Count + Repeat Count + No comment provided by engineer. + + + Running splits + Running splits + No comment provided by engineer. + + + Save + Save + No comment provided by engineer. + + + Seconds + Seconds + No comment provided by engineer. + + + Show permissions + Show permissions + No comment provided by engineer. + + + Soft boiled eggs + Soft boiled eggs + No comment provided by engineer. + + + Sound + Sound + No comment provided by engineer. + + + Sounds + Sounds + No comment provided by engineer. + + + Stats + Stats + No comment provided by engineer. + + + Stop + Stop + No comment provided by engineer. + + + Stopwatch + Stopwatch + No comment provided by engineer. + + + T + T + No comment provided by engineer. + + + Tea + Tea + No comment provided by engineer. + + + Time + Time + No comment provided by engineer. + + + Time's up for (name)! + Time's up for (name)! + No comment provided by engineer. + + + Tooth brushing + Tooth brushing + No comment provided by engineer. + + + Train horn + Train horn + No comment provided by engineer. + + + Workout + Workout + No comment provided by engineer. + + + Year + Year + No comment provided by engineer. + + + Yes + Yes + No comment provided by engineer. + + + You can ask Siri to create and launch countdowns and stopwatches + You can ask Siri to create and launch countdowns and stopwatches + No comment provided by engineer. + + + You can edit the duration, sound and label before adding + You can edit the duration, sound and label before adding + No comment provided by engineer. + + + You don't have any recorded activity yet + You don't have any recorded activity yet + No comment provided by engineer. + + + You need to accept notifications, please check your settings + You need to accept notifications, please check your settings + No comment provided by engineer. + + + Your (duration.minuteSecond) countdown is over! + Your (duration.minuteSecond) countdown is over! + No comment provided by engineer. + + + alarm + alarm + No comment provided by engineer. + + + countdown + countdown + No comment provided by engineer. + + + date + date + No comment provided by engineer. + + + haha + haha + No comment provided by engineer. + + + missing dial view + missing dial view + No comment provided by engineer. + + + missing edit view + missing edit view + No comment provided by engineer. + + + name + name + No comment provided by engineer. + + + sounds + sounds + sounds + + + stopwatch + stopwatch + No comment provided by engineer. + + + todo + todo + No comment provided by engineer. + + + unmanaged timer: %@ + unmanaged timer: %@ + No comment provided by engineer. + + + value + value + No comment provided by engineer. + + +
+
diff --git a/LeCountdown/Localizations/en.xcloc/Source Contents/LaunchIntents/en.lproj/InfoPlist.strings b/LeCountdown/Localizations/en.xcloc/Source Contents/LaunchIntents/en.lproj/InfoPlist.strings new file mode 100644 index 0000000..c7abb4a --- /dev/null +++ b/LeCountdown/Localizations/en.xcloc/Source Contents/LaunchIntents/en.lproj/InfoPlist.strings @@ -0,0 +1,6 @@ +/* Bundle display name */ +"CFBundleDisplayName" = "LaunchIntents"; +/* Bundle name */ +"CFBundleName" = "LaunchIntents"; +/* Copyright (human-readable) */ +"NSHumanReadableCopyright" = ""; diff --git a/LeCountdown/Localizations/en.xcloc/Source Contents/LaunchIntents/en.lproj/Localizable.strings b/LeCountdown/Localizations/en.xcloc/Source Contents/LaunchIntents/en.lproj/Localizable.strings new file mode 100644 index 0000000000000000000000000000000000000000..bba65fa18e9508ae4e5817ee52ff8261c16554f4 GIT binary patch literal 1384 zcmcJP!EVAZ5Jcz9R~Rk@4&?(7ClC@BE^w*Dg^~a{5Ku@!d~$!H^sR$LLQ$nkSWz5% zY-eW2>%D&W)Rogzd)gK4jwe>Cobf>!$VrJJun6Q+7h0R&fTr|f*1Ust)l)+)4OQsK zZu?UUe8BsN_F36r{cD*=`hs(bo(xrY?ngWf`3!7HZ?ZS19Ef+U!<4ZN1`Z=FIW(_iPv?AF$imm5xQeZ|9kSr&ODrS6P6>n((^b literal 0 HcmV?d00001 diff --git a/LeCountdown/Localizations/en.xcloc/Source Contents/LaunchWidget/en.lproj/InfoPlist.strings b/LeCountdown/Localizations/en.xcloc/Source Contents/LaunchWidget/en.lproj/InfoPlist.strings new file mode 100644 index 0000000..3eff3a6 --- /dev/null +++ b/LeCountdown/Localizations/en.xcloc/Source Contents/LaunchWidget/en.lproj/InfoPlist.strings @@ -0,0 +1,6 @@ +/* Bundle display name */ +"CFBundleDisplayName" = "LaunchWidget"; +/* Bundle name */ +"CFBundleName" = "LaunchWidgetExtension"; +/* Copyright (human-readable) */ +"NSHumanReadableCopyright" = ""; diff --git a/LeCountdown/Localizations/en.xcloc/Source Contents/LaunchWidget/en.lproj/Localizable.strings b/LeCountdown/Localizations/en.xcloc/Source Contents/LaunchWidget/en.lproj/Localizable.strings new file mode 100644 index 0000000..b133a5f --- /dev/null +++ b/LeCountdown/Localizations/en.xcloc/Source Contents/LaunchWidget/en.lproj/Localizable.strings @@ -0,0 +1,27 @@ +/* No comment provided by engineer. */ +"4:00" = "4:00"; + +/* No comment provided by engineer. */ +"Configure me!" = "Configure me!"; + +/* No comment provided by engineer. */ +"Configure me!\n" = "Configure me!\n"; + +/* No comment provided by engineer. */ +"L" = "L"; + +/* No comment provided by engineer. */ +"Launch Widget" = "Launch Widget"; + +/* No comment provided by engineer. */ +"Min" = "Min"; + +/* No comment provided by engineer. */ +"Select and launch your timers" = "Select and launch your timers"; + +/* No comment provided by engineer. */ +"Stop" = "Stop"; + +/* No comment provided by engineer. */ +"T" = "T"; + diff --git a/LeCountdown/Localizations/en.xcloc/Source Contents/LeCountdown/en.lproj/InfoPlist.strings b/LeCountdown/Localizations/en.xcloc/Source Contents/LeCountdown/en.lproj/InfoPlist.strings new file mode 100644 index 0000000..3e9e4d7 --- /dev/null +++ b/LeCountdown/Localizations/en.xcloc/Source Contents/LeCountdown/en.lproj/InfoPlist.strings @@ -0,0 +1,4 @@ +/* Bundle name */ +"CFBundleName" = "LeCountdown"; +/* Privacy - Media Library Usage Description */ +"NSAppleMusicUsageDescription" = "NSAppleMusicUsageDescription"; diff --git a/LeCountdown/Localizations/en.xcloc/Source Contents/LeCountdown/en.lproj/Localizable.strings b/LeCountdown/Localizations/en.xcloc/Source Contents/LeCountdown/en.lproj/Localizable.strings new file mode 100644 index 0000000000000000000000000000000000000000..b8367afd72cb630d89b3f480e94305c89a199081 GIT binary patch literal 5018 zcmchb!EVz)5QgX6r!c)hduSg3ae!2X9-2xd5~{?-)Fwm$Cra#AedN9b@Xff^u4C6O zQU^t`;@NTje`o%ko%NsJr*bTbOl8gWhU+grxfD`zzmYALTUknmEyMCn?z!st0&Bsq z9G??x$8stMawzZRC!a$s@A!uMw~QX(^U`Ry#vp}H4qhe|d{WpiVP3R&jCuMn{6I8P zBD;cJ3CA?z)HmkCVghafi`=rKxeOWV8}nlEgS@o$F_B>NLS3VUmFacSns?johh7o; z3=VfKMNY7^M|>HSdvjN8wRxd#P3@}r1ob7LQ%(5f7FM`C5p}9P!h9lXVgFH%cLS6+D#5;u3}n z<-=@--oL|Re5HQ*vBIgT)I` xXWD3Y|1Ho7O4h7sEOMFg)w7z`pCdBWJ+~!zYu~2tzH~Q;SHQK!)Dx+W&|h@MAN&9S literal 0 HcmV?d00001 diff --git a/LeCountdown/Localizations/en.xcloc/contents.json b/LeCountdown/Localizations/en.xcloc/contents.json new file mode 100644 index 0000000..162c5d0 --- /dev/null +++ b/LeCountdown/Localizations/en.xcloc/contents.json @@ -0,0 +1,12 @@ +{ + "developmentRegion" : "en", + "project" : "LeCountdown.xcodeproj", + "targetLocale" : "en", + "toolInfo" : { + "toolBuildNumber" : "14C18", + "toolID" : "com.apple.dt.xcode", + "toolName" : "Xcode", + "toolVersion" : "14.2" + }, + "version" : "1.0" +} \ No newline at end of file diff --git a/LeCountdown/Localizations/fr.xcloc/Localized Contents/fr.xliff b/LeCountdown/Localizations/fr.xcloc/Localized Contents/fr.xliff new file mode 100644 index 0000000..944ef4b --- /dev/null +++ b/LeCountdown/Localizations/fr.xcloc/Localized Contents/fr.xliff @@ -0,0 +1,617 @@ + + + +
+ +
+ + + LaunchIntents + Bundle display name + + + LaunchIntents + Bundle name + + + + Copyright (human-readable) + + +
+ +
+ +
+ + + Custom + Personnalisé + No comment provided by engineer. + + + Démarre + No comment provided by engineer. + + + Forest stream + No comment provided by engineer. + + + Fun + No comment provided by engineer. + + + It's time! + C'est l'heure ! + No comment provided by engineer. + + + Nature + Nature + No comment provided by engineer. + + + Time's up for (name)! + C'est l'heure pour (name) ! + No comment provided by engineer. + + + Train horn + No comment provided by engineer. + + + Your (duration.minuteSecond) countdown is over! + Votre minuteur de (duration.minuteSecond) est terminé ! + No comment provided by engineer. + + +
+ +
+ +
+ + + LaunchWidget + Bundle display name + + + LaunchWidgetExtension + Bundle name + + + + Copyright (human-readable) + + +
+ +
+ +
+ + + 4:00 + No comment provided by engineer. + + + Configure me! + Configurez moi ! + No comment provided by engineer. + + + Configure me! + + Configurez moi ! + No comment provided by engineer. + + + L + No comment provided by engineer. + + + Launch Widget + Widget de lancement + No comment provided by engineer. + + + Min + Min + No comment provided by engineer. + + + Select and launch your timers + Sélectionnez et lancer vos minuteurs + No comment provided by engineer. + + + Stop + Arrêter + No comment provided by engineer. + + + T + No comment provided by engineer. + + +
+ +
+ +
+ + + LeCountdown + Bundle name + + + NSAppleMusicUsageDescription + Privacy - Media Library Usage Description + + +
+ +
+ +
+ + + %d + No comment provided by engineer. + + + .create countdown + .Créer minuteur + No comment provided by engineer. + + + .create stopwatch + .Créer un chrono + No comment provided by engineer. + + + Activities + Activités + No comment provided by engineer. + + + All + Tout + No comment provided by engineer. + + + Average duration + Durée moyenne + No comment provided by engineer. + + + Background + No comment provided by engineer. + + + Black tea + Thé noir + No comment provided by engineer. + + + Cancel + Annuler + No comment provided by engineer. + + + Cancelled + Annulé + No comment provided by engineer. + + + Chill + No comment provided by engineer. + + + Cooking + Cuisine + No comment provided by engineer. + + + Coundown + Minuteur + No comment provided by engineer. + + + Count + Nombre + No comment provided by engineer. + + + Create + Nouveau + No comment provided by engineer. + + + Create a new countdown + Créer un nouveau minuteur + No comment provided by engineer. + + + Create countdown + Créer un minuteur + No comment provided by engineer. + + + Custom + Personnalisé + No comment provided by engineer. + + + Démarre + No comment provided by engineer. + + + Do you really want to delete? + Voulez-vous vraiment effacer ? + No comment provided by engineer. + + + Do you wish to rename or create a new activity + Souhaitez-vous renommer ou créer une nouvelle activité ? + No comment provided by engineer. + + + Don't show this again + Ne plus montrer + No comment provided by engineer. + + + Done + Sauver + No comment provided by engineer. + + + Duration + Durée + No comment provided by engineer. + + + Edit + Editer + No comment provided by engineer. + + + Edit alarm + Éditer alarme + No comment provided by engineer. + + + Edit countdown + Éditer minuteur + No comment provided by engineer. + + + Edit stopwatch + Éditer chrono + No comment provided by engineer. + + + Forest stream + No comment provided by engineer. + + + Fun + Fun + No comment provided by engineer. + + + Green tea + Thé vert + No comment provided by engineer. + + + Hard boiled eggs + Oeufs dur + No comment provided by engineer. + + + Hello Store! + No comment provided by engineer. + + + Home + Kikai + No comment provided by engineer. + + + It's time! + C'est l'heure ! + No comment provided by engineer. + + + L + No comment provided by engineer. + + + Make sure your device is not on silent mode + Vérifiez que votre appareil n'est pas en mode silencieux + No comment provided by engineer. + + + Meditation + Méditation + No comment provided by engineer. + + + Medium boiled eggs + Oeufs mollets + No comment provided by engineer. + + + Min + Min + No comment provided by engineer. + + + Minutes + Minutes + No comment provided by engineer. + + + Month + Mois + No comment provided by engineer. + + + Name (activates tracking) + Nom (active le suivi) + No comment provided by engineer. + + + Name for tracking the activity + Nom pour suivre l'activité + No comment provided by engineer. + + + Nap + Sieste + No comment provided by engineer. + + + Nature + Nature + No comment provided by engineer. + + + New activity + Nouvelle activité + No comment provided by engineer. + + + New alarm + Nouvelle alarme + No comment provided by engineer. + + + New countdown + Nouveau minuteur + No comment provided by engineer. + + + New stopwatch + Nouveau chrono + No comment provided by engineer. + + + No + Non + No comment provided by engineer. + + + OK + OK + No comment provided by engineer. + + + Other + Autre + No comment provided by engineer. + + + Play sound on end + Jouer un son de fin + No comment provided by engineer. + + + Presets + Préselection + No comment provided by engineer. + + + Properties + Propriétes + No comment provided by engineer. + + + Rename + Renommer + No comment provided by engineer. + + + Repeat Count + Nombre de répétitions + No comment provided by engineer. + + + Running splits + No comment provided by engineer. + + + Save + Sauvegarder + No comment provided by engineer. + + + Seconds + Secondes + No comment provided by engineer. + + + Show permissions + Voir permissions + No comment provided by engineer. + + + Soft boiled eggs + Oeufs coque + No comment provided by engineer. + + + Sound + Son + No comment provided by engineer. + + + Sounds + Sons + No comment provided by engineer. + + + Stats + Statistiques + No comment provided by engineer. + + + Stop + Arrêter + No comment provided by engineer. + + + Stopwatch + Chrono + No comment provided by engineer. + + + T + No comment provided by engineer. + + + Tea + Thé + No comment provided by engineer. + + + Time + Temps + No comment provided by engineer. + + + Time's up for (name)! + C'est l'heure pour (name) ! + No comment provided by engineer. + + + Tooth brushing + Brossage de dent + No comment provided by engineer. + + + Train horn + No comment provided by engineer. + + + Workout + Exercice + No comment provided by engineer. + + + Year + Année + No comment provided by engineer. + + + Yes + Oui + No comment provided by engineer. + + + You can ask Siri to create and launch countdowns and stopwatches + Vous pouvez demander à Siri de vous lancer les minuteurs et les chronos + No comment provided by engineer. + + + You can edit the duration, sound and label before adding + Vous pouvez changer la durée, le son et le label avant l'ajout + No comment provided by engineer. + + + You don't have any recorded activity yet + Vous n'avez pas encore d'activités enregistrées + No comment provided by engineer. + + + You need to accept notifications, please check your settings + Vous devez accepter les notifications, veuillez vérifier vos réglages + No comment provided by engineer. + + + Your (duration.minuteSecond) countdown is over! + Votre minuteur de (duration.minuteSecond) est terminé ! + No comment provided by engineer. + + + alarm + Alarme + No comment provided by engineer. + + + countdown + compteur + No comment provided by engineer. + + + date + Date + No comment provided by engineer. + + + haha + + No comment provided by engineer. + + + missing dial view + No comment provided by engineer. + + + missing edit view + No comment provided by engineer. + + + name + nom + No comment provided by engineer. + + + sounds + sons + sounds + + + stopwatch + chrono + No comment provided by engineer. + + + todo + No comment provided by engineer. + + + unmanaged timer: %@ + No comment provided by engineer. + + + value + valeur + No comment provided by engineer. + + +
+
diff --git a/LeCountdown/Localizations/fr.xcloc/Source Contents/LaunchIntents/en.lproj/InfoPlist.strings b/LeCountdown/Localizations/fr.xcloc/Source Contents/LaunchIntents/en.lproj/InfoPlist.strings new file mode 100644 index 0000000..c7abb4a --- /dev/null +++ b/LeCountdown/Localizations/fr.xcloc/Source Contents/LaunchIntents/en.lproj/InfoPlist.strings @@ -0,0 +1,6 @@ +/* Bundle display name */ +"CFBundleDisplayName" = "LaunchIntents"; +/* Bundle name */ +"CFBundleName" = "LaunchIntents"; +/* Copyright (human-readable) */ +"NSHumanReadableCopyright" = ""; diff --git a/LeCountdown/Localizations/fr.xcloc/Source Contents/LaunchIntents/en.lproj/Localizable.strings b/LeCountdown/Localizations/fr.xcloc/Source Contents/LaunchIntents/en.lproj/Localizable.strings new file mode 100644 index 0000000000000000000000000000000000000000..bba65fa18e9508ae4e5817ee52ff8261c16554f4 GIT binary patch literal 1384 zcmcJP!EVAZ5Jcz9R~Rk@4&?(7ClC@BE^w*Dg^~a{5Ku@!d~$!H^sR$LLQ$nkSWz5% zY-eW2>%D&W)Rogzd)gK4jwe>Cobf>!$VrJJun6Q+7h0R&fTr|f*1Ust)l)+)4OQsK zZu?UUe8BsN_F36r{cD*=`hs(bo(xrY?ngWf`3!7HZ?ZS19Ef+U!<4ZN1`Z=FIW(_iPv?AF$imm5xQeZ|9kSr&ODrS6P6>n((^b literal 0 HcmV?d00001 diff --git a/LeCountdown/Localizations/fr.xcloc/Source Contents/LaunchWidget/en.lproj/InfoPlist.strings b/LeCountdown/Localizations/fr.xcloc/Source Contents/LaunchWidget/en.lproj/InfoPlist.strings new file mode 100644 index 0000000..3eff3a6 --- /dev/null +++ b/LeCountdown/Localizations/fr.xcloc/Source Contents/LaunchWidget/en.lproj/InfoPlist.strings @@ -0,0 +1,6 @@ +/* Bundle display name */ +"CFBundleDisplayName" = "LaunchWidget"; +/* Bundle name */ +"CFBundleName" = "LaunchWidgetExtension"; +/* Copyright (human-readable) */ +"NSHumanReadableCopyright" = ""; diff --git a/LeCountdown/Localizations/fr.xcloc/Source Contents/LaunchWidget/en.lproj/Localizable.strings b/LeCountdown/Localizations/fr.xcloc/Source Contents/LaunchWidget/en.lproj/Localizable.strings new file mode 100644 index 0000000..b133a5f --- /dev/null +++ b/LeCountdown/Localizations/fr.xcloc/Source Contents/LaunchWidget/en.lproj/Localizable.strings @@ -0,0 +1,27 @@ +/* No comment provided by engineer. */ +"4:00" = "4:00"; + +/* No comment provided by engineer. */ +"Configure me!" = "Configure me!"; + +/* No comment provided by engineer. */ +"Configure me!\n" = "Configure me!\n"; + +/* No comment provided by engineer. */ +"L" = "L"; + +/* No comment provided by engineer. */ +"Launch Widget" = "Launch Widget"; + +/* No comment provided by engineer. */ +"Min" = "Min"; + +/* No comment provided by engineer. */ +"Select and launch your timers" = "Select and launch your timers"; + +/* No comment provided by engineer. */ +"Stop" = "Stop"; + +/* No comment provided by engineer. */ +"T" = "T"; + diff --git a/LeCountdown/Localizations/fr.xcloc/Source Contents/LeCountdown/en.lproj/InfoPlist.strings b/LeCountdown/Localizations/fr.xcloc/Source Contents/LeCountdown/en.lproj/InfoPlist.strings new file mode 100644 index 0000000..3e9e4d7 --- /dev/null +++ b/LeCountdown/Localizations/fr.xcloc/Source Contents/LeCountdown/en.lproj/InfoPlist.strings @@ -0,0 +1,4 @@ +/* Bundle name */ +"CFBundleName" = "LeCountdown"; +/* Privacy - Media Library Usage Description */ +"NSAppleMusicUsageDescription" = "NSAppleMusicUsageDescription"; diff --git a/LeCountdown/Localizations/fr.xcloc/Source Contents/LeCountdown/en.lproj/Localizable.strings b/LeCountdown/Localizations/fr.xcloc/Source Contents/LeCountdown/en.lproj/Localizable.strings new file mode 100644 index 0000000000000000000000000000000000000000..b8367afd72cb630d89b3f480e94305c89a199081 GIT binary patch literal 5018 zcmchb!EVz)5QgX6r!c)hduSg3ae!2X9-2xd5~{?-)Fwm$Cra#AedN9b@Xff^u4C6O zQU^t`;@NTje`o%ko%NsJr*bTbOl8gWhU+grxfD`zzmYALTUknmEyMCn?z!st0&Bsq z9G??x$8stMawzZRC!a$s@A!uMw~QX(^U`Ry#vp}H4qhe|d{WpiVP3R&jCuMn{6I8P zBD;cJ3CA?z)HmkCVghafi`=rKxeOWV8}nlEgS@o$F_B>NLS3VUmFacSns?johh7o; z3=VfKMNY7^M|>HSdvjN8wRxd#P3@}r1ob7LQ%(5f7FM`C5p}9P!h9lXVgFH%cLS6+D#5;u3}n z<-=@--oL|Re5HQ*vBIgT)I` xXWD3Y|1Ho7O4h7sEOMFg)w7z`pCdBWJ+~!zYu~2tzH~Q;SHQK!)Dx+W&|h@MAN&9S literal 0 HcmV?d00001 diff --git a/LeCountdown/Localizations/fr.xcloc/contents.json b/LeCountdown/Localizations/fr.xcloc/contents.json new file mode 100644 index 0000000..423be3c --- /dev/null +++ b/LeCountdown/Localizations/fr.xcloc/contents.json @@ -0,0 +1,12 @@ +{ + "developmentRegion" : "en", + "project" : "LeCountdown.xcodeproj", + "targetLocale" : "fr", + "toolInfo" : { + "toolBuildNumber" : "14C18", + "toolID" : "com.apple.dt.xcode", + "toolName" : "Xcode", + "toolVersion" : "14.2" + }, + "version" : "1.0" +} \ No newline at end of file diff --git a/LeCountdown/Model/Model+Extensions.swift b/LeCountdown/Model/Model+Extensions.swift index e13ce5e..017c097 100644 --- a/LeCountdown/Model/Model+Extensions.swift +++ b/LeCountdown/Model/Model+Extensions.swift @@ -9,9 +9,6 @@ import Foundation import SwiftUI import CoreData -enum TimerError: Error { - case notificationAuthorizationMissing -} extension AbstractSoundTimer { @@ -106,19 +103,6 @@ extension Record { } } - func point(stat: Stat) -> Point? { - if let start { - let day = start.startOfDay - switch stat { - case .count: - return Point(date: day, value: NSNumber(value: 1)) - case .totalDuration, .averageDuration: - return Point(date: day, value: NSNumber(value: self.duration / 3600.0)) - } - } - return nil - } - } extension Activity { diff --git a/LeCountdown/Stats/Context+Calculations.swift b/LeCountdown/Stats/Context+Calculations.swift index 4090fa8..bdfcf7a 100644 --- a/LeCountdown/Stats/Context+Calculations.swift +++ b/LeCountdown/Stats/Context+Calculations.swift @@ -94,3 +94,20 @@ extension NSManagedObjectContext { return statValues } } + +fileprivate extension Record { + + func point(stat: Stat) -> Point? { + if let start { + let day = start.startOfDay + switch stat { + case .count: + return Point(date: day, value: NSNumber(value: 1)) + case .totalDuration, .averageDuration: + return Point(date: day, value: NSNumber(value: self.duration / 3600.0)) + } + } + return nil + } + +} diff --git a/LeCountdown/TimerRouter.swift b/LeCountdown/TimerRouter.swift index 74a02ff..17110cf 100644 --- a/LeCountdown/TimerRouter.swift +++ b/LeCountdown/TimerRouter.swift @@ -8,17 +8,38 @@ import Foundation import NotificationCenter +enum TimerRouterError: Error { + case notificationAuthorizationMissing + case unmanagedTimer(_ timer: AbstractTimer) +} + class TimerRouter { - static func performAction(timer: AbstractTimer, handler: @escaping (Result) -> Void) { + static func performAction(timer: AbstractTimer) async throws -> Bool { + + return try await withCheckedThrowingContinuation { (continuation: CheckedContinuation) in + self.performAction(timer: timer) { result in + switch result { + case .success: + continuation.resume(returning: true) + case .failure(let failure): + continuation.resume(throwing: failure) + } + } + } + + } + + static func performAction(timer: AbstractTimer, handler: @escaping (Result) -> Void) { switch timer { case let countdown as Countdown: self._launchCountdown(countdown, handler: handler) - case let alarm as Alarm: - self._scheduleAlarm(alarm, handler: handler) case let stopwatch as Stopwatch: self._startStopwatch(stopwatch, handler: handler) + case let alarm as Alarm: + self._scheduleAlarm(alarm, handler: handler) default: + handler(Result.failure(TimerRouterError.unmanagedTimer(timer))) print("missing launcher for \(self)") } @@ -35,17 +56,17 @@ class TimerRouter { } } - fileprivate static func _launchCountdown(_ countdown: Countdown, handler: @escaping (Result) -> Void) { + fileprivate static func _launchCountdown(_ countdown: Countdown, handler: @escaping (Result) -> Void) { UNUserNotificationCenter.current().getNotificationSettings { settings in switch settings.authorizationStatus { case .notDetermined, .denied: - handler(.failure(TimerError.notificationAuthorizationMissing)) + handler(.failure(TimerRouterError.notificationAuthorizationMissing)) default: CountdownScheduler.master.scheduleIfPossible(countdown: countdown) { result in switch result { - case .success(_): - handler(.success(true)) + case .success: + handler(.success(Void())) case .failure(let failure): handler(.failure(failure)) } @@ -55,12 +76,13 @@ class TimerRouter { } - fileprivate static func _scheduleAlarm(_ alarm: Alarm, handler: @escaping (Result) -> Void) { + fileprivate static func _scheduleAlarm(_ alarm: Alarm, handler: @escaping (Result) -> Void) { } - fileprivate static func _startStopwatch(_ stopwatch: Stopwatch, handler: @escaping (Result) -> Void) { + fileprivate static func _startStopwatch(_ stopwatch: Stopwatch, handler: @escaping (Result) -> Void) { Conductor.maestro.startStopwatch(stopwatch) + handler(.success(Void())) } fileprivate static func _stopStopwatch(_ stopwatch: Stopwatch, end: Date? = nil) { diff --git a/LeCountdown/Views/ContentView.swift b/LeCountdown/Views/ContentView.swift index b9a5305..0379191 100644 --- a/LeCountdown/Views/ContentView.swift +++ b/LeCountdown/Views/ContentView.swift @@ -8,7 +8,6 @@ import SwiftUI import CoreData import Combine -//import CloudKit class BoringContext : ObservableObject { @@ -42,12 +41,6 @@ class TimerSpot : Identifiable, Equatable { } -//class TimersModel : ObservableObject { -// -// @Published var spots: [TimerSpot] = [] -// -//} - struct ContentView: View { @StateObject var boringContext: BoringContext = BoringContext() @@ -60,11 +53,6 @@ struct ContentView: View { animation: .default) private var timers: FetchedResults -// var coreDataPublisher: NotificationCenter.Publisher { NotificationCenter.default -// .publisher(for: .NSManagedObjectContextDidSave, object: viewContext) } - - @State private var showLiveTimersSheet = false - @State private var isEditing: Bool = false fileprivate let itemSpacing: CGFloat = 10.0 @@ -139,22 +127,9 @@ struct ContentView: View { } } } -// .onReceive(cloudkitPublisher, perform: { _ in -// print(">>>cloudkitPublisher") -// withAnimation { -// self._buildItemsList() -// } -// }) -// .onReceive(coreDataPublisher, perform: { _ in -// withAnimation { -// self._buildItemsList() -// } -// }) .onAppear { -// self._buildItemsList() self._askPermissions() - - self.showLiveTimersSheet = !conductor.liveTimers.isEmpty +// self.showLiveTimersSheet = !conductor.liveTimers.isEmpty } .onOpenURL { url in self._performActionIfPossible(url: url) @@ -177,59 +152,9 @@ struct ContentView: View { fileprivate func _columns() -> [GridItem] { return (0..) -> some View { -// switch T.self { -// case is Countdown.Type: -// NewCountdownView(isPresented: isPresented, tabSelection: self.tabse) -// case is Alarm.Type: -// NewAlarmView(isPresented: isPresented) -// case is Stopwatch.Type: -// NewStopwatchView(isPresented: isPresented, tabSelection: <#Binding#>) -// default: -// NewDataView(isPresented: isPresented, tabSelection: <#Binding#>) -// } -// -// } - + // MARK: - Business -// fileprivate func _reorderSpots(from: IndexSet, to: Int) { -// var spots: [TimerSpot] = self.model.spots -// spots.move(fromOffsets: from, toOffset: to) -// self.model.spots = spots -// } - fileprivate func _reorder(from: IndexSet, to: Int) { var timers: [AbstractTimer] = Array(self.timers) timers.move(fromOffsets: from, toOffset: to) @@ -245,7 +170,7 @@ struct ContentView: View { } fileprivate func _askPermissions() { - UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .criticalAlert]) { success, error in + UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound]) { success, error in print("requestAuthorization > success = \(success), error = \(String(describing: error))") } } @@ -269,7 +194,7 @@ struct ContentView: View { break case .failure(let failure): switch failure { - case TimerError.notificationAuthorizationMissing: + case TimerRouterError.notificationAuthorizationMissing: self.boringContext.showPermissionAlert = true default: self.boringContext.error = failure @@ -333,13 +258,13 @@ fileprivate extension Countdown { return endDate != nil } - var colorForStatus: Color { - if isLive { - return Color(red: 0.9, green: 1.0, blue: 0.95) - } else { - return Color(red: 0.9, green: 0.95, blue: 1.0) - } - } +// var colorForStatus: Color { +// if isLive { +// return Color(red: 0.9, green: 1.0, blue: 0.95) +// } else { +// return Color(red: 0.9, green: 0.95, blue: 1.0) +// } +// } } diff --git a/LeCountdown/Views/Countdown/NewCountdownView.swift b/LeCountdown/Views/Countdown/NewCountdownView.swift index 23fbdfb..1d79e5a 100644 --- a/LeCountdown/Views/Countdown/NewCountdownView.swift +++ b/LeCountdown/Views/Countdown/NewCountdownView.swift @@ -8,6 +8,7 @@ import SwiftUI import CoreData import WidgetKit +import Intents struct NewCountdownView : View { @@ -21,6 +22,8 @@ struct NewCountdownView : View { _isPresented = isPresented self.tabSelection = tabSelection self.userActivity = Shortcut.newCountdown.userActivity + +// let shortcut = INShortcut(userActivity: self.userActivity) } var body: some View { @@ -312,13 +315,16 @@ struct CountdownEditView : View { guard let countdown else { return } - + // remove the siri donation + INInteraction.delete(with: [countdown.stringId]) { _ in } + viewContext.delete(countdown) self._saveContext() WidgetCenter.shared.reloadAllTimelines() // refreshes the visual of existing widgets self._popOrDismiss() + } fileprivate func _saveContext() { diff --git a/LeCountdown/Views/DialView.swift b/LeCountdown/Views/DialView.swift index fbd264f..022c710 100644 --- a/LeCountdown/Views/DialView.swift +++ b/LeCountdown/Views/DialView.swift @@ -132,7 +132,7 @@ struct DialView: View { break case .failure(let failure): switch failure { - case TimerError.notificationAuthorizationMissing: + case TimerRouterError.notificationAuthorizationMissing: self.boringContext.showPermissionAlert = true default: self.boringContext.error = failure diff --git a/LeCountdown/Views/HomeView.swift b/LeCountdown/Views/HomeView.swift index 4acfabc..b76f651 100644 --- a/LeCountdown/Views/HomeView.swift +++ b/LeCountdown/Views/HomeView.swift @@ -21,36 +21,33 @@ struct CompactHomeView: View { var body: some View { + NavigationView { + TabView(selection: $tabSelection) { - NavigationStack { - PresetsView(tabSelection: $tabSelection) - .environment(\.managedObjectContext, viewContext) - .tabItem { Label("Presets", systemImage: "globe") } + PresetsView(tabSelection: $tabSelection) + .environment(\.managedObjectContext, viewContext) + .tabItem { Label("Presets", systemImage: "globe") } .tag(0) - } - NavigationStack { - ContentView() - .environment(\.managedObjectContext, viewContext) - .environmentObject(Conductor.maestro) - .tabItem { Label("Home", systemImage: "clock.fill") } + ContentView() + .environment(\.managedObjectContext, viewContext) + .environmentObject(Conductor.maestro) + .tabItem { Label("Home", systemImage: "clock.fill") } .tag(1) - } - NavigationStack { - ActivitiesView() - .environment(\.managedObjectContext, viewContext) - .tabItem { Label("Stats", systemImage: "chart.bar.fill") } + ActivitiesView() + .environment(\.managedObjectContext, viewContext) + .tabItem { Label("Stats", systemImage: "chart.bar.fill") } .tag(2) - } } .tabViewStyle(.page(indexDisplayMode: .never)) - .onAppear { - if self.timers.count > 0 { - self.tabSelection = 1 - } - } - .onOpenURL { _ in + } + .onAppear { + if self.timers.count > 0 { self.tabSelection = 1 } + } + .onOpenURL { _ in + self.tabSelection = 1 + } } } diff --git a/LeCountdown/Views/Stopwatch/NewStopwatchView.swift b/LeCountdown/Views/Stopwatch/NewStopwatchView.swift index 599b35f..6c95477 100644 --- a/LeCountdown/Views/Stopwatch/NewStopwatchView.swift +++ b/LeCountdown/Views/Stopwatch/NewStopwatchView.swift @@ -8,6 +8,7 @@ import SwiftUI import CoreData import WidgetKit +import Intents struct NewStopwatchView: View { @@ -294,13 +295,16 @@ struct StopwatchEditView: View { guard let stopwatch else { return } - + // remove the siri donation + INInteraction.delete(with: [stopwatch.stringId]) { _ in } + viewContext.delete(stopwatch) self._saveContext() WidgetCenter.shared.reloadAllTimelines() // refreshes the visual of existing widgets self._popOrDismiss() + } fileprivate func _saveContext() { diff --git a/LeCountdown/Widget/LaunchWidgetAttributes.swift b/LeCountdown/Widget/LaunchWidgetAttributes.swift new file mode 100644 index 0000000..1273017 --- /dev/null +++ b/LeCountdown/Widget/LaunchWidgetAttributes.swift @@ -0,0 +1,22 @@ +// +// LaunchWidgetAttributes.swift +// LeCountdown +// +// Created by Laurent Morvillier on 24/02/2023. +// + +import Foundation +import ActivityKit + +struct LaunchWidgetAttributes: ActivityAttributes { + public struct ContentState: Codable, Hashable { + // Dynamic stateful properties about your activity go here! + var ended: Bool + } + + // Fixed non-changing properties about your activity go here! + var id: String + var name: String + var date: Date + +} diff --git a/LeCountdown/SiriIntents.intentdefinition b/LeCountdown/en.lproj/SiriIntents.intentdefinition similarity index 88% rename from LeCountdown/SiriIntents.intentdefinition rename to LeCountdown/en.lproj/SiriIntents.intentdefinition index ca40c31..2116907 100644 --- a/LeCountdown/SiriIntents.intentdefinition +++ b/LeCountdown/en.lproj/SiriIntents.intentdefinition @@ -19,46 +19,28 @@ INIntentCategory start - INIntentConfigurable - INIntentDescription Launch timers and stopwatches INIntentDescriptionID NdKydA - INIntentInput - timer - INIntentKeyParameter - timer INIntentLastParameterTag 2 - INIntentManagedParameterCombinations - - timer - - INIntentParameterCombinationSupportsBackgroundExecution - - INIntentParameterCombinationTitle - Launch your timer - INIntentParameterCombinationTitleID - PE02Dd - INIntentParameterCombinationUpdatesLinked - - - INIntentName LaunchTimer INIntentParameterCombinations timer - INIntentParameterCombinationIsLinked - INIntentParameterCombinationIsPrimary + INIntentParameterCombinationSubtitle + Starts immediately + INIntentParameterCombinationSubtitleID + r4Ikzx INIntentParameterCombinationSupportsBackgroundExecution INIntentParameterCombinationTitle - Launch your timer + Launch ${timer} INIntentParameterCombinationTitleID JfqtH6 @@ -77,7 +59,7 @@ INIntentParameterName timer INIntentParameterObjectType - Type + TimerIdentifier INIntentParameterObjectTypeNamespace ggxqDx INIntentParameterPromptDialogs @@ -142,7 +124,7 @@ INIntentResponseParameterName timer INIntentResponseParameterObjectType - Type + TimerIdentifier INIntentResponseParameterObjectTypeNamespace ggxqDx INIntentResponseParameterTag @@ -166,13 +148,13 @@ INTypeDisplayName - Timer + Timer Identifier INTypeDisplayNameID 02RXTq INTypeLastPropertyTag 99 INTypeName - Type + TimerIdentifier INTypeProperties diff --git a/LeCountdown/fr.lproj/Localizable.strings b/LeCountdown/fr.lproj/Localizable.strings new file mode 100644 index 0000000..b2265a5 --- /dev/null +++ b/LeCountdown/fr.lproj/Localizable.strings @@ -0,0 +1,241 @@ +/* No comment provided by engineer. */ +".create countdown" = ".Créer minuteur"; + +/* No comment provided by engineer. */ +".create stopwatch" = ".Créer un chrono"; + +/* No comment provided by engineer. */ +"Activities" = "Activités"; + +/* No comment provided by engineer. */ +"alarm" = "Alarme"; + +/* No comment provided by engineer. */ +"All" = "Tout"; + +/* No comment provided by engineer. */ +"Average duration" = "Durée moyenne"; + +/* No comment provided by engineer. */ +"Black tea" = "Thé noir"; + +/* No comment provided by engineer. */ +"Cancel" = "Annuler"; + +/* No comment provided by engineer. */ +"Cancelled" = "Annulé"; + +/* No comment provided by engineer. */ +"Cooking" = "Cuisine"; + +/* No comment provided by engineer. */ +"Coundown" = "Minuteur"; + +/* No comment provided by engineer. */ +"Count" = "Nombre"; + +/* No comment provided by engineer. */ +"countdown" = "compteur"; + +/* No comment provided by engineer. */ +"Create" = "Nouveau"; + +/* No comment provided by engineer. */ +"Create a new countdown" = "Créer un nouveau minuteur"; + +/* No comment provided by engineer. */ +"Create countdown" = "Créer un minuteur"; + +/* No comment provided by engineer. */ +"Custom" = "Personnalisé"; + +/* No comment provided by engineer. */ +"date" = "Date"; + +/* No comment provided by engineer. */ +"Do you really want to delete?" = "Voulez-vous vraiment effacer ?"; + +/* No comment provided by engineer. */ +"Do you wish to rename or create a new activity" = "Souhaitez-vous renommer ou créer une nouvelle activité ?"; + +/* No comment provided by engineer. */ +"Don't show this again" = "Ne plus montrer"; + +/* No comment provided by engineer. */ +"Done" = "Sauver"; + +/* No comment provided by engineer. */ +"Duration" = "Durée"; + +/* No comment provided by engineer. */ +"Edit" = "Editer"; + +/* No comment provided by engineer. */ +"Edit alarm" = "Éditer alarme"; + +/* No comment provided by engineer. */ +"Edit countdown" = "Éditer minuteur"; + +/* No comment provided by engineer. */ +"Edit stopwatch" = "Éditer chrono"; + +/* No comment provided by engineer. */ +"Fun" = "Fun"; + +/* No comment provided by engineer. */ +"Green tea" = "Thé vert"; + +/* No comment provided by engineer. */ +"haha" = ""; + +/* No comment provided by engineer. */ +"Hard boiled eggs" = "Oeufs dur"; + +/* No comment provided by engineer. */ +"Home" = "Kikai"; + +/* No comment provided by engineer. */ +"It's time!" = "C'est l'heure !"; + +/* No comment provided by engineer. */ +"Make sure your device is not on silent mode" = "Vérifiez que votre appareil n'est pas en mode silencieux"; + +/* No comment provided by engineer. */ +"Meditation" = "Méditation"; + +/* No comment provided by engineer. */ +"Medium boiled eggs" = "Oeufs mollets"; + +/* No comment provided by engineer. */ +"Min" = "Min"; + +/* No comment provided by engineer. */ +"Minutes" = "Minutes"; + +/* No comment provided by engineer. */ +"Month" = "Mois"; + +/* No comment provided by engineer. */ +"name" = "nom"; + +/* No comment provided by engineer. */ +"Name (activates tracking)" = "Nom (active le suivi)"; + +/* No comment provided by engineer. */ +"Name for tracking the activity" = "Nom pour suivre l'activité"; + +/* No comment provided by engineer. */ +"Nap" = "Sieste"; + +/* No comment provided by engineer. */ +"Nature" = "Nature"; + +/* No comment provided by engineer. */ +"New activity" = "Nouvelle activité"; + +/* No comment provided by engineer. */ +"New alarm" = "Nouvelle alarme"; + +/* No comment provided by engineer. */ +"New countdown" = "Nouveau minuteur"; + +/* No comment provided by engineer. */ +"New stopwatch" = "Nouveau chrono"; + +/* No comment provided by engineer. */ +"No" = "Non"; + +/* No comment provided by engineer. */ +"OK" = "OK"; + +/* No comment provided by engineer. */ +"Other" = "Autre"; + +/* No comment provided by engineer. */ +"Play sound on end" = "Jouer un son de fin"; + +/* No comment provided by engineer. */ +"Presets" = "Préselection"; + +/* No comment provided by engineer. */ +"Properties" = "Propriétes"; + +/* No comment provided by engineer. */ +"Rename" = "Renommer"; + +/* No comment provided by engineer. */ +"Repeat Count" = "Nombre de répétitions"; + +/* No comment provided by engineer. */ +"Save" = "Sauvegarder"; + +/* No comment provided by engineer. */ +"Seconds" = "Secondes"; + +/* No comment provided by engineer. */ +"Show permissions" = "Voir permissions"; + +/* No comment provided by engineer. */ +"Soft boiled eggs" = "Oeufs coque"; + +/* No comment provided by engineer. */ +"Sound" = "Son"; + +/* sounds */ +"sounds" = "sons"; + +/* No comment provided by engineer. */ +"Sounds" = "Sons"; + +/* No comment provided by engineer. */ +"Stats" = "Statistiques"; + +/* No comment provided by engineer. */ +"Stop" = "Arrêter"; + +/* No comment provided by engineer. */ +"stopwatch" = "chrono"; + +/* No comment provided by engineer. */ +"Stopwatch" = "Chrono"; + +/* No comment provided by engineer. */ +"Tea" = "Thé"; + +/* No comment provided by engineer. */ +"Time" = "Temps"; + +/* No comment provided by engineer. */ +"Time's up for (name)!" = "C'est l'heure pour (name) !"; + +/* No comment provided by engineer. */ +"Tooth brushing" = "Brossage de dent"; + +/* No comment provided by engineer. */ +"value" = "valeur"; + +/* No comment provided by engineer. */ +"Workout" = "Exercice"; + +/* No comment provided by engineer. */ +"Year" = "Année"; + +/* No comment provided by engineer. */ +"Yes" = "Oui"; + +/* No comment provided by engineer. */ +"You can ask Siri to create and launch countdowns and stopwatches" = "Vous pouvez demander à Siri de vous lancer les minuteurs et les chronos"; + +/* No comment provided by engineer. */ +"You can edit the duration, sound and label before adding" = "Vous pouvez changer la durée, le son et le label avant l'ajout"; + +/* No comment provided by engineer. */ +"You don't have any recorded activity yet" = "Vous n'avez pas encore d'activités enregistrées"; + +/* No comment provided by engineer. */ +"You need to accept notifications, please check your settings" = "Vous devez accepter les notifications, veuillez vérifier vos réglages"; + +/* No comment provided by engineer. */ +"Your (duration.minuteSecond) countdown is over!" = "Votre minuteur de (duration.minuteSecond) est terminé !"; + +"Launch ${timer}" = "Démarrer ${timer}"; diff --git a/LeCountdown/fr.lproj/SiriIntents.intentdefinition b/LeCountdown/fr.lproj/SiriIntents.intentdefinition new file mode 100644 index 0000000..444e012 --- /dev/null +++ b/LeCountdown/fr.lproj/SiriIntents.intentdefinition @@ -0,0 +1,214 @@ + + + + + INEnums + + INIntentDefinitionModelVersion + 1.2 + INIntentDefinitionNamespace + ggxqDx + INIntentDefinitionSystemVersion + 22A400 + INIntentDefinitionToolsBuildVersion + 14C18 + INIntentDefinitionToolsVersion + 14.2 + INIntents + + + INIntentCategory + start + INIntentDescription + Minuteurs et chronos + INIntentDescriptionID + NdKydA + INIntentLastParameterTag + 2 + INIntentName + LaunchTimer + INIntentParameterCombinations + + timer + + INIntentParameterCombinationIsPrimary + + INIntentParameterCombinationSubtitle + Lancement immédiat + INIntentParameterCombinationSubtitleID + r4Ikzx + INIntentParameterCombinationSupportsBackgroundExecution + + INIntentParameterCombinationTitle + Démarrer ${timer} + INIntentParameterCombinationTitleID + JfqtH6 + + + INIntentParameters + + + INIntentParameterConfigurable + + INIntentParameterDisplayName + Compteur + INIntentParameterDisplayNameID + wU1mYs + INIntentParameterDisplayPriority + 1 + INIntentParameterName + timer + INIntentParameterObjectType + TimerIdentifier + INIntentParameterObjectTypeNamespace + ggxqDx + INIntentParameterPromptDialogs + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogType + Configuration + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogFormatString + This is the mandatory prompt for your ${timer} + INIntentParameterPromptDialogFormatStringID + 6ZcaR8 + INIntentParameterPromptDialogType + Primary + + + INIntentParameterSupportsResolution + + INIntentParameterTag + 2 + INIntentParameterType + Object + + + INIntentResponse + + INIntentResponseCodes + + + INIntentResponseCodeFormatString + Your ${timer} has been launched + INIntentResponseCodeFormatStringID + E3Sz5n + INIntentResponseCodeName + success + INIntentResponseCodeSuccess + + + + INIntentResponseCodeName + failure + + + INIntentResponseLastParameterTag + 2 + INIntentResponseOutput + timer + INIntentResponseParameters + + + INIntentResponseParameterDisplayName + Timer + INIntentResponseParameterDisplayNameID + Vfpf1t + INIntentResponseParameterDisplayPriority + 1 + INIntentResponseParameterName + timer + INIntentResponseParameterObjectType + TimerIdentifier + INIntentResponseParameterObjectTypeNamespace + ggxqDx + INIntentResponseParameterTag + 2 + INIntentResponseParameterType + Object + + + + INIntentTitle + Démarrer vos compteurs + INIntentTitleID + nrTIGB + INIntentType + Custom + INIntentVerb + Start + + + INTypes + + + INTypeDisplayName + Timer Identifier + INTypeDisplayNameID + 02RXTq + INTypeLastPropertyTag + 99 + INTypeName + TimerIdentifier + INTypeProperties + + + INTypePropertyDefault + + INTypePropertyDisplayPriority + 1 + INTypePropertyName + identifier + INTypePropertyTag + 1 + INTypePropertyType + String + + + INTypePropertyDefault + + INTypePropertyDisplayPriority + 2 + INTypePropertyName + displayString + INTypePropertyTag + 2 + INTypePropertyType + String + + + INTypePropertyDefault + + INTypePropertyDisplayPriority + 3 + INTypePropertyName + pronunciationHint + INTypePropertyTag + 3 + INTypePropertyType + String + + + INTypePropertyDefault + + INTypePropertyDisplayPriority + 4 + INTypePropertyName + alternativeSpeakableMatches + INTypePropertySupportsMultipleValues + + INTypePropertyTag + 4 + INTypePropertyType + SpeakableString + + + + + +