forked from firka/firka
Show active break in timetable widget
Add break detection and UI for active breaks in timetable widgets. Introduces a new localization key "break_between" and a BreakIndicatorRow view that displays a break marker and minutes left. TimetableMediumView and TimetableLargeView now detect when the current time falls between consecutive lessons, reduce the number of visible lessons accordingly, and inject a BreakIndicatorRow between lessons when in a break (minutes are calculated using ceil of time interval). Also clean up commented/debug lines in the iOS widget cache helper (widget.dart) for locale/theme and removed a TODO comment.
This commit is contained in:
@@ -149,6 +149,11 @@ struct WidgetLocalization {
|
||||
"en": "lesson",
|
||||
"de": "Std"
|
||||
],
|
||||
"break_between": [
|
||||
"hu": "Szünet",
|
||||
"en": "Break",
|
||||
"de": "Pause"
|
||||
],
|
||||
"in_minutes": [
|
||||
"hu": "%d perc múlva",
|
||||
"en": "in %d min",
|
||||
|
||||
@@ -116,9 +116,19 @@ struct TimetableMediumView: View {
|
||||
return max(0, entry.lessons.count - 1)
|
||||
}
|
||||
|
||||
var hasActiveBreak: Bool {
|
||||
let checkDate = entry.date
|
||||
for i in 0..<entry.lessons.count - 1 {
|
||||
if checkDate > entry.lessons[i].end && checkDate < entry.lessons[i + 1].start {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var visibleLessons: [WidgetLesson] {
|
||||
let totalLessons = entry.lessons.count
|
||||
let maxVisible = 4
|
||||
let maxVisible = hasActiveBreak ? 3 : 4
|
||||
|
||||
if totalLessons <= maxVisible {
|
||||
return Array(entry.lessons)
|
||||
@@ -154,8 +164,17 @@ struct TimetableMediumView: View {
|
||||
.widgetTextStyle(style, colors: nil, isPrimary: false)
|
||||
|
||||
Spacer(minLength: 0)
|
||||
ForEach(visibleLessons) { lesson in
|
||||
ForEach(Array(visibleLessons.enumerated()), id: \.element.id) { index, lesson in
|
||||
LessonRow(lesson: lesson, isActive: isLessonActive(lesson), style: style, compact: true)
|
||||
|
||||
if index < visibleLessons.count - 1 {
|
||||
let nextLesson = visibleLessons[index + 1]
|
||||
let isInBreak = entry.date > lesson.end && entry.date < nextLesson.start
|
||||
if isInBreak {
|
||||
let breakMinutes = Int(ceil(nextLesson.start.timeIntervalSince(entry.date) / 60))
|
||||
BreakIndicatorRow(minutesLeft: breakMinutes, localization: localization, style: style, compact: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
Spacer(minLength: 0)
|
||||
}
|
||||
@@ -178,6 +197,16 @@ struct TimetableLargeView: View {
|
||||
return checkDate >= lesson.start && checkDate <= lesson.end
|
||||
}
|
||||
|
||||
var hasActiveBreak: Bool {
|
||||
let checkDate = entry.date
|
||||
for i in 0..<entry.lessons.count - 1 {
|
||||
if checkDate > entry.lessons[i].end && checkDate < entry.lessons[i + 1].start {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var headerText: String {
|
||||
if entry.isNextSchoolDay {
|
||||
let dateStr = WidgetLocalization.formatShortDate(entry.nextSchoolDayDateString, locale: localization.locale)
|
||||
@@ -199,8 +228,19 @@ struct TimetableLargeView: View {
|
||||
.fontWeight(.semibold)
|
||||
.widgetTextStyle(style, colors: nil)
|
||||
|
||||
ForEach(entry.lessons.prefix(7)) { lesson in
|
||||
let maxLessons = hasActiveBreak ? 6 : 7
|
||||
let lessonsToShow = Array(entry.lessons.prefix(maxLessons))
|
||||
ForEach(Array(lessonsToShow.enumerated()), id: \.element.id) { index, lesson in
|
||||
LessonRow(lesson: lesson, isActive: isLessonActive(lesson), style: style, showRoom: true)
|
||||
|
||||
if index < lessonsToShow.count - 1 {
|
||||
let nextLesson = lessonsToShow[index + 1]
|
||||
let isInBreak = entry.date > lesson.end && entry.date < nextLesson.start
|
||||
if isInBreak {
|
||||
let breakMinutes = Int(ceil(nextLesson.start.timeIntervalSince(entry.date) / 60))
|
||||
BreakIndicatorRow(minutesLeft: breakMinutes, localization: localization, style: style)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
@@ -209,6 +249,50 @@ struct TimetableLargeView: View {
|
||||
}
|
||||
}
|
||||
|
||||
struct BreakIndicatorRow: View {
|
||||
let minutesLeft: Int
|
||||
let localization: WidgetLocalization
|
||||
let style: WidgetStyleType
|
||||
var compact: Bool = false
|
||||
@Environment(\.colorScheme) var colorScheme
|
||||
|
||||
var liquidGlassPrimary: Color {
|
||||
colorScheme == .dark ? .white : .black
|
||||
}
|
||||
|
||||
var liquidGlassSecondary: Color {
|
||||
colorScheme == .dark ? .white.opacity(0.7) : .black.opacity(0.6)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
HStack(spacing: 12) {
|
||||
Text("–")
|
||||
.font(.caption)
|
||||
.fontWeight(.bold)
|
||||
.frame(width: 24, height: 24)
|
||||
.background(
|
||||
Circle()
|
||||
.fill(Color.green.opacity(0.3))
|
||||
)
|
||||
.foregroundColor(style == .liquidGlass ? liquidGlassPrimary : .primary)
|
||||
|
||||
Text(localization.string("break_between"))
|
||||
.font(.subheadline)
|
||||
.fontWeight(.semibold)
|
||||
.foregroundColor(style == .liquidGlass ? liquidGlassPrimary : .primary)
|
||||
|
||||
Spacer()
|
||||
|
||||
Text("\(minutesLeft) \(localization.string("minutes_abbrev"))")
|
||||
.font(.caption)
|
||||
.foregroundColor(style == .liquidGlass ? liquidGlassSecondary : .secondary)
|
||||
}
|
||||
.padding(.vertical, compact ? 2 : 4)
|
||||
.padding(.horizontal, 8)
|
||||
.currentLessonGlow(isActive: true)
|
||||
}
|
||||
}
|
||||
|
||||
struct LessonRow: View {
|
||||
let lesson: WidgetLesson
|
||||
let isActive: Bool
|
||||
|
||||
@@ -109,7 +109,6 @@ class WidgetCacheHelper {
|
||||
if (!Platform.isIOS) return;
|
||||
|
||||
try {
|
||||
// Get locale
|
||||
final langIndex = (settings.group("settings").subGroup("application")["language"]
|
||||
as SettingsItemsRadio)
|
||||
.activeIndex;
|
||||
@@ -125,10 +124,9 @@ class WidgetCacheHelper {
|
||||
locale = 'de';
|
||||
break;
|
||||
default:
|
||||
locale = 'hu'; // Default to Hungarian
|
||||
locale = 'hu';
|
||||
}
|
||||
|
||||
// Get theme
|
||||
final themeIndex = (settings.group("settings").subGroup("customization")["theme"]
|
||||
as SettingsItemsRadio)
|
||||
.activeIndex;
|
||||
@@ -189,7 +187,6 @@ class WidgetCacheHelper {
|
||||
|
||||
debugPrint('iOS widget refresh: ${grades.length} grades fetched (cached: ${gradesResponse.cached})');
|
||||
|
||||
// Calculate subject averages
|
||||
final Map<String, double> subjectAverages = {};
|
||||
final Set<String> subjectUids = {};
|
||||
|
||||
@@ -214,9 +211,7 @@ class WidgetCacheHelper {
|
||||
? overallSum / validSubjectCount
|
||||
: null;
|
||||
|
||||
// Check for break (simplified - you might want to enhance this)
|
||||
WidgetBreakInfo? currentBreak;
|
||||
// TODO: Add break detection if needed
|
||||
|
||||
await updateIOSWidgets(
|
||||
locale: locale,
|
||||
|
||||
Reference in New Issue
Block a user