forked from firka/firka
Add iOS Control widgets & timetable UI updates
Introduce iOS 18 Control widgets and improve timetable/widget UI and behavior. - Add Home, Grades and Timetable Control widgets (AppIntents) that write a "controlNavigation" value into the app group (group.app.firka.firkaa) so the main app can open the requested page. - Register control widgets in HomeWidgetsBundle for iOS 18+. - Extend WidgetLocalization with short/abbrev strings (tomorrow_short, hours_abbrev, in_hours) and related localization keys. - Enhance Lock Screen and Timetable widgets to handle next-day lessons, show hours when >60 minutes, and use localized hour/minute strings. - Update TimetableProvider timeline generation to avoid producing per-minute entries far before the next lesson; if the next lesson is >60 minutes away, add only a single entry ~60 minutes before it. - Adjust various widget views (Averages, Grades, Timetable) for more compact layout: spacing, font weights/sizes, compact modes, and added average color logic. - Update project.pbxproj to add a file-system-synchronized exception for the HomeWidgetsExtension files in the Runner target. - AppDelegate: read and remove "controlNavigation" from the shared app group and return it via the Flutter method channel as a pending deep link; fall back to existing pendingWidgetDeepLink. - Flutter: map a received 'home' deep link to HomePage.home in the home screen navigation switch. These changes add Control Center / Lock Screen launch shortcuts and refine widget presentation and timeline performance.
This commit is contained in:
89
firka/ios/HomeWidgetsExtension/Controls/AppControls.swift
Normal file
89
firka/ios/HomeWidgetsExtension/Controls/AppControls.swift
Normal file
@@ -0,0 +1,89 @@
|
||||
import WidgetKit
|
||||
import SwiftUI
|
||||
import AppIntents
|
||||
|
||||
private let appGroup = "group.app.firka.firkaa"
|
||||
|
||||
// MARK: - Home Control
|
||||
|
||||
@available(iOS 18.0, *)
|
||||
struct HomeControl: ControlWidget {
|
||||
static let kind = "app.firka.firkaa.control.home"
|
||||
|
||||
var body: some ControlWidgetConfiguration {
|
||||
StaticControlConfiguration(kind: Self.kind) {
|
||||
ControlWidgetButton(action: OpenHomeIntent()) {
|
||||
Label("Főoldal", systemImage: "house.fill")
|
||||
}
|
||||
}
|
||||
.displayName("Firka - Főoldal")
|
||||
.description("Firka app főoldal megnyitása")
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 18.0, *)
|
||||
struct OpenHomeIntent: AppIntent {
|
||||
static var title: LocalizedStringResource = "Firka Főoldal"
|
||||
static var openAppWhenRun: Bool = true
|
||||
|
||||
func perform() async throws -> some IntentResult {
|
||||
UserDefaults(suiteName: appGroup)?.set("home", forKey: "controlNavigation")
|
||||
return .result()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Grades Control
|
||||
|
||||
@available(iOS 18.0, *)
|
||||
struct GradesControl: ControlWidget {
|
||||
static let kind = "app.firka.firkaa.control.grades"
|
||||
|
||||
var body: some ControlWidgetConfiguration {
|
||||
StaticControlConfiguration(kind: Self.kind) {
|
||||
ControlWidgetButton(action: OpenGradesIntent()) {
|
||||
Label("Jegyek", systemImage: "star.fill")
|
||||
}
|
||||
}
|
||||
.displayName("Firka - Jegyek")
|
||||
.description("Firka app jegyek megnyitása")
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 18.0, *)
|
||||
struct OpenGradesIntent: AppIntent {
|
||||
static var title: LocalizedStringResource = "Firka Jegyek"
|
||||
static var openAppWhenRun: Bool = true
|
||||
|
||||
func perform() async throws -> some IntentResult {
|
||||
UserDefaults(suiteName: appGroup)?.set("grades", forKey: "controlNavigation")
|
||||
return .result()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Timetable Control
|
||||
|
||||
@available(iOS 18.0, *)
|
||||
struct TimetableControl: ControlWidget {
|
||||
static let kind = "app.firka.firkaa.control.timetable"
|
||||
|
||||
var body: some ControlWidgetConfiguration {
|
||||
StaticControlConfiguration(kind: Self.kind) {
|
||||
ControlWidgetButton(action: OpenTimetableIntent()) {
|
||||
Label("Órarend", systemImage: "calendar")
|
||||
}
|
||||
}
|
||||
.displayName("Firka - Órarend")
|
||||
.description("Firka app órarend megnyitása")
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 18.0, *)
|
||||
struct OpenTimetableIntent: AppIntent {
|
||||
static var title: LocalizedStringResource = "Firka Órarend"
|
||||
static var openAppWhenRun: Bool = true
|
||||
|
||||
func perform() async throws -> some IntentResult {
|
||||
UserDefaults(suiteName: appGroup)?.set("timetable", forKey: "controlNavigation")
|
||||
return .result()
|
||||
}
|
||||
}
|
||||
@@ -119,6 +119,11 @@ struct WidgetLocalization {
|
||||
"en": "Tomorrow",
|
||||
"de": "Morgen"
|
||||
],
|
||||
"tomorrow_short": [
|
||||
"hu": "holnap",
|
||||
"en": "tmrw",
|
||||
"de": "morgen"
|
||||
],
|
||||
"next": [
|
||||
"hu": "Következő",
|
||||
"en": "Next",
|
||||
@@ -193,6 +198,16 @@ struct WidgetLocalization {
|
||||
"hu": "p",
|
||||
"en": "min",
|
||||
"de": "Min"
|
||||
],
|
||||
"hours_abbrev": [
|
||||
"hu": "ó",
|
||||
"en": "h",
|
||||
"de": "Std"
|
||||
],
|
||||
"in_hours": [
|
||||
"hu": "%d óra múlva",
|
||||
"en": "in %d h",
|
||||
"de": "in %d Std"
|
||||
]
|
||||
]
|
||||
}
|
||||
|
||||
@@ -18,5 +18,12 @@ struct HomeWidgetsBundle: WidgetBundle {
|
||||
TimetableInlineWidget()
|
||||
GradesInlineWidget()
|
||||
AveragesInlineWidget()
|
||||
|
||||
// Control Widgets (iOS 18+ Control Center & Lock Screen buttons)
|
||||
if #available(iOS 18.0, *) {
|
||||
HomeControl()
|
||||
GradesControl()
|
||||
TimetableControl()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,19 +34,23 @@ struct TimetableInlineWidgetView: View {
|
||||
} else if let current = entry.currentLesson {
|
||||
let remaining = minutesRemaining(until: current.end)
|
||||
Text("\(current.subject.name) · \(remaining) \(localization.string("minutes_abbrev"))")
|
||||
} else if entry.isNextDay {
|
||||
if let first = entry.lessons.first {
|
||||
let lessonNum = first.lessonNumber ?? 1
|
||||
Text("\(localization.string("tomorrow")): \(lessonNum). \(first.subject.name)")
|
||||
} else {
|
||||
Text(localization.string("no_lessons"))
|
||||
}
|
||||
} else if let next = entry.nextLesson {
|
||||
let until = minutesRemaining(until: next.start)
|
||||
if until <= 0 {
|
||||
Text("→ \(next.subject.name)")
|
||||
} else if until > 60 {
|
||||
let hours = until / 60
|
||||
Text("→ \(next.subject.name) · \(hours) \(localization.string("hours_abbrev"))")
|
||||
} else {
|
||||
Text("→ \(next.subject.name) · \(until) \(localization.string("minutes_abbrev"))")
|
||||
}
|
||||
} else if entry.isNextDay {
|
||||
if let first = entry.lessons.first {
|
||||
Text("\(localization.string("tomorrow")): \(first.subject.name)")
|
||||
} else {
|
||||
Text(localization.string("no_lessons"))
|
||||
}
|
||||
} else {
|
||||
Text(localization.string("no_lessons"))
|
||||
}
|
||||
|
||||
@@ -59,19 +59,23 @@ struct TimetableInlineView: View {
|
||||
} else if let current = entry.currentLesson {
|
||||
let remaining = minutesRemaining(until: current.end)
|
||||
Text("\(current.subject.name) - \(remaining) \(localization.string("minutes_short"))")
|
||||
} else if entry.isNextDay {
|
||||
if let first = entry.lessons.first {
|
||||
let lessonNum = first.lessonNumber ?? 1
|
||||
Text("\(localization.string("tomorrow")): \(lessonNum). \(first.subject.name)")
|
||||
} else {
|
||||
Text(localization.string("no_lessons"))
|
||||
}
|
||||
} else if let next = entry.nextLesson {
|
||||
let until = minutesRemaining(until: next.start)
|
||||
if until <= 0 {
|
||||
Text("\(localization.string("next")): \(next.subject.name)")
|
||||
} else if until > 60 {
|
||||
let hours = until / 60
|
||||
Text("\(next.subject.name) \(localization.string("in_hours", hours))")
|
||||
} else {
|
||||
Text("\(next.subject.name) \(localization.string("in_minutes", until))")
|
||||
}
|
||||
} else if entry.isNextDay {
|
||||
if let first = entry.lessons.first {
|
||||
Text("\(localization.string("tomorrow")): \(first.subject.name)")
|
||||
} else {
|
||||
Text(localization.string("no_lessons"))
|
||||
}
|
||||
} else {
|
||||
Text(localization.string("no_lessons"))
|
||||
}
|
||||
@@ -105,16 +109,45 @@ struct TimetableCircularView: View {
|
||||
.font(.system(.title2, design: .rounded, weight: .bold))
|
||||
}
|
||||
.gaugeStyle(.accessoryCircularCapacity)
|
||||
} else if entry.isNextDay {
|
||||
let lessonCount = entry.lessons.count
|
||||
if lessonCount > 0 {
|
||||
ZStack {
|
||||
AccessoryWidgetBackground()
|
||||
VStack(spacing: 0) {
|
||||
Text("\(lessonCount)")
|
||||
.font(.system(.title2, design: .rounded, weight: .bold))
|
||||
Text(localization.string("lesson_short"))
|
||||
.font(.system(.caption2))
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ZStack {
|
||||
AccessoryWidgetBackground()
|
||||
Image(systemName: "calendar.badge.checkmark")
|
||||
.font(.title2)
|
||||
}
|
||||
}
|
||||
} else if let next = entry.nextLesson {
|
||||
let until = minutesRemaining(until: next.start)
|
||||
ZStack {
|
||||
AccessoryWidgetBackground()
|
||||
VStack(spacing: 0) {
|
||||
Text("\(until)")
|
||||
.font(.system(.title2, design: .rounded, weight: .bold))
|
||||
Text(localization.string("minutes_short"))
|
||||
.font(.system(.caption2))
|
||||
.foregroundStyle(.secondary)
|
||||
if until > 60 {
|
||||
let hours = until / 60
|
||||
Text("\(hours)")
|
||||
.font(.system(.title2, design: .rounded, weight: .bold))
|
||||
Text(localization.string("hours_abbrev"))
|
||||
.font(.system(.caption2))
|
||||
.foregroundStyle(.secondary)
|
||||
} else {
|
||||
Text("\(until)")
|
||||
.font(.system(.title2, design: .rounded, weight: .bold))
|
||||
Text(localization.string("minutes_abbrev"))
|
||||
.font(.system(.caption2))
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if let lesson = entry.lessons.first, let lessonNum = lesson.lessonNumber {
|
||||
@@ -194,9 +227,15 @@ struct TimetableRectangularView: View {
|
||||
.foregroundStyle(.secondary)
|
||||
Spacer()
|
||||
if until > 0 && !entry.isNextDay {
|
||||
Text(localization.string("in_minutes", until))
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
if until > 60 {
|
||||
Text(localization.string("in_hours", until / 60))
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
} else {
|
||||
Text(localization.string("in_minutes", until))
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
}
|
||||
Text("\(next.lessonNumber ?? 0). \(next.subject.name)")
|
||||
|
||||
@@ -94,10 +94,19 @@ struct TimetableProvider: AppIntentTimelineProvider {
|
||||
}
|
||||
|
||||
if let next = nextLesson {
|
||||
var time = currentLesson?.end.addingTimeInterval(60) ?? now.addingTimeInterval(60)
|
||||
while time < next.start && minuteEntries.count < 120 {
|
||||
minuteEntries.append(time)
|
||||
time = time.addingTimeInterval(60)
|
||||
let minutesUntilNext = next.start.timeIntervalSince(now) / 60
|
||||
|
||||
if minutesUntilNext <= 60 {
|
||||
var time = currentLesson?.end.addingTimeInterval(60) ?? now.addingTimeInterval(60)
|
||||
while time < next.start && minuteEntries.count < 120 {
|
||||
minuteEntries.append(time)
|
||||
time = time.addingTimeInterval(60)
|
||||
}
|
||||
} else {
|
||||
let sixtyMinutesBefore = next.start.addingTimeInterval(-60 * 60)
|
||||
if sixtyMinutesBefore > now {
|
||||
minuteEntries.append(sixtyMinutesBefore)
|
||||
}
|
||||
}
|
||||
minuteEntries.append(next.start)
|
||||
}
|
||||
|
||||
@@ -65,11 +65,11 @@ struct AveragesMediumView: View {
|
||||
ZStack {
|
||||
WidgetBackground(style: style, colors: nil)
|
||||
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
VStack(alignment: .leading, spacing: 6) {
|
||||
HStack {
|
||||
Text(localization.string("subject_averages"))
|
||||
.font(.caption)
|
||||
.fontWeight(.medium)
|
||||
.fontWeight(.semibold)
|
||||
.widgetTextStyle(style, colors: nil, isPrimary: false)
|
||||
|
||||
Spacer()
|
||||
@@ -86,6 +86,13 @@ struct AveragesMediumView: View {
|
||||
)
|
||||
.widgetTextStyle(style, colors: nil, isPrimary: false)
|
||||
}
|
||||
|
||||
if let overall = entry.overallAverage {
|
||||
Text(String(format: "%.2f", overall))
|
||||
.font(.subheadline)
|
||||
.fontWeight(.bold)
|
||||
.foregroundStyle(averageColor(for: overall))
|
||||
}
|
||||
}
|
||||
|
||||
if entry.subjectAverages.isEmpty {
|
||||
@@ -95,15 +102,26 @@ struct AveragesMediumView: View {
|
||||
.widgetTextStyle(style, colors: nil, isPrimary: false)
|
||||
Spacer()
|
||||
} else {
|
||||
Spacer(minLength: 0)
|
||||
ForEach(entry.subjectAverages.prefix(maxVisible)) { subject in
|
||||
AverageRow(subject: subject, style: style)
|
||||
AverageRow(subject: subject, style: style, compact: true)
|
||||
}
|
||||
Spacer()
|
||||
Spacer(minLength: 0)
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
|
||||
func averageColor(for value: Double) -> Color {
|
||||
switch value {
|
||||
case 4.5...: return .green
|
||||
case 3.5..<4.5: return .blue
|
||||
case 2.5..<3.5: return .yellow
|
||||
case 1.5..<2.5: return .orange
|
||||
default: return .red
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct AveragesLargeView: View {
|
||||
@@ -127,11 +145,11 @@ struct AveragesLargeView: View {
|
||||
ZStack {
|
||||
WidgetBackground(style: style, colors: nil)
|
||||
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
HStack {
|
||||
Text(localization.string("subject_averages"))
|
||||
.font(.headline)
|
||||
.fontWeight(.semibold)
|
||||
.fontWeight(.bold)
|
||||
.widgetTextStyle(style, colors: nil)
|
||||
|
||||
Spacer()
|
||||
@@ -189,11 +207,12 @@ struct AverageRow: View {
|
||||
let subject: SubjectAverage
|
||||
let style: WidgetStyleType
|
||||
var showGradeCount: Bool = false
|
||||
var compact: Bool = false
|
||||
|
||||
var body: some View {
|
||||
HStack(spacing: 12) {
|
||||
Text(subject.name)
|
||||
.font(.subheadline)
|
||||
.font(compact ? .footnote : .subheadline)
|
||||
.widgetTextStyle(style, colors: nil)
|
||||
.lineLimit(1)
|
||||
|
||||
@@ -201,15 +220,15 @@ struct AverageRow: View {
|
||||
|
||||
if showGradeCount {
|
||||
Text("(\(subject.gradeCount))")
|
||||
.font(.caption)
|
||||
.font(.caption2)
|
||||
.widgetTextStyle(style, colors: nil, isPrimary: false)
|
||||
}
|
||||
|
||||
Text(subject.formattedAverage)
|
||||
.font(.subheadline)
|
||||
.font(compact ? .footnote : .subheadline)
|
||||
.fontWeight(.bold)
|
||||
.foregroundStyle(subject.averageColor)
|
||||
}
|
||||
.padding(.vertical, 4)
|
||||
.padding(.vertical, compact ? 2 : 4)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,10 +64,10 @@ struct GradesMediumView: View {
|
||||
ZStack {
|
||||
WidgetBackground(style: style, colors: nil)
|
||||
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
VStack(alignment: .leading, spacing: 6) {
|
||||
Text(localization.string("recent_grades"))
|
||||
.font(.caption)
|
||||
.fontWeight(.medium)
|
||||
.fontWeight(.semibold)
|
||||
.widgetTextStyle(style, colors: nil, isPrimary: false)
|
||||
|
||||
if entry.grades.isEmpty {
|
||||
@@ -77,9 +77,11 @@ struct GradesMediumView: View {
|
||||
.widgetTextStyle(style, colors: nil, isPrimary: false)
|
||||
Spacer()
|
||||
} else {
|
||||
Spacer(minLength: 0)
|
||||
ForEach(entry.grades.prefix(3)) { grade in
|
||||
GradeRow(grade: grade, style: style, showTeacher: true)
|
||||
GradeRow(grade: grade, style: style, showTeacher: true, compact: true)
|
||||
}
|
||||
Spacer(minLength: 0)
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
@@ -129,18 +131,19 @@ struct GradeRow: View {
|
||||
let style: WidgetStyleType
|
||||
var showTeacher: Bool = false
|
||||
var showTopic: Bool = false
|
||||
var compact: Bool = false
|
||||
|
||||
var body: some View {
|
||||
HStack(spacing: 12) {
|
||||
Text(grade.displayValue)
|
||||
.font(.title2)
|
||||
.font(compact ? .title3 : .title2)
|
||||
.fontWeight(.bold)
|
||||
.foregroundStyle(grade.gradeColor)
|
||||
.frame(width: 32)
|
||||
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
VStack(alignment: .leading, spacing: compact ? 1 : 2) {
|
||||
Text(grade.subjectNameWithWeight)
|
||||
.font(.subheadline)
|
||||
.font(compact ? .footnote : .subheadline)
|
||||
.fontWeight(.medium)
|
||||
.widgetTextStyle(style, colors: nil)
|
||||
.lineLimit(1)
|
||||
@@ -148,23 +151,23 @@ struct GradeRow: View {
|
||||
HStack(spacing: 4) {
|
||||
if showTeacher, let teacher = grade.teacherName {
|
||||
Text(teacher)
|
||||
.font(.caption)
|
||||
.font(.caption2)
|
||||
.widgetTextStyle(style, colors: nil, isPrimary: false)
|
||||
.lineLimit(1)
|
||||
|
||||
Text("•")
|
||||
.font(.caption)
|
||||
.font(.caption2)
|
||||
.widgetTextStyle(style, colors: nil, isPrimary: false)
|
||||
}
|
||||
|
||||
Text(grade.dateString)
|
||||
.font(.caption)
|
||||
.font(.caption2)
|
||||
.widgetTextStyle(style, colors: nil, isPrimary: false)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.padding(.vertical, 4)
|
||||
.padding(.vertical, compact ? 2 : 4)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,13 +48,14 @@ struct TimetableSmallView: View {
|
||||
|
||||
if let lesson = displayLesson {
|
||||
Text(lesson.displayName)
|
||||
.font(.headline)
|
||||
.font(.subheadline)
|
||||
.fontWeight(.semibold)
|
||||
.strikethrough(lesson.isCancelled, color: .red)
|
||||
.foregroundColor(lesson.isCancelled ? .red :
|
||||
lesson.isSubstitution ? .orange :
|
||||
(style == .liquidGlass ? liquidGlassPrimary : .primary))
|
||||
.lineLimit(2)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
|
||||
Text(lesson.timeString)
|
||||
.font(.subheadline)
|
||||
@@ -131,12 +132,14 @@ struct TimetableMediumView: View {
|
||||
VStack(alignment: .leading, spacing: 6) {
|
||||
Text(entry.isNextDay ? localization.string("tomorrow_timetable") : localization.string("today_timetable"))
|
||||
.font(.caption)
|
||||
.fontWeight(.medium)
|
||||
.fontWeight(.semibold)
|
||||
.widgetTextStyle(style, colors: nil, isPrimary: false)
|
||||
|
||||
Spacer(minLength: 0)
|
||||
ForEach(visibleLessons) { lesson in
|
||||
LessonRow(lesson: lesson, isActive: isLessonActive(lesson), style: style)
|
||||
LessonRow(lesson: lesson, isActive: isLessonActive(lesson), style: style, compact: true)
|
||||
}
|
||||
Spacer(minLength: 0)
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
@@ -182,6 +185,7 @@ struct LessonRow: View {
|
||||
let isActive: Bool
|
||||
let style: WidgetStyleType
|
||||
var showRoom: Bool = false
|
||||
var compact: Bool = false
|
||||
@Environment(\.colorScheme) var colorScheme
|
||||
|
||||
var lessonTextColor: Color? {
|
||||
@@ -253,7 +257,7 @@ struct LessonRow: View {
|
||||
.foregroundColor(lessonTextColor?.opacity(0.8) ?? (style == .liquidGlass ? liquidGlassSecondary : .secondary))
|
||||
}
|
||||
}
|
||||
.padding(.vertical, 4)
|
||||
.padding(.vertical, compact ? 2 : 4)
|
||||
.padding(.horizontal, 8)
|
||||
.currentLessonGlow(isActive: isActive && !lesson.isCancelled)
|
||||
}
|
||||
|
||||
@@ -112,6 +112,13 @@
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
|
||||
4F0EA0512F2BD2A2003CC89E /* Exceptions for "HomeWidgetsExtension" folder in "Runner" target */ = {
|
||||
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
|
||||
membershipExceptions = (
|
||||
Controls/AppControls.swift,
|
||||
);
|
||||
target = 97C146ED1CF9000F007C117D /* Runner */;
|
||||
};
|
||||
4F4E70D02EF565FF00C90AD1 /* Exceptions for "LiveActivityWidget" folder in "Runner" target */ = {
|
||||
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
|
||||
membershipExceptions = (
|
||||
@@ -152,6 +159,7 @@
|
||||
4FE64E362F27B07A006F9205 /* HomeWidgetsExtension */ = {
|
||||
isa = PBXFileSystemSynchronizedRootGroup;
|
||||
exceptions = (
|
||||
4F0EA0512F2BD2A2003CC89E /* Exceptions for "HomeWidgetsExtension" folder in "Runner" target */,
|
||||
4FE64E472F27B07B006F9205 /* Exceptions for "HomeWidgetsExtension" folder in "HomeWidgetsExtension" target */,
|
||||
);
|
||||
explicitFileTypes = {
|
||||
|
||||
@@ -29,7 +29,10 @@ import BackgroundTasks
|
||||
widgetDeepLinkChannel = FlutterMethodChannel(name: "firka.app/widget_deep_link", binaryMessenger: controller.binaryMessenger)
|
||||
widgetDeepLinkChannel?.setMethodCallHandler { [weak self] (call: FlutterMethodCall, result: @escaping FlutterResult) in
|
||||
if call.method == "getPendingDeepLink" {
|
||||
if let link = self?.pendingWidgetDeepLink {
|
||||
if let controlNav = UserDefaults(suiteName: "group.app.firka.firkaa")?.string(forKey: "controlNavigation") {
|
||||
UserDefaults(suiteName: "group.app.firka.firkaa")?.removeObject(forKey: "controlNavigation")
|
||||
result(controlNav)
|
||||
} else if let link = self?.pendingWidgetDeepLink {
|
||||
self?.pendingWidgetDeepLink = nil
|
||||
result(link)
|
||||
} else {
|
||||
|
||||
@@ -149,6 +149,9 @@ class _HomeScreenState extends FirkaState<HomeScreen> {
|
||||
|
||||
HomePage targetPage;
|
||||
switch (link) {
|
||||
case 'home':
|
||||
targetPage = HomePage.home;
|
||||
break;
|
||||
case 'timetable':
|
||||
targetPage = HomePage.timetable;
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user