diff --git a/app/build.gradle b/app/build.gradle index fc167a8..d427160 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -12,8 +12,8 @@ android { applicationId "com.thatsmanmeet.taskyapp" minSdk 26 targetSdk 34 - versionCode 19 - versionName "2.3.5" + versionCode 20 + versionName "2.3.6" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables { useSupportLibrary true @@ -77,7 +77,7 @@ dependencies { annotationProcessor "androidx.room:room-compiler:$room_version" kapt "androidx.room:room-compiler:$room_version" implementation 'androidx.core:core-splashscreen:1.0.1' - implementation "androidx.navigation:navigation-compose:2.7.0-beta01" + implementation "androidx.navigation:navigation-compose:2.7.0-beta02" implementation "androidx.datastore:datastore-preferences:1.0.0" def lottieVersion = "6.0.0" implementation "com.airbnb.android:lottie-compose:$lottieVersion" diff --git a/app/release/output-metadata.json b/app/release/output-metadata.json index 66dc40e..f05cff4 100644 --- a/app/release/output-metadata.json +++ b/app/release/output-metadata.json @@ -11,7 +11,7 @@ "type": "SINGLE", "filters": [], "attributes": [], - "versionCode": 18, + "versionCode": 19, "versionName": "2.3.5", "outputFile": "app-release.apk" } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 975b609..0c9dfbe 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -20,7 +20,7 @@ android:name=".MainActivity" android:exported="true" android:theme="@style/Theme.App.Starting" - android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"> + android:configChanges="orientation|screenSize|screenLayout|keyboardHidden|uiMode"> diff --git a/app/src/main/java/com/thatsmanmeet/taskyapp/components/DateHeader.kt b/app/src/main/java/com/thatsmanmeet/taskyapp/components/DateHeader.kt index 7184cc4..0719ed4 100644 --- a/app/src/main/java/com/thatsmanmeet/taskyapp/components/DateHeader.kt +++ b/app/src/main/java/com/thatsmanmeet/taskyapp/components/DateHeader.kt @@ -1,6 +1,5 @@ package com.thatsmanmeet.taskyapp.components -import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.DateRange @@ -21,8 +20,7 @@ fun DateHeader( Row( modifier = modifier .padding(bottom = 10.dp, top = 0.dp) - .fillMaxWidth() - .background(MaterialTheme.colorScheme.surface), + .fillMaxWidth(), verticalAlignment = Alignment.CenterVertically ) { Icon( diff --git a/app/src/main/java/com/thatsmanmeet/taskyapp/components/OpenEditTodoDialog.kt b/app/src/main/java/com/thatsmanmeet/taskyapp/components/OpenEditTodoDialog.kt index e92255d..062614f 100644 --- a/app/src/main/java/com/thatsmanmeet/taskyapp/components/OpenEditTodoDialog.kt +++ b/app/src/main/java/com/thatsmanmeet/taskyapp/components/OpenEditTodoDialog.kt @@ -16,7 +16,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.thatsmanmeet.taskyapp.R -import com.thatsmanmeet.taskyapp.constants.Constants +import com.thatsmanmeet.taskyapp.datastore.SettingsStore import com.thatsmanmeet.taskyapp.room.Todo import com.thatsmanmeet.taskyapp.room.TodoViewModel import com.thatsmanmeet.taskyapp.screens.cancelNotification @@ -81,6 +81,8 @@ fun OpenEditTodoDialog( set(Calendar.MINUTE, 0) set(Calendar.SECOND, 0) } + val settingsStore = SettingsStore(context = context) + val savedSoundKey = settingsStore.getSoundKey.collectAsState(initial = true) var todo : Todo AlertDialog( onDismissRequest = { @@ -272,7 +274,9 @@ fun OpenEditTodoDialog( todo = todo ) enteredText1 = "" - todoViewModel.playDeletedSound(context) + if(savedSoundKey.value == true){ + todoViewModel.playDeletedSound(context) + } }, colors = ButtonDefaults.buttonColors( containerColor = Color( diff --git a/app/src/main/java/com/thatsmanmeet/taskyapp/components/TaskCompleteAnimations.kt b/app/src/main/java/com/thatsmanmeet/taskyapp/components/TaskCompleteAnimations.kt index d5c8b10..4ba232e 100644 --- a/app/src/main/java/com/thatsmanmeet/taskyapp/components/TaskCompleteAnimations.kt +++ b/app/src/main/java/com/thatsmanmeet/taskyapp/components/TaskCompleteAnimations.kt @@ -26,7 +26,7 @@ fun TaskCompleteAnimations( progressAnimation }, modifier = modifier.fillMaxSize(), - contentScale = ContentScale.Fit + contentScale = ContentScale.Crop ) } \ No newline at end of file diff --git a/app/src/main/java/com/thatsmanmeet/taskyapp/components/ThemeDialog.kt b/app/src/main/java/com/thatsmanmeet/taskyapp/components/ThemeDialog.kt new file mode 100644 index 0000000..ad7c034 --- /dev/null +++ b/app/src/main/java/com/thatsmanmeet/taskyapp/components/ThemeDialog.kt @@ -0,0 +1,125 @@ +package com.thatsmanmeet.taskyapp.components + + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Check +import androidx.compose.material3.AlertDialog +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonColors +import androidx.compose.material3.Icon +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import com.thatsmanmeet.taskyapp.R +import com.thatsmanmeet.taskyapp.misc.AppTheme + + +@Composable +fun ThemeChangerDialog( + modifier: Modifier = Modifier, + selectedItem:MutableState, + isShowing:MutableState, + onClick : (String) -> Unit +) { + if(isShowing.value){ + AlertDialog( + onDismissRequest = { + isShowing.value = false + }, + title = { + Text(text = stringResource(R.string.select_app_theme_text)) + }, + text = { + Column( + horizontalAlignment = Alignment.Start, + verticalArrangement = Arrangement.Center + ) { + val list = mutableListOf( + AppTheme("0","System Default",false, R.drawable.ic_phone), + AppTheme("1","Light",false,R.drawable.ic_light), + AppTheme("2","Dark",false,R.drawable.ic_dark) + ) + LazyColumn(modifier = modifier.padding(2.dp)){ + items(list){theme-> + ThemeItem(appTheme = theme, selectedThemeId = selectedItem) { selectedThemeId -> + selectedItem.value = selectedThemeId + } + } + } + } + }, + confirmButton = { + Button( + onClick = { + onClick(selectedItem.value) + isShowing.value = false + }, + colors = ButtonColors(containerColor = Color(0xFF229E28), contentColor = Color.White, disabledContentColor = Color.White, disabledContainerColor = Color.Gray) + ) { + Text(text = "OK") + } + }, + dismissButton = { + Button( + onClick = { + isShowing.value = false + }, + colors = ButtonColors(containerColor = Color(0xFFDB4C41), contentColor = Color.White, disabledContentColor = Color.White, disabledContainerColor = Color.Gray) + ) { + Text(text = "Cancel") + } + } + ) + } +} + +@Composable +fun ThemeItem( + modifier: Modifier = Modifier, + appTheme: AppTheme, + selectedThemeId: MutableState, + onThemeItemSelected: (String) -> Unit +) { + val isSelected = remember(appTheme.id == selectedThemeId.value) { + mutableStateOf(appTheme.id == selectedThemeId.value) + } + + Row( + modifier = modifier.padding(10.dp).fillMaxWidth().clickable { + onThemeItemSelected(appTheme.id) + }, + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Row(verticalAlignment = Alignment.CenterVertically) { + Icon(painter = painterResource(id = appTheme.icon), contentDescription = null) + Spacer(modifier = modifier.width(10.dp)) + Text(text = appTheme.mode) + } + if (isSelected.value) { + Icon( + imageVector = Icons.Default.Check, + contentDescription = null, + tint = Color(0xFF009688) + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/thatsmanmeet/taskyapp/datastore/SettingsStore.kt b/app/src/main/java/com/thatsmanmeet/taskyapp/datastore/SettingsStore.kt index 6acd899..66179ec 100644 --- a/app/src/main/java/com/thatsmanmeet/taskyapp/datastore/SettingsStore.kt +++ b/app/src/main/java/com/thatsmanmeet/taskyapp/datastore/SettingsStore.kt @@ -5,6 +5,7 @@ import androidx.datastore.core.DataStore import androidx.datastore.preferences.core.Preferences import androidx.datastore.preferences.core.booleanPreferencesKey import androidx.datastore.preferences.core.edit +import androidx.datastore.preferences.core.stringPreferencesKey import androidx.datastore.preferences.preferencesDataStore import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map @@ -18,6 +19,7 @@ class SettingsStore( val ANIMATION_SHOW_KEY = booleanPreferencesKey("animation_list_preference") val SHOW_24_HOUR_CLOCK_KEY = booleanPreferencesKey("show_24_hour_clock_preference") val TASK_COMPLETION_SOUNDS = booleanPreferencesKey("sound_list_preference") + val THEME_MODE_KEY = stringPreferencesKey("theme_mode_preference") } val getTaskListKey : Flow = context.dataStore.data.map {preference-> @@ -35,6 +37,10 @@ class SettingsStore( preference[TASK_COMPLETION_SOUNDS] ?: true } + val getThemeModeKey : Flow = context.dataStore.data.map {preference -> + preference[THEME_MODE_KEY] ?: "" + } + suspend fun saveTaskListKey(isEnabled:Boolean) { context.dataStore.edit {preferences-> preferences[TASK_LIST_KEY] = isEnabled @@ -57,4 +63,10 @@ class SettingsStore( preference[SHOW_24_HOUR_CLOCK_KEY] = isEnabled } } + + suspend fun saveThemeModeKey(mode:String){ + context.dataStore.edit { preference-> + preference[THEME_MODE_KEY] = mode + } + } } diff --git a/app/src/main/java/com/thatsmanmeet/taskyapp/misc/AppTheme.kt b/app/src/main/java/com/thatsmanmeet/taskyapp/misc/AppTheme.kt new file mode 100644 index 0000000..53f8b61 --- /dev/null +++ b/app/src/main/java/com/thatsmanmeet/taskyapp/misc/AppTheme.kt @@ -0,0 +1,8 @@ +package com.thatsmanmeet.taskyapp.misc + +data class AppTheme( + val id:String, + val mode:String, + var isSelected:Boolean, + val icon:Int +) diff --git a/app/src/main/java/com/thatsmanmeet/taskyapp/screens/App.kt b/app/src/main/java/com/thatsmanmeet/taskyapp/screens/App.kt index 47db26f..141e812 100644 --- a/app/src/main/java/com/thatsmanmeet/taskyapp/screens/App.kt +++ b/app/src/main/java/com/thatsmanmeet/taskyapp/screens/App.kt @@ -7,6 +7,7 @@ import android.content.Context import android.content.Intent import android.media.AudioAttributes import android.net.Uri +import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.* import androidx.compose.material.icons.Icons @@ -92,7 +93,15 @@ fun MyApp( val settingsStore = SettingsStore(context) val savedTaskKey = settingsStore.getTaskListKey.collectAsState(initial = true) val savedAnimationKey = settingsStore.getAnimationKey.collectAsState(initial = true) - TaskyTheme { + val savedThemeKey = settingsStore.getThemeModeKey.collectAsState(initial = "") + TaskyTheme(darkTheme = when (savedThemeKey.value) { + "0" -> { + isSystemInDarkTheme() + } + "1" -> {false} + else -> {true} + } + ) { Scaffold( topBar = { TopAppBar( @@ -152,7 +161,9 @@ fun MyApp( color = MaterialTheme.colorScheme.background ) { if(todoListFromFlow.isEmpty()){ - Box(modifier = modifier.fillMaxSize(), + Box(modifier = modifier + .fillMaxSize() + .padding(paddingValues), contentAlignment = Alignment.Center) { Column( modifier = modifier, @@ -176,28 +187,27 @@ fun MyApp( } } }else { - if(savedTaskKey.value == null || savedTaskKey.value == true){ - TaskList( - state = listState, - list = todoListFromFlow, - todoViewModel = todoViewModel, - onClick = {index-> - selectedItem.value = index - openEditDialog.value = true - } - ) - }else{ - LegacyTaskList( - state = listState, - list = todoListFromFlow, - todoViewModel = todoViewModel, - onClick = {index-> - selectedItem.value = index - openEditDialog.value = true - } - ) - } - + if(savedTaskKey.value == null || savedTaskKey.value == true){ + TaskList( + state = listState, + list = todoListFromFlow, + todoViewModel = todoViewModel, + onClick = {index-> + selectedItem.value = index + openEditDialog.value = true + } + ) + }else{ + LegacyTaskList( + state = listState, + list = todoListFromFlow, + todoViewModel = todoViewModel, + onClick = {index-> + selectedItem.value = index + openEditDialog.value = true + } + ) + } } if (openEditDialog.value){ OpenEditTodoDialog( diff --git a/app/src/main/java/com/thatsmanmeet/taskyapp/screens/SettingsScreen.kt b/app/src/main/java/com/thatsmanmeet/taskyapp/screens/SettingsScreen.kt index 1733fc1..2e534b8 100644 --- a/app/src/main/java/com/thatsmanmeet/taskyapp/screens/SettingsScreen.kt +++ b/app/src/main/java/com/thatsmanmeet/taskyapp/screens/SettingsScreen.kt @@ -2,6 +2,7 @@ package com.thatsmanmeet.taskyapp.screens import android.app.Activity import androidx.compose.foundation.background +import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.* import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape @@ -23,6 +24,7 @@ import androidx.navigation.NavHostController import com.thatsmanmeet.taskyapp.MainActivity import com.thatsmanmeet.taskyapp.R import com.thatsmanmeet.taskyapp.components.SettingsComponent +import com.thatsmanmeet.taskyapp.components.ThemeChangerDialog import com.thatsmanmeet.taskyapp.datastore.SettingsStore import com.thatsmanmeet.taskyapp.ui.theme.TaskyTheme import com.thatsmanmeet.taskyapp.viewmodels.MainViewModel @@ -43,6 +45,7 @@ fun SettingsScreen( val context = LocalContext.current val scope = rememberCoroutineScope() val settingStore = SettingsStore(context) + val savedThemeKey = settingStore.getThemeModeKey.collectAsState(initial = "") val isCheckedState = remember { mutableStateOf(isChecked.value) } @@ -58,10 +61,20 @@ fun SettingsScreen( var isDialogShowingState by rememberSaveable { mutableStateOf(false) } + val isThemeChangerShowing = rememberSaveable { + mutableStateOf(false) + } val mainViewModel = MainViewModel() val activity = LocalContext.current as Activity val dbPath = activity.getDatabasePath("todo_database").absolutePath - TaskyTheme{ + TaskyTheme(darkTheme = when (savedThemeKey.value) { + "0" -> { + isSystemInDarkTheme() + } + "1" -> {false} + else -> {true} + } + ){ Scaffold( modifier = modifier.fillMaxSize(), topBar = { @@ -110,6 +123,14 @@ fun SettingsScreen( ) .verticalScroll(rememberScrollState()), ) { + SettingsComponent( + settingHeaderText = stringResource(R.string.set_app_theme_settings_text), + settingText = stringResource(R.string.set_app_theme_info_text), + painterResourceID = R.drawable.ic_phone + ) { + isThemeChangerShowing.value = true + } + Spacer(modifier = modifier.height(12.dp)) Card( modifier = modifier .clip(RoundedCornerShape(15.dp)) @@ -298,5 +319,16 @@ fun SettingsScreen( } ) } + // Backup dialog ends here + ThemeChangerDialog( + selectedItem = remember { + mutableStateOf(savedThemeKey.value.toString()) + }, + isShowing = isThemeChangerShowing + ){mode-> + scope.launch { + settingStore.saveThemeModeKey(mode) + } + } } } diff --git a/app/src/main/res/drawable/ic_dark.xml b/app/src/main/res/drawable/ic_dark.xml new file mode 100644 index 0000000..c384362 --- /dev/null +++ b/app/src/main/res/drawable/ic_dark.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_light.xml b/app/src/main/res/drawable/ic_light.xml new file mode 100644 index 0000000..ab9995a --- /dev/null +++ b/app/src/main/res/drawable/ic_light.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_phone.xml b/app/src/main/res/drawable/ic_phone.xml new file mode 100644 index 0000000..e948564 --- /dev/null +++ b/app/src/main/res/drawable/ic_phone.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 308a35f..35dec03 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -17,17 +17,20 @@ Haben Sie Ihre Aufgabe heute erledigt ? Keine Aufgaben Erlaubnis erforderlich - Beginnend mit Android 13+, Anwendungen benötigen Benchrichtigungserlaubnis um Benachrichtigungen anzuzeigen. + Beginnend mit Android 13+, Anwendungen benötigen Benachrichtigungserlaubnis um Benachrichtigungen anzuzeigen. Erlaubnis erforderlich Einstellungen Aufgaben trennen durch Verwendung von Daten Verwendung von Animation bei erfüllter Aufgabe AutoStart aktivieren - Bei einigen Geräten kommen die Benachrichtigungen nicht rechtzeitig oder funktionieren nicht nach einem rebootnotifications. Klicken Sie hier um autostart zu aktivieren. \n\n(Nützlich für Xiaomi, vivo, Oppo ähnliche Geräte die stock rom verwenden) + Bei einigen Geräten kommen die Benachrichtigungen nicht rechtzeitig oder funktionieren nicht nach einer Rebootbenachrichtigung. Klicken Sie hier um autostart zu aktivieren. \n\n(Nützlich für Xiaomi, vivo, Oppo ähnliche Geräte die stock rom verwenden) Quelle ansehen Tasky ist komplett quelloffen. Für Rückmeldungen oder Beteiligung an der Entwicklung ? besuchen Sie Github! Oh vergessen Sie nicht mir einen ⭐️ zu geben ;) - Verwenden Sie die 24-Stunden-Uhr + 24-Stunden-Uhr verwenden Sicherung/Wiederherstellung - Sicherung oder Wiederherstellung ihrer Aufgaben durch eine lokale Zip-Datei - Verwenden Sie Sounds zum Erledigen von Aufgaben + Sicherung oder zu Wiederherstellung ihrer Aufgaben durch eine lokale Zip-Datei + Verwende Töne bei erfüllter Aufgabe + Wählen Sie App-Theme + Wählen Sie App-Theme + Ändern Sie das aktuelle Design der App in hell, dunkel oder Systemstandard. \ 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 fd86e6f..4e67015 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -29,5 +29,7 @@ Backup/Restore Backup or Restore your tasks from a local zip file. Use task complete sounds - + Select App Theme + Set app theme + Change current theme of the app to light, dark or system default. \ No newline at end of file