1
0
forked from firka/firka

firka(android): timetable widget responsive layout, resize handling, centered lessons

This commit is contained in:
2026-02-28 22:05:30 +01:00
parent 5c205a9844
commit a11f118861
3 changed files with 69 additions and 15 deletions

View File

@@ -9,8 +9,10 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.glance.GlanceId
import androidx.glance.GlanceModifier
import androidx.glance.LocalSize
import androidx.glance.appwidget.GlanceAppWidget
import androidx.glance.appwidget.provideContent
import androidx.glance.appwidget.SizeMode
import androidx.glance.background
import androidx.glance.color.ColorProvider
import androidx.glance.currentState
@@ -39,6 +41,9 @@ class TimetableWidget : GlanceAppWidget() {
override val stateDefinition: GlanceStateDefinition<*>?
get() = HomeWidgetGlanceStateDefinition()
override val sizeMode: SizeMode
get() = SizeMode.Exact
override suspend fun provideGlance(context: Context, id: GlanceId) {
val data = withContext(Dispatchers.IO) {
loadWidgetData(context)
@@ -73,7 +78,7 @@ class TimetableWidget : GlanceAppWidget() {
val end = start.plusHours(23)
val filtered = lessons.filter { it.start.isAfter(start) && it.end.isBefore(end) }
val headerText = if (displayDateStr.isNotEmpty()) displayDateStr else "Mai órarend"
return WidgetData(colors, headerText, filtered.take(4))
return WidgetData(colors, headerText, filtered)
}
@Composable
@@ -98,26 +103,55 @@ class TimetableWidget : GlanceAppWidget() {
return
}
val size = LocalSize.current
val lessonRowHeightDp = 52f
val scale = lessonRowHeightDp / 52f
val headerHeightDp = 20f * scale
val verticalPaddingDp = 32f * scale
val spacerDp = 4f * scale
val paddingDp = 16f * scale
val availableHeightDp = size.height.value - verticalPaddingDp - headerHeightDp - spacerDp
val maxVisibleLessons = (availableHeightDp / lessonRowHeightDp).toInt().coerceAtLeast(0)
val maxLessons = (maxVisibleLessons.coerceAtMost(16) / 2 * 2).coerceAtLeast(1)
val displayLessons = data.lessons.take(maxLessons)
val lessonChunks = displayLessons.chunked(2)
val showDate = maxLessons > 1
val dateSectionHeight = if (showDate) headerHeightDp + spacerDp else 0f
val lessonListHeight = when (val n = displayLessons.size) {
0 -> 0f
else -> n * lessonRowHeightDp + (n - 1) * spacerDp
}
val remainingHeight = (size.height.value - 2 * paddingDp - dateSectionHeight - lessonListHeight).coerceAtLeast(0f)
val verticalPaddingAroundLessons = remainingHeight / 2f
Box(
modifier = GlanceModifier
.background(data.colors.background)
.padding(16.dp)
.padding(paddingDp.dp)
.fillMaxSize()
) {
Column {
Text(
data.headerText,
style = TextStyle(
color = ColorProvider(data.colors.textSecondary, data.colors.textSecondary),
fontSize = 12.sp,
fontWeight = FontWeight.Medium
if (showDate) {
Text(
data.headerText,
style = TextStyle(
color = ColorProvider(data.colors.textSecondary, data.colors.textSecondary),
fontSize = 12.sp,
fontWeight = FontWeight.Medium
)
)
)
Spacer(modifier = GlanceModifier.height(4.dp))
for (lesson in data.lessons) {
LessonCard(lesson, data.colors)
Spacer(modifier = GlanceModifier.height(4.dp))
Spacer(modifier = GlanceModifier.height(spacerDp.dp))
}
Spacer(modifier = GlanceModifier.height(verticalPaddingAroundLessons.dp))
for (chunk in lessonChunks) {
Column {
for (lesson in chunk) {
LessonCard(lesson, data.colors)
Spacer(modifier = GlanceModifier.height(spacerDp.dp))
}
}
}
Spacer(modifier = GlanceModifier.height(verticalPaddingAroundLessons.dp))
}
}
}

View File

@@ -1,7 +1,25 @@
package app.firka.naplo.glance
import android.appwidget.AppWidgetManager
import android.content.Context
import android.os.Bundle
import HomeWidgetGlanceWidgetReceiver
import androidx.glance.appwidget.GlanceAppWidgetManager
import kotlinx.coroutines.runBlocking
class TimetableWidgetReceiver : HomeWidgetGlanceWidgetReceiver<TimetableWidget>() {
override val glanceAppWidget = TimetableWidget()
override fun onAppWidgetOptionsChanged(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetId: Int,
newOptions: Bundle,
) {
super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions)
runBlocking {
val glanceId = GlanceAppWidgetManager(context).getGlanceIdBy(appWidgetId)
glanceAppWidget.update(context, glanceId)
}
}
}

View File

@@ -1,7 +1,9 @@
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:initialLayout="@layout/glance_default_loading_layout"
android:minWidth="300dp"
android:minHeight="100dp"
android:minWidth="250dp"
android:minHeight="93dp"
android:minResizeWidth="180dp"
android:minResizeHeight="93dp"
android:resizeMode="horizontal|vertical"
android:updatePeriodMillis="1800000">
</appwidget-provider>