1.1: Home-Screen-Widget + Siri-Kurzbefehl „Gassi gehen"
App Group group.app.banyaro.ios verbindet App und Widget-Extension (Entitlements in beiden Targets, CODE_SIGN_ENTITLEMENTS fürs Widget). Home-Screen-Widget (D): - BanYaroHomeWidget (klein + mittel): Tagesfoto, Hundename, nächster Termin. - App schreibt beim Heim-Laden einen Snapshot (HomeWidgetData) in die App Group und triggert WidgetCenter-Reload; Snapshot wird bei Logout/401 geleert. Siri-/Kurzbefehl (E): - StartWalkIntent „Gassi gehen" + AppShortcutsProvider (öffnet die App). - WalkLauncher überbrückt Intent → UI: Flag in der App Group, beim Aktivwerden eingelöst → Aufnehmen-Tab + Aufnahme-Start (TrackingView.startFresh). - MainTabView mit Tab-Auswahl (Tags), BanYaroGoApp liest scenePhase.
This commit is contained in:
parent
a2646a18ef
commit
d807db57a2
14 changed files with 307 additions and 6 deletions
33
BanYaroGo/Support/HomeWidgetData.swift
Normal file
33
BanYaroGo/Support/HomeWidgetData.swift
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
import Foundation
|
||||
|
||||
/// Vom App-Target geschrieben, vom Widget-Target gelesen — über die App Group
|
||||
/// `group.app.banyaro.ios` geteilt. Bewusst in beiden Targets identisch
|
||||
/// dupliziert (statt Shared/-pbxproj-Handarbeit); JSON-kompatibel.
|
||||
struct HomeWidgetData: Codable {
|
||||
var dogName: String
|
||||
var photoJPEG: Data?
|
||||
var nextAppointment: String?
|
||||
var diaryCount: Int?
|
||||
var updatedAt: Date
|
||||
}
|
||||
|
||||
enum HomeWidgetStore {
|
||||
static let appGroup = "group.app.banyaro.ios"
|
||||
static let key = "homeWidgetData"
|
||||
|
||||
static func save(_ data: HomeWidgetData) {
|
||||
guard let defaults = UserDefaults(suiteName: appGroup),
|
||||
let encoded = try? JSONEncoder().encode(data) else { return }
|
||||
defaults.set(encoded, forKey: key)
|
||||
}
|
||||
|
||||
static func load() -> HomeWidgetData? {
|
||||
guard let defaults = UserDefaults(suiteName: appGroup),
|
||||
let data = defaults.data(forKey: key) else { return nil }
|
||||
return try? JSONDecoder().decode(HomeWidgetData.self, from: data)
|
||||
}
|
||||
|
||||
static func clear() {
|
||||
UserDefaults(suiteName: appGroup)?.removeObject(forKey: key)
|
||||
}
|
||||
}
|
||||
32
BanYaroGo/Support/StartWalkIntent.swift
Normal file
32
BanYaroGo/Support/StartWalkIntent.swift
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
import AppIntents
|
||||
|
||||
/// Siri-/Kurzbefehl-Intent „Gassi gehen": öffnet die App und stößt die
|
||||
/// Aufzeichnung an (über das App-Group-Flag, das die App beim Aktivwerden liest).
|
||||
struct StartWalkIntent: AppIntent {
|
||||
static var title: LocalizedStringResource = "Gassi gehen"
|
||||
static var description = IntentDescription("Startet die Aufzeichnung einer Gassi-Tour in Ban Yaro Go.")
|
||||
static var openAppWhenRun: Bool = true
|
||||
|
||||
@MainActor
|
||||
func perform() async throws -> some IntentResult {
|
||||
WalkLauncher.requestStartViaAppGroup()
|
||||
WalkLauncher.shared.pendingStart = true // Fast-Path, falls in-process
|
||||
return .result()
|
||||
}
|
||||
}
|
||||
|
||||
/// Macht den Intent als Siri-Phrase + Kurzbefehl verfügbar (automatisch erkannt).
|
||||
struct BanYaroAppShortcuts: AppShortcutsProvider {
|
||||
static var appShortcuts: [AppShortcut] {
|
||||
AppShortcut(
|
||||
intent: StartWalkIntent(),
|
||||
phrases: [
|
||||
"Gassi gehen mit \(.applicationName)",
|
||||
"Geh Gassi mit \(.applicationName)",
|
||||
"\(.applicationName) Gassi gehen"
|
||||
],
|
||||
shortTitle: "Gassi gehen",
|
||||
systemImageName: "figure.walk"
|
||||
)
|
||||
}
|
||||
}
|
||||
33
BanYaroGo/Support/WalkLauncher.swift
Normal file
33
BanYaroGo/Support/WalkLauncher.swift
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
import Foundation
|
||||
import Observation
|
||||
|
||||
/// Brücke vom Siri-Kurzbefehl „Gassi gehen" zur UI.
|
||||
///
|
||||
/// Der App Intent läuft evtl. außerhalb des App-Prozesses → er setzt ein Flag in
|
||||
/// der **App Group**. Beim Aktivwerden liest die App das Flag und stößt über
|
||||
/// `pendingStart` den Wechsel auf den Aufnehmen-Tab + den Aufnahme-Start an.
|
||||
@Observable
|
||||
@MainActor
|
||||
final class WalkLauncher {
|
||||
static let shared = WalkLauncher()
|
||||
private init() {}
|
||||
|
||||
/// UI-Signal: true → Aufnehmen-Tab wählen und Aufnahme starten.
|
||||
var pendingStart = false
|
||||
|
||||
static let appGroup = "group.app.banyaro.ios"
|
||||
static let flagKey = "pendingStartWalk"
|
||||
|
||||
/// Vom App Intent aufgerufen (cross-process über die App Group).
|
||||
static func requestStartViaAppGroup() {
|
||||
UserDefaults(suiteName: appGroup)?.set(true, forKey: flagKey)
|
||||
}
|
||||
|
||||
/// Beim Aktivwerden der App das Flag einlösen → `pendingStart`.
|
||||
func consumePendingFlag() {
|
||||
let defaults = UserDefaults(suiteName: Self.appGroup)
|
||||
guard defaults?.bool(forKey: Self.flagKey) == true else { return }
|
||||
defaults?.removeObject(forKey: Self.flagKey)
|
||||
pendingStart = true
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue