From 983c93b1b45a00829063af2d26e605841576939d Mon Sep 17 00:00:00 2001 From: "hector.godoy" Date: Mon, 9 Sep 2024 15:06:58 +0200 Subject: [PATCH 1/2] Update libraries to last version --- app/build.gradle | 30 +-- .../raco/ui/components/RacoAboutScreen.kt | 4 +- .../raco/ui/components/RacoEvaluationList.kt | 15 +- .../raco/ui/components/RacoMainNavHost.kt | 32 +-- .../yara/raco/ui/components/RacoMainScreen.kt | 10 +- .../raco/ui/components/RacoMainTopAppBar.kt | 18 +- .../yara/raco/ui/components/RacoNoticeList.kt | 16 +- .../yara/raco/ui/components/RacoSchedule.kt | 7 +- .../raco/ui/components/htmltext/HtmlText.kt | 19 +- .../yara/raco/ui/components/pager/PagerTab.kt | 71 ----- .../ui/components/pullrefresh/PullRefresh.kt | 111 -------- .../pullrefresh/PullRefreshIndicator.kt | 243 ------------------ .../PullRefreshIndicatorTransform.kt | 70 ----- .../pullrefresh/PullRefreshState.kt | 227 ---------------- build.gradle | 10 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 16 files changed, 77 insertions(+), 808 deletions(-) delete mode 100644 app/src/main/java/com/yara/raco/ui/components/pager/PagerTab.kt delete mode 100644 app/src/main/java/com/yara/raco/ui/components/pullrefresh/PullRefresh.kt delete mode 100644 app/src/main/java/com/yara/raco/ui/components/pullrefresh/PullRefreshIndicator.kt delete mode 100644 app/src/main/java/com/yara/raco/ui/components/pullrefresh/PullRefreshIndicatorTransform.kt delete mode 100644 app/src/main/java/com/yara/raco/ui/components/pullrefresh/PullRefreshState.kt diff --git a/app/build.gradle b/app/build.gradle index 2c93714..1b6018e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -69,7 +69,7 @@ android { compose true } composeOptions { - kotlinCompilerExtensionVersion '1.5.3' + kotlinCompilerExtensionVersion '1.5.15' } packagingOptions { resources { @@ -81,38 +81,38 @@ android { dependencies { //Android dependencies - implementation 'androidx.core:core-ktx:1.12.0' - implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.2' - implementation 'androidx.datastore:datastore-preferences:1.0.0' + implementation 'androidx.core:core-ktx:1.13.1' + implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.8.5' + implementation 'androidx.datastore:datastore-preferences:1.1.1' //Compose dependencies - implementation platform('androidx.compose:compose-bom:2023.09.00') + implementation platform('androidx.compose:compose-bom:2024.09.00') implementation "androidx.compose.ui:ui" implementation "androidx.compose.runtime:runtime-livedata" implementation "androidx.compose.ui:ui-tooling-preview" implementation 'androidx.compose.material:material-icons-extended' implementation 'androidx.compose.material3:material3' - implementation 'androidx.activity:activity-compose:1.7.2' - implementation 'androidx.navigation:navigation-compose:2.7.2' + implementation 'androidx.activity:activity-compose:1.9.2' + implementation 'androidx.navigation:navigation-compose:2.8.0' //Room dependencies implementation "androidx.room:room-ktx:$room_version" ksp "androidx.room:room-compiler:$room_version" - implementation 'androidx.work:work-runtime-ktx:2.8.1' + implementation 'androidx.work:work-runtime-ktx:2.9.1' - implementation 'com.squareup.okhttp3:okhttp:4.11.0' + implementation 'com.squareup.okhttp3:okhttp:4.12.0' - implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0' + implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3' //Debug and test implementations testImplementation 'junit:junit:4.13.2' - androidTestImplementation 'androidx.test.ext:junit:1.1.5' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' - androidTestImplementation 'androidx.compose.ui:ui-test-junit4:1.5.1' - debugImplementation "androidx.compose.ui:ui-tooling:1.5.1" - debugImplementation "androidx.compose.ui:ui-test-manifest:1.5.1" + androidTestImplementation 'androidx.test.ext:junit:1.2.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1' + androidTestImplementation 'androidx.compose.ui:ui-test-junit4:1.7.0' + debugImplementation "androidx.compose.ui:ui-tooling:1.7.0" + debugImplementation "androidx.compose.ui:ui-test-manifest:1.7.0" } // Compiler flag to use experimental Compose APIs diff --git a/app/src/main/java/com/yara/raco/ui/components/RacoAboutScreen.kt b/app/src/main/java/com/yara/raco/ui/components/RacoAboutScreen.kt index dd9219d..f957a41 100644 --- a/app/src/main/java/com/yara/raco/ui/components/RacoAboutScreen.kt +++ b/app/src/main/java/com/yara/raco/ui/components/RacoAboutScreen.kt @@ -15,7 +15,7 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.CircleShape import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.outlined.Campaign import androidx.compose.material.icons.outlined.Code import androidx.compose.material.icons.outlined.Description @@ -81,7 +81,7 @@ fun RacoAboutScreen( navigationIcon = { IconButton(onClick = onBackPressed) { Icon( - imageVector = Icons.Default.ArrowBack, + imageVector = Icons.AutoMirrored.Filled.ArrowBack, contentDescription = stringResource(id = R.string.back) ) } diff --git a/app/src/main/java/com/yara/raco/ui/components/RacoEvaluationList.kt b/app/src/main/java/com/yara/raco/ui/components/RacoEvaluationList.kt index dab17de..8709153 100644 --- a/app/src/main/java/com/yara/raco/ui/components/RacoEvaluationList.kt +++ b/app/src/main/java/com/yara/raco/ui/components/RacoEvaluationList.kt @@ -6,7 +6,6 @@ import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.WindowInsets @@ -32,17 +31,18 @@ import androidx.compose.material.icons.outlined.Edit import androidx.compose.material.icons.outlined.Save import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults -import androidx.compose.material3.Divider import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.ElevatedCard import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExposedDropdownMenuBox import androidx.compose.material3.ExposedDropdownMenuDefaults import androidx.compose.material3.FloatingActionButton +import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.ListItem import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.MenuAnchorType import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Scaffold import androidx.compose.material3.Surface @@ -75,6 +75,7 @@ import com.yara.raco.model.grade.Grade import com.yara.raco.model.grade.MutableGrade import com.yara.raco.model.subject.Subject import com.yara.raco.utils.Json +import java.util.Locale class EditableEvaluationState(private val evaluationWithGrades: EvaluationWithGrades) { private constructor( @@ -188,7 +189,7 @@ fun RacoEvaluationList( key = { _, evaluation -> evaluation.evaluation.id } ) { index, evaluation -> if (index != 0) { - Divider() + HorizontalDivider() } EvaluationListEntry( evaluation = evaluation, @@ -212,7 +213,6 @@ fun RacoEvaluationList( } } -@OptIn(ExperimentalLayoutApi::class) @Composable fun DetailedEvaluation( evaluation: EvaluationWithGrades, @@ -301,7 +301,6 @@ fun DetailedEvaluation( } } -@OptIn(ExperimentalLayoutApi::class) @Composable fun EditableEvaluation( editableEvaluationState: EditableEvaluationState, @@ -436,7 +435,7 @@ fun EditableGradeMark( }, supportingContent = { Text( - text = "${String.format("%.0f", grade.weight)}%" + text = "${String.format(Locale.getDefault(), "%.0f", grade.weight)}%" ) }, trailingContent = { @@ -452,7 +451,7 @@ fun EditableGradeMark( }, placeholder = { Text( - text = String.format("%.2f", neededMark) + text = String.format(Locale.getDefault(), "%.2f", neededMark) ) }, modifier = Modifier.width(80.dp), @@ -595,7 +594,7 @@ fun AddEvaluationDialog( onExpandedChange = { subjectsMenuExpanded = !subjectsMenuExpanded } ) { OutlinedTextField( - modifier = Modifier.menuAnchor(), + modifier = Modifier.menuAnchor(MenuAnchorType.PrimaryNotEditable), value = subjects.find { it.id == subjectId }?.nom ?: "", onValueChange = {}, readOnly = true, diff --git a/app/src/main/java/com/yara/raco/ui/components/RacoMainNavHost.kt b/app/src/main/java/com/yara/raco/ui/components/RacoMainNavHost.kt index 71ccad0..d8b5a59 100644 --- a/app/src/main/java/com/yara/raco/ui/components/RacoMainNavHost.kt +++ b/app/src/main/java/com/yara/raco/ui/components/RacoMainNavHost.kt @@ -5,7 +5,6 @@ import androidx.compose.animation.Crossfade import androidx.compose.animation.core.tween import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut -import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize @@ -13,8 +12,10 @@ import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.pager.PagerState import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.material3.CircularProgressIndicator -import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Text +import androidx.compose.material3.pulltorefresh.PullToRefreshBox +import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState @@ -25,7 +26,6 @@ import androidx.compose.runtime.produceState import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource @@ -39,9 +39,6 @@ import com.yara.raco.R import com.yara.raco.model.evaluation.EvaluationWithGrades import com.yara.raco.model.notices.NoticeWithFiles import com.yara.raco.ui.RacoScreen -import com.yara.raco.ui.components.pullrefresh.PullRefreshIndicator -import com.yara.raco.ui.components.pullrefresh.pullRefresh -import com.yara.raco.ui.components.pullrefresh.rememberPullRefreshState import com.yara.raco.ui.viewmodel.RacoViewModel import com.yara.raco.utils.Result import kotlinx.coroutines.launch @@ -52,7 +49,6 @@ data class DetailsUiState( val throwError: Boolean = false ) -@OptIn(ExperimentalFoundationApi::class) @Composable fun RacoMainNavHost( navHostController: NavHostController, @@ -337,25 +333,19 @@ fun RacoMainNavHost( } } +@OptIn(ExperimentalMaterial3Api::class) @Composable fun RacoSwipeRefresh( isRefreshing: Boolean, onRefresh: () -> Unit, content: @Composable () -> Unit ) { - val pullRefreshState = rememberPullRefreshState( - refreshing = isRefreshing, - onRefresh = onRefresh - ) - - Box(modifier = Modifier.pullRefresh(pullRefreshState)) { - content() + val pullRefreshState = rememberPullToRefreshState() - PullRefreshIndicator( - refreshing = isRefreshing, - state = pullRefreshState, - contentColor = MaterialTheme.colorScheme.primary, - modifier = Modifier.align(Alignment.TopCenter) - ) - } + PullToRefreshBox( + state = pullRefreshState, + onRefresh = onRefresh, + isRefreshing = isRefreshing, + content = { content() } + ) } \ No newline at end of file diff --git a/app/src/main/java/com/yara/raco/ui/components/RacoMainScreen.kt b/app/src/main/java/com/yara/raco/ui/components/RacoMainScreen.kt index 217ed5a..c085978 100644 --- a/app/src/main/java/com/yara/raco/ui/components/RacoMainScreen.kt +++ b/app/src/main/java/com/yara/raco/ui/components/RacoMainScreen.kt @@ -1,8 +1,6 @@ package com.yara.raco.ui.components import android.content.Intent -import androidx.compose.foundation.ExperimentalFoundationApi -import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.padding import androidx.compose.foundation.pager.rememberPagerState @@ -52,11 +50,7 @@ import java.time.temporal.TemporalAdjusters import java.time.temporal.WeekFields import java.util.Locale -@OptIn( - ExperimentalMaterial3Api::class, - ExperimentalLayoutApi::class, - ExperimentalFoundationApi::class -) +@OptIn(ExperimentalMaterial3Api::class) @Composable fun RacoMainScreen( racoViewModel: RacoViewModel, @@ -177,7 +171,7 @@ fun RacoMainScreen( else -> null } - val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior( + val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior( rememberTopAppBarState() ) diff --git a/app/src/main/java/com/yara/raco/ui/components/RacoMainTopAppBar.kt b/app/src/main/java/com/yara/raco/ui/components/RacoMainTopAppBar.kt index 1b342f5..6be2629 100644 --- a/app/src/main/java/com/yara/raco/ui/components/RacoMainTopAppBar.kt +++ b/app/src/main/java/com/yara/raco/ui/components/RacoMainTopAppBar.kt @@ -4,7 +4,7 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.statusBars import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.filled.MoreVert import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenuItem @@ -12,17 +12,19 @@ import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.RichTooltipBox +import androidx.compose.material3.PlainTooltip import androidx.compose.material3.Text +import androidx.compose.material3.TooltipBox +import androidx.compose.material3.TooltipDefaults import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.TopAppBarScrollBehavior +import androidx.compose.material3.rememberTooltipState import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue -import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.res.stringResource import com.yara.raco.R @@ -49,7 +51,7 @@ fun RacoMainTopAppBar( if (onBackPress != null) { IconButton(onClick = onBackPress) { Icon( - imageVector = Icons.Default.ArrowBack, contentDescription = stringResource( + imageVector = Icons.AutoMirrored.Filled.ArrowBack, contentDescription = stringResource( id = R.string.back ) ) @@ -58,8 +60,12 @@ fun RacoMainTopAppBar( }, actions = { iconActions?.forEach { (imageVector, function) -> - RichTooltipBox(text = { Text(text = imageVector.second) }) { - IconButton(onClick = function, modifier = Modifier.tooltipAnchor()) { + TooltipBox( + positionProvider = TooltipDefaults.rememberRichTooltipPositionProvider(), + tooltip = { PlainTooltip { Text(text = imageVector.second) } }, + state = rememberTooltipState() + ) { + IconButton(onClick = function) { Icon( imageVector = imageVector.first, contentDescription = imageVector.second diff --git a/app/src/main/java/com/yara/raco/ui/components/RacoNoticeList.kt b/app/src/main/java/com/yara/raco/ui/components/RacoNoticeList.kt index e59efc8..493f03b 100644 --- a/app/src/main/java/com/yara/raco/ui/components/RacoNoticeList.kt +++ b/app/src/main/java/com/yara/raco/ui/components/RacoNoticeList.kt @@ -3,7 +3,6 @@ package com.yara.raco.ui.components import android.text.Html import android.text.format.DateUtils import android.text.format.Formatter.formatShortFileSize -import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box @@ -28,7 +27,7 @@ import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.AttachFile import androidx.compose.material.icons.outlined.Description -import androidx.compose.material3.Divider +import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.ListItem import androidx.compose.material3.LocalContentColor @@ -38,6 +37,7 @@ import androidx.compose.material3.OutlinedCard import androidx.compose.material3.ScrollableTabRow import androidx.compose.material3.Tab import androidx.compose.material3.TabPosition +import androidx.compose.material3.TabRowDefaults.tabIndicatorOffset import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -69,14 +69,12 @@ import com.yara.raco.model.notices.Notice import com.yara.raco.model.notices.NoticeWithFiles import com.yara.raco.model.subject.Subject import com.yara.raco.ui.components.htmltext.HtmlText -import com.yara.raco.ui.components.pager.pagerTabIndicatorOffset import com.yara.raco.ui.theme.RacoTheme import kotlinx.coroutines.launch import java.text.SimpleDateFormat import java.util.Date import java.util.Locale -@OptIn(ExperimentalFoundationApi::class) @Composable fun RacoNoticeTabs( subjects: List, @@ -86,7 +84,7 @@ fun RacoNoticeTabs( val indicator = @Composable { tabPositions: List -> Spacer( Modifier - .pagerTabIndicatorOffset(pagerState, tabPositions) + .tabIndicatorOffset(tabPositions[pagerState.currentPage]) .padding(horizontal = 12.dp) .height(3.dp) .background( @@ -97,7 +95,7 @@ fun RacoNoticeTabs( } Box(modifier = modifier.fillMaxWidth(), contentAlignment = BottomCenter) { - Divider(modifier = Modifier.fillMaxWidth()) + HorizontalDivider(modifier = Modifier.fillMaxWidth()) ScrollableTabRow( selectedTabIndex = pagerState.currentPage, @@ -134,7 +132,6 @@ fun RacoNoticeTabs( } } -@OptIn(ExperimentalFoundationApi::class) @Composable fun RacoNoticePager( showAllNoticesSelected: Boolean, @@ -166,7 +163,6 @@ fun RacoNoticePager( } } -@OptIn(ExperimentalFoundationApi::class) @Composable fun RacoNoticeList( noticesWithFiles: List, @@ -190,12 +186,12 @@ fun RacoNoticeList( key = { _, noticeWithFiles -> noticeWithFiles.notice.id } ) { index, noticeWithFiles -> if (index != 0) { - Divider() + HorizontalDivider() } NoticeListEntry( noticeWithFiles = noticeWithFiles, onNoticeClick = onNoticeClick, - modifier = Modifier.animateItemPlacement() + modifier = Modifier.animateItem() ) } } else { diff --git a/app/src/main/java/com/yara/raco/ui/components/RacoSchedule.kt b/app/src/main/java/com/yara/raco/ui/components/RacoSchedule.kt index 0adbc6c..281dc0e 100644 --- a/app/src/main/java/com/yara/raco/ui/components/RacoSchedule.kt +++ b/app/src/main/java/com/yara/raco/ui/components/RacoSchedule.kt @@ -1,6 +1,5 @@ package com.yara.raco.ui.components -import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.horizontalScroll @@ -26,7 +25,7 @@ import androidx.compose.foundation.text.appendInlineContent import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.LocationOn -import androidx.compose.material3.Divider +import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.MaterialTheme @@ -513,7 +512,7 @@ fun Schedule( ) } } - Divider() + HorizontalDivider() Row( modifier = Modifier .weight(1f) @@ -781,7 +780,6 @@ fun ScheduleEventDetailsDialog( } -@OptIn(ExperimentalFoundationApi::class) @Composable fun RacoScheduleDay( schedules: List, @@ -869,7 +867,6 @@ fun RacoScheduleDay( } } -@OptIn(ExperimentalFoundationApi::class) @Composable fun RacoScheduleWeek( schedules: List, diff --git a/app/src/main/java/com/yara/raco/ui/components/htmltext/HtmlText.kt b/app/src/main/java/com/yara/raco/ui/components/htmltext/HtmlText.kt index 6924464..272a09d 100644 --- a/app/src/main/java/com/yara/raco/ui/components/htmltext/HtmlText.kt +++ b/app/src/main/java/com/yara/raco/ui/components/htmltext/HtmlText.kt @@ -23,6 +23,7 @@ import android.text.style.* import androidx.compose.foundation.gestures.detectTapGestures import androidx.compose.foundation.layout.Box import androidx.compose.foundation.text.InlineTextContent +import androidx.compose.material3.LocalContentColor import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text @@ -31,6 +32,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.text.* @@ -41,6 +43,7 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.TextUnit +import androidx.core.graphics.ColorUtils import androidx.core.text.getSpans /** @@ -85,9 +88,11 @@ fun HtmlText( onTextLayout: (TextLayoutResult) -> Unit = {}, style: TextStyle = LocalTextStyle.current ) { + val backgroundColor = MaterialTheme.colorScheme.background + val contentColor = if (color == Color.Unspecified) LocalContentColor.current else color val annotatedString = remember { Html.fromHtml(text, Html.FROM_HTML_MODE_LEGACY) - .toAnnotatedString(urlSpanStyle, colorMapping) + .toAnnotatedString(urlSpanStyle, colorMapping, contentColor, backgroundColor) } val uriHandler = LocalUriHandler.current @@ -144,7 +149,9 @@ fun Spanned.toAnnotatedString( color = Color.Blue, textDecoration = TextDecoration.Underline ), - colorMapping: Map = emptyMap() + colorMapping: Map = emptyMap(), + contentColor: Color, + backgroundColor: Color ): AnnotatedString { return buildAnnotatedString { append(this@toAnnotatedString.toString()) @@ -160,12 +167,14 @@ fun Spanned.toAnnotatedString( addStringAnnotation("url", urlSpan.url, start, end) // NON-NLS } colorSpans.forEach { colorSpan -> + val originalColor = Color(colorSpan.foregroundColor) + val contrast = ColorUtils.calculateContrast(originalColor.toArgb(), backgroundColor.toArgb()) + val definitiveColor = if (contrast < 4.5) contentColor else originalColor + val start = getSpanStart(colorSpan) val end = getSpanEnd(colorSpan) addStyle(SpanStyle(color = colorMapping.getOrElse(Color(colorSpan.foregroundColor)) { - Color( - colorSpan.foregroundColor - ) + definitiveColor }), start, end) } styleSpans.forEach { styleSpan -> diff --git a/app/src/main/java/com/yara/raco/ui/components/pager/PagerTab.kt b/app/src/main/java/com/yara/raco/ui/components/pager/PagerTab.kt deleted file mode 100644 index ed3882d..0000000 --- a/app/src/main/java/com/yara/raco/ui/components/pager/PagerTab.kt +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2021 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 - * - * https://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.yara.raco.ui.components.pager - -import androidx.compose.foundation.ExperimentalFoundationApi -import androidx.compose.foundation.pager.PagerState -import androidx.compose.material3.TabPosition -import androidx.compose.ui.Modifier -import androidx.compose.ui.layout.layout -import androidx.compose.ui.unit.Constraints -import androidx.compose.ui.unit.lerp - -@ExperimentalFoundationApi -fun Modifier.pagerTabIndicatorOffset( - pagerState: PagerState, - tabPositions: List, - pageIndexMapping: (Int) -> Int = { it }, -): Modifier = layout { measurable, constraints -> - if (tabPositions.isEmpty()) { - // If there are no pages, nothing to show - layout(constraints.maxWidth, 0) {} - } else { - val currentPage = minOf(tabPositions.lastIndex, pageIndexMapping(pagerState.currentPage)) - val currentTab = tabPositions[currentPage] - val previousTab = tabPositions.getOrNull(currentPage - 1) - val nextTab = tabPositions.getOrNull(currentPage + 1) - val fraction = pagerState.currentPageOffsetFraction - val indicatorWidth = if (fraction > 0 && nextTab != null) { - lerp(currentTab.width, nextTab.width, fraction).roundToPx() - } else if (fraction < 0 && previousTab != null) { - lerp(currentTab.width, previousTab.width, -fraction).roundToPx() - } else { - currentTab.width.roundToPx() - } - val indicatorOffset = if (fraction > 0 && nextTab != null) { - lerp(currentTab.left, nextTab.left, fraction).roundToPx() - } else if (fraction < 0 && previousTab != null) { - lerp(currentTab.left, previousTab.left, -fraction).roundToPx() - } else { - currentTab.left.roundToPx() - } - val placeable = measurable.measure( - Constraints( - minWidth = indicatorWidth, - maxWidth = indicatorWidth, - minHeight = 0, - maxHeight = constraints.maxHeight - ) - ) - layout(constraints.maxWidth, maxOf(placeable.height, constraints.minHeight)) { - placeable.placeRelative( - indicatorOffset, - maxOf(constraints.minHeight - placeable.height, 0) - ) - } - } -} diff --git a/app/src/main/java/com/yara/raco/ui/components/pullrefresh/PullRefresh.kt b/app/src/main/java/com/yara/raco/ui/components/pullrefresh/PullRefresh.kt deleted file mode 100644 index bae2f14..0000000 --- a/app/src/main/java/com/yara/raco/ui/components/pullrefresh/PullRefresh.kt +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright 2022 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.yara.raco.ui.components.pullrefresh - -import androidx.compose.ui.Modifier -import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.input.nestedscroll.NestedScrollConnection -import androidx.compose.ui.input.nestedscroll.NestedScrollSource -import androidx.compose.ui.input.nestedscroll.NestedScrollSource.Companion.Drag -import androidx.compose.ui.input.nestedscroll.nestedScroll -import androidx.compose.ui.platform.debugInspectorInfo -import androidx.compose.ui.platform.inspectable -import androidx.compose.ui.unit.Velocity - -/** - * A nested scroll modifier that provides scroll events to [state]. - * - * Note that this modifier must be added above a scrolling container, such as a lazy column, in - * order to receive scroll events. For example: - * - * @param state The [PullRefreshState] associated with this pull-to-refresh component. - * The state will be updated by this modifier. - * @param enabled If not enabled, all scroll delta and fling velocity will be ignored. - */ -fun Modifier.pullRefresh( - state: PullRefreshState, - enabled: Boolean = true -) = inspectable(inspectorInfo = debugInspectorInfo { - name = "pullRefresh" - properties["state"] = state - properties["enabled"] = enabled -}) { - Modifier.pullRefresh(state::onPull, state::onRelease, enabled) -} - -/** - * A nested scroll modifier that provides [onPull] and [onRelease] callbacks to aid building custom - * pull refresh components. - * - * Note that this modifier must be added above a scrolling container, such as a lazy column, in - * order to receive scroll events. For example: - * - * @param onPull Callback for dispatching vertical scroll delta, takes float pullDelta as argument. - * Positive delta (pulling down) is dispatched only if the child does not consume it (i.e. pulling - * down despite being at the top of a scrollable component), whereas negative delta (swiping up) is - * dispatched first (in case it is needed to push the indicator back up), and then the unconsumed - * delta is passed on to the child. The callback returns how much delta was consumed. - * @param onRelease Callback for when drag is released, takes float flingVelocity as argument. - * The callback returns how much velocity was consumed - in most cases this should only consume - * velocity if pull refresh has been dragged already and the velocity is positive (the fling is - * downwards), as an upwards fling should typically still scroll a scrollable component beneath the - * pullRefresh. This is invoked before any remaining velocity is passed to the child. - * @param enabled If not enabled, all scroll delta and fling velocity will be ignored and neither - * [onPull] nor [onRelease] will be invoked. - */ -fun Modifier.pullRefresh( - onPull: (pullDelta: Float) -> Float, - onRelease: suspend (flingVelocity: Float) -> Float, - enabled: Boolean = true -) = inspectable(inspectorInfo = debugInspectorInfo { - name = "pullRefresh" - properties["onPull"] = onPull - properties["onRelease"] = onRelease - properties["enabled"] = enabled -}) { - Modifier.nestedScroll(PullRefreshNestedScrollConnection(onPull, onRelease, enabled)) -} - -private class PullRefreshNestedScrollConnection( - private val onPull: (pullDelta: Float) -> Float, - private val onRelease: suspend (flingVelocity: Float) -> Float, - private val enabled: Boolean -) : NestedScrollConnection { - - override fun onPreScroll( - available: Offset, - source: NestedScrollSource - ): Offset = when { - !enabled -> Offset.Zero - source == Drag && available.y < 0 -> Offset(0f, onPull(available.y)) // Swiping up - else -> Offset.Zero - } - - override fun onPostScroll( - consumed: Offset, - available: Offset, - source: NestedScrollSource - ): Offset = when { - !enabled -> Offset.Zero - source == Drag && available.y > 0 -> Offset(0f, onPull(available.y)) // Pulling down - else -> Offset.Zero - } - - override suspend fun onPreFling(available: Velocity): Velocity { - return Velocity(0f, onRelease(available.y)) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/yara/raco/ui/components/pullrefresh/PullRefreshIndicator.kt b/app/src/main/java/com/yara/raco/ui/components/pullrefresh/PullRefreshIndicator.kt deleted file mode 100644 index 3f3b63b..0000000 --- a/app/src/main/java/com/yara/raco/ui/components/pullrefresh/PullRefreshIndicator.kt +++ /dev/null @@ -1,243 +0,0 @@ -/* - * Copyright 2022 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.yara.raco.ui.components.pullrefresh - -import androidx.compose.animation.Crossfade -import androidx.compose.animation.core.LinearEasing -import androidx.compose.animation.core.animateFloatAsState -import androidx.compose.animation.core.tween -import androidx.compose.foundation.Canvas -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.shape.CircleShape -import androidx.compose.material3.CircularProgressIndicator -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.contentColorFor -import androidx.compose.material3.surfaceColorAtElevation -import androidx.compose.runtime.Composable -import androidx.compose.runtime.Immutable -import androidx.compose.runtime.derivedStateOf -import androidx.compose.runtime.getValue -import androidx.compose.runtime.remember -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.shadow -import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.geometry.Rect -import androidx.compose.ui.geometry.center -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.Path -import androidx.compose.ui.graphics.PathFillType -import androidx.compose.ui.graphics.StrokeCap -import androidx.compose.ui.graphics.drawscope.DrawScope -import androidx.compose.ui.graphics.drawscope.Stroke -import androidx.compose.ui.graphics.drawscope.rotate -import androidx.compose.ui.semantics.semantics -import androidx.compose.ui.unit.dp -import kotlin.math.abs -import kotlin.math.max -import kotlin.math.min -import kotlin.math.pow - -/** - * The default indicator for Compose pull-to-refresh, based on Android's SwipeRefreshLayout. - * - * @param refreshing A boolean representing whether a refresh is occurring. - * @param state The [PullRefreshState] which controls where and how the indicator will be drawn. - * @param modifier Modifiers for the indicator. - * @param backgroundColor The color of the indicator's background. - * @param contentColor The color of the indicator's arc and arrow. - * @param scale A boolean controlling whether the indicator's size scales with pull progress or not. - */ -@Composable -fun PullRefreshIndicator( - refreshing: Boolean, - state: PullRefreshState, - modifier: Modifier = Modifier, - backgroundColor: Color = MaterialTheme.colorScheme.surface, - contentColor: Color = contentColorFor(backgroundColor), - scale: Boolean = false -) { - val showElevation by remember(refreshing, state) { - derivedStateOf { refreshing || state.position > 0.5f } - } - - // Apply an elevation overlay if needed. Note that we aren't using Surface here, as we do not - // want its input-blocking behaviour, since the indicator is typically displayed above other - // (possibly) interactive content. - val color = MaterialTheme.colorScheme.surfaceColorAtElevation(Elevation) - - Box( - modifier = modifier - .size(IndicatorSize) - .pullRefreshIndicatorTransform(state, scale) - .shadow(if (showElevation) Elevation else 0.dp, SpinnerShape, clip = true) - .background(color = color, shape = SpinnerShape) - ) { - Crossfade( - targetState = refreshing, - animationSpec = tween(durationMillis = CrossfadeDurationMs), label = "refreshing" - ) { refreshing -> - Box( - modifier = Modifier.fillMaxSize(), - contentAlignment = Alignment.Center - ) { - val spinnerSize = (ArcRadius + StrokeWidth).times(2) - - if (refreshing) { - CircularProgressIndicator( - color = contentColor, - strokeWidth = StrokeWidth, - modifier = Modifier.size(spinnerSize), - ) - } else { - CircularArrowIndicator(state, contentColor, Modifier.size(spinnerSize)) - } - } - } - } -} - -/** - * Modifier.size MUST be specified. - */ -@Composable -private fun CircularArrowIndicator( - state: PullRefreshState, - color: Color, - modifier: Modifier, -) { - val path = remember { Path().apply { fillType = PathFillType.EvenOdd } } - - val targetAlpha by remember(state) { - derivedStateOf { - if (state.progress >= 1f) MaxAlpha else MinAlpha - } - } - - val alphaState = animateFloatAsState( - targetValue = targetAlpha, animationSpec = AlphaTween, - label = "alpha" - ) - - // Empty semantics for tests - Canvas(modifier.semantics {}) { - val values = ArrowValues(state.progress) - val alpha = alphaState.value - - rotate(degrees = values.rotation) { - val arcRadius = ArcRadius.toPx() + StrokeWidth.toPx() / 2f - val arcBounds = Rect( - size.center.x - arcRadius, - size.center.y - arcRadius, - size.center.x + arcRadius, - size.center.y + arcRadius - ) - drawArc( - color = color, - alpha = alpha, - startAngle = values.startAngle, - sweepAngle = values.endAngle - values.startAngle, - useCenter = false, - topLeft = arcBounds.topLeft, - size = arcBounds.size, - style = Stroke( - width = StrokeWidth.toPx(), - cap = StrokeCap.Square - ) - ) - drawArrow(path, arcBounds, color, alpha, values) - } - } -} - -@Immutable -private class ArrowValues( - val rotation: Float, - val startAngle: Float, - val endAngle: Float, - val scale: Float -) - -private fun ArrowValues(progress: Float): ArrowValues { - // Discard first 40% of progress. Scale remaining progress to full range between 0 and 100%. - val adjustedPercent = max(min(1f, progress) - 0.4f, 0f) * 5 / 3 - // How far beyond the threshold pull has gone, as a percentage of the threshold. - val overshootPercent = abs(progress) - 1.0f - // Limit the overshoot to 200%. Linear between 0 and 200. - val linearTension = overshootPercent.coerceIn(0f, 2f) - // Non-linear tension. Increases with linearTension, but at a decreasing rate. - val tensionPercent = linearTension - linearTension.pow(2) / 4 - - // Calculations based on SwipeRefreshLayout specification. - val endTrim = adjustedPercent * MaxProgressArc - val rotation = (-0.25f + 0.4f * adjustedPercent + tensionPercent) * 0.5f - val startAngle = rotation * 360 - val endAngle = (rotation + endTrim) * 360 - val scale = min(1f, adjustedPercent) - - return ArrowValues(rotation, startAngle, endAngle, scale) -} - -private fun DrawScope.drawArrow( - arrow: Path, - bounds: Rect, - color: Color, - alpha: Float, - values: ArrowValues -) { - arrow.reset() - arrow.moveTo(0f, 0f) // Move to left corner - arrow.lineTo(x = ArrowWidth.toPx() * values.scale, y = 0f) // Line to right corner - - // Line to tip of arrow - arrow.lineTo( - x = ArrowWidth.toPx() * values.scale / 2, - y = ArrowHeight.toPx() * values.scale - ) - - val radius = min(bounds.width, bounds.height) / 2f - val inset = ArrowWidth.toPx() * values.scale / 2f - arrow.translate( - Offset( - x = radius + bounds.center.x - inset, - y = bounds.center.y + StrokeWidth.toPx() / 2f - ) - ) - arrow.close() - rotate(degrees = values.endAngle) { - drawPath(path = arrow, color = color, alpha = alpha) - } -} - -private const val CrossfadeDurationMs = 100 -private const val MaxProgressArc = 0.8f - -private val IndicatorSize = 40.dp -private val SpinnerShape = CircleShape -private val ArcRadius = 7.5.dp -private val StrokeWidth = 2.5.dp -private val ArrowWidth = 10.dp -private val ArrowHeight = 5.dp -private val Elevation = 6.dp - -// Values taken from SwipeRefreshLayout -private const val MinAlpha = 0.3f -private const val MaxAlpha = 1f -private val AlphaTween = tween(300, easing = LinearEasing) diff --git a/app/src/main/java/com/yara/raco/ui/components/pullrefresh/PullRefreshIndicatorTransform.kt b/app/src/main/java/com/yara/raco/ui/components/pullrefresh/PullRefreshIndicatorTransform.kt deleted file mode 100644 index 0397e47..0000000 --- a/app/src/main/java/com/yara/raco/ui/components/pullrefresh/PullRefreshIndicatorTransform.kt +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2022 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.yara.raco.ui.components.pullrefresh - -import androidx.compose.animation.core.LinearOutSlowInEasing -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.drawWithContent -import androidx.compose.ui.graphics.drawscope.clipRect -import androidx.compose.ui.graphics.graphicsLayer -import androidx.compose.ui.platform.debugInspectorInfo -import androidx.compose.ui.platform.inspectable - -/** - * A modifier for translating the position and scaling the size of a pull-to-refresh indicator - * based on the given [PullRefreshState]. - * - * @param state The [PullRefreshState] which determines the position of the indicator. - * @param scale A boolean controlling whether the indicator's size scales with pull progress or not. - */ -fun Modifier.pullRefreshIndicatorTransform( - state: PullRefreshState, - scale: Boolean = false, -) = inspectable(inspectorInfo = debugInspectorInfo { - name = "pullRefreshIndicatorTransform" - properties["state"] = state - properties["scale"] = scale -}) { - Modifier - // Essentially we only want to clip the at the top, so the indicator will not appear when - // the position is 0. It is preferable to clip the indicator as opposed to the layout that - // contains the indicator, as this would also end up clipping shadows drawn by items in a - // list for example - so we leave the clipping to the scrolling container. We use MAX_VALUE - // for the other dimensions to allow for more room for elevation / arbitrary indicators - we - // only ever really want to clip at the top edge. - .drawWithContent { - clipRect( - top = 0f, - left = -Float.MAX_VALUE, - right = Float.MAX_VALUE, - bottom = Float.MAX_VALUE - ) { - this@drawWithContent.drawContent() - } - } - .graphicsLayer { - translationY = state.position - size.height - - if (scale && !state.refreshing) { - val scaleFraction = LinearOutSlowInEasing - .transform(state.position / state.threshold) - .coerceIn(0f, 1f) - scaleX = scaleFraction - scaleY = scaleFraction - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/yara/raco/ui/components/pullrefresh/PullRefreshState.kt b/app/src/main/java/com/yara/raco/ui/components/pullrefresh/PullRefreshState.kt deleted file mode 100644 index 6d214f1..0000000 --- a/app/src/main/java/com/yara/raco/ui/components/pullrefresh/PullRefreshState.kt +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright 2022 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.yara.raco.ui.components.pullrefresh - -import androidx.compose.animation.core.animate -import androidx.compose.foundation.MutatorMutex -import androidx.compose.runtime.Composable -import androidx.compose.runtime.SideEffect -import androidx.compose.runtime.State -import androidx.compose.runtime.derivedStateOf -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableFloatStateOf -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.rememberUpdatedState -import androidx.compose.runtime.setValue -import androidx.compose.ui.platform.LocalDensity -import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.dp -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.launch -import kotlin.math.abs -import kotlin.math.pow - -/** - * Creates a [PullRefreshState] that is remembered across compositions. - * - * Changes to [refreshing] will result in [PullRefreshState] being updated. - * - * @param refreshing A boolean representing whether a refresh is currently occurring. - * @param onRefresh The function to be called to trigger a refresh. - * @param refreshThreshold The threshold below which, if a release - * occurs, [onRefresh] will be called. - * @param refreshingOffset The offset at which the indicator will be drawn while refreshing. This - * offset corresponds to the position of the bottom of the indicator. - */ -@Composable -fun rememberPullRefreshState( - refreshing: Boolean, - onRefresh: () -> Unit, - refreshThreshold: Dp = PullRefreshDefaults.RefreshThreshold, - refreshingOffset: Dp = PullRefreshDefaults.RefreshingOffset, -): PullRefreshState { - require(refreshThreshold > 0.dp) { "The refresh trigger must be greater than zero!" } - - val scope = rememberCoroutineScope() - val onRefreshState = rememberUpdatedState(onRefresh) - val thresholdPx: Float - val refreshingOffsetPx: Float - - with(LocalDensity.current) { - thresholdPx = refreshThreshold.toPx() - refreshingOffsetPx = refreshingOffset.toPx() - } - - val state = remember(scope) { - PullRefreshState(scope, onRefreshState, refreshingOffsetPx, thresholdPx) - } - - SideEffect { - state.setRefreshing(refreshing) - state.setThreshold(thresholdPx) - state.setRefreshingOffset(refreshingOffsetPx) - } - - return state -} - -/** - * A state object that can be used in conjunction with [pullRefresh] to add pull-to-refresh - * behaviour to a scroll component. Based on Android's SwipeRefreshLayout. - * - * Provides [progress], a float representing how far the user has pulled as a percentage of the - * refreshThreshold. Values of one or less indicate that the user has not yet pulled past the - * threshold. Values greater than one indicate how far past the threshold the user has pulled. - * - * Can be used in conjunction with [pullRefreshIndicatorTransform] to implement Android-like - * pull-to-refresh behaviour with a custom indicator. - * - * Should be created using [rememberPullRefreshState]. - */ -class PullRefreshState internal constructor( - private val animationScope: CoroutineScope, - private val onRefreshState: State<() -> Unit>, - refreshingOffset: Float, - threshold: Float -) { - /** - * A float representing how far the user has pulled as a percentage of the refreshThreshold. - * - * If the component has not been pulled at all, progress is zero. If the pull has reached - * halfway to the threshold, progress is 0.5f. A value greater than 1 indicates that pull has - * gone beyond the refreshThreshold - e.g. a value of 2f indicates that the user has pulled to - * two times the refreshThreshold. - */ - val progress get() = adjustedDistancePulled / threshold - - internal val refreshing get() = _refreshing - internal val position get() = _position - internal val threshold get() = _threshold - - private val adjustedDistancePulled by derivedStateOf { distancePulled * DragMultiplier } - - private var _refreshing by mutableStateOf(false) - private var _position by mutableFloatStateOf(0f) - private var distancePulled by mutableFloatStateOf(0f) - private var _threshold by mutableFloatStateOf(threshold) - private var _refreshingOffset by mutableFloatStateOf(refreshingOffset) - - internal fun onPull(pullDelta: Float): Float { - if (_refreshing) return 0f // Already refreshing, do nothing. - - val newOffset = (distancePulled + pullDelta).coerceAtLeast(0f) - val dragConsumed = newOffset - distancePulled - distancePulled = newOffset - _position = calculateIndicatorPosition() - return dragConsumed - } - - internal fun onRelease(velocity: Float): Float { - if (refreshing) return 0f // Already refreshing, do nothing - - if (adjustedDistancePulled > threshold) { - onRefreshState.value() - } - animateIndicatorTo(0f) - val consumed = when { - // We are flinging without having dragged the pull refresh (for example a fling inside - // a list) - don't consume - distancePulled == 0f -> 0f - // If the velocity is negative, the fling is upwards, and we don't want to prevent the - // the list from scrolling - velocity < 0f -> 0f - // We are showing the indicator, and the fling is downwards - consume everything - else -> velocity - } - distancePulled = 0f - return consumed - } - - internal fun setRefreshing(refreshing: Boolean) { - if (_refreshing != refreshing) { - _refreshing = refreshing - distancePulled = 0f - animateIndicatorTo(if (refreshing) _refreshingOffset else 0f) - } - } - - internal fun setThreshold(threshold: Float) { - _threshold = threshold - } - - internal fun setRefreshingOffset(refreshingOffset: Float) { - if (_refreshingOffset != refreshingOffset) { - _refreshingOffset = refreshingOffset - if (refreshing) animateIndicatorTo(refreshingOffset) - } - } - - // Make sure to cancel any existing animations when we launch a new one. We use this instead of - // Animatable as calling snapTo() on every drag delta has a one frame delay, and some extra - // overhead of running through the animation pipeline instead of directly mutating the state. - private val mutatorMutex = MutatorMutex() - - private fun animateIndicatorTo(offset: Float) = animationScope.launch { - mutatorMutex.mutate { - animate(initialValue = _position, targetValue = offset) { value, _ -> - _position = value - } - } - } - - private fun calculateIndicatorPosition(): Float = when { - // If drag hasn't gone past the threshold, the position is the adjustedDistancePulled. - adjustedDistancePulled <= threshold -> adjustedDistancePulled - else -> { - // How far beyond the threshold pull has gone, as a percentage of the threshold. - val overshootPercent = abs(progress) - 1.0f - // Limit the overshoot to 200%. Linear between 0 and 200. - val linearTension = overshootPercent.coerceIn(0f, 2f) - // Non-linear tension. Increases with linearTension, but at a decreasing rate. - val tensionPercent = linearTension - linearTension.pow(2) / 4 - // The additional offset beyond the threshold. - val extraOffset = threshold * tensionPercent - threshold + extraOffset - } - } -} - -/** - * Default parameter values for [rememberPullRefreshState]. - */ -object PullRefreshDefaults { - /** - * If the indicator is below this threshold offset when it is released, a refresh - * will be triggered. - */ - val RefreshThreshold = 80.dp - - /** - * The offset at which the indicator should be rendered whilst a refresh is occurring. - */ - val RefreshingOffset = 56.dp -} - -/** - * The distance pulled is multiplied by this value to give us the adjusted distance pulled, which - * is used in calculating the indicator position (when the adjusted distance pulled is less than - * the refresh threshold, it is the indicator position, otherwise the indicator position is - * derived from the progress). - */ -private const val DragMultiplier = 0.5f diff --git a/build.gradle b/build.gradle index 71ffefa..7912d7a 100644 --- a/build.gradle +++ b/build.gradle @@ -1,12 +1,12 @@ buildscript { ext { - room_version = '2.5.2' - ksp_version = '1.0.13' - kotlin_version = '1.9.10' + room_version = '2.6.1' + ksp_version = '1.0.20' + kotlin_version = '1.9.25' } }// Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { - id 'com.android.application' version '8.1.1' apply false - id 'com.android.library' version '8.1.1' apply false + id 'com.android.application' version '8.6.0' apply false + id 'com.android.library' version '8.6.0' apply false id 'org.jetbrains.kotlin.android' version "$kotlin_version" apply false } \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 15204a5..58c8be8 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Wed Oct 19 21:29:49 CEST 2022 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME From fc747c4c7f868718d7b0c2b1deda4e9c5fe4463e Mon Sep 17 00:00:00 2001 From: hegocre <15657088+hegocre@users.noreply.github.com> Date: Fri, 8 Aug 2025 11:54:25 +0200 Subject: [PATCH 2/2] Library and version updates --- .github/workflows/android.yml | 6 +- app/build.gradle | 66 +++++++++---------- .../main/java/com/yara/raco/api/EventsApi.kt | 6 +- .../main/java/com/yara/raco/api/NoticesApi.kt | 12 ++-- .../java/com/yara/raco/api/ScheduleApi.kt | 4 +- .../java/com/yara/raco/api/SemesterApi.kt | 12 ++-- .../java/com/yara/raco/api/SubjectsAPI.kt | 4 +- .../main/java/com/yara/raco/api/TokenApi.kt | 24 ++++--- .../com/yara/raco/database/RacoDatabase.kt | 2 +- .../main/java/com/yara/raco/ui/RacoScreen.kt | 2 +- .../yara/raco/ui/activities/MainActivity.kt | 5 +- .../raco/ui/components/RacoMainNavHost.kt | 2 +- .../yara/raco/ui/components/RacoSchedule.kt | 2 + .../main/java/com/yara/raco/ui/theme/Theme.kt | 4 -- app/src/main/java/com/yara/raco/utils/Json.kt | 1 - build.gradle | 27 +++++--- gradle.properties | 1 - gradle/wrapper/gradle-wrapper.properties | 2 +- settings.gradle | 8 +-- 19 files changed, 97 insertions(+), 93 deletions(-) diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index e285939..fa4559a 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Access CLIENT_ID env: CLIENT_ID: ${{ secrets.CLIENT_ID }} @@ -22,13 +22,13 @@ jobs: CLIENT_SECRET: ${{ secrets.CLIENT_SECRET }} run: echo CLIENT_SECRET=\"$CLIENT_SECRET\" >> ./apikey.properties - name: set up JDK 11 - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: java-version: '17' distribution: 'zulu' - name: Build with Gradle run: ./gradlew clean && ./gradlew assembleDebug - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: app-debug.apk path: app/build/outputs/apk/debug/app-debug.apk diff --git a/app/build.gradle b/app/build.gradle index 1b6018e..ce7f681 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,10 +1,17 @@ -import org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { id 'com.android.application' id 'kotlin-android' id 'com.google.devtools.ksp' version "$kotlin_version-$ksp_version" id 'org.jetbrains.kotlin.plugin.serialization' version "$kotlin_version" + id 'org.jetbrains.kotlin.plugin.compose' version "$kotlin_version" +} + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(17) + } } def apiKeyPropertiesFile = rootProject.file("apikey.properties") @@ -12,19 +19,19 @@ def apiKeyProperties = new Properties() apiKeyProperties.load(new FileInputStream(apiKeyPropertiesFile)) android { - namespace 'com.yara.raco' - compileSdk 34 + namespace = 'com.yara.raco' + compileSdk = 36 defaultConfig { applicationId "com.yara.raco" minSdk 26 - targetSdk 34 - versionCode 34 - versionName "1.0.7" + targetSdk 36 + versionCode 36 + versionName "1.0.8" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables { - useSupportLibrary true + useSupportLibrary = true } resourceConfigurations += ['ca', 'es', 'en'] @@ -50,7 +57,7 @@ android { buildTypes { release { minifyEnabled true - shrinkResources true + shrinkResources = true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } debug { @@ -58,18 +65,9 @@ android { applicationIdSuffix ".debug" } } - compileOptions { - sourceCompatibility JavaVersion.VERSION_17 - targetCompatibility JavaVersion.VERSION_17 - } - kotlinOptions { - jvmTarget = '17' - } buildFeatures { - compose true - } - composeOptions { - kotlinCompilerExtensionVersion '1.5.15' + compose = true + buildConfig = true } packagingOptions { resources { @@ -81,42 +79,42 @@ android { dependencies { //Android dependencies - implementation 'androidx.core:core-ktx:1.13.1' - implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.8.5' - implementation 'androidx.datastore:datastore-preferences:1.1.1' + implementation 'androidx.core:core-ktx:1.16.0' + implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.9.2' + implementation 'androidx.datastore:datastore-preferences:1.1.7' //Compose dependencies - implementation platform('androidx.compose:compose-bom:2024.09.00') + implementation platform('androidx.compose:compose-bom:2025.07.00') implementation "androidx.compose.ui:ui" implementation "androidx.compose.runtime:runtime-livedata" implementation "androidx.compose.ui:ui-tooling-preview" implementation 'androidx.compose.material:material-icons-extended' implementation 'androidx.compose.material3:material3' - implementation 'androidx.activity:activity-compose:1.9.2' - implementation 'androidx.navigation:navigation-compose:2.8.0' + implementation 'androidx.activity:activity-compose:1.10.1' + implementation 'androidx.navigation:navigation-compose:2.9.3' //Room dependencies implementation "androidx.room:room-ktx:$room_version" ksp "androidx.room:room-compiler:$room_version" - implementation 'androidx.work:work-runtime-ktx:2.9.1' + implementation 'androidx.work:work-runtime-ktx:2.10.3' - implementation 'com.squareup.okhttp3:okhttp:4.12.0' + implementation 'com.squareup.okhttp3:okhttp:5.1.0' - implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3' + implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0' //Debug and test implementations testImplementation 'junit:junit:4.13.2' - androidTestImplementation 'androidx.test.ext:junit:1.2.1' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1' - androidTestImplementation 'androidx.compose.ui:ui-test-junit4:1.7.0' - debugImplementation "androidx.compose.ui:ui-tooling:1.7.0" - debugImplementation "androidx.compose.ui:ui-test-manifest:1.7.0" + androidTestImplementation 'androidx.test.ext:junit:1.3.0' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.7.0' + androidTestImplementation 'androidx.compose.ui:ui-test-junit4:1.8.3' + debugImplementation "androidx.compose.ui:ui-tooling:1.8.3" + debugImplementation "androidx.compose.ui:ui-test-manifest:1.8.3" } // Compiler flag to use experimental Compose APIs -tasks.withType(KotlinCompilationTask).configureEach { +tasks.withType(KotlinCompile).configureEach { compilerOptions { freeCompilerArgs.addAll("-opt-in=kotlin.RequiresOptIn", "-Xjvm-default=all-compatibility") } diff --git a/app/src/main/java/com/yara/raco/api/EventsApi.kt b/app/src/main/java/com/yara/raco/api/EventsApi.kt index c55b9a7..4b91ed1 100644 --- a/app/src/main/java/com/yara/raco/api/EventsApi.kt +++ b/app/src/main/java/com/yara/raco/api/EventsApi.kt @@ -20,21 +20,21 @@ class EventsApi private constructor() { val status = response.code val body = withContext(Dispatchers.IO) { - response.body?.string() + response.body.string() } withContext(Dispatchers.IO) { response.close() } - if (status == 200 && body != null) { + if (status == 200) { val results = Json.decodeFromString(body).results Result.Success(results) } else { Result.Error(ResultCode.ERROR_API_BAD_REQUEST) } - } catch (e: Exception) { + } catch (_: Exception) { Result.Error(ResultCode.ERROR_API_BAD_REQUEST) } diff --git a/app/src/main/java/com/yara/raco/api/NoticesApi.kt b/app/src/main/java/com/yara/raco/api/NoticesApi.kt index b013d6b..aa7aead 100644 --- a/app/src/main/java/com/yara/raco/api/NoticesApi.kt +++ b/app/src/main/java/com/yara/raco/api/NoticesApi.kt @@ -3,7 +3,6 @@ package com.yara.raco.api import android.annotation.SuppressLint import android.app.DownloadManager import android.content.* -import android.net.Uri import android.os.Build import android.os.Environment import android.webkit.MimeTypeMap @@ -19,6 +18,7 @@ import com.yara.raco.utils.ResultCode import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import kotlinx.serialization.Serializable +import androidx.core.net.toUri class NoticesApi private constructor() { @@ -32,14 +32,14 @@ class NoticesApi private constructor() { val statusCode = response.code val body = withContext(Dispatchers.IO) { - response.body?.string() + response.body.string() } withContext(Dispatchers.IO) { response.close() } - if (statusCode == 200 && body != null) { + if (statusCode == 200) { val aux = Json.decodeFromString(body).results Result.Success(aux) } else { @@ -53,7 +53,7 @@ class NoticesApi private constructor() { @SuppressLint("UnspecifiedRegisterReceiverFlag") fun getAttachment(context: Context, file: File, accessToken: String) { - val request = DownloadManager.Request(Uri.parse(file.url)) + val request = DownloadManager.Request(file.url.toUri()) .setTitle(file.nom) .setMimeType(file.nom.getMime() ?: file.tipusMime) .setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, file.nom) @@ -81,7 +81,7 @@ class NoticesApi private constructor() { if (status == DownloadManager.STATUS_SUCCESSFUL) { columIndex = cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI) if (columIndex < 0) return - val filePath = Uri.parse(cursor.getString(columIndex)) + val filePath = cursor.getString(columIndex).toUri() columIndex = cursor.getColumnIndex(DownloadManager.COLUMN_MEDIA_TYPE) if (columIndex < 0) return @@ -100,7 +100,7 @@ class NoticesApi private constructor() { try { context.startActivity(intent) - } catch (e: ActivityNotFoundException) { + } catch (_: ActivityNotFoundException) { Toast.makeText( context, context.getString(R.string.cannot_open_file), diff --git a/app/src/main/java/com/yara/raco/api/ScheduleApi.kt b/app/src/main/java/com/yara/raco/api/ScheduleApi.kt index b888daa..150e77a 100644 --- a/app/src/main/java/com/yara/raco/api/ScheduleApi.kt +++ b/app/src/main/java/com/yara/raco/api/ScheduleApi.kt @@ -21,14 +21,14 @@ class ScheduleApi private constructor() { val statusCode = response.code val body = withContext(Dispatchers.IO) { - response.body?.string() + response.body.string() } withContext(Dispatchers.IO) { response.close() } - if (statusCode == 200 && body != null) { + if (statusCode == 200) { val aux = Json.decodeFromString(body).results Result.Success(aux) } else { diff --git a/app/src/main/java/com/yara/raco/api/SemesterApi.kt b/app/src/main/java/com/yara/raco/api/SemesterApi.kt index c681a99..a151315 100644 --- a/app/src/main/java/com/yara/raco/api/SemesterApi.kt +++ b/app/src/main/java/com/yara/raco/api/SemesterApi.kt @@ -21,21 +21,21 @@ class SemesterApi private constructor() { val statusCode = response.code val body = withContext(Dispatchers.IO) { - response.body?.string() + response.body.string() } withContext(Dispatchers.IO) { response.close() } - if (statusCode == 200 && body != null) { + if (statusCode == 200) { val id = Json.decodeFromString(body).id Result.Success(id) } else { Result.Error(ResultCode.ERROR_API_BAD_RESPONSE) } - } catch (e: Exception) { + } catch (_: Exception) { Result.Error(ResultCode.ERROR_API_BAD_REQUEST) } @@ -59,21 +59,21 @@ class SemesterApi private constructor() { val statusCode = response.code val body = withContext(Dispatchers.IO) { - response.body?.string() + response.body.string() } withContext(Dispatchers.IO) { response.close() } - if (statusCode == 200 && body != null) { + if (statusCode == 200) { val id = Json.decodeFromString(body).results Result.Success(id) } else { Result.Error(ResultCode.ERROR_API_BAD_RESPONSE) } - } catch (e: Exception) { + } catch (_: Exception) { Result.Error(ResultCode.ERROR_API_BAD_REQUEST) } } diff --git a/app/src/main/java/com/yara/raco/api/SubjectsAPI.kt b/app/src/main/java/com/yara/raco/api/SubjectsAPI.kt index 500cb66..279225a 100644 --- a/app/src/main/java/com/yara/raco/api/SubjectsAPI.kt +++ b/app/src/main/java/com/yara/raco/api/SubjectsAPI.kt @@ -23,14 +23,14 @@ class SubjectsAPI private constructor() { val statusCode = response.code val body = withContext(Dispatchers.IO) { - response.body?.string() + response.body.string() } withContext(Dispatchers.IO) { response.close() } - if (statusCode == 200 && body != null) { + if (statusCode == 200) { val aux = Json.decodeFromString(body).results Result.Success(aux) } diff --git a/app/src/main/java/com/yara/raco/api/TokenApi.kt b/app/src/main/java/com/yara/raco/api/TokenApi.kt index 8281e44..9b48ce3 100644 --- a/app/src/main/java/com/yara/raco/api/TokenApi.kt +++ b/app/src/main/java/com/yara/raco/api/TokenApi.kt @@ -26,20 +26,20 @@ class TokenApi private constructor() { val code = tokenResponse.code val body = withContext(Dispatchers.IO) { - tokenResponse.body?.string() + tokenResponse.body.string() } withContext(Dispatchers.IO) { tokenResponse.close() } - if (code == 200 && body != null) { + if (code == 200) { Result.Success(Json.decodeFromString(body)) } else { Result.Error(0) } - } catch (e: Exception) { + } catch (_: Exception) { Result.Error(1) } @@ -60,19 +60,23 @@ class TokenApi private constructor() { val code = tokenResponse.code val body = withContext(Dispatchers.IO) { - tokenResponse.body?.string() + tokenResponse.body.string() } withContext(Dispatchers.IO) { tokenResponse.close() } - if (code == 200 && body != null) { - Result.Success(Json.decodeFromString(body)) - } else if (code == 400) { - Result.Error(400) - } else { - Result.Error(0) + when (code) { + 200 -> { + Result.Success(Json.decodeFromString(body)) + } + 400 -> { + Result.Error(400) + } + else -> { + Result.Error(0) + } } } catch (e: Exception) { diff --git a/app/src/main/java/com/yara/raco/database/RacoDatabase.kt b/app/src/main/java/com/yara/raco/database/RacoDatabase.kt index a1c8e3b..027dab2 100644 --- a/app/src/main/java/com/yara/raco/database/RacoDatabase.kt +++ b/app/src/main/java/com/yara/raco/database/RacoDatabase.kt @@ -55,7 +55,7 @@ abstract class RacoDatabase : RoomDatabase() { RacoDatabase::class.java, "raco.db" ) - .fallbackToDestructiveMigration() + .fallbackToDestructiveMigration(false) .build() INSTANCE = instance diff --git a/app/src/main/java/com/yara/raco/ui/RacoScreen.kt b/app/src/main/java/com/yara/raco/ui/RacoScreen.kt index e10615f..4a60d73 100644 --- a/app/src/main/java/com/yara/raco/ui/RacoScreen.kt +++ b/app/src/main/java/com/yara/raco/ui/RacoScreen.kt @@ -12,7 +12,7 @@ import androidx.compose.ui.graphics.vector.ImageVector import com.yara.raco.R enum class RacoScreen( - @StringRes val title: Int, + @param:StringRes val title: Int, val selectedIcon: ImageVector, val unselectedIcon: ImageVector ) { diff --git a/app/src/main/java/com/yara/raco/ui/activities/MainActivity.kt b/app/src/main/java/com/yara/raco/ui/activities/MainActivity.kt index d5822ad..0c5d245 100644 --- a/app/src/main/java/com/yara/raco/ui/activities/MainActivity.kt +++ b/app/src/main/java/com/yara/raco/ui/activities/MainActivity.kt @@ -3,7 +3,6 @@ package com.yara.raco.ui.activities import android.Manifest import android.app.NotificationChannel import android.app.NotificationManager -import android.content.Context import android.content.Intent import android.content.pm.PackageManager import android.os.Build @@ -75,7 +74,7 @@ class MainActivity : ComponentActivity() { //Dismiss existing notifications val notificationManager = - getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + getSystemService(NOTIFICATION_SERVICE) as NotificationManager notificationManager.cancelAll() } @@ -85,7 +84,7 @@ class MainActivity : ComponentActivity() { val importance = NotificationManager.IMPORTANCE_DEFAULT val channel = NotificationChannel(name, name, importance) val notificationManager = - getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + getSystemService(NOTIFICATION_SERVICE) as NotificationManager notificationManager.createNotificationChannel(channel) notificationManager.cancelAll() diff --git a/app/src/main/java/com/yara/raco/ui/components/RacoMainNavHost.kt b/app/src/main/java/com/yara/raco/ui/components/RacoMainNavHost.kt index d8b5a59..72c57ed 100644 --- a/app/src/main/java/com/yara/raco/ui/components/RacoMainNavHost.kt +++ b/app/src/main/java/com/yara/raco/ui/components/RacoMainNavHost.kt @@ -309,7 +309,7 @@ fun RacoMainNavHost( try { racoViewModel.saveEvaluation(editableEvaluationState.getEvaluationWithGrades()) navHostController.popBackStack() - } catch (e: IllegalArgumentException) { + } catch (_: IllegalArgumentException) { Toast.makeText( context, context.getString(R.string.evaluation_invalid_arguments), diff --git a/app/src/main/java/com/yara/raco/ui/components/RacoSchedule.kt b/app/src/main/java/com/yara/raco/ui/components/RacoSchedule.kt index 281dc0e..d5fae99 100644 --- a/app/src/main/java/com/yara/raco/ui/components/RacoSchedule.kt +++ b/app/src/main/java/com/yara/raco/ui/components/RacoSchedule.kt @@ -1,5 +1,6 @@ package com.yara.raco.ui.components +import android.annotation.SuppressLint import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.horizontalScroll @@ -415,6 +416,7 @@ sealed class ScheduleSize { class Adaptive(val minSize: Dp) : ScheduleSize() } +@SuppressLint("UnusedBoxWithConstraintsScope") @Composable fun Schedule( scheduleEvents: List, diff --git a/app/src/main/java/com/yara/raco/ui/theme/Theme.kt b/app/src/main/java/com/yara/raco/ui/theme/Theme.kt index 175cf4d..1863824 100644 --- a/app/src/main/java/com/yara/raco/ui/theme/Theme.kt +++ b/app/src/main/java/com/yara/raco/ui/theme/Theme.kt @@ -6,9 +6,7 @@ import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.material3.* import androidx.compose.runtime.Composable import androidx.compose.runtime.SideEffect -import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.luminance -import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalView import androidx.core.view.WindowCompat.getInsetsController @@ -98,12 +96,10 @@ fun RacoTheme( if (!view.isInEditMode) { SideEffect { val window = (view.context as Activity).window - window.statusBarColor = Color.Transparent.toArgb() val insetsController = getInsetsController(window, view) insetsController.isAppearanceLightStatusBars = colorScheme.isLight() insetsController.isAppearanceLightNavigationBars = colorScheme.isLight() - window.navigationBarColor = Color.Transparent.toArgb() } } diff --git a/app/src/main/java/com/yara/raco/utils/Json.kt b/app/src/main/java/com/yara/raco/utils/Json.kt index 7997671..8450d27 100644 --- a/app/src/main/java/com/yara/raco/utils/Json.kt +++ b/app/src/main/java/com/yara/raco/utils/Json.kt @@ -1,6 +1,5 @@ package com.yara.raco.utils -import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json val json = Json { ignoreUnknownKeys = true } diff --git a/build.gradle b/build.gradle index 7912d7a..bfb53c9 100644 --- a/build.gradle +++ b/build.gradle @@ -1,12 +1,23 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { ext { - room_version = '2.6.1' - ksp_version = '1.0.20' - kotlin_version = '1.9.25' + kotlin_version = '2.2.0' + room_version = '2.7.2' + ksp_version = '2.0.2' } -}// Top-level build file where you can add configuration options common to all sub-projects/modules. -plugins { - id 'com.android.application' version '8.6.0' apply false - id 'com.android.library' version '8.6.0' apply false - id 'org.jetbrains.kotlin.android' version "$kotlin_version" apply false + repositories { + google() + mavenCentral() + } + dependencies { + classpath 'com.android.tools.build:gradle:8.12.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +tasks.register('clean', Delete) { + delete rootProject.layout.buildDirectory } \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 38f144c..8267388 100644 --- a/gradle.properties +++ b/gradle.properties @@ -21,6 +21,5 @@ kotlin.code.style=official # resources declared in the library itself and none from the library's dependencies, # thereby reducing the size of the R class for that library android.nonTransitiveRClass=true -android.defaults.buildfeatures.buildconfig=true android.nonFinalResIds=true org.gradle.unsafe.configuration-cache=true \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 58c8be8..874804c 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Wed Oct 19 21:29:49 CEST 2022 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME diff --git a/settings.gradle b/settings.gradle index 984bb71..8d07493 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,9 +1,5 @@ -pluginManagement { - repositories { - gradlePluginPortal() - google() - mavenCentral() - } +plugins { + id 'org.gradle.toolchains.foojay-resolver-convention' version '1.0.0' } dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)