From 568f19eeca095c39bb08ce25ea57a00841c37e4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20M=C3=BChlbauer?= <59062169+lm41@users.noreply.github.com> Date: Sat, 4 Nov 2023 15:18:27 +0100 Subject: [PATCH 01/11] Fix: #415 (#419) Make homework copyable --- .../untis/ui/dialogs/TimetableItemDetailsDialog.kt | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/sapuseven/untis/ui/dialogs/TimetableItemDetailsDialog.kt b/app/src/main/java/com/sapuseven/untis/ui/dialogs/TimetableItemDetailsDialog.kt index ee5b2dfe..93232210 100644 --- a/app/src/main/java/com/sapuseven/untis/ui/dialogs/TimetableItemDetailsDialog.kt +++ b/app/src/main/java/com/sapuseven/untis/ui/dialogs/TimetableItemDetailsDialog.kt @@ -19,10 +19,12 @@ import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.platform.LocalClipboardManager import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.unit.dp @@ -42,7 +44,6 @@ import com.sapuseven.untis.data.connectivity.UntisRequest import com.sapuseven.untis.data.databases.entities.User import com.sapuseven.untis.data.timetable.PeriodData import com.sapuseven.untis.helpers.DateTimeUtils -import com.sapuseven.untis.helpers.SerializationUtils import com.sapuseven.untis.helpers.timetable.TimetableDatabaseInterface import com.sapuseven.untis.models.UntisAbsence import com.sapuseven.untis.models.untis.UntisAttachment @@ -61,10 +62,10 @@ import com.sapuseven.untis.ui.common.conditional import com.sapuseven.untis.ui.functional.bottomInsets import com.sapuseven.untis.ui.functional.insetsPaddingValues import kotlinx.coroutines.launch -import kotlinx.serialization.decodeFromString import org.joda.time.LocalDateTime import org.joda.time.format.DateTimeFormat + @OptIn( ExperimentalMaterial3Api::class, ExperimentalPagerApi::class, ExperimentalAnimationApi::class @@ -81,6 +82,7 @@ fun BaseComposeActivity.TimetableItemDetailsDialog( val pagerState = rememberPagerState(initialPage) val scope = rememberCoroutineScope() val context = LocalContext.current + val clipboardManager = LocalClipboardManager.current var absenceCheck by rememberSaveable { mutableStateOf?>(null) } @@ -357,7 +359,10 @@ fun BaseComposeActivity.TimetableItemDetailsDialog( ) } } - } else null + } else null, + modifier = Modifier.clickable { + clipboardManager.setText(AnnotatedString(it.text)) + } ) } From df718bacaf23db5ad635217d87260a8155fe272c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20M=C3=BChlbauer?= <59062169+lm41@users.noreply.github.com> Date: Sat, 4 Nov 2023 16:30:32 +0100 Subject: [PATCH 02/11] Fix: #422 (#423) Fix unable to use ARGB Values for Theme Colors --- .../main/java/com/sapuseven/untis/ui/colorpicker/ColorPicker.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/sapuseven/untis/ui/colorpicker/ColorPicker.kt b/app/src/main/java/com/sapuseven/untis/ui/colorpicker/ColorPicker.kt index 140d55d7..0a6a0549 100644 --- a/app/src/main/java/com/sapuseven/untis/ui/colorpicker/ColorPicker.kt +++ b/app/src/main/java/com/sapuseven/untis/ui/colorpicker/ColorPicker.kt @@ -96,7 +96,7 @@ fun ColorPicker( onValueChange = { newColor -> if (newColor.matches(Regex("^#[0-9a-fA-F]{0,8}$"))) { colorHex = newColor - newColor.toUIntOrNull(16)?.let { + newColor.replace("#", "").toUIntOrNull(16)?.let { onColorChanged(HsvColor.from(Color(it.toInt())), false) } } From a0dce42c555fa95b3adbc1590a54edb860cc4e69 Mon Sep 17 00:00:00 2001 From: SapuSeven Date: Sat, 4 Nov 2023 16:35:31 +0100 Subject: [PATCH 03/11] #415 Add clickable homework links --- .../com/sapuseven/untis/helpers/TextUtils.kt | 50 ++++++++++++++- .../untis/ui/common/ClickableUrlText.kt | 41 ++++++++++++ .../ui/dialogs/TimetableItemDetailsDialog.kt | 63 +++++++++++-------- 3 files changed, 128 insertions(+), 26 deletions(-) create mode 100644 app/src/main/java/com/sapuseven/untis/ui/common/ClickableUrlText.kt diff --git a/app/src/main/java/com/sapuseven/untis/helpers/TextUtils.kt b/app/src/main/java/com/sapuseven/untis/helpers/TextUtils.kt index 8357f677..a29d7f8f 100755 --- a/app/src/main/java/com/sapuseven/untis/helpers/TextUtils.kt +++ b/app/src/main/java/com/sapuseven/untis/helpers/TextUtils.kt @@ -1,7 +1,55 @@ package com.sapuseven.untis.helpers +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.text.substring +import androidx.compose.ui.text.withStyle + object TextUtils { fun isNullOrEmpty(obj: Any?): Boolean { return obj?.toString()?.length ?: 0 == 0 } -} \ No newline at end of file + + @Composable + fun annotateUrls( + text: String, + urlColor: Color = MaterialTheme.colorScheme.primary + ): AnnotatedString = buildAnnotatedString { + val urlRegex = """(?:https?:\/\/|www\.)[\w-@:%_+.~#?&/=]+""".toRegex() + + var startIndex = 0 + while (startIndex < text.length) { + // find the next match + val match = urlRegex.find(text, startIndex) + + if (match == null) { + // no more matches - append remaining text and return + append(text.substring(startIndex)) + return@buildAnnotatedString + } + + if (match.range.start > startIndex) { + // matching url found with preceding text - append text first + append(text.substring(startIndex, match.range.start)) + } + + // append matched url + appendUrl(match.value, urlColor) + + // set new start index to the end of the matched url + startIndex = match.range.endInclusive + 1 + } + } + + private fun AnnotatedString.Builder.appendUrl(url: String, color: Color) { + pushStringAnnotation("url", url) + withStyle(style = SpanStyle(color = color)) { + append(url) + } + pop() + } +} diff --git a/app/src/main/java/com/sapuseven/untis/ui/common/ClickableUrlText.kt b/app/src/main/java/com/sapuseven/untis/ui/common/ClickableUrlText.kt new file mode 100644 index 00000000..14584748 --- /dev/null +++ b/app/src/main/java/com/sapuseven/untis/ui/common/ClickableUrlText.kt @@ -0,0 +1,41 @@ +package com.sapuseven.untis.ui.common + +import androidx.compose.foundation.text.ClickableText +import androidx.compose.material.LocalContentAlpha +import androidx.compose.material3.LocalContentColor +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.TextLayoutResult +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.style.TextOverflow +import com.sapuseven.untis.helpers.TextUtils.annotateUrls + +@Composable +fun ClickableUrlText( + text: String, + modifier: Modifier = Modifier, + style: TextStyle = TextStyle.Default.copy(LocalContentColor.current.copy(alpha = LocalContentAlpha.current)), + softWrap: Boolean = true, + overflow: TextOverflow = TextOverflow.Clip, + maxLines: Int = Int.MAX_VALUE, + onTextLayout: (TextLayoutResult) -> Unit = {}, + onClick: (String) -> Unit +) { + val annotatedText = annotateUrls(text) + ClickableText( + annotatedText, + modifier = modifier, + style = style, + softWrap = softWrap, + overflow = overflow, + maxLines = maxLines, + onTextLayout = onTextLayout, + onClick = { clickPos -> + annotatedText.getStringAnnotations(tag = "url", start = clickPos, end = clickPos) + .firstOrNull() + ?.let { + onClick(it.item) + } + } + ) +} diff --git a/app/src/main/java/com/sapuseven/untis/ui/dialogs/TimetableItemDetailsDialog.kt b/app/src/main/java/com/sapuseven/untis/ui/dialogs/TimetableItemDetailsDialog.kt index 93232210..293f3125 100644 --- a/app/src/main/java/com/sapuseven/untis/ui/dialogs/TimetableItemDetailsDialog.kt +++ b/app/src/main/java/com/sapuseven/untis/ui/dialogs/TimetableItemDetailsDialog.kt @@ -19,12 +19,10 @@ import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip -import androidx.compose.ui.platform.LocalClipboardManager import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.unit.dp @@ -57,6 +55,7 @@ import com.sapuseven.untis.models.untis.timetable.PeriodElement import com.sapuseven.untis.ui.animations.fullscreenDialogAnimationEnter import com.sapuseven.untis.ui.animations.fullscreenDialogAnimationExit import com.sapuseven.untis.ui.common.AppScaffold +import com.sapuseven.untis.ui.common.ClickableUrlText import com.sapuseven.untis.ui.common.SmallCircularProgressIndicator import com.sapuseven.untis.ui.common.conditional import com.sapuseven.untis.ui.functional.bottomInsets @@ -82,9 +81,12 @@ fun BaseComposeActivity.TimetableItemDetailsDialog( val pagerState = rememberPagerState(initialPage) val scope = rememberCoroutineScope() val context = LocalContext.current - val clipboardManager = LocalClipboardManager.current - var absenceCheck by rememberSaveable { mutableStateOf?>(null) } + var absenceCheck by rememberSaveable { + mutableStateOf?>( + null + ) + } var untisPeriodData by remember { mutableStateOf(null) } var untisStudents by rememberSaveable { mutableStateOf?>(null) } @@ -331,7 +333,11 @@ fun BaseComposeActivity.TimetableItemDetailsDialog( val endDate = it.endDate.toLocalDate() ListItem( - headlineText = { Text(it.text) }, + headlineText = { + ClickableUrlText(it.text) { + openUrl(it) + } + }, supportingText = { Text( stringResource( @@ -359,10 +365,7 @@ fun BaseComposeActivity.TimetableItemDetailsDialog( ) } } - } else null, - modifier = Modifier.clickable { - clipboardManager.setText(AnnotatedString(it.text)) - } + } else null ) } @@ -444,7 +447,13 @@ fun BaseComposeActivity.TimetableItemDetailsDialog( ) }, onClick = { - absenceCheck = periodData.element.let { Triple(it.id, it.startDateTime, it.endDateTime) } + absenceCheck = periodData.element.let { + Triple( + it.id, + it.startDateTime, + it.endDateTime + ) + } } ) @@ -640,7 +649,11 @@ fun BaseComposeActivity.TimetableItemDetailsDialog( ) else Toast - .makeText(context, errorMessageGeneric, Toast.LENGTH_LONG) + .makeText( + context, + errorMessageGeneric, + Toast.LENGTH_LONG + ) .show() }, { Toast @@ -777,8 +790,8 @@ private fun TimetableDatabaseInterface.TimetableItemDetailsDialogElement( } private suspend fun loadPeriodData( - user: User, - period: Period + user: User, + period: Period ): Result { val query = UntisRequest.UntisRequestQuery(user).apply { data.method = UntisApiConstants.METHOD_GET_PERIOD_DATA @@ -800,11 +813,11 @@ private suspend fun loadPeriodData( } private suspend fun createAbsence( - user: User, - ttId: Int, - student: UntisStudent, - startDateTime: LocalDateTime, - endDateTime: LocalDateTime + user: User, + ttId: Int, + student: UntisStudent, + startDateTime: LocalDateTime, + endDateTime: LocalDateTime ): Result { val query = UntisRequest.UntisRequestQuery(user).apply { @@ -830,8 +843,8 @@ private suspend fun createAbsence( } private suspend fun deleteAbsence( - user: User, - absence: UntisAbsence + user: User, + absence: UntisAbsence ): Result { val query = UntisRequest.UntisRequestQuery(user).apply { @@ -854,8 +867,8 @@ private suspend fun deleteAbsence( } private suspend fun submitAbsencesChecked( - user: User, - ttId: Int + user: User, + ttId: Int ): Result { val query = UntisRequest.UntisRequestQuery(user).apply { @@ -879,9 +892,9 @@ private suspend fun submitAbsencesChecked( } private suspend fun submitLessonTopic( - user: User, - ttId: Int, - lessonTopic: String + user: User, + ttId: Int, + lessonTopic: String ): Result { val query = UntisRequest.UntisRequestQuery(user).apply { From 60e6f6b2326763f7a6ad28aef1d13029b2a8d268 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20M=C3=BChlbauer?= <59062169+lm41@users.noreply.github.com> Date: Sat, 4 Nov 2023 19:16:34 +0100 Subject: [PATCH 04/11] [ENH] add detailed-absence-dialog (#367) * add detailed-absence-dialog * added hint, if absent * extract string ressources * prepare to set absence reason * Update TimePickerDialog to match DatePickerDialog * Update Material3 library --------- Co-authored-by: SapuSeven --- app/build.gradle | 2 +- .../untis/activities/LoginActivity.kt | 5 +- .../untis/activities/RoomFinderActivity.kt | 8 +- .../untis/activities/SettingsActivity.kt | 6 +- .../untis/models/untis/UntisDateTime.kt | 3 +- .../untis/preferences/Preferences.kt | 2 +- .../untis/ui/activities/InfoCenter.kt | 26 +- .../untis/ui/common/ReportsInfoBottomSheet.kt | 2 +- .../untis/ui/dialogs/AttachmentsDialog.kt | 2 +- .../untis/ui/dialogs/DatePickerDialog.kt | 3 +- .../ui/dialogs/ProfileManagementDialog.kt | 8 +- .../untis/ui/dialogs/TimePickerDialog.kt | 105 ++++++ .../ui/dialogs/TimetableItemDetailsDialog.kt | 348 ++++++++++++++---- .../untis/ui/preferences/Preference.kt | 4 +- .../untis/ui/widgets/WidgetListView.kt | 26 +- .../untis/widgets/BaseComposeWidget.kt | 4 +- .../untis/workers/WidgetUpdateWorker.kt | 4 +- app/src/main/res/values-de/strings.xml | 7 +- app/src/main/res/values/strings.xml | 7 +- 19 files changed, 448 insertions(+), 124 deletions(-) create mode 100644 app/src/main/java/com/sapuseven/untis/ui/dialogs/TimePickerDialog.kt diff --git a/app/build.gradle b/app/build.gradle index e63b1419..b5e8b84a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -157,7 +157,7 @@ dependencies { implementation "androidx.compose.animation:animation:$compose_version" implementation "androidx.compose.ui:ui:$compose_version" implementation "androidx.compose.ui:ui-tooling:$compose_version" - implementation 'androidx.compose.material3:material3:1.1.0-alpha06' + implementation 'androidx.compose.material3:material3:1.1.2' implementation 'androidx.glance:glance-appwidget:1.0.0-alpha05' implementation 'androidx.navigation:navigation-compose:2.5.0' implementation 'androidx.datastore:datastore-preferences:1.0.0' diff --git a/app/src/main/java/com/sapuseven/untis/activities/LoginActivity.kt b/app/src/main/java/com/sapuseven/untis/activities/LoginActivity.kt index 58d467ea..1bc551b5 100755 --- a/app/src/main/java/com/sapuseven/untis/activities/LoginActivity.kt +++ b/app/src/main/java/com/sapuseven/untis/activities/LoginActivity.kt @@ -270,8 +270,9 @@ class LoginActivity : BaseComposeActivity() { if (items.isNotEmpty()) LazyColumn(modifier) { items(items) { - ListItem(headlineText = { Text(it.displayName) }, - supportingText = { Text(it.address) }, + ListItem( + headlineContent = { Text(it.displayName) }, + supportingContent = { Text(it.address) }, modifier = Modifier.clickable { val builder = Uri.Builder() .appendQueryParameter("schoolInfo", getJSON().encodeToString(it)) diff --git a/app/src/main/java/com/sapuseven/untis/activities/RoomFinderActivity.kt b/app/src/main/java/com/sapuseven/untis/activities/RoomFinderActivity.kt index 4c2e12e1..53015046 100644 --- a/app/src/main/java/com/sapuseven/untis/activities/RoomFinderActivity.kt +++ b/app/src/main/java/com/sapuseven/untis/activities/RoomFinderActivity.kt @@ -245,7 +245,7 @@ fun RoomFinderListEmpty(modifier: Modifier = Modifier) { fun RoomFinderHourSelector(state: RoomFinderState) { state.currentUnit?.let { unit -> ListItem( - headlineText = { + headlineContent = { Text( text = stringResource( id = R.string.roomfinder_current_hour, @@ -256,7 +256,7 @@ fun RoomFinderHourSelector(state: RoomFinderState) { modifier = Modifier.fillMaxWidth() ) }, - supportingText = { + supportingContent = { Text( text = stringResource( id = R.string.roomfinder_current_hour_time, @@ -312,8 +312,8 @@ fun RoomListItem( // TODO: Show "Free for the rest of the day/week" (if applicable) ListItem( - headlineText = { Text(item.name) }, - supportingText = { + headlineContent = { Text(item.name) }, + supportingContent = { Text( when { isOccupied -> stringResource(R.string.roomfinder_item_desc_occupied) diff --git a/app/src/main/java/com/sapuseven/untis/activities/SettingsActivity.kt b/app/src/main/java/com/sapuseven/untis/activities/SettingsActivity.kt index a42eb78a..11a1ac06 100755 --- a/app/src/main/java/com/sapuseven/untis/activities/SettingsActivity.kt +++ b/app/src/main/java/com/sapuseven/untis/activities/SettingsActivity.kt @@ -1107,7 +1107,7 @@ class SettingsActivity : BaseComposeActivity() { } } else { ListItem( - headlineText = { + headlineContent = { Text(loadingText) }, leadingContent = { @@ -1183,10 +1183,10 @@ class SettingsActivity : BaseComposeActivity() { ) { ListItem( modifier = Modifier.clickable(onClick = onClick), - headlineText = { + headlineContent = { Text(githubUser.login) }, - supportingText = { + supportingContent = { Text( pluralStringResource( id = R.plurals.preferences_contributors_contributions, diff --git a/app/src/main/java/com/sapuseven/untis/models/untis/UntisDateTime.kt b/app/src/main/java/com/sapuseven/untis/models/untis/UntisDateTime.kt index aa71ef4c..be6e5e04 100755 --- a/app/src/main/java/com/sapuseven/untis/models/untis/UntisDateTime.kt +++ b/app/src/main/java/com/sapuseven/untis/models/untis/UntisDateTime.kt @@ -11,12 +11,11 @@ import org.joda.time.DateTime import org.joda.time.DateTimeZone import org.joda.time.LocalDateTime -@Serializable +@Serializable(UntisDateTime.Companion::class) class UntisDateTime( val dateTime: String ) { @OptIn(ExperimentalSerializationApi::class) - @Serializer(forClass = UntisDateTime::class) companion object : KSerializer { override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("UntisDateTime", PrimitiveKind.STRING) diff --git a/app/src/main/java/com/sapuseven/untis/preferences/Preferences.kt b/app/src/main/java/com/sapuseven/untis/preferences/Preferences.kt index 8ec4bb06..412c4617 100644 --- a/app/src/main/java/com/sapuseven/untis/preferences/Preferences.kt +++ b/app/src/main/java/com/sapuseven/untis/preferences/Preferences.kt @@ -86,7 +86,7 @@ fun PreferenceScreen( navController: NavController ) { ListItem( - headlineText = title, + headlineContent = title, leadingContent = icon, modifier = Modifier.clickable { navController.navigate(key) diff --git a/app/src/main/java/com/sapuseven/untis/ui/activities/InfoCenter.kt b/app/src/main/java/com/sapuseven/untis/ui/activities/InfoCenter.kt index 3eeb9629..c927d400 100644 --- a/app/src/main/java/com/sapuseven/untis/ui/activities/InfoCenter.kt +++ b/app/src/main/java/com/sapuseven/untis/ui/activities/InfoCenter.kt @@ -278,8 +278,8 @@ private fun MessageItem( val textColor = MaterialTheme.colorScheme.onSurfaceVariant ListItem( - headlineText = { Text(item.subject) }, - supportingText = { + headlineContent = { Text(item.subject) }, + supportingContent = { AndroidView( factory = { context -> TextView(context).apply { @@ -315,7 +315,7 @@ private fun EventItem(item: EventListItem) { TimetableDatabaseInterface.Type.SUBJECT ) ListItem( - overlineText = { + overlineContent = { Text( formatExamTime( item.exam.startDateTime.toLocalDateTime(), @@ -323,7 +323,7 @@ private fun EventItem(item: EventListItem) { ) ) }, - headlineText = { + headlineContent = { Text( if (!item.exam.name.contains(subject)) stringResource( R.string.infocenter_events_exam_name_long, @@ -337,12 +337,12 @@ private fun EventItem(item: EventListItem) { if (item.homework != null) { ListItem( - overlineText = { + overlineContent = { Text( item.homework.endDate.toLocalDate().toString(DateTimeFormat.mediumDate()) ) }, - headlineText = { + headlineContent = { Text( item.timetableDatabaseInterface.getLongName( item.lessonsById?.get(item.homework.lessonId.toString())?.subjectId @@ -350,7 +350,7 @@ private fun EventItem(item: EventListItem) { ) ) }, - supportingText = if (item.homework.text.isNotBlank()) { + supportingContent = if (item.homework.text.isNotBlank()) { { Text(item.homework.text) } } else null ) @@ -367,7 +367,7 @@ private fun OfficeHourItem(item: UntisOfficeHour) { ).filter { it?.isNotEmpty() == true }.joinToString("\n") ListItem( - overlineText = { + overlineContent = { Text( formatOfficeHourTime( item.startDateTime.toLocalDateTime(), @@ -375,8 +375,8 @@ private fun OfficeHourItem(item: UntisOfficeHour) { ) ) }, - headlineText = { Text(item.displayNameTeacher) }, - supportingText = if (body.isNotBlank()) { + headlineContent = { Text(item.displayNameTeacher) }, + supportingContent = if (body.isNotBlank()) { { Text(body) } } else null ) @@ -386,7 +386,7 @@ private fun OfficeHourItem(item: UntisOfficeHour) { @Composable private fun AbsenceItem(item: UntisAbsence) { ListItem( - overlineText = { + overlineContent = { Text( formatAbsenceTime( item.startDateTime.toLocalDateTime(), @@ -394,7 +394,7 @@ private fun AbsenceItem(item: UntisAbsence) { ) ) }, - headlineText = { + headlineContent = { Text( if (item.absenceReason.isNotEmpty()) item.absenceReason.substring(0, 1) @@ -403,7 +403,7 @@ private fun AbsenceItem(item: UntisAbsence) { stringResource(R.string.infocenter_absence_unknown_reason) ) }, - supportingText = if (item.text.isNotBlank()) { + supportingContent = if (item.text.isNotBlank()) { { Text(item.text) } } else null, leadingContent = { diff --git a/app/src/main/java/com/sapuseven/untis/ui/common/ReportsInfoBottomSheet.kt b/app/src/main/java/com/sapuseven/untis/ui/common/ReportsInfoBottomSheet.kt index 924f09e6..dcce2f3a 100644 --- a/app/src/main/java/com/sapuseven/untis/ui/common/ReportsInfoBottomSheet.kt +++ b/app/src/main/java/com/sapuseven/untis/ui/common/ReportsInfoBottomSheet.kt @@ -29,7 +29,7 @@ fun BaseComposeActivity.ReportsInfoBottomSheet() { val scope = rememberCoroutineScope() var bottomSheetVisible by rememberSaveable { mutableStateOf(false) } - val bottomSheetState = rememberSheetState(skipHalfExpanded = true) + val bottomSheetState = rememberStandardBottomSheetState(initialValue = SheetValue.Expanded) var saveEnabled by rememberSaveable { mutableStateOf(true) } LaunchedEffect(Unit) { diff --git a/app/src/main/java/com/sapuseven/untis/ui/dialogs/AttachmentsDialog.kt b/app/src/main/java/com/sapuseven/untis/ui/dialogs/AttachmentsDialog.kt index ae04a603..9207a7c6 100644 --- a/app/src/main/java/com/sapuseven/untis/ui/dialogs/AttachmentsDialog.kt +++ b/app/src/main/java/com/sapuseven/untis/ui/dialogs/AttachmentsDialog.kt @@ -51,7 +51,7 @@ fun AttachmentsDialog( ) { items(attachments) { ListItem( - headlineText = { Text(it.name) }, + headlineContent = { Text(it.name) }, leadingContent = { Icon( painter = painterResource(id = R.drawable.infocenter_attachment), diff --git a/app/src/main/java/com/sapuseven/untis/ui/dialogs/DatePickerDialog.kt b/app/src/main/java/com/sapuseven/untis/ui/dialogs/DatePickerDialog.kt index 04c83c4b..87be8399 100644 --- a/app/src/main/java/com/sapuseven/untis/ui/dialogs/DatePickerDialog.kt +++ b/app/src/main/java/com/sapuseven/untis/ui/dialogs/DatePickerDialog.kt @@ -61,8 +61,7 @@ fun DatePickerDialog( mainAxisSpacing = 8.dp, modifier = Modifier .fillMaxWidth() - .padding(top = 16.dp, bottom = 24.dp) - .padding(horizontal = 24.dp), + .padding(horizontal = 24.dp, vertical = 16.dp) ) { TextButton( onClick = { onDateSelected(LocalDate.now()) } diff --git a/app/src/main/java/com/sapuseven/untis/ui/dialogs/ProfileManagementDialog.kt b/app/src/main/java/com/sapuseven/untis/ui/dialogs/ProfileManagementDialog.kt index 5285183c..d51c1e70 100644 --- a/app/src/main/java/com/sapuseven/untis/ui/dialogs/ProfileManagementDialog.kt +++ b/app/src/main/java/com/sapuseven/untis/ui/dialogs/ProfileManagementDialog.kt @@ -80,7 +80,7 @@ fun BaseComposeActivity.ProfileManagementDialog( // TODO: Remove inheritance of ) { item { ListItem( - headlineText = { Text(stringResource(R.string.mainactivitydrawer_profile_edit_hint)) }, + headlineContent = { Text(stringResource(R.string.mainactivitydrawer_profile_edit_hint)) }, leadingContent = { Icon( imageVector = Icons.Outlined.Info, @@ -94,8 +94,8 @@ fun BaseComposeActivity.ProfileManagementDialog( // TODO: Remove inheritance of items(profiles) { profile -> ListItem( - headlineText = { Text(profile.getDisplayedName()) }, - supportingText = { Text(profile.userData.schoolName) }, + headlineContent = { Text(profile.getDisplayedName()) }, + supportingContent = { Text(profile.userData.schoolName) }, leadingContent = { Icon( imageVector = Icons.Outlined.Person, @@ -127,7 +127,7 @@ fun BaseComposeActivity.ProfileManagementDialog( // TODO: Remove inheritance of item { ListItem( - headlineText = { Text(stringResource(id = R.string.mainactivitydrawer_profile_add)) }, + headlineContent = { Text(stringResource(id = R.string.mainactivitydrawer_profile_add)) }, leadingContent = { Icon( imageVector = Icons.Outlined.Add, diff --git a/app/src/main/java/com/sapuseven/untis/ui/dialogs/TimePickerDialog.kt b/app/src/main/java/com/sapuseven/untis/ui/dialogs/TimePickerDialog.kt new file mode 100644 index 00000000..68c16257 --- /dev/null +++ b/app/src/main/java/com/sapuseven/untis/ui/dialogs/TimePickerDialog.kt @@ -0,0 +1,105 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package com.sapuseven.untis.ui.dialogs + +import android.content.Context +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.material3.AlertDialogDefaults +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.material3.TimePicker +import androidx.compose.material3.rememberTimePickerState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.intl.Locale +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Dialog +import androidx.compose.ui.window.DialogProperties +import com.sapuseven.untis.R +import org.joda.time.LocalTime +import java.text.DateFormat + + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun TimePickerDialog( + initialSelection: LocalTime = LocalTime.now(), + onDismiss: () -> Unit, + onTimeSelected: (LocalTime) -> Unit, +) { + Dialog(onDismissRequest = onDismiss) { + val timePickerState = rememberTimePickerState( + initialHour = initialSelection.hourOfDay, + initialMinute = initialSelection.minuteOfHour + ) + + Surface( + shape = AlertDialogDefaults.shape, + color = AlertDialogDefaults.containerColor + ) { + Column( + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = stringResource(R.string.all_timepicker_select).uppercase(), + style = MaterialTheme.typography.labelSmall, + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 24.dp, vertical = 16.dp) + .padding(bottom = 8.dp) + ) + + TimePicker( + state = timePickerState + ) + + Row( + horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.End), + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 24.dp, vertical = 16.dp) + ) { + TextButton( + onClick = onDismiss + ) { + Text(text = stringResource(id = R.string.all_cancel)) + } + + TextButton( + onClick = { onTimeSelected(LocalTime(timePickerState.hour, timePickerState.minute)) } + ) { + Text(text = stringResource(id = R.string.all_ok)) + } + } + } + } + } +} + + + diff --git a/app/src/main/java/com/sapuseven/untis/ui/dialogs/TimetableItemDetailsDialog.kt b/app/src/main/java/com/sapuseven/untis/ui/dialogs/TimetableItemDetailsDialog.kt index 293f3125..2dee7bf2 100644 --- a/app/src/main/java/com/sapuseven/untis/ui/dialogs/TimetableItemDetailsDialog.kt +++ b/app/src/main/java/com/sapuseven/untis/ui/dialogs/TimetableItemDetailsDialog.kt @@ -57,11 +57,13 @@ import com.sapuseven.untis.ui.animations.fullscreenDialogAnimationExit import com.sapuseven.untis.ui.common.AppScaffold import com.sapuseven.untis.ui.common.ClickableUrlText import com.sapuseven.untis.ui.common.SmallCircularProgressIndicator +import com.sapuseven.untis.ui.common.VerticalScrollColumn import com.sapuseven.untis.ui.common.conditional import com.sapuseven.untis.ui.functional.bottomInsets import com.sapuseven.untis.ui.functional.insetsPaddingValues import kotlinx.coroutines.launch import org.joda.time.LocalDateTime +import org.joda.time.LocalTime import org.joda.time.format.DateTimeFormat @@ -88,6 +90,13 @@ fun BaseComposeActivity.TimetableItemDetailsDialog( ) } + var detailedAbsenceCheck by rememberSaveable { + mutableStateOf, Pair>?>( + null + ) + } + var studentName by rememberSaveable { mutableStateOf(null) } + var untisPeriodData by remember { mutableStateOf(null) } var untisStudents by rememberSaveable { mutableStateOf?>(null) } var error by remember { mutableStateOf(null) } @@ -108,11 +117,13 @@ fun BaseComposeActivity.TimetableItemDetailsDialog( AppScaffold( topBar = { CenterAlignedTopAppBar( - title = { Text(stringResource(id = R.string.all_lesson_details)) }, + title = { Text(studentName ?: stringResource(id = R.string.all_lesson_details)) }, navigationIcon = { IconButton(onClick = { - if (absenceCheck != null) + if (absenceCheck != null && detailedAbsenceCheck == null) absenceCheck = null + else if (detailedAbsenceCheck != null) + detailedAbsenceCheck = null else dismiss() }) { @@ -137,6 +148,30 @@ fun BaseComposeActivity.TimetableItemDetailsDialog( onClick = { loading = true + if (detailedAbsenceCheck != null) { + scope.launch { + createAbsence( + user = user, + ttId = detailedAbsenceCheck?.first?.first ?: -1, + student = detailedAbsenceCheck?.first?.second!!, + startDateTime = detailedAbsenceCheck?.second?.first!!.toLocalDateTime(), + endDateTime = detailedAbsenceCheck?.second?.second!!.toLocalDateTime() + ).fold({ + untisPeriodData = untisPeriodData?.copy( + absences = untisPeriodData?.absences?.plus(it) + ) + }, { + Toast + .makeText(context, it.message, Toast.LENGTH_LONG) + .show() + }) + detailedAbsenceCheck = null + loading = false + } + return@FloatingActionButton + } + + scope.launch { submitAbsencesChecked( user, @@ -316,7 +351,7 @@ fun BaseComposeActivity.TimetableItemDetailsDialog( ).forEach { if (it.isNotBlank()) ListItem( - headlineText = { Text(it) }, + headlineContent = { Text(it) }, leadingContent = { Icon( painter = painterResource(id = R.drawable.all_info), @@ -333,12 +368,12 @@ fun BaseComposeActivity.TimetableItemDetailsDialog( val endDate = it.endDate.toLocalDate() ListItem( - headlineText = { + headlineContent = { ClickableUrlText(it.text) { openUrl(it) } }, - supportingText = { + supportingContent = { Text( stringResource( id = R.string.homeworks_due_time, @@ -372,10 +407,10 @@ fun BaseComposeActivity.TimetableItemDetailsDialog( // Lesson exam periodData.element.exam?.also { ListItem( - headlineText = { + headlineContent = { Text(it.name ?: stringResource(id = R.string.all_exam)) }, - supportingText = it.text?.let { { Text(it) } }, + supportingContent = it.text?.let { { Text(it) } }, leadingContent = { Icon( painter = painterResource(id = R.drawable.infocenter_exam), @@ -390,7 +425,7 @@ fun BaseComposeActivity.TimetableItemDetailsDialog( // Online lesson if (periodData.element.isOnlinePeriod == true) { ListItem( - headlineText = { Text(stringResource(R.string.all_lesson_online)) }, + headlineContent = { Text(stringResource(R.string.all_lesson_online)) }, leadingContent = { Icon( painter = painterResource(id = R.drawable.all_lesson_online), @@ -422,10 +457,10 @@ fun BaseComposeActivity.TimetableItemDetailsDialog( error = error, errorMessage = errorMessage, editPermission = CAN_WRITE_STUDENT_ABSENCE, - headlineText = { + headlineContent = { Text(stringResource(id = R.string.all_absences)) }, - supportingText = { + supportingContent = { Text( stringResource( if (it.absenceChecked) R.string.all_dialog_absences_checked @@ -465,10 +500,10 @@ fun BaseComposeActivity.TimetableItemDetailsDialog( error = error, errorMessage = errorMessage, editPermission = CAN_WRITE_LESSON_TOPIC, - headlineText = { + headlineContent = { Text(stringResource(id = R.string.all_lessontopic)) }, - supportingText = { + supportingContent = { val topic = lessonTopicNew ?: it.topic?.text Text( @@ -588,7 +623,7 @@ fun BaseComposeActivity.TimetableItemDetailsDialog( exit = fullscreenDialogAnimationExit() ) { BackHandler( - enabled = absenceCheck != null, + enabled = absenceCheck != null && detailedAbsenceCheck == null, ) { absenceCheck = null } @@ -610,10 +645,10 @@ fun BaseComposeActivity.TimetableItemDetailsDialog( untisPeriodData?.absences?.findLast { it.studentId == student.id } ListItem( - headlineText = { + headlineContent = { Text(text = student.fullName()) }, - supportingText = absence?.let { + supportingContent = absence?.let { { it.text } @@ -632,67 +667,246 @@ fun BaseComposeActivity.TimetableItemDetailsDialog( contentDescription = "Present" ) }, - modifier = Modifier.clickable { - absence?.let { - loading = true - - scope.launch { - deleteAbsence( - user, - absence - ).fold({ - if (it) - untisPeriodData = untisPeriodData?.copy( - absences = untisPeriodData?.absences?.minus( - absence + modifier = Modifier.conditional( + detailedAbsenceCheck == null, + ) { + this.clickable { + absence?.let { + loading = true + + scope.launch { + deleteAbsence( + user, + absence + ).fold({ + if (it) + untisPeriodData = untisPeriodData?.copy( + absences = untisPeriodData?.absences?.minus( + absence + ) ) + else + Toast + .makeText( + context, + errorMessageGeneric, + Toast.LENGTH_LONG + ) + .show() + }, { + Toast + .makeText(context, it.message, Toast.LENGTH_LONG) + .show() + }) + loading = false + } + } ?: absenceCheck?.let { absenceCheckPeriod -> + loading = true + + scope.launch { + createAbsence( + user, + absenceCheckPeriod.first, + student, + absenceCheckPeriod.second.toLocalDateTime(), + absenceCheckPeriod.third.toLocalDateTime() + ).fold({ + untisPeriodData = untisPeriodData?.copy( + absences = untisPeriodData?.absences?.plus(it) ) - else + }, { Toast - .makeText( - context, - errorMessageGeneric, - Toast.LENGTH_LONG - ) + .makeText(context, it.message, Toast.LENGTH_LONG) .show() - }, { - Toast - .makeText(context, it.message, Toast.LENGTH_LONG) - .show() - }) - loading = false + }) + loading = false + } } - } ?: absenceCheck?.let { absenceCheckPeriod -> - loading = true - - scope.launch { - createAbsence( - user, - absenceCheckPeriod.first, - student, - absenceCheckPeriod.second.toLocalDateTime(), - absenceCheckPeriod.third.toLocalDateTime() - ).fold({ - untisPeriodData = untisPeriodData?.copy( - absences = untisPeriodData?.absences?.plus(it) - ) - }, { - Toast - .makeText(context, it.message, Toast.LENGTH_LONG) - .show() - }) - loading = false + } + }, + trailingContent = { + IconButton( + onClick = { + detailedAbsenceCheck = + (absenceCheck!!.first to student) to (absenceCheck!!.second to absenceCheck!!.third) } + ) { + Icon( + painter = painterResource(id = R.drawable.notification_clock), + contentDescription = null + ) } } ) } } } + + AnimatedVisibility( + visible = detailedAbsenceCheck != null, + enter = fullscreenDialogAnimationEnter(), + exit = fullscreenDialogAnimationExit() + ) { + studentName = detailedAbsenceCheck?.first?.second?.fullName() + + BackHandler( + enabled = detailedAbsenceCheck != null, + ) { + detailedAbsenceCheck = null + studentName = null + } + Box( + modifier = Modifier + .padding(innerPadding) + .fillMaxSize() + .background(MaterialTheme.colorScheme.surface) + ) { + VerticalScrollColumn { + var showStartTimePicker by remember { mutableStateOf(false) } + var showEndTimePicker by remember { mutableStateOf(false) } + /* + * See line 800 for explaination. + * + var isDropdownExpanded by remember { mutableStateOf(false) } + var menuOptions = listOf() + var selectedOptionText by remember { + mutableStateOf(untisPeriodData?.absences?.findLast { + it.studentId == detailedAbsenceCheck?.first?.second?.id + }?.absenceReason ?: "Absence reason unknown") + }*/ + + + + ListItem( + modifier = Modifier.clickable { + showStartTimePicker = true + }, + headlineContent = { + Text(text = stringResource(id = R.string.all_start_time)) + }, + trailingContent = { + Text( + text = detailedAbsenceCheck?.second?.first?.toLocalDateTime() + ?.toString( + DateTimeFormat.forStyle("MS") + .withLocale(context.resources.configuration.locales[0]) + ) + ?: "", + style = MaterialTheme.typography.labelLarge + ) + } + ) + + ListItem( + modifier = Modifier.clickable { + showEndTimePicker = true + }, + headlineContent = { + Text(text = stringResource(id = R.string.all_end_time)) + }, + trailingContent = { + Text( + text = detailedAbsenceCheck?.second?.second?.toLocalDateTime() + ?.toString( + DateTimeFormat.forStyle("MS") + .withLocale(context.resources.configuration.locales[0]) + ) + ?: "", + style = MaterialTheme.typography.labelLarge + ) + } + ) + + + /* + * This is experimental code we have to test with a real teacher account. + * The PR can be merged without this as this is only a little addition to the functionality + * The outcommented aims to get a dropdown working for the absence reasons + * ListItem( + modifier = Modifier.clickable { + scope.launch { + menuOptions = + userDatabase.userDao().getByIdWithData(user.id)?.absenceReasons ?: listOf() + } + + }, + headlineContent = { + Text(text = "Absence reason") + }, + trailingContent = { + ExposedDropdownMenuBox( + expanded = isDropdownExpanded, + onExpandedChange = { + isDropdownExpanded = !isDropdownExpanded + }) + { + TextField( + modifier = Modifier.menuAnchor(), + readOnly = true, + value = selectedOptionText, + onValueChange = {} + ) + ExposedDropdownMenu( + expanded = isDropdownExpanded, + onDismissRequest = { isDropdownExpanded = false } + ) { + menuOptions.forEach { selectionOption -> + DropdownMenuItem( + text = { + Text(text = selectionOption.longName) + }, + onClick = { + selectedOptionText = selectionOption.longName + isDropdownExpanded = false + }, + contentPadding = ExposedDropdownMenuDefaults.ItemContentPadding + ) + } + } + } + } + )*/ + + if (showStartTimePicker) { + val startTime = detailedAbsenceCheck?.let { + it.second.first.toLocalDateTime() + } ?: LocalDateTime() + TimePickerDialog( + initialSelection = startTime.toLocalTime(), + onDismiss = { + showStartTimePicker = false + } + ) { time -> + detailedAbsenceCheck = + detailedAbsenceCheck!!.first to (UntisDateTime( + time.toDateTime(startTime.toDateTime()).toLocalDateTime() + ) to detailedAbsenceCheck?.second?.second!!) + showStartTimePicker = false + } + } + if (showEndTimePicker) { + val endTime = detailedAbsenceCheck?.let { + it.second.second.toLocalDateTime() + } ?: LocalDateTime().plusHours(1) + TimePickerDialog( + initialSelection = endTime.toLocalTime(), + onDismiss = { + showEndTimePicker = false + } + ) { time -> + detailedAbsenceCheck = + detailedAbsenceCheck!!.first to (detailedAbsenceCheck?.second?.first!! to UntisDateTime( + time.toDateTime(endTime.toDateTime()).toLocalDateTime() + )) + showEndTimePicker = false + } + } + } + } + } } } -@OptIn(ExperimentalMaterial3Api::class) @Composable private fun TimetableItemDetailsDialogWithPeriodData( periodData: PeriodData, @@ -700,8 +914,8 @@ private fun TimetableItemDetailsDialogWithPeriodData( error: Throwable?, errorMessage: String?, editPermission: String? = null, - headlineText: @Composable () -> Unit, - supportingText: @Composable (UntisPeriodData) -> Unit, + headlineContent: @Composable () -> Unit, + supportingContent: @Composable (UntisPeriodData) -> Unit, leadingContent: @Composable (UntisPeriodData?) -> Unit, onClick: () -> Unit ) { @@ -712,10 +926,10 @@ private fun TimetableItemDetailsDialogWithPeriodData( ) == true ListItem( - headlineText = headlineText, - supportingText = { + headlineContent = headlineContent, + supportingContent = { untisPeriodData?.let { - supportingText(it) + supportingContent(it) } ?: error?.let { Text(stringResource(R.string.all_error)) } ?: Text(stringResource(R.string.loading)) @@ -751,7 +965,7 @@ private fun TimetableDatabaseInterface.TimetableItemDetailsDialogElement( ) { if (elements.isNotEmpty()) ListItem( - headlineText = { + headlineContent = { Row( modifier = Modifier.horizontalScroll(rememberScrollState()), horizontalArrangement = Arrangement.spacedBy(8.dp) diff --git a/app/src/main/java/com/sapuseven/untis/ui/preferences/Preference.kt b/app/src/main/java/com/sapuseven/untis/ui/preferences/Preference.kt index 8166b2ea..fba4b948 100644 --- a/app/src/main/java/com/sapuseven/untis/ui/preferences/Preference.kt +++ b/app/src/main/java/com/sapuseven/untis/ui/preferences/Preference.kt @@ -59,12 +59,12 @@ fun Preference( } ListItem( - headlineText = { + headlineContent = { Box(modifier = Modifier.disabled(!enabled)) { title() } }, - supportingText = summary?.let { + supportingContent = summary?.let { { Column { Box(modifier = Modifier.disabled(!enabled)) { diff --git a/app/src/main/java/com/sapuseven/untis/ui/widgets/WidgetListView.kt b/app/src/main/java/com/sapuseven/untis/ui/widgets/WidgetListView.kt index 0ef3af02..d1bb40e0 100644 --- a/app/src/main/java/com/sapuseven/untis/ui/widgets/WidgetListView.kt +++ b/app/src/main/java/com/sapuseven/untis/ui/widgets/WidgetListView.kt @@ -22,8 +22,8 @@ fun WidgetListViewHeader( modifier: GlanceModifier = GlanceModifier, dayColorScheme: ColorScheme, nightColorScheme: ColorScheme, - headlineText: String, - supportingText: String? = null, + headlineContent: String, + supportingContent: String? = null, ) { val primary = ColorProvider( day = dayColorScheme.primary, @@ -37,8 +37,8 @@ fun WidgetListViewHeader( WidgetListItem( modifier = modifier, - headlineText = headlineText, - supportingText = supportingText, + headlineContent = headlineContent, + supportingContent = supportingContent, surfaceColor = primary, textColor = onPrimary, /*trailingContent = { @@ -78,8 +78,8 @@ fun WidgetListView( // TODO: Use actionStartActivity on timetable item click, otherwise show reload action modifier = GlanceModifier.clickable(onClickAction), leadingContent = it.leadingContent, - headlineText = it.headlineText, - supportingText = it.supportingText, + headlineContent = it.headlineContent, + supportingContent = it.supportingContent, surfaceColor = surface, textColor = onSurface ) @@ -90,8 +90,8 @@ fun WidgetListView( @Composable private fun WidgetListItem( modifier: GlanceModifier = GlanceModifier, - headlineText: String, - supportingText: String? = null, + headlineContent: String, + supportingContent: String? = null, surfaceColor: ColorProvider, textColor: ColorProvider, typography: Typography = MaterialTheme.typography, @@ -121,12 +121,12 @@ private fun WidgetListItem( .padding(vertical = 8.dp) ) { Text( - headlineText, + headlineContent, style = typography.bodyLarge.toGlanceTextStyle(textColor) ) - supportingText?.let { + supportingContent?.let { Text( - supportingText, + supportingContent, style = typography.bodyMedium.toGlanceTextStyle(textColor) ) } @@ -137,7 +137,7 @@ private fun WidgetListItem( } data class WidgetListItemModel( - val headlineText: String, - val supportingText: String, + val headlineContent: String, + val supportingContent: String, val leadingContent: @Composable ((surfaceColor: ColorProvider, textColor: ColorProvider) -> Unit)? ) diff --git a/app/src/main/java/com/sapuseven/untis/widgets/BaseComposeWidget.kt b/app/src/main/java/com/sapuseven/untis/widgets/BaseComposeWidget.kt index 2034b8df..ea22ce2b 100644 --- a/app/src/main/java/com/sapuseven/untis/widgets/BaseComposeWidget.kt +++ b/app/src/main/java/com/sapuseven/untis/widgets/BaseComposeWidget.kt @@ -111,8 +111,8 @@ open class BaseComposeWidget : GlanceAppWidget() { .fillMaxWidth(), dayColorScheme = colorSchemeLight, nightColorScheme = colorSchemeDark, - headlineText = user?.getDisplayedName(LocalContext.current) ?: "(Invalid user)", - supportingText = user?.userData?.schoolName + headlineContent = user?.getDisplayedName(LocalContext.current) ?: "(Invalid user)", + supportingContent = user?.userData?.schoolName ) diff --git a/app/src/main/java/com/sapuseven/untis/workers/WidgetUpdateWorker.kt b/app/src/main/java/com/sapuseven/untis/workers/WidgetUpdateWorker.kt index f2d8fc67..a6248f8c 100644 --- a/app/src/main/java/com/sapuseven/untis/workers/WidgetUpdateWorker.kt +++ b/app/src/main/java/com/sapuseven/untis/workers/WidgetUpdateWorker.kt @@ -81,10 +81,10 @@ class WidgetUpdateWorker(context: Context, params: WorkerParameters) : timetableItems.getOrNull(index + 1)?.startDateTime == item.startDateTime WidgetListItemModel( - headlineText = item.periodData.getLong( + headlineContent = item.periodData.getLong( TimetableDatabaseInterface.Type.SUBJECT ), - supportingText = arrayOf(item.top, item.bottom) + supportingContent = arrayOf(item.top, item.bottom) .filter { s -> s.isNotBlank() } .joinToString(" - "), leadingContent = { surfaceColor, textColor -> diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index f88cfdfc..dd9bcf5b 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -368,6 +368,9 @@ Letzten 30 Tage anzeigen Letzten 90 Tage anzeigen Aktuelles Schuljahr - App Sprache - App Sprache + Zeit auswählen + Startzeit + Endzeit + App-Sprache + App-Sprache diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ba4c6293..0186a210 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -387,6 +387,9 @@ Show last 30 days Show last 90 days Current school year - App Language - App language + Select Time + Start time + End time + App Language + App language From d32c73b2af9ff286b5c772751feffbf4eea3f4f5 Mon Sep 17 00:00:00 2001 From: SapuSeven Date: Sun, 5 Nov 2023 00:08:27 +0100 Subject: [PATCH 05/11] Add debug info screen --- .../untis/activities/MainActivity.kt | 4 ++ .../untis/ui/common/ActionButtons.kt | 52 ++++++++++++++++++- app/src/main/res/drawable/all_debug.xml | 9 ++++ 3 files changed, 63 insertions(+), 2 deletions(-) create mode 100755 app/src/main/res/drawable/all_debug.xml diff --git a/app/src/main/java/com/sapuseven/untis/activities/MainActivity.kt b/app/src/main/java/com/sapuseven/untis/activities/MainActivity.kt index 173d69fd..d86d62df 100644 --- a/app/src/main/java/com/sapuseven/untis/activities/MainActivity.kt +++ b/app/src/main/java/com/sapuseven/untis/activities/MainActivity.kt @@ -48,6 +48,7 @@ import androidx.datastore.core.DataStore import androidx.datastore.preferences.core.Preferences import androidx.datastore.preferences.core.edit import androidx.datastore.preferences.core.intPreferencesKey +import com.sapuseven.untis.BuildConfig import com.sapuseven.untis.R import com.sapuseven.untis.activities.SettingsActivity.Companion.EXTRA_STRING_PREFERENCE_HIGHLIGHT import com.sapuseven.untis.activities.SettingsActivity.Companion.EXTRA_STRING_PREFERENCE_ROUTE @@ -540,6 +541,9 @@ fun BaseComposeActivity.MainApp(state: MainAppState) { } }, actions = { + if (BuildConfig.DEBUG) + DebugInfoAction() + ProfileSelectorAction( users = state.userDatabase.userDao().getAll(), currentSelectionId = state.user.id, diff --git a/app/src/main/java/com/sapuseven/untis/ui/common/ActionButtons.kt b/app/src/main/java/com/sapuseven/untis/ui/common/ActionButtons.kt index d7b48f9e..996e3a0d 100644 --- a/app/src/main/java/com/sapuseven/untis/ui/common/ActionButtons.kt +++ b/app/src/main/java/com/sapuseven/untis/ui/common/ActionButtons.kt @@ -5,10 +5,23 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.AccountCircle import androidx.compose.material.icons.outlined.Check import androidx.compose.material.icons.outlined.Edit -import androidx.compose.material3.* -import androidx.compose.runtime.* +import androidx.compose.material3.AlertDialog +import androidx.compose.material3.Button +import androidx.compose.material3.Divider +import androidx.compose.material3.DropdownMenu +import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.testTag +import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import com.sapuseven.untis.R @@ -75,6 +88,41 @@ fun ProfileSelectorAction( } } +@Composable +fun DebugInfoAction() { + var showInfoDialog by remember { mutableStateOf(false) } + + IconButton(onClick = { showInfoDialog = true }) { + Icon( + painterResource(R.drawable.all_debug), + contentDescription = "Debug info" + ) + } + + if (showInfoDialog) { + AlertDialog( + onDismissRequest = { showInfoDialog = false }, + title = { Text("Debug information") }, + text = { + Text( + "You are running a debug build of the app.\n\n" + + "This means that the app is not optimized and you will see some additional settings and functions.\n" + + "It is only recommended to use this variant when developing or gathering information about specific issues.\n" + + "For normal daily use, you should switch to a stable release build of the app.\n\n" + + "Please remember that diagnostic data may include personal details, " + + "so it is your responsibility to check and obfuscate any gathered data before uploading." + ) + }, + confirmButton = { + TextButton( + onClick = { showInfoDialog = false }) { + Text(stringResource(R.string.all_ok)) + } + } + ) + } +} + @Composable internal fun DropdownMenuDivider() { Divider(modifier = Modifier.padding(vertical = 8.dp)) diff --git a/app/src/main/res/drawable/all_debug.xml b/app/src/main/res/drawable/all_debug.xml new file mode 100755 index 00000000..f0891107 --- /dev/null +++ b/app/src/main/res/drawable/all_debug.xml @@ -0,0 +1,9 @@ + + + From 22dd0fe5c3b47e10780ca32e42fa37e4815458aa Mon Sep 17 00:00:00 2001 From: SapuSeven Date: Sun, 5 Nov 2023 00:54:33 +0100 Subject: [PATCH 06/11] Add timetable item details debug dialog --- .../untis/activities/MainActivity.kt | 2 +- .../untis/ui/common/ActionButtons.kt | 39 ----- .../untis/ui/common/DebugActionButtons.kt | 136 ++++++++++++++++++ .../ui/dialogs/TimetableItemDetailsDialog.kt | 7 +- app/src/main/res/drawable/all_copy.xml | 9 ++ 5 files changed, 152 insertions(+), 41 deletions(-) create mode 100644 app/src/main/java/com/sapuseven/untis/ui/common/DebugActionButtons.kt create mode 100644 app/src/main/res/drawable/all_copy.xml diff --git a/app/src/main/java/com/sapuseven/untis/activities/MainActivity.kt b/app/src/main/java/com/sapuseven/untis/activities/MainActivity.kt index d86d62df..86ade7fb 100644 --- a/app/src/main/java/com/sapuseven/untis/activities/MainActivity.kt +++ b/app/src/main/java/com/sapuseven/untis/activities/MainActivity.kt @@ -542,7 +542,7 @@ fun BaseComposeActivity.MainApp(state: MainAppState) { }, actions = { if (BuildConfig.DEBUG) - DebugInfoAction() + DebugDesclaimerAction() ProfileSelectorAction( users = state.userDatabase.userDao().getAll(), diff --git a/app/src/main/java/com/sapuseven/untis/ui/common/ActionButtons.kt b/app/src/main/java/com/sapuseven/untis/ui/common/ActionButtons.kt index 996e3a0d..9415e03a 100644 --- a/app/src/main/java/com/sapuseven/untis/ui/common/ActionButtons.kt +++ b/app/src/main/java/com/sapuseven/untis/ui/common/ActionButtons.kt @@ -5,15 +5,12 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.AccountCircle import androidx.compose.material.icons.outlined.Check import androidx.compose.material.icons.outlined.Edit -import androidx.compose.material3.AlertDialog -import androidx.compose.material3.Button import androidx.compose.material3.Divider import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.Text -import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -21,7 +18,6 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.testTag -import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import com.sapuseven.untis.R @@ -88,41 +84,6 @@ fun ProfileSelectorAction( } } -@Composable -fun DebugInfoAction() { - var showInfoDialog by remember { mutableStateOf(false) } - - IconButton(onClick = { showInfoDialog = true }) { - Icon( - painterResource(R.drawable.all_debug), - contentDescription = "Debug info" - ) - } - - if (showInfoDialog) { - AlertDialog( - onDismissRequest = { showInfoDialog = false }, - title = { Text("Debug information") }, - text = { - Text( - "You are running a debug build of the app.\n\n" + - "This means that the app is not optimized and you will see some additional settings and functions.\n" + - "It is only recommended to use this variant when developing or gathering information about specific issues.\n" + - "For normal daily use, you should switch to a stable release build of the app.\n\n" + - "Please remember that diagnostic data may include personal details, " + - "so it is your responsibility to check and obfuscate any gathered data before uploading." - ) - }, - confirmButton = { - TextButton( - onClick = { showInfoDialog = false }) { - Text(stringResource(R.string.all_ok)) - } - } - ) - } -} - @Composable internal fun DropdownMenuDivider() { Divider(modifier = Modifier.padding(vertical = 8.dp)) diff --git a/app/src/main/java/com/sapuseven/untis/ui/common/DebugActionButtons.kt b/app/src/main/java/com/sapuseven/untis/ui/common/DebugActionButtons.kt new file mode 100644 index 00000000..9cc988fe --- /dev/null +++ b/app/src/main/java/com/sapuseven/untis/ui/common/DebugActionButtons.kt @@ -0,0 +1,136 @@ +package com.sapuseven.untis.ui.common + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.AlertDialog +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.platform.ClipboardManager +import androidx.compose.ui.platform.LocalClipboardManager +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.unit.dp +import com.sapuseven.untis.R +import com.sapuseven.untis.data.timetable.PeriodData +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.encodeToString +import kotlinx.serialization.json.Json + +@OptIn(ExperimentalSerializationApi::class) +private val json = Json { + encodeDefaults = true + prettyPrint = true + prettyPrintIndent = " " +} + +@Composable +internal fun DebugInfoAction( + title: @Composable (() -> Unit)? = null, + content: @Composable (() -> Unit)? = null, +) { + var showInfoDialog by remember { mutableStateOf(false) } + + IconButton(onClick = { showInfoDialog = true }) { + Icon( + painterResource(R.drawable.all_debug), + contentDescription = "Debug info" + ) + } + + if (showInfoDialog) { + AlertDialog( + onDismissRequest = { showInfoDialog = false }, + title = title, + text = content, + confirmButton = { + TextButton( + onClick = { showInfoDialog = false }) { + Text(stringResource(R.string.all_ok)) + } + } + ) + } +} + +@Composable +fun DebugDesclaimerAction() { + DebugInfoAction( + title = { Text("Debug information") } + ) { + Text( + "You are running a debug build of the app.\n\n" + + "This means that the app is not optimized and you will see some additional settings and functions.\n" + + "It is only recommended to use this variant when developing or gathering information about specific issues.\n" + + "For normal daily use, you should switch to a stable release build of the app.\n\n" + + "Please remember that diagnostic data may include personal details, " + + "so it is your responsibility to check and obfuscate any gathered data before uploading." + ) + } +} + +@Composable +fun DebugTimetableItemDetailsAction(timegridItems: List) { + DebugInfoAction( + title = { Text("Raw lesson details") } + ) { + LazyColumn( + verticalArrangement = Arrangement.spacedBy(16.dp), + modifier = Modifier + .fillMaxWidth() + ) { + items(timegridItems) { + Column( + horizontalAlignment = Alignment.End, + modifier = Modifier + .clip(RoundedCornerShape(8.dp)) + .background(MaterialTheme.colorScheme.background) + .padding(8.dp) + ) { + RawText(item = it.element) + } + } + } + } +} + +@Composable +private inline fun RawText(item: T) { + val clipboardManager: ClipboardManager = LocalClipboardManager.current + val itemText = remember { json.encodeToString(item) } + + Text( + color = MaterialTheme.colorScheme.onSurface, + fontFamily = FontFamily.Monospace, + text = itemText + ) + TextButton( + onClick = { clipboardManager.setText(AnnotatedString(itemText)) } + ) { + Icon( + painter = painterResource(R.drawable.all_copy), + contentDescription = "Copy", + modifier = Modifier + .padding(end = 8.dp) + ) + Text("Copy") + } +} diff --git a/app/src/main/java/com/sapuseven/untis/ui/dialogs/TimetableItemDetailsDialog.kt b/app/src/main/java/com/sapuseven/untis/ui/dialogs/TimetableItemDetailsDialog.kt index 2dee7bf2..e70efafc 100644 --- a/app/src/main/java/com/sapuseven/untis/ui/dialogs/TimetableItemDetailsDialog.kt +++ b/app/src/main/java/com/sapuseven/untis/ui/dialogs/TimetableItemDetailsDialog.kt @@ -30,6 +30,7 @@ import com.google.accompanist.pager.ExperimentalPagerApi import com.google.accompanist.pager.HorizontalPager import com.google.accompanist.pager.HorizontalPagerIndicator import com.google.accompanist.pager.rememberPagerState +import com.sapuseven.untis.BuildConfig import com.sapuseven.untis.R import com.sapuseven.untis.activities.BaseComposeActivity import com.sapuseven.untis.data.connectivity.UntisApiConstants @@ -56,6 +57,7 @@ import com.sapuseven.untis.ui.animations.fullscreenDialogAnimationEnter import com.sapuseven.untis.ui.animations.fullscreenDialogAnimationExit import com.sapuseven.untis.ui.common.AppScaffold import com.sapuseven.untis.ui.common.ClickableUrlText +import com.sapuseven.untis.ui.common.DebugTimetableItemDetailsAction import com.sapuseven.untis.ui.common.SmallCircularProgressIndicator import com.sapuseven.untis.ui.common.VerticalScrollColumn import com.sapuseven.untis.ui.common.conditional @@ -63,7 +65,6 @@ import com.sapuseven.untis.ui.functional.bottomInsets import com.sapuseven.untis.ui.functional.insetsPaddingValues import kotlinx.coroutines.launch import org.joda.time.LocalDateTime -import org.joda.time.LocalTime import org.joda.time.format.DateTimeFormat @@ -132,6 +133,10 @@ fun BaseComposeActivity.TimetableItemDetailsDialog( contentDescription = stringResource(id = R.string.all_close) ) } + }, + actions = { + if (BuildConfig.DEBUG) + DebugTimetableItemDetailsAction(timegridItems) } ) }, diff --git a/app/src/main/res/drawable/all_copy.xml b/app/src/main/res/drawable/all_copy.xml new file mode 100644 index 00000000..5d309f10 --- /dev/null +++ b/app/src/main/res/drawable/all_copy.xml @@ -0,0 +1,9 @@ + + + From 028ce6786163ecc8423011c91fba34aae4ee7062 Mon Sep 17 00:00:00 2001 From: SapuSeven Date: Sun, 5 Nov 2023 01:00:41 +0100 Subject: [PATCH 07/11] Add whole lesson details to debug dialog --- .../java/com/sapuseven/untis/ui/common/DebugActionButtons.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/sapuseven/untis/ui/common/DebugActionButtons.kt b/app/src/main/java/com/sapuseven/untis/ui/common/DebugActionButtons.kt index 9cc988fe..0592750a 100644 --- a/app/src/main/java/com/sapuseven/untis/ui/common/DebugActionButtons.kt +++ b/app/src/main/java/com/sapuseven/untis/ui/common/DebugActionButtons.kt @@ -105,7 +105,7 @@ fun DebugTimetableItemDetailsAction(timegridItems: List) { .background(MaterialTheme.colorScheme.background) .padding(8.dp) ) { - RawText(item = it.element) + RawText(item = it) } } } From 1504b0edecf2aeda6d29f7e87d558f73c0dfe239 Mon Sep 17 00:00:00 2001 From: SapuSeven Date: Mon, 6 Nov 2023 02:51:41 +0100 Subject: [PATCH 08/11] Update fdroid release commands --- .circleci/config.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 40d2085f..d61e8708 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -163,6 +163,7 @@ jobs: git config user.name "CircleCI" git checkout -B release + git reset --hard HEAD~1 git merge $CIRCLE_TAG versionCode=$(jq '.elements[0].versionCode' ./workspace/outputs/apk/gms/release/output-metadata.json) @@ -171,7 +172,7 @@ jobs: git add ./app/build.gradle git commit -m "[skip ci] Update F-Droid release" git tag fdroid-$CIRCLE_TAG - git push --set-upstream origin release + git push --force --set-upstream origin release git push origin fdroid-$CIRCLE_TAG workflows: version: 2 From 6f924eb11a0bb80ee6042f5fb94c31d05180466b Mon Sep 17 00:00:00 2001 From: SapuSeven Date: Tue, 7 Nov 2023 02:45:36 +0100 Subject: [PATCH 09/11] Update build config --- .circleci/config.yml | 2 +- gradle.properties | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index d61e8708..b5ca88e5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -34,7 +34,7 @@ jobs: echo 'export KEY_RELEASE_PASSWORD=$(echo "$KEY_RELEASE_PASSWORD_ENCODED" | base64 --decode)' >> $BASH_ENV - run: name: Initial build - command: ./gradlew --no-daemon assemble bundle + command: ./gradlew --no-configuration-cache --no-daemon assemble bundle environment: GRADLE_OPTS: ' -Dorg.gradle.daemon=false diff --git a/gradle.properties b/gradle.properties index 6446e923..98e9d12c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,10 +11,13 @@ # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true #Sun Mar 05 16:05:18 CET 2023 -org.gradle.jvmargs=-Xmx2g -Dkotlin.daemon.jvm.options\="-Xmx2g" +org.gradle.jvmargs=-Xmx4g -Dkotlin.daemon.jvm.options\="-Xmx4g" +android.defaults.buildfeatures.buildconfig=true android.enableJetifier=false android.useAndroidX=true + +# https://developer.android.com/build/optimize-your-build org.gradle.unsafe.configuration-cache=true -android.defaults.buildfeatures.buildconfig=true +org.gradle.unsafe.configuration-cache.problems=warn android.nonTransitiveRClass=true android.nonFinalResIds=true From a9265a44f44fe4573c3246949b247df553fc56c4 Mon Sep 17 00:00:00 2001 From: SapuSeven Date: Tue, 7 Nov 2023 02:55:30 +0100 Subject: [PATCH 10/11] Update build config --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 98e9d12c..e7e31b41 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,7 +11,7 @@ # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true #Sun Mar 05 16:05:18 CET 2023 -org.gradle.jvmargs=-Xmx4g -Dkotlin.daemon.jvm.options\="-Xmx4g" +org.gradle.jvmargs=-Xmx2g -Dkotlin.daemon.jvm.options\="-Xmx2g" android.defaults.buildfeatures.buildconfig=true android.enableJetifier=false android.useAndroidX=true From c536a1f4ea3c2122dd684440ecd23fbada71c273 Mon Sep 17 00:00:00 2001 From: SapuSeven Date: Tue, 7 Nov 2023 03:19:28 +0100 Subject: [PATCH 11/11] Update build config --- .circleci/config.yml | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index b5ca88e5..629d604c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -2,6 +2,7 @@ version: 2.1 orbs: gh: circleci/github-cli@2.2.0 jq: circleci/jq@2.2.0 + android: circleci/android@2.3.0 filters: &release branches: ignore: /.*/ @@ -10,20 +11,16 @@ filters: &release jobs: build: working_directory: ~/betteruntis - docker: - - image: cimg/android:2023.06.1 - resource_class: large + executor: + name: android/android-machine + resource-class: large + tag: 2023.10.1 steps: - checkout - - restore_cache: - key: jars-{{ checksum "build.gradle" }}-{{ checksum "app/build.gradle" }} + - android/restore-gradle-cache - run: name: Download Dependencies command: ./gradlew androidDependencies - - save_cache: - paths: - - ~/.gradle - key: jars-{{ checksum "build.gradle" }}-{{ checksum "app/build.gradle" }} - run: name: Prepare signing config command: | @@ -42,6 +39,7 @@ jobs: -Dorg.gradle.workers.max=3 -Dkotlin.incremental=false ' + - android/save-gradle-cache - store_artifacts: name: Upload build artifacts path: app/build/outputs