diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml new file mode 100644 index 0000000..b268ef3 --- /dev/null +++ b/.idea/deploymentTargetSelector.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 68388f5..fbb9fc9 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -53,23 +53,22 @@ android { } dependencies { - implementation 'androidx.core:core-ktx:1.12.0' + implementation 'androidx.core:core-ktx:1.13.1' implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.7.0' - implementation 'androidx.activity:activity-compose:1.8.2' - implementation platform('androidx.compose:compose-bom:2024.04.00') - implementation "androidx.compose.ui:ui:1.6.5" - implementation "androidx.compose.ui:ui-tooling-preview:1.6.5" - implementation 'androidx.compose.material3:material3' - implementation platform('androidx.compose:compose-bom:2024.04.00') + implementation 'androidx.activity:activity-compose:1.9.0' + implementation platform('androidx.compose:compose-bom:2024.05.00') + implementation "androidx.compose.ui:ui:1.6.7" + implementation "androidx.compose.ui:ui-tooling-preview:1.6.7" + implementation platform('androidx.compose:compose-bom:2024.05.00') implementation 'androidx.compose.ui:ui-graphics' testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' - androidTestImplementation platform('androidx.compose:compose-bom:2024.04.00') - androidTestImplementation "androidx.compose.ui:ui-test-junit4:1.6.5" - androidTestImplementation platform('androidx.compose:compose-bom:2024.04.00') - debugImplementation "androidx.compose.ui:ui-tooling:1.6.5" - debugImplementation "androidx.compose.ui:ui-test-manifest:1.6.5" + androidTestImplementation platform('androidx.compose:compose-bom:2024.05.00') + androidTestImplementation "androidx.compose.ui:ui-test-junit4:1.6.7" + androidTestImplementation platform('androidx.compose:compose-bom:2024.05.00') + debugImplementation "androidx.compose.ui:ui-tooling:1.6.7" + debugImplementation "androidx.compose.ui:ui-test-manifest:1.6.7" implementation "androidx.appcompat:appcompat:1.6.1" implementation "androidx.appcompat:appcompat-resources:1.6.1" @@ -82,10 +81,10 @@ dependencies { runtimeOnly 'androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0' // https://mvnrepository.com/artifact/androidx.fragment/fragment-ktx - runtimeOnly 'androidx.fragment:fragment-ktx:1.7.0-rc01' + runtimeOnly 'androidx.fragment:fragment-ktx:1.7.0' // https://mvnrepository.com/artifact/androidx.compose.material3/material3 - runtimeOnly 'androidx.compose.material3:material3:1.2.1' + implementation 'androidx.compose.material3:material3:1.2.1' // AlarmManager for restart service after closed // Required to avoid crash on Android 12 - API 31 @@ -126,10 +125,12 @@ dependencies { implementation 'com.github.dutwrapper:dutwrapper-java:v1.9.0' - implementation 'com.google.android.material:material:1.11.0' + implementation 'com.google.android.material:material:1.12.0' // Display time ago in news subject implementation 'com.github.marlonlom:timeago:4.0.3' + + implementation 'androidx.core:core-splashscreen:1.2.0-alpha01' } // Allow references to generated code diff --git a/app/src/main/ic_launcher-playstore.png b/app/src/main/ic_launcher-playstore.png index 8842667..371c693 100644 Binary files a/app/src/main/ic_launcher-playstore.png and b/app/src/main/ic_launcher-playstore.png differ diff --git a/app/src/main/java/io/zoemeow/dutschedule/activity/BaseActivity.kt b/app/src/main/java/io/zoemeow/dutschedule/activity/BaseActivity.kt index d80cb98..89467a9 100644 --- a/app/src/main/java/io/zoemeow/dutschedule/activity/BaseActivity.kt +++ b/app/src/main/java/io/zoemeow/dutschedule/activity/BaseActivity.kt @@ -6,6 +6,7 @@ import android.graphics.Bitmap import android.net.Uri import android.os.Bundle import android.os.StrictMode +import android.window.SplashScreen import androidx.activity.ComponentActivity import androidx.activity.SystemBarStyle import androidx.activity.compose.setContent @@ -14,15 +15,18 @@ import androidx.browser.customtabs.CustomTabColorSchemeParams import androidx.browser.customtabs.CustomTabsIntent import androidx.compose.foundation.Image import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material3.MaterialTheme import androidx.compose.material3.SnackbarDuration import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.SnackbarResult +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusManager import androidx.compose.ui.graphics.Color @@ -32,6 +36,7 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.platform.SoftwareKeyboardController +import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewmodel.compose.viewModel import io.zoemeow.dutschedule.model.settings.BackgroundImageOption @@ -72,6 +77,11 @@ abstract class BaseActivity: ComponentActivity() { permitAllPolicy() setContent { + // Initialize MainViewModel + if (!isMainViewModelInitialized()) { + mainViewModel = viewModel() + } + // SnackBar state snackBarHostState = remember { SnackbarHostState() } snackBarScope = rememberCoroutineScope() @@ -80,11 +90,6 @@ abstract class BaseActivity: ComponentActivity() { focusManager = LocalFocusManager.current keyboardController = LocalSoftwareKeyboardController.current - // Initialize MainViewModel - if (!isMainViewModelInitialized()) { - mainViewModel = viewModel() - } - DutScheduleTheme( darkTheme = when (mainViewModel.appSettings.value.themeMode) { ThemeMode.DarkMode -> true diff --git a/app/src/main/java/io/zoemeow/dutschedule/model/NavBarItem.kt b/app/src/main/java/io/zoemeow/dutschedule/model/NavBarItem.kt index 82c34f0..a691054 100644 --- a/app/src/main/java/io/zoemeow/dutschedule/model/NavBarItem.kt +++ b/app/src/main/java/io/zoemeow/dutschedule/model/NavBarItem.kt @@ -8,32 +8,32 @@ import androidx.compose.ui.graphics.vector.ImageVector import io.zoemeow.dutschedule.R data class NavBarItem( - val title: String, + val titleResId: Int, val icon: ImageVector? = null, val resourceIconId: Int? = null, val route: String ) { companion object { val news = NavBarItem( - title = "News", + titleResId = R.string.news_title, resourceIconId = R.drawable.ic_baseline_newspaper_24, route = "news" ) val account = NavBarItem( - title = "Account", + titleResId = R.string.account_title, icon = Icons.Default.AccountCircle, route = "account" ) val notification = NavBarItem( - title = "Notifications", + titleResId = R.string.notification_panel_title, icon = Icons.Default.Notifications, route = "notifications" ) val settings = NavBarItem( - title = "Settings", + titleResId = R.string.settings_title, icon = Icons.Default.Settings, route = "settings" ) diff --git a/app/src/main/java/io/zoemeow/dutschedule/ui/component/main/NotificationItem.kt b/app/src/main/java/io/zoemeow/dutschedule/ui/component/main/NotificationItem.kt index 9f9c517..724a2cf 100644 --- a/app/src/main/java/io/zoemeow/dutschedule/ui/component/main/NotificationItem.kt +++ b/app/src/main/java/io/zoemeow/dutschedule/ui/component/main/NotificationItem.kt @@ -1,5 +1,6 @@ package io.zoemeow.dutschedule.ui.component.main +import android.content.Context import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.core.tween import androidx.compose.animation.fadeIn @@ -23,6 +24,9 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.text.intl.Locale import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -32,6 +36,7 @@ import io.zoemeow.dutschedule.utils.getRandomString @Composable fun NotificationItem( + context: Context, modifier: Modifier = Modifier, item: NotificationHistory, showDate: Boolean = false, @@ -66,7 +71,10 @@ fun NotificationItem( ) { if (showDate) { Text( - CustomDateUtil.unixToDuration(item.timestamp), + CustomDateUtil.unixToDurationWithLocale( + context = context, + unix = item.timestamp + ), style = MaterialTheme.typography.titleMedium, modifier = Modifier.padding(bottom = 5.dp) ) @@ -117,6 +125,7 @@ private fun Preview1() { isRead = false ) NotificationItem( + context = LocalContext.current, item = notificationHistory ) } @@ -134,6 +143,7 @@ private fun Preview2() { isRead = false ) NotificationItem( + context = LocalContext.current, item = notificationHistory ) } \ No newline at end of file diff --git a/app/src/main/java/io/zoemeow/dutschedule/ui/component/news/NewsDetailScreen.kt b/app/src/main/java/io/zoemeow/dutschedule/ui/component/news/NewsDetailScreen.kt index da11988..aaffd8d 100644 --- a/app/src/main/java/io/zoemeow/dutschedule/ui/component/news/NewsDetailScreen.kt +++ b/app/src/main/java/io/zoemeow/dutschedule/ui/component/news/NewsDetailScreen.kt @@ -1,5 +1,6 @@ package io.zoemeow.dutschedule.ui.component.news +import android.content.Context import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -30,6 +31,7 @@ import io.zoemeow.dutschedule.utils.CustomDateUtil @Composable fun NewsDetailScreen( + context: Context, newsItem: NewsGlobalItem, newsType: NewsType, padding: PaddingValues = PaddingValues(0.dp), @@ -38,6 +40,7 @@ fun NewsDetailScreen( when (newsType) { NewsType.Global -> { NewsDetailBody_NewsGlobal( + context = context, padding = padding, newsItem = newsItem, linkClicked = linkClicked @@ -45,6 +48,7 @@ fun NewsDetailScreen( } NewsType.Subject -> { NewsDetailBody_NewsSubject( + context = context, padding = padding, newsItem = newsItem as NewsSubjectItem, linkClicked = linkClicked @@ -55,6 +59,7 @@ fun NewsDetailScreen( @Composable private fun NewsDetailBody_NewsGlobal( + context: Context, padding: PaddingValues, newsItem: NewsGlobalItem, linkClicked: ((String) -> Unit)? = null @@ -81,7 +86,10 @@ private fun NewsDetailBody_NewsGlobal( "dd/MM/yyyy", "UTC" ) - } (${CustomDateUtil.unixToDuration(newsItem.date)})", + } (${CustomDateUtil.unixToDurationWithLocale( + context = context, + unix = newsItem.date + )})", style = MaterialTheme.typography.titleLarge, modifier = Modifier.padding(vertical = 7.dp) ) @@ -154,6 +162,7 @@ private fun NewsDetailBody_NewsGlobal( @Composable private fun NewsDetailBody_NewsSubject( + context: Context, padding: PaddingValues, newsItem: NewsSubjectItem, linkClicked: ((String) -> Unit)? = null @@ -184,7 +193,10 @@ private fun NewsDetailBody_NewsSubject( "dd/MM/yyyy", "UTC" ) - } (${CustomDateUtil.unixToDuration(newsItem.date)})", + } (${CustomDateUtil.unixToDurationWithLocale( + context = context, + unix = newsItem.date + )})", style = MaterialTheme.typography.titleLarge, modifier = Modifier.padding(vertical = 7.dp) ) diff --git a/app/src/main/java/io/zoemeow/dutschedule/ui/view/account/AccountInformation.kt b/app/src/main/java/io/zoemeow/dutschedule/ui/view/account/AccountInformation.kt index fb9acea..f906731 100644 --- a/app/src/main/java/io/zoemeow/dutschedule/ui/view/account/AccountInformation.kt +++ b/app/src/main/java/io/zoemeow/dutschedule/ui/view/account/AccountInformation.kt @@ -1,5 +1,6 @@ package io.zoemeow.dutschedule.ui.view.account +import android.app.Activity.RESULT_OK import androidx.activity.ComponentActivity import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -52,7 +53,7 @@ fun AccountActivity.AccountInformation( navigationIcon = { IconButton( onClick = { - setResult(ComponentActivity.RESULT_OK) + setResult(RESULT_OK) finish() }, content = { diff --git a/app/src/main/java/io/zoemeow/dutschedule/ui/view/account/MainView.kt b/app/src/main/java/io/zoemeow/dutschedule/ui/view/account/MainView.kt index 72008df..700cb6e 100644 --- a/app/src/main/java/io/zoemeow/dutschedule/ui/view/account/MainView.kt +++ b/app/src/main/java/io/zoemeow/dutschedule/ui/view/account/MainView.kt @@ -1,5 +1,6 @@ package io.zoemeow.dutschedule.ui.view.account +import android.app.Activity.RESULT_OK import android.content.Context import android.content.Intent import androidx.activity.ComponentActivity @@ -30,6 +31,7 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp +import io.zoemeow.dutschedule.R import io.zoemeow.dutschedule.activity.AccountActivity import io.zoemeow.dutschedule.model.ProcessState import io.zoemeow.dutschedule.model.account.AccountAuth @@ -61,7 +63,7 @@ fun AccountActivity.MainView( showSnackBar(text = text, clearPrevious = clearPrevious, actionText = actionText, action = action) }, onBack = { - setResult(ComponentActivity.RESULT_OK) + setResult(RESULT_OK) finish() } ) @@ -90,7 +92,7 @@ fun AccountMainView( contentColor = contentColor, topBar = { TopAppBar( - title = { Text("Account") }, + title = { Text(context.getString(R.string.account_title)) }, colors = TopAppBarDefaults.topAppBarColors(containerColor = Color.Transparent), navigationIcon = { if (onBack != null) { diff --git a/app/src/main/java/io/zoemeow/dutschedule/ui/view/account/SubjectFee.kt b/app/src/main/java/io/zoemeow/dutschedule/ui/view/account/SubjectFee.kt index 6d502e4..454e33f 100644 --- a/app/src/main/java/io/zoemeow/dutschedule/ui/view/account/SubjectFee.kt +++ b/app/src/main/java/io/zoemeow/dutschedule/ui/view/account/SubjectFee.kt @@ -1,5 +1,6 @@ package io.zoemeow.dutschedule.ui.view.account +import android.app.Activity.RESULT_OK import androidx.activity.ComponentActivity import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -53,7 +54,7 @@ fun AccountActivity.SubjectFee( navigationIcon = { IconButton( onClick = { - setResult(ComponentActivity.RESULT_OK) + setResult(RESULT_OK) finish() }, content = { diff --git a/app/src/main/java/io/zoemeow/dutschedule/ui/view/account/SubjectInformation.kt b/app/src/main/java/io/zoemeow/dutschedule/ui/view/account/SubjectInformation.kt index c546c0b..0bb6e88 100644 --- a/app/src/main/java/io/zoemeow/dutschedule/ui/view/account/SubjectInformation.kt +++ b/app/src/main/java/io/zoemeow/dutschedule/ui/view/account/SubjectInformation.kt @@ -1,5 +1,6 @@ package io.zoemeow.dutschedule.ui.view.account +import android.app.Activity.RESULT_CANCELED import androidx.activity.ComponentActivity import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -59,7 +60,7 @@ fun AccountActivity.SubjectInformation( navigationIcon = { IconButton( onClick = { - setResult(ComponentActivity.RESULT_CANCELED) + setResult(RESULT_CANCELED) finish() }, content = { diff --git a/app/src/main/java/io/zoemeow/dutschedule/ui/view/account/TrainingResult.kt b/app/src/main/java/io/zoemeow/dutschedule/ui/view/account/TrainingResult.kt index 13079da..0fa93d8 100644 --- a/app/src/main/java/io/zoemeow/dutschedule/ui/view/account/TrainingResult.kt +++ b/app/src/main/java/io/zoemeow/dutschedule/ui/view/account/TrainingResult.kt @@ -1,5 +1,6 @@ package io.zoemeow.dutschedule.ui.view.account +import android.app.Activity.RESULT_OK import android.content.Context import android.content.Intent import androidx.activity.ComponentActivity @@ -61,7 +62,7 @@ fun AccountActivity.TrainingResult( navigationIcon = { IconButton( onClick = { - setResult(ComponentActivity.RESULT_OK) + setResult(RESULT_OK) finish() }, content = { diff --git a/app/src/main/java/io/zoemeow/dutschedule/ui/view/account/TrainingSubjectResult.kt b/app/src/main/java/io/zoemeow/dutschedule/ui/view/account/TrainingSubjectResult.kt index fe6db53..d5beea1 100644 --- a/app/src/main/java/io/zoemeow/dutschedule/ui/view/account/TrainingSubjectResult.kt +++ b/app/src/main/java/io/zoemeow/dutschedule/ui/view/account/TrainingSubjectResult.kt @@ -1,5 +1,6 @@ package io.zoemeow.dutschedule.ui.view.account +import android.app.Activity.RESULT_CANCELED import androidx.activity.ComponentActivity import androidx.activity.compose.BackHandler import androidx.compose.foundation.background @@ -155,7 +156,7 @@ fun AccountActivity.TrainingSubjectResult( if (searchEnabled.value) { dismissSearchBar() } else { - setResult(ComponentActivity.RESULT_CANCELED) + setResult(RESULT_CANCELED) finish() } }, diff --git a/app/src/main/java/io/zoemeow/dutschedule/ui/view/main/MainViewTabbed.kt b/app/src/main/java/io/zoemeow/dutschedule/ui/view/main/MainViewTabbed.kt index 9baad50..4924e6f 100644 --- a/app/src/main/java/io/zoemeow/dutschedule/ui/view/main/MainViewTabbed.kt +++ b/app/src/main/java/io/zoemeow/dutschedule/ui/view/main/MainViewTabbed.kt @@ -77,14 +77,14 @@ fun MainActivity.MainViewTabbed( }, icon = { if (it.resourceIconId != null) { - Icon(painter = painterResource(id = it.resourceIconId), it.title) + Icon(painter = painterResource(id = it.resourceIconId), context.getString(it.titleResId)) } else if (it.icon != null) { - Icon(imageVector = it.icon, it.title) + Icon(imageVector = it.icon, context.getString(it.titleResId)) } else { - Icon(imageVector = Icons.Default.Info, it.title) + Icon(imageVector = Icons.Default.Info, context.getString(it.titleResId)) } }, - label = { Text(it.title) } + label = { Text(context.getString(it.titleResId)) } ) } ) @@ -140,12 +140,12 @@ fun MainActivity.MainViewTabbed( contentColor = contentColor, onClick = { item -> if (listOf(1, 2).contains(item.tag)) { - Intent(context, NewsActivity::class.java).also { - it.action = "activity_detail" + Intent(context, NewsActivity::class.java).also { intent -> + intent.action = "activity_detail" for (map1 in item.parameters) { - it.putExtra(map1.key, map1.value) + intent.putExtra(map1.key, map1.value) } - context.startActivity(it) + context.startActivity(intent) } } }, diff --git a/app/src/main/java/io/zoemeow/dutschedule/ui/view/main/NotificationScaffold.kt b/app/src/main/java/io/zoemeow/dutschedule/ui/view/main/NotificationScaffold.kt index 6f8ce6c..703bf67 100644 --- a/app/src/main/java/io/zoemeow/dutschedule/ui/view/main/NotificationScaffold.kt +++ b/app/src/main/java/io/zoemeow/dutschedule/ui/view/main/NotificationScaffold.kt @@ -106,11 +106,11 @@ fun NotificationScaffold( ) }, snackbarHost = { snackBarHostState?.let { SnackbarHost(hostState = it) } }, - content = { + content = { paddingValues -> Column( modifier = Modifier .fillMaxSize() - .padding(it) + .padding(paddingValues) .padding(horizontal = 15.dp) ) { Column( @@ -130,12 +130,16 @@ fun NotificationScaffold( .toSortedMap(compareByDescending { it }) .forEach(action = { group -> Text( - CustomDateUtil.unixToDuration(group.key), + CustomDateUtil.unixToDurationWithLocale( + context = context, + unix = group.key + ), style = MaterialTheme.typography.titleMedium, modifier = Modifier.padding(top = 5.dp, bottom = 4.dp) ) group.value.forEach { item -> NotificationItem( + context = context, modifier = Modifier.padding(top = 2.dp, bottom = 5.dp), isVisible = true, opacity = opacity, diff --git a/app/src/main/java/io/zoemeow/dutschedule/ui/view/news/MainView.kt b/app/src/main/java/io/zoemeow/dutschedule/ui/view/news/MainView.kt index 5c7f330..4ef40a8 100644 --- a/app/src/main/java/io/zoemeow/dutschedule/ui/view/news/MainView.kt +++ b/app/src/main/java/io/zoemeow/dutschedule/ui/view/news/MainView.kt @@ -1,5 +1,6 @@ package io.zoemeow.dutschedule.ui.view.news +import android.app.Activity.RESULT_OK import android.content.Context import android.content.Intent import androidx.activity.ComponentActivity @@ -70,7 +71,7 @@ fun NewsActivity.MainView( componentBackgroundAlpha = getControlBackgroundAlpha(), mainViewModel = getMainViewModel(), onBack = { - setResult(ComponentActivity.RESULT_OK) + setResult(RESULT_OK) finish() } ) diff --git a/app/src/main/java/io/zoemeow/dutschedule/ui/view/news/NewsDetail.kt b/app/src/main/java/io/zoemeow/dutschedule/ui/view/news/NewsDetail.kt index 5cfa0b3..982f6ef 100644 --- a/app/src/main/java/io/zoemeow/dutschedule/ui/view/news/NewsDetail.kt +++ b/app/src/main/java/io/zoemeow/dutschedule/ui/view/news/NewsDetail.kt @@ -1,5 +1,6 @@ package io.zoemeow.dutschedule.ui.view.news +import android.app.Activity.RESULT_OK import android.content.Context import androidx.activity.ComponentActivity import androidx.compose.foundation.layout.Row @@ -55,7 +56,7 @@ fun NewsActivity.NewsDetail( navigationIcon = { IconButton( onClick = { - setResult(ComponentActivity.RESULT_OK) + setResult(RESULT_OK) finish() }, content = { @@ -104,6 +105,7 @@ fun NewsActivity.NewsDetail( when (newsType) { "news_global" -> { NewsDetailScreen( + context = context, padding = it, newsItem = Gson().fromJson(newsData, object : TypeToken() {}.type), newsType = NewsType.Global, @@ -118,6 +120,7 @@ fun NewsActivity.NewsDetail( } "news_subject" -> { NewsDetailScreen( + context = context, padding = it, newsItem = Gson().fromJson(newsData, object : TypeToken() {}.type) as NewsGlobalItem, newsType = NewsType.Subject, diff --git a/app/src/main/java/io/zoemeow/dutschedule/ui/view/news/NewsSearch.kt b/app/src/main/java/io/zoemeow/dutschedule/ui/view/news/NewsSearch.kt index e18339c..2f85a6d 100644 --- a/app/src/main/java/io/zoemeow/dutschedule/ui/view/news/NewsSearch.kt +++ b/app/src/main/java/io/zoemeow/dutschedule/ui/view/news/NewsSearch.kt @@ -1,5 +1,6 @@ package io.zoemeow.dutschedule.ui.view.news +import android.app.Activity.RESULT_OK import android.content.Context import android.content.Intent import androidx.activity.ComponentActivity @@ -124,7 +125,7 @@ fun NewsActivity.NewsSearch( if (isSearchFocused.targetState) { dismissFocus() } else { - setResult(ComponentActivity.RESULT_OK) + setResult(RESULT_OK) finish() } }, diff --git a/app/src/main/java/io/zoemeow/dutschedule/ui/view/settings/ExperimentSettings.kt b/app/src/main/java/io/zoemeow/dutschedule/ui/view/settings/ExperimentSettings.kt index 2f39815..ea0a712 100644 --- a/app/src/main/java/io/zoemeow/dutschedule/ui/view/settings/ExperimentSettings.kt +++ b/app/src/main/java/io/zoemeow/dutschedule/ui/view/settings/ExperimentSettings.kt @@ -1,5 +1,6 @@ package io.zoemeow.dutschedule.ui.view.settings +import android.app.Activity.RESULT_CANCELED import android.content.ComponentName import android.content.Context import android.content.Intent @@ -62,7 +63,7 @@ fun SettingsActivity.ExperimentSettings( navigationIcon = { IconButton( onClick = { - setResult(ComponentActivity.RESULT_CANCELED) + setResult(RESULT_CANCELED) finish() }, content = { diff --git a/app/src/main/java/io/zoemeow/dutschedule/ui/view/settings/LanguageSettings.kt b/app/src/main/java/io/zoemeow/dutschedule/ui/view/settings/LanguageSettings.kt index dc583f3..b763d76 100644 --- a/app/src/main/java/io/zoemeow/dutschedule/ui/view/settings/LanguageSettings.kt +++ b/app/src/main/java/io/zoemeow/dutschedule/ui/view/settings/LanguageSettings.kt @@ -1,5 +1,6 @@ package io.zoemeow.dutschedule.ui.view.settings +import android.app.Activity.RESULT_CANCELED import android.app.LocaleManager import android.content.Context import android.os.Build @@ -65,13 +66,13 @@ fun SettingsActivity.LanguageSettings( navigationIcon = { IconButton( onClick = { - setResult(ComponentActivity.RESULT_CANCELED) + setResult(RESULT_CANCELED) finish() }, content = { Icon( Icons.AutoMirrored.Filled.ArrowBack, - "", + context.getString(R.string.action_back), modifier = Modifier.size(25.dp) ) } diff --git a/app/src/main/java/io/zoemeow/dutschedule/ui/view/settings/MainView.kt b/app/src/main/java/io/zoemeow/dutschedule/ui/view/settings/MainView.kt index ad27859..b00979c 100644 --- a/app/src/main/java/io/zoemeow/dutschedule/ui/view/settings/MainView.kt +++ b/app/src/main/java/io/zoemeow/dutschedule/ui/view/settings/MainView.kt @@ -1,11 +1,11 @@ package io.zoemeow.dutschedule.ui.view.settings +import android.app.Activity.RESULT_OK import android.content.Context import android.content.Intent import android.net.Uri import android.os.Build import android.provider.Settings -import androidx.activity.ComponentActivity import androidx.activity.compose.BackHandler import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues @@ -71,7 +71,7 @@ fun SettingsActivity.MainView( showSnackBar(text = text, clearPrevious = clearPrevious, actionText = actionText, action = action) }, onBack = { - setResult(ComponentActivity.RESULT_OK) + setResult(RESULT_OK) finish() } ) @@ -100,7 +100,7 @@ fun SettingsMainView( contentColor = contentColor, topBar = { TopAppBar( - title = { Text(context.getString(R.string.settings_name)) }, + title = { Text(context.getString(R.string.settings_title)) }, colors = TopAppBarDefaults.topAppBarColors(containerColor = Color.Transparent), navigationIcon = { if (onBack != null) { diff --git a/app/src/main/java/io/zoemeow/dutschedule/ui/view/settings/NewsNotificationSettings.kt b/app/src/main/java/io/zoemeow/dutschedule/ui/view/settings/NewsNotificationSettings.kt index 438a0d4..6be5bd0 100644 --- a/app/src/main/java/io/zoemeow/dutschedule/ui/view/settings/NewsNotificationSettings.kt +++ b/app/src/main/java/io/zoemeow/dutschedule/ui/view/settings/NewsNotificationSettings.kt @@ -1,5 +1,6 @@ package io.zoemeow.dutschedule.ui.view.settings +import android.app.Activity.RESULT_OK import android.content.Context import android.content.Intent import androidx.activity.ComponentActivity @@ -94,7 +95,7 @@ fun SettingsActivity.NewsNotificationSettings( navigationIcon = { IconButton( onClick = { - setResult(ComponentActivity.RESULT_OK) + setResult(RESULT_OK) finish() }, content = { diff --git a/app/src/main/java/io/zoemeow/dutschedule/ui/view/settings/ParseNewsSubjectNotification.kt b/app/src/main/java/io/zoemeow/dutschedule/ui/view/settings/ParseNewsSubjectNotification.kt index e99ad57..32253bd 100644 --- a/app/src/main/java/io/zoemeow/dutschedule/ui/view/settings/ParseNewsSubjectNotification.kt +++ b/app/src/main/java/io/zoemeow/dutschedule/ui/view/settings/ParseNewsSubjectNotification.kt @@ -1,5 +1,6 @@ package io.zoemeow.dutschedule.ui.view.settings +import android.app.Activity.RESULT_OK import android.content.Context import androidx.activity.ComponentActivity import androidx.compose.foundation.layout.Arrangement @@ -56,7 +57,7 @@ fun SettingsActivity.ParseNewsSubjectNotification( navigationIcon = { IconButton( onClick = { - setResult(ComponentActivity.RESULT_OK) + setResult(RESULT_OK) finish() }, content = { diff --git a/app/src/main/java/io/zoemeow/dutschedule/utils/CustomDateUtil.kt b/app/src/main/java/io/zoemeow/dutschedule/utils/CustomDateUtil.kt index cfe7310..c106054 100644 --- a/app/src/main/java/io/zoemeow/dutschedule/utils/CustomDateUtil.kt +++ b/app/src/main/java/io/zoemeow/dutschedule/utils/CustomDateUtil.kt @@ -1,7 +1,14 @@ package io.zoemeow.dutschedule.utils import android.annotation.SuppressLint +import android.content.Context +import androidx.compose.ui.platform.LocalConfiguration import com.github.marlonlom.utilities.timeago.TimeAgo +import com.github.marlonlom.utilities.timeago.TimeAgoMessages +import io.zoemeow.dutschedule.R +import kotlinx.datetime.Clock +import kotlinx.datetime.Instant +import kotlinx.datetime.toLocalDateTime import java.text.SimpleDateFormat import java.util.Calendar import java.util.Date @@ -10,6 +17,7 @@ import java.util.TimeZone import kotlin.time.DurationUnit import kotlin.time.toDuration + class CustomDateUtil { companion object { /** @@ -52,18 +60,25 @@ class CustomDateUtil { return SimpleDateFormat(format, Locale.getDefault()).format(Date()) } - fun unixToDuration(unix: Long = System.currentTimeMillis()): String { + fun unixToDurationWithLocale( + context: Context, + unix: Long = System.currentTimeMillis(), + langTag: String = Locale.getDefault().toLanguageTag() + ): String { val duration = (System.currentTimeMillis() - unix).toDuration(DurationUnit.MILLISECONDS) return when (duration.inWholeHours) { in 0..23 -> { - "Today" + context.getString(R.string.time_today) } in 24..47 -> { - "Yesterday" + context.getString(R.string.time_yesterday) } else -> { - TimeAgo.using(unix) + val localeByLangTag = Locale.forLanguageTag(langTag) + val messages: TimeAgoMessages = + TimeAgoMessages.Builder().withLocale(localeByLangTag).build() + TimeAgo.using(unix, messages) } } } diff --git a/app/src/main/java/io/zoemeow/dutschedule/viewmodel/MainViewModel.kt b/app/src/main/java/io/zoemeow/dutschedule/viewmodel/MainViewModel.kt index 4b8177c..589da38 100644 --- a/app/src/main/java/io/zoemeow/dutschedule/viewmodel/MainViewModel.kt +++ b/app/src/main/java/io/zoemeow/dutschedule/viewmodel/MainViewModel.kt @@ -21,6 +21,8 @@ import io.zoemeow.dutschedule.repository.DutRequestRepository import io.zoemeow.dutschedule.repository.FileModuleRepository import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import javax.inject.Inject @@ -162,13 +164,13 @@ class MainViewModel @Inject constructor( } } - private val runOnStartupEnabled = mutableStateOf(true) + private val _runOnStartup = MutableStateFlow(false) + val runOnStartup = _runOnStartup.asStateFlow() + private fun runOnStartup(invokeOnCompleted: (() -> Unit)? = null) { - if (!runOnStartupEnabled.value) + if (_runOnStartup.value) return - runOnStartupEnabled.value = false - appSettings.value = fileModuleRepository.getAppSettings() accountSession.setAccountSession(fileModuleRepository.getAccountSession()) accountSession.setSchoolYear(schoolYearItem = appSettings.value.currentSchoolYear) @@ -193,6 +195,7 @@ class MainViewModel @Inject constructor( forceRequest = true ) }) + _runOnStartup.value = true } ) } diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml index 47d318e..48a0b2c 100644 --- a/app/src/main/res/drawable/ic_launcher_foreground.xml +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -3,609 +3,174 @@ android:height="108dp" android:viewportWidth="256" android:viewportHeight="256"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/app/src/main/res/mipmap-hdpi/ic_launcher.webp index 6fd3463..f5b3906 100644 Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher.webp and b/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp index a66e6a8..f5b3906 100644 Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/app/src/main/res/mipmap-mdpi/ic_launcher.webp index eb951cb..4f9d658 100644 Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher.webp and b/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp index 5607e58..4f9d658 100644 Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp index 8b30a1a..c099cdd 100644 Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp and b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp index 4240685..c099cdd 100644 Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp index 4b87a90..c4d2c93 100644 Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp index b75745e..c4d2c93 100644 Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp index e07c0d6..d74963f 100644 Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp index 5e5574b..d74963f 100644 Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/values-night-v31/themes.xml b/app/src/main/res/values-night-v31/themes.xml new file mode 100644 index 0000000..d04320c --- /dev/null +++ b/app/src/main/res/values-night-v31/themes.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index 426b3be..0dcbbc1 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -4,6 +4,9 @@ Tính năng này đang được phát triển. Hãy kiểm tra lại sau. Bạn cần phải cho phép Quyền truy cập mọi tệp trong quyền hạn ứng dụng để sử dụng tùy chọn này. Bạn cần phải bật quyền Chuông báo và lời nhắc trong cài đặt Android để sử dụng tính năng này. + + Hôm nay + Hôm qua OK Mở @@ -37,7 +40,7 @@ Vào ngày %1$s với tiết học %2$s Phòng sẽ học bù: %1$s - Cài đặt + Cài đặt Thông báo Cài đặt cập nhật tin tức trong nền Cấu hình cài đặt thông báo tin tức cho bạn, bao gồm thời gian cập nhật, tin tức nào sẽ được bật, cài đặt bộ lọc tin tức và hơn thế nữa. @@ -185,4 +188,6 @@ Lớp học phần Lịch sử tìm kiếm Tìm kiếm %2$s theo %1$s + + Tài khoản \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f0cb02d..1887d6d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -4,6 +4,9 @@ This function is in development. Check back soon. You need to grant All files access in application permissions to use this option. You need to enable Alarms & Reminders in Android app settings to use this feature. + + Today + Yesterday OK Open @@ -37,7 +40,7 @@ On %1$s at lesson(s) %2$s Room will make up: %1$s - Settings + Settings Notifications News schedule in background settings Configure your news notification settings, include duration, which news is enabled, news filter settings, and more. @@ -185,4 +188,6 @@ News Subject Search history Search %1$s in %2$s + + Account \ No newline at end of file diff --git a/build.gradle b/build.gradle index 35fb10a..8de17f9 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { - id 'com.android.application' version '8.3.2' apply false + id 'com.android.application' version '8.4.0' apply false id 'org.jetbrains.kotlin.android' version '1.8.10' apply false id 'com.google.dagger.hilt.android' version '2.44' apply false }