diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 2f6be48b..be712480 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -5,7 +5,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/sadellie/unitto/UnittoApp.kt b/app/src/main/java/com/sadellie/unitto/UnittoApp.kt index cc1bb5f9..4bd03aff 100644 --- a/app/src/main/java/com/sadellie/unitto/UnittoApp.kt +++ b/app/src/main/java/com/sadellie/unitto/UnittoApp.kt @@ -63,7 +63,8 @@ internal fun UnittoApp() { // Anything below will not be called if theming mode is still loading from DataStore themingMode = userPrefs.value.themingMode ?: return, dynamicThemeEnabled = userPrefs.value.enableDynamicTheme, - amoledThemeEnabled = userPrefs.value.enableAmoledTheme + amoledThemeEnabled = userPrefs.value.enableAmoledTheme, + customColor = userPrefs.value.customColor ) val navController = rememberNavController() val sysUiController = rememberSystemUiController() diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml deleted file mode 100644 index 6a7128f4..00000000 --- a/app/src/main/res/drawable/ic_launcher_foreground.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_launcher_monochrome.xml b/app/src/main/res/drawable/ic_launcher_monochrome.xml deleted file mode 100644 index 9b58398e..00000000 --- a/app/src/main/res/drawable/ic_launcher_monochrome.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml deleted file mode 100644 index 7b32835e..00000000 --- a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index 2bde775e..00000000 Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index e808cbff..00000000 Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index 6d592b62..00000000 Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index 667a2fce..00000000 Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index d55a909d..00000000 Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/core/base/src/main/ic_launcher_3_green-playstore.png b/core/base/src/main/ic_launcher_3_green-playstore.png new file mode 100644 index 00000000..da2313ed Binary files /dev/null and b/core/base/src/main/ic_launcher_3_green-playstore.png differ diff --git a/core/base/src/main/res/drawable/ic_launcher_1_foreground.xml b/core/base/src/main/res/drawable/ic_launcher_1_foreground.xml new file mode 100644 index 00000000..49768b8d --- /dev/null +++ b/core/base/src/main/res/drawable/ic_launcher_1_foreground.xml @@ -0,0 +1,45 @@ + + + + + + + + + + diff --git a/core/base/src/main/res/drawable/ic_launcher_2_foreground.xml b/core/base/src/main/res/drawable/ic_launcher_2_foreground.xml new file mode 100644 index 00000000..8e7f2b97 --- /dev/null +++ b/core/base/src/main/res/drawable/ic_launcher_2_foreground.xml @@ -0,0 +1,33 @@ + + + + + + + diff --git a/core/base/src/main/res/drawable/ic_launcher_3_foreground.xml b/core/base/src/main/res/drawable/ic_launcher_3_foreground.xml new file mode 100644 index 00000000..a85ec69f --- /dev/null +++ b/core/base/src/main/res/drawable/ic_launcher_3_foreground.xml @@ -0,0 +1,45 @@ + + + + + + + + + + diff --git a/core/base/src/main/res/mipmap-anydpi-v26/ic_launcher_1_green.xml b/core/base/src/main/res/mipmap-anydpi-v26/ic_launcher_1_green.xml new file mode 100644 index 00000000..7ab49ade --- /dev/null +++ b/core/base/src/main/res/mipmap-anydpi-v26/ic_launcher_1_green.xml @@ -0,0 +1,24 @@ + + + + + + + + \ No newline at end of file diff --git a/core/base/src/main/res/mipmap-anydpi-v26/ic_launcher_1_orange.xml b/core/base/src/main/res/mipmap-anydpi-v26/ic_launcher_1_orange.xml new file mode 100644 index 00000000..9dbdd14d --- /dev/null +++ b/core/base/src/main/res/mipmap-anydpi-v26/ic_launcher_1_orange.xml @@ -0,0 +1,24 @@ + + + + + + + + \ No newline at end of file diff --git a/core/base/src/main/res/mipmap-anydpi-v26/ic_launcher_1_red.xml b/core/base/src/main/res/mipmap-anydpi-v26/ic_launcher_1_red.xml new file mode 100644 index 00000000..f368821a --- /dev/null +++ b/core/base/src/main/res/mipmap-anydpi-v26/ic_launcher_1_red.xml @@ -0,0 +1,24 @@ + + + + + + + + \ No newline at end of file diff --git a/core/base/src/main/res/mipmap-anydpi-v26/ic_launcher_2_green.xml b/core/base/src/main/res/mipmap-anydpi-v26/ic_launcher_2_green.xml new file mode 100644 index 00000000..65cea040 --- /dev/null +++ b/core/base/src/main/res/mipmap-anydpi-v26/ic_launcher_2_green.xml @@ -0,0 +1,24 @@ + + + + + + + + \ No newline at end of file diff --git a/core/base/src/main/res/mipmap-anydpi-v26/ic_launcher_2_orange.xml b/core/base/src/main/res/mipmap-anydpi-v26/ic_launcher_2_orange.xml new file mode 100644 index 00000000..96547697 --- /dev/null +++ b/core/base/src/main/res/mipmap-anydpi-v26/ic_launcher_2_orange.xml @@ -0,0 +1,24 @@ + + + + + + + + \ No newline at end of file diff --git a/core/base/src/main/res/mipmap-anydpi-v26/ic_launcher_2_red.xml b/core/base/src/main/res/mipmap-anydpi-v26/ic_launcher_2_red.xml new file mode 100644 index 00000000..6ed087c9 --- /dev/null +++ b/core/base/src/main/res/mipmap-anydpi-v26/ic_launcher_2_red.xml @@ -0,0 +1,24 @@ + + + + + + + + \ No newline at end of file diff --git a/core/base/src/main/res/mipmap-anydpi-v26/ic_launcher_3_green.xml b/core/base/src/main/res/mipmap-anydpi-v26/ic_launcher_3_green.xml new file mode 100644 index 00000000..d56b3738 --- /dev/null +++ b/core/base/src/main/res/mipmap-anydpi-v26/ic_launcher_3_green.xml @@ -0,0 +1,24 @@ + + + + + + + + \ No newline at end of file diff --git a/core/base/src/main/res/mipmap-anydpi-v26/ic_launcher_3_orange.xml b/core/base/src/main/res/mipmap-anydpi-v26/ic_launcher_3_orange.xml new file mode 100644 index 00000000..b42d62bc --- /dev/null +++ b/core/base/src/main/res/mipmap-anydpi-v26/ic_launcher_3_orange.xml @@ -0,0 +1,24 @@ + + + + + + + + \ No newline at end of file diff --git a/core/base/src/main/res/mipmap-anydpi-v26/ic_launcher_3_red.xml b/core/base/src/main/res/mipmap-anydpi-v26/ic_launcher_3_red.xml new file mode 100644 index 00000000..866e20de --- /dev/null +++ b/core/base/src/main/res/mipmap-anydpi-v26/ic_launcher_3_red.xml @@ -0,0 +1,24 @@ + + + + + + + + \ No newline at end of file diff --git a/core/base/src/main/res/mipmap-hdpi/ic_launcher_1_green.png b/core/base/src/main/res/mipmap-hdpi/ic_launcher_1_green.png new file mode 100644 index 00000000..2a2737fd Binary files /dev/null and b/core/base/src/main/res/mipmap-hdpi/ic_launcher_1_green.png differ diff --git a/core/base/src/main/res/mipmap-hdpi/ic_launcher_1_orange.png b/core/base/src/main/res/mipmap-hdpi/ic_launcher_1_orange.png new file mode 100644 index 00000000..0bf2874c Binary files /dev/null and b/core/base/src/main/res/mipmap-hdpi/ic_launcher_1_orange.png differ diff --git a/core/base/src/main/res/mipmap-hdpi/ic_launcher_1_red.png b/core/base/src/main/res/mipmap-hdpi/ic_launcher_1_red.png new file mode 100644 index 00000000..4b9697a2 Binary files /dev/null and b/core/base/src/main/res/mipmap-hdpi/ic_launcher_1_red.png differ diff --git a/core/base/src/main/res/mipmap-hdpi/ic_launcher_2_green.png b/core/base/src/main/res/mipmap-hdpi/ic_launcher_2_green.png new file mode 100644 index 00000000..342ebf24 Binary files /dev/null and b/core/base/src/main/res/mipmap-hdpi/ic_launcher_2_green.png differ diff --git a/core/base/src/main/res/mipmap-hdpi/ic_launcher_2_orange.png b/core/base/src/main/res/mipmap-hdpi/ic_launcher_2_orange.png new file mode 100644 index 00000000..75160b4f Binary files /dev/null and b/core/base/src/main/res/mipmap-hdpi/ic_launcher_2_orange.png differ diff --git a/core/base/src/main/res/mipmap-hdpi/ic_launcher_2_red.png b/core/base/src/main/res/mipmap-hdpi/ic_launcher_2_red.png new file mode 100644 index 00000000..1f502550 Binary files /dev/null and b/core/base/src/main/res/mipmap-hdpi/ic_launcher_2_red.png differ diff --git a/core/base/src/main/res/mipmap-hdpi/ic_launcher_3_green.png b/core/base/src/main/res/mipmap-hdpi/ic_launcher_3_green.png new file mode 100644 index 00000000..e54454f7 Binary files /dev/null and b/core/base/src/main/res/mipmap-hdpi/ic_launcher_3_green.png differ diff --git a/core/base/src/main/res/mipmap-hdpi/ic_launcher_3_orange.png b/core/base/src/main/res/mipmap-hdpi/ic_launcher_3_orange.png new file mode 100644 index 00000000..8c3f5f55 Binary files /dev/null and b/core/base/src/main/res/mipmap-hdpi/ic_launcher_3_orange.png differ diff --git a/core/base/src/main/res/mipmap-hdpi/ic_launcher_3_red.png b/core/base/src/main/res/mipmap-hdpi/ic_launcher_3_red.png new file mode 100644 index 00000000..e07823f3 Binary files /dev/null and b/core/base/src/main/res/mipmap-hdpi/ic_launcher_3_red.png differ diff --git a/core/base/src/main/res/mipmap-mdpi/ic_launcher_1_green.png b/core/base/src/main/res/mipmap-mdpi/ic_launcher_1_green.png new file mode 100644 index 00000000..6d28a7d5 Binary files /dev/null and b/core/base/src/main/res/mipmap-mdpi/ic_launcher_1_green.png differ diff --git a/core/base/src/main/res/mipmap-mdpi/ic_launcher_1_orange.png b/core/base/src/main/res/mipmap-mdpi/ic_launcher_1_orange.png new file mode 100644 index 00000000..7c6ecae6 Binary files /dev/null and b/core/base/src/main/res/mipmap-mdpi/ic_launcher_1_orange.png differ diff --git a/core/base/src/main/res/mipmap-mdpi/ic_launcher_1_red.png b/core/base/src/main/res/mipmap-mdpi/ic_launcher_1_red.png new file mode 100644 index 00000000..88bde280 Binary files /dev/null and b/core/base/src/main/res/mipmap-mdpi/ic_launcher_1_red.png differ diff --git a/core/base/src/main/res/mipmap-mdpi/ic_launcher_2_green.png b/core/base/src/main/res/mipmap-mdpi/ic_launcher_2_green.png new file mode 100644 index 00000000..07cfdad1 Binary files /dev/null and b/core/base/src/main/res/mipmap-mdpi/ic_launcher_2_green.png differ diff --git a/core/base/src/main/res/mipmap-mdpi/ic_launcher_2_orange.png b/core/base/src/main/res/mipmap-mdpi/ic_launcher_2_orange.png new file mode 100644 index 00000000..43de32e0 Binary files /dev/null and b/core/base/src/main/res/mipmap-mdpi/ic_launcher_2_orange.png differ diff --git a/core/base/src/main/res/mipmap-mdpi/ic_launcher_2_red.png b/core/base/src/main/res/mipmap-mdpi/ic_launcher_2_red.png new file mode 100644 index 00000000..aa27c24a Binary files /dev/null and b/core/base/src/main/res/mipmap-mdpi/ic_launcher_2_red.png differ diff --git a/core/base/src/main/res/mipmap-mdpi/ic_launcher_3_green.png b/core/base/src/main/res/mipmap-mdpi/ic_launcher_3_green.png new file mode 100644 index 00000000..c564b0ff Binary files /dev/null and b/core/base/src/main/res/mipmap-mdpi/ic_launcher_3_green.png differ diff --git a/core/base/src/main/res/mipmap-mdpi/ic_launcher_3_orange.png b/core/base/src/main/res/mipmap-mdpi/ic_launcher_3_orange.png new file mode 100644 index 00000000..46b86e9b Binary files /dev/null and b/core/base/src/main/res/mipmap-mdpi/ic_launcher_3_orange.png differ diff --git a/core/base/src/main/res/mipmap-mdpi/ic_launcher_3_red.png b/core/base/src/main/res/mipmap-mdpi/ic_launcher_3_red.png new file mode 100644 index 00000000..f5ccaeef Binary files /dev/null and b/core/base/src/main/res/mipmap-mdpi/ic_launcher_3_red.png differ diff --git a/core/base/src/main/res/mipmap-xhdpi/ic_launcher_1_green.png b/core/base/src/main/res/mipmap-xhdpi/ic_launcher_1_green.png new file mode 100644 index 00000000..837bd9f2 Binary files /dev/null and b/core/base/src/main/res/mipmap-xhdpi/ic_launcher_1_green.png differ diff --git a/core/base/src/main/res/mipmap-xhdpi/ic_launcher_1_orange.png b/core/base/src/main/res/mipmap-xhdpi/ic_launcher_1_orange.png new file mode 100644 index 00000000..477861cf Binary files /dev/null and b/core/base/src/main/res/mipmap-xhdpi/ic_launcher_1_orange.png differ diff --git a/core/base/src/main/res/mipmap-xhdpi/ic_launcher_1_red.png b/core/base/src/main/res/mipmap-xhdpi/ic_launcher_1_red.png new file mode 100644 index 00000000..550a7031 Binary files /dev/null and b/core/base/src/main/res/mipmap-xhdpi/ic_launcher_1_red.png differ diff --git a/core/base/src/main/res/mipmap-xhdpi/ic_launcher_2_green.png b/core/base/src/main/res/mipmap-xhdpi/ic_launcher_2_green.png new file mode 100644 index 00000000..c898a7a2 Binary files /dev/null and b/core/base/src/main/res/mipmap-xhdpi/ic_launcher_2_green.png differ diff --git a/core/base/src/main/res/mipmap-xhdpi/ic_launcher_2_orange.png b/core/base/src/main/res/mipmap-xhdpi/ic_launcher_2_orange.png new file mode 100644 index 00000000..8e5f90e4 Binary files /dev/null and b/core/base/src/main/res/mipmap-xhdpi/ic_launcher_2_orange.png differ diff --git a/core/base/src/main/res/mipmap-xhdpi/ic_launcher_2_red.png b/core/base/src/main/res/mipmap-xhdpi/ic_launcher_2_red.png new file mode 100644 index 00000000..292071f4 Binary files /dev/null and b/core/base/src/main/res/mipmap-xhdpi/ic_launcher_2_red.png differ diff --git a/core/base/src/main/res/mipmap-xhdpi/ic_launcher_3_green.png b/core/base/src/main/res/mipmap-xhdpi/ic_launcher_3_green.png new file mode 100644 index 00000000..6965ba9e Binary files /dev/null and b/core/base/src/main/res/mipmap-xhdpi/ic_launcher_3_green.png differ diff --git a/core/base/src/main/res/mipmap-xhdpi/ic_launcher_3_orange.png b/core/base/src/main/res/mipmap-xhdpi/ic_launcher_3_orange.png new file mode 100644 index 00000000..b1ebafad Binary files /dev/null and b/core/base/src/main/res/mipmap-xhdpi/ic_launcher_3_orange.png differ diff --git a/core/base/src/main/res/mipmap-xhdpi/ic_launcher_3_red.png b/core/base/src/main/res/mipmap-xhdpi/ic_launcher_3_red.png new file mode 100644 index 00000000..b52c03bb Binary files /dev/null and b/core/base/src/main/res/mipmap-xhdpi/ic_launcher_3_red.png differ diff --git a/core/base/src/main/res/mipmap-xxhdpi/ic_launcher_1_green.png b/core/base/src/main/res/mipmap-xxhdpi/ic_launcher_1_green.png new file mode 100644 index 00000000..1ff614e7 Binary files /dev/null and b/core/base/src/main/res/mipmap-xxhdpi/ic_launcher_1_green.png differ diff --git a/core/base/src/main/res/mipmap-xxhdpi/ic_launcher_1_orange.png b/core/base/src/main/res/mipmap-xxhdpi/ic_launcher_1_orange.png new file mode 100644 index 00000000..41c4b560 Binary files /dev/null and b/core/base/src/main/res/mipmap-xxhdpi/ic_launcher_1_orange.png differ diff --git a/core/base/src/main/res/mipmap-xxhdpi/ic_launcher_1_red.png b/core/base/src/main/res/mipmap-xxhdpi/ic_launcher_1_red.png new file mode 100644 index 00000000..0d7066c6 Binary files /dev/null and b/core/base/src/main/res/mipmap-xxhdpi/ic_launcher_1_red.png differ diff --git a/core/base/src/main/res/mipmap-xxhdpi/ic_launcher_2_green.png b/core/base/src/main/res/mipmap-xxhdpi/ic_launcher_2_green.png new file mode 100644 index 00000000..4ca55d7d Binary files /dev/null and b/core/base/src/main/res/mipmap-xxhdpi/ic_launcher_2_green.png differ diff --git a/core/base/src/main/res/mipmap-xxhdpi/ic_launcher_2_orange.png b/core/base/src/main/res/mipmap-xxhdpi/ic_launcher_2_orange.png new file mode 100644 index 00000000..126b3e38 Binary files /dev/null and b/core/base/src/main/res/mipmap-xxhdpi/ic_launcher_2_orange.png differ diff --git a/core/base/src/main/res/mipmap-xxhdpi/ic_launcher_2_red.png b/core/base/src/main/res/mipmap-xxhdpi/ic_launcher_2_red.png new file mode 100644 index 00000000..772ee987 Binary files /dev/null and b/core/base/src/main/res/mipmap-xxhdpi/ic_launcher_2_red.png differ diff --git a/core/base/src/main/res/mipmap-xxhdpi/ic_launcher_3_green.png b/core/base/src/main/res/mipmap-xxhdpi/ic_launcher_3_green.png new file mode 100644 index 00000000..8a6381e4 Binary files /dev/null and b/core/base/src/main/res/mipmap-xxhdpi/ic_launcher_3_green.png differ diff --git a/core/base/src/main/res/mipmap-xxhdpi/ic_launcher_3_orange.png b/core/base/src/main/res/mipmap-xxhdpi/ic_launcher_3_orange.png new file mode 100644 index 00000000..2025c39c Binary files /dev/null and b/core/base/src/main/res/mipmap-xxhdpi/ic_launcher_3_orange.png differ diff --git a/core/base/src/main/res/mipmap-xxhdpi/ic_launcher_3_red.png b/core/base/src/main/res/mipmap-xxhdpi/ic_launcher_3_red.png new file mode 100644 index 00000000..c04b30d9 Binary files /dev/null and b/core/base/src/main/res/mipmap-xxhdpi/ic_launcher_3_red.png differ diff --git a/core/base/src/main/res/mipmap-xxxhdpi/ic_launcher_1_green.png b/core/base/src/main/res/mipmap-xxxhdpi/ic_launcher_1_green.png new file mode 100644 index 00000000..53c54fa7 Binary files /dev/null and b/core/base/src/main/res/mipmap-xxxhdpi/ic_launcher_1_green.png differ diff --git a/core/base/src/main/res/mipmap-xxxhdpi/ic_launcher_1_orange.png b/core/base/src/main/res/mipmap-xxxhdpi/ic_launcher_1_orange.png new file mode 100644 index 00000000..c4dece23 Binary files /dev/null and b/core/base/src/main/res/mipmap-xxxhdpi/ic_launcher_1_orange.png differ diff --git a/core/base/src/main/res/mipmap-xxxhdpi/ic_launcher_1_red.png b/core/base/src/main/res/mipmap-xxxhdpi/ic_launcher_1_red.png new file mode 100644 index 00000000..f79e98a6 Binary files /dev/null and b/core/base/src/main/res/mipmap-xxxhdpi/ic_launcher_1_red.png differ diff --git a/core/base/src/main/res/mipmap-xxxhdpi/ic_launcher_2_green.png b/core/base/src/main/res/mipmap-xxxhdpi/ic_launcher_2_green.png new file mode 100644 index 00000000..cff15555 Binary files /dev/null and b/core/base/src/main/res/mipmap-xxxhdpi/ic_launcher_2_green.png differ diff --git a/core/base/src/main/res/mipmap-xxxhdpi/ic_launcher_2_orange.png b/core/base/src/main/res/mipmap-xxxhdpi/ic_launcher_2_orange.png new file mode 100644 index 00000000..33001066 Binary files /dev/null and b/core/base/src/main/res/mipmap-xxxhdpi/ic_launcher_2_orange.png differ diff --git a/core/base/src/main/res/mipmap-xxxhdpi/ic_launcher_2_red.png b/core/base/src/main/res/mipmap-xxxhdpi/ic_launcher_2_red.png new file mode 100644 index 00000000..75b5149c Binary files /dev/null and b/core/base/src/main/res/mipmap-xxxhdpi/ic_launcher_2_red.png differ diff --git a/core/base/src/main/res/mipmap-xxxhdpi/ic_launcher_3_green.png b/core/base/src/main/res/mipmap-xxxhdpi/ic_launcher_3_green.png new file mode 100644 index 00000000..0e30e949 Binary files /dev/null and b/core/base/src/main/res/mipmap-xxxhdpi/ic_launcher_3_green.png differ diff --git a/core/base/src/main/res/mipmap-xxxhdpi/ic_launcher_3_orange.png b/core/base/src/main/res/mipmap-xxxhdpi/ic_launcher_3_orange.png new file mode 100644 index 00000000..f074609a Binary files /dev/null and b/core/base/src/main/res/mipmap-xxxhdpi/ic_launcher_3_orange.png differ diff --git a/core/base/src/main/res/mipmap-xxxhdpi/ic_launcher_3_red.png b/core/base/src/main/res/mipmap-xxxhdpi/ic_launcher_3_red.png new file mode 100644 index 00000000..4adf8b57 Binary files /dev/null and b/core/base/src/main/res/mipmap-xxxhdpi/ic_launcher_3_red.png differ diff --git a/core/base/src/main/res/values/colors.xml b/core/base/src/main/res/values/colors.xml new file mode 100644 index 00000000..e00bc481 --- /dev/null +++ b/core/base/src/main/res/values/colors.xml @@ -0,0 +1,23 @@ + + + + #186C31 + #FF9800 + #E91E63 + \ No newline at end of file diff --git a/core/base/src/main/res/values/strings.xml b/core/base/src/main/res/values/strings.xml index ab3740f5..4b9d976a 100644 --- a/core/base/src/main/res/values/strings.xml +++ b/core/base/src/main/res/values/strings.xml @@ -1064,9 +1064,9 @@ tf Millinewton mN - attonewton + Attonewton aN - dyne + Dyne dyn Joule/meter J/m @@ -1317,10 +1317,14 @@ Light Dark Color theme + Pick a theming mode AMOLED Dark Use black background for dark themes Dynamic colors Use colors from your wallpaper + Color scheme + Selected color + Selected icon Loading… @@ -1328,6 +1332,9 @@ Copied %1$s! Cancel OK + Apply + Warning! + This feature is unstable. App will be closed to apply changes. Restart your launcher if nothing changes. Reinstall app from phone settings if things go horribly. You have been warned! Search units No results found Open settings diff --git a/core/ui/src/main/java/com/sadellie/unitto/core/ui/common/SegmentedButton.kt b/core/ui/src/main/java/com/sadellie/unitto/core/ui/common/SegmentedButton.kt new file mode 100644 index 00000000..097cd368 --- /dev/null +++ b/core/ui/src/main/java/com/sadellie/unitto/core/ui/common/SegmentedButton.kt @@ -0,0 +1,106 @@ +/* + * Unitto is a unit converter for Android + * Copyright (c) 2023 Elshan Agaev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sadellie.unitto.core.ui.common + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.RowScope +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.widthIn +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Check +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedButton +import androidx.compose.material3.OutlinedCard +import androidx.compose.material3.contentColorFor +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.RectangleShape +import androidx.compose.ui.unit.dp + +private val GroupRowContainerHeight = 40.dp +private val GroupRowItemMinWidth = 58.dp + +@Composable +fun SegmentedButtonRow( + modifier: Modifier = Modifier, + content: @Composable RowScope.() -> Unit +) { + OutlinedCard( + modifier = modifier, + shape = CircleShape + ) { + Row( + modifier = Modifier + .height(GroupRowContainerHeight) + .widthIn(min = GroupRowItemMinWidth), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center + ) { + content() + } + } +} + +@Composable +fun RowScope.SegmentedButton( + onClick: () -> Unit, + selected: Boolean, + modifier: Modifier = Modifier, + enabled: Boolean = true, + content: @Composable () -> Unit, +) { + val containerColor = + if (selected) + MaterialTheme.colorScheme.secondaryContainer + else + MaterialTheme.colorScheme.surface + OutlinedButton( + modifier = modifier.weight(1f), + onClick = onClick, + shape = RectangleShape, + colors = ButtonDefaults.outlinedButtonColors( + containerColor = containerColor, + contentColor = contentColorFor(containerColor) + ), + enabled = enabled, + contentPadding = PaddingValues(horizontal = 12.dp) + ) { + AnimatedVisibility(visible = selected) { + Row { + Icon( + modifier = Modifier.size(18.dp), + imageVector = Icons.Default.Check, + contentDescription = null + ) + Spacer(Modifier.width(8.dp)) + } + } + content() + } +} diff --git a/core/ui/src/main/java/com/sadellie/unitto/core/ui/common/UnittoListItem.kt b/core/ui/src/main/java/com/sadellie/unitto/core/ui/common/UnittoListItem.kt index 08514aa3..6dcf5ae6 100644 --- a/core/ui/src/main/java/com/sadellie/unitto/core/ui/common/UnittoListItem.kt +++ b/core/ui/src/main/java/com/sadellie/unitto/core/ui/common/UnittoListItem.kt @@ -33,9 +33,9 @@ import androidx.compose.material3.Icon import androidx.compose.material3.ListItem import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.OutlinedTextFieldDefaults import androidx.compose.material3.Switch import androidx.compose.material3.Text -import androidx.compose.material3.TextFieldDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -52,7 +52,7 @@ import com.sadellie.unitto.core.ui.R * Represents one item in list on Settings screen. * * @param label Main text. - * @param supportText Text that is located below label. + * @param supportContent Text that is located below label. * @param switchState Current switch state. * @param onSwitchChange Action to perform when user clicks on this component or just switch. Gives * you new value. @@ -61,7 +61,7 @@ import com.sadellie.unitto.core.ui.R fun UnittoListItem( label: String, leadingContent: @Composable (() -> Unit)?, - supportText: String? = null, + supportContent: String? = null, switchState: Boolean, onSwitchChange: (Boolean) -> Unit ) { @@ -72,8 +72,8 @@ fun UnittoListItem( indication = rememberRipple(), onClick = { onSwitchChange(!switchState) } ), - headlineText = { Text(label) }, - supportingText = { supportText?.let { Text(text = it) } }, + headlineContent = { Text(label) }, + supportingContent = { supportContent?.let { Text(text = it) } }, leadingContent = leadingContent, trailingContent = { Switch( @@ -111,8 +111,8 @@ fun UnittoListItem( ) ListItem( - headlineText = { Text(label) }, - supportingText = { supportText?.let { Text(text = it) } }, + headlineContent = { Text(label) }, + supportingContent = { supportText?.let { Text(text = it) } }, leadingContent = leadingContent, trailingContent = { ExposedDropdownMenuBox( @@ -130,10 +130,10 @@ fun UnittoListItem( singleLine = true, enabled = false, textStyle = MaterialTheme.typography.bodyLarge, - colors = TextFieldDefaults.outlinedTextFieldColors( - disabledBorderColor = MaterialTheme.colorScheme.outline, + colors = OutlinedTextFieldDefaults.colors( disabledTextColor = MaterialTheme.colorScheme.onSurface, - disabledTrailingIconColor = MaterialTheme.colorScheme.onSurfaceVariant + disabledBorderColor = MaterialTheme.colorScheme.outline, + disabledTrailingIconColor = MaterialTheme.colorScheme.onSurfaceVariant, ), trailingIcon = { Icon( diff --git a/data/model/src/main/java/com/sadellie/unitto/data/model/AppIcon.kt b/data/model/src/main/java/com/sadellie/unitto/data/model/AppIcon.kt new file mode 100644 index 00000000..5d3b108c --- /dev/null +++ b/data/model/src/main/java/com/sadellie/unitto/data/model/AppIcon.kt @@ -0,0 +1,47 @@ +/* + * Unitto is a unit converter for Android + * Copyright (c) 2023 Elshan Agaev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sadellie.unitto.data.model + +import androidx.annotation.DrawableRes +import androidx.annotation.StringRes + +private const val unitto = 0xFF186c31 +private const val white = 0xFFFFFFFF +private const val red = 0xFFE91E63 +private const val orange = 0xFFFF9800 + +enum class LauncherIcon( + val component: String, + @StringRes val labelString: Int = R.string.app_name, + @DrawableRes val foregroundDrawable: Int, + val foregroundColor: Long, + val backgroundColor: Long, +) { + MAIN_DEFAULT( "com.sadellie.unitto.MainActivity", R.string.app_name, R.drawable.ic_launcher_1_foreground, white, unitto), + MAIN_RED( "com.sadellie.unitto.custom.MainActivity2", R.string.app_name, R.drawable.ic_launcher_1_foreground, white, red), + MAIN_ORANGE( "com.sadellie.unitto.custom.MainActivity3", R.string.app_name, R.drawable.ic_launcher_1_foreground, white, orange), + + CALC1_DEFAULT( "com.sadellie.unitto.custom.MainActivity4", R.string.calculator, R.drawable.ic_launcher_2_foreground, white, unitto), + CALC1_RED( "com.sadellie.unitto.custom.MainActivity5", R.string.calculator, R.drawable.ic_launcher_2_foreground, white, red), + CALC1_ORANGE( "com.sadellie.unitto.custom.MainActivity6", R.string.calculator, R.drawable.ic_launcher_2_foreground, white, orange), + + CALC2_DEFAULT( "com.sadellie.unitto.custom.MainActivity7", R.string.calculator, R.drawable.ic_launcher_3_foreground, white, unitto), + CALC2_RED( "com.sadellie.unitto.custom.MainActivity8", R.string.calculator, R.drawable.ic_launcher_3_foreground, white, red), + CALC2_ORANGE( "com.sadellie.unitto.custom.MainActivity9", R.string.calculator, R.drawable.ic_launcher_3_foreground, white, orange), +} diff --git a/data/userprefs/src/main/java/com/sadellie/unitto/data/userprefs/UserPreferences.kt b/data/userprefs/src/main/java/com/sadellie/unitto/data/userprefs/UserPreferences.kt index 5942b3ff..9b15672b 100644 --- a/data/userprefs/src/main/java/com/sadellie/unitto/data/userprefs/UserPreferences.kt +++ b/data/userprefs/src/main/java/com/sadellie/unitto/data/userprefs/UserPreferences.kt @@ -18,18 +18,21 @@ package com.sadellie.unitto.data.userprefs +import androidx.compose.ui.graphics.Color 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.emptyPreferences import androidx.datastore.preferences.core.intPreferencesKey +import androidx.datastore.preferences.core.longPreferencesKey import androidx.datastore.preferences.core.stringPreferencesKey import com.sadellie.unitto.core.base.OutputFormat import com.sadellie.unitto.core.base.Separator import com.sadellie.unitto.core.base.TopLevelDestinations import com.sadellie.unitto.data.model.ALL_UNIT_GROUPS import com.sadellie.unitto.data.model.AbstractUnit +import com.sadellie.unitto.data.model.LauncherIcon import com.sadellie.unitto.data.model.UnitGroup import com.sadellie.unitto.data.model.UnitsListSorting import com.sadellie.unitto.data.units.MyUnitIDS @@ -47,6 +50,7 @@ import javax.inject.Inject * still loading. * @property enableDynamicTheme Use dynamic color scheme * @property enableAmoledTheme Use amoled color scheme + * @property customColor Generate custom color scheme from this color. * @property digitsPrecision Current [PRECISIONS]. Number of digits in fractional part * @property separator Current [Separator] that used to separate thousands * @property outputFormat Current [OutputFormat] that is applied to converted value (not input) @@ -59,11 +63,13 @@ import javax.inject.Inject * @property unitConverterFavoritesOnly If true will show only units that are marked as favorite. * @property unitConverterFormatTime If true will format time to be more human readable. * @property unitConverterSorting Units list sorting mode. + * @property launcherIcon Current [LauncherIcon]/ */ data class UserPreferences( val themingMode: ThemingMode? = null, val enableDynamicTheme: Boolean = false, val enableAmoledTheme: Boolean = false, + val customColor: Color = Color.Unspecified, val digitsPrecision: Int = 3, val separator: Int = Separator.SPACES, val outputFormat: Int = OutputFormat.PLAIN, @@ -77,6 +83,7 @@ data class UserPreferences( val unitConverterFavoritesOnly: Boolean = false, val unitConverterFormatTime: Boolean = false, val unitConverterSorting: UnitsListSorting = UnitsListSorting.USAGE, + val launcherIcon: LauncherIcon = LauncherIcon.MAIN_DEFAULT ) /** @@ -90,6 +97,7 @@ class UserPreferencesRepository @Inject constructor(private val dataStore: DataS val THEMING_MODE = stringPreferencesKey("THEMING_MODE_PREF_KEY") val ENABLE_DYNAMIC_THEME = booleanPreferencesKey("ENABLE_DYNAMIC_THEME_PREF_KEY") val ENABLE_AMOLED_THEME = booleanPreferencesKey("ENABLE_AMOLED_THEME_PREF_KEY") + val CUSTOM_COLOR = longPreferencesKey("CUSTOM_COLOR_PREF_KEY") val DIGITS_PRECISION = intPreferencesKey("DIGITS_PRECISION_PREF_KEY") val SEPARATOR = intPreferencesKey("SEPARATOR_PREF_KEY") val OUTPUT_FORMAT = intPreferencesKey("OUTPUT_FORMAT_PREF_KEY") @@ -103,6 +111,7 @@ class UserPreferencesRepository @Inject constructor(private val dataStore: DataS val UNIT_CONVERTER_FAVORITES_ONLY = booleanPreferencesKey("UNIT_CONVERTER_FAVORITES_ONLY_PREF_KEY") val UNIT_CONVERTER_FORMAT_TIME = booleanPreferencesKey("UNIT_CONVERTER_FORMAT_TIME_PREF_KEY") val UNIT_CONVERTER_SORTING = stringPreferencesKey("UNIT_CONVERTER_SORTING_PREF_KEY") + val LAUNCHER_ICON = stringPreferencesKey("LAUNCHER_ICON_PREF_KEY") } val userPreferencesFlow: Flow = dataStore.data @@ -117,20 +126,14 @@ class UserPreferencesRepository @Inject constructor(private val dataStore: DataS val themingMode: ThemingMode = preferences[PrefsKeys.THEMING_MODE]?.let { ThemingMode.valueOf(it) } ?: ThemingMode.AUTO - val enableDynamicTheme: Boolean = - preferences[PrefsKeys.ENABLE_DYNAMIC_THEME] ?: false - val enableAmoledTheme: Boolean = - preferences[PrefsKeys.ENABLE_AMOLED_THEME] ?: false - val digitsPrecision: Int = - preferences[PrefsKeys.DIGITS_PRECISION] ?: 3 - val separator: Int = - preferences[PrefsKeys.SEPARATOR] ?: Separator.SPACES - val outputFormat: Int = - preferences[PrefsKeys.OUTPUT_FORMAT] ?: OutputFormat.PLAIN - val latestLeftSideUnit: String = - preferences[PrefsKeys.LATEST_LEFT_SIDE] ?: MyUnitIDS.kilometer - val latestRightSideUnit: String = - preferences[PrefsKeys.LATEST_RIGHT_SIDE] ?: MyUnitIDS.mile + val enableDynamicTheme: Boolean = preferences[PrefsKeys.ENABLE_DYNAMIC_THEME] ?: false + val enableAmoledTheme: Boolean = preferences[PrefsKeys.ENABLE_AMOLED_THEME] ?: false + val customColor: Color = preferences[PrefsKeys.CUSTOM_COLOR]?.let { Color(it.toULong()) } ?: Color.Unspecified + val digitsPrecision: Int = preferences[PrefsKeys.DIGITS_PRECISION] ?: 3 + val separator: Int = preferences[PrefsKeys.SEPARATOR] ?: Separator.SPACES + val outputFormat: Int = preferences[PrefsKeys.OUTPUT_FORMAT] ?: OutputFormat.PLAIN + val latestLeftSideUnit: String = preferences[PrefsKeys.LATEST_LEFT_SIDE] ?: MyUnitIDS.kilometer + val latestRightSideUnit: String = preferences[PrefsKeys.LATEST_RIGHT_SIDE] ?: MyUnitIDS.mile val shownUnitGroups: List = preferences[PrefsKeys.SHOWN_UNIT_GROUPS]?.let { list -> // Everything is in hidden (nothing in shown) @@ -150,13 +153,14 @@ class UserPreferencesRepository @Inject constructor(private val dataStore: DataS val radianMode: Boolean = preferences[PrefsKeys.RADIAN_MODE] ?: true val unitConverterFavoritesOnly: Boolean = preferences[PrefsKeys.UNIT_CONVERTER_FAVORITES_ONLY] ?: false val unitConverterFormatTime: Boolean = preferences[PrefsKeys.UNIT_CONVERTER_FORMAT_TIME] ?: false - val unitConverterSorting: UnitsListSorting = preferences[PrefsKeys.UNIT_CONVERTER_SORTING]?.let { UnitsListSorting.valueOf(it) } - ?: UnitsListSorting.USAGE + val unitConverterSorting: UnitsListSorting = preferences[PrefsKeys.UNIT_CONVERTER_SORTING]?.let { UnitsListSorting.valueOf(it) } ?: UnitsListSorting.USAGE + val launcherIcon: LauncherIcon = preferences[PrefsKeys.LAUNCHER_ICON]?.let { LauncherIcon.valueOf(it) } ?: LauncherIcon.MAIN_DEFAULT UserPreferences( themingMode = themingMode, enableDynamicTheme = enableDynamicTheme, enableAmoledTheme = enableAmoledTheme, + customColor = customColor, digitsPrecision = digitsPrecision, separator = separator, outputFormat = outputFormat, @@ -169,7 +173,8 @@ class UserPreferencesRepository @Inject constructor(private val dataStore: DataS radianMode = radianMode, unitConverterFavoritesOnly = unitConverterFavoritesOnly, unitConverterFormatTime = unitConverterFormatTime, - unitConverterSorting = unitConverterSorting + unitConverterSorting = unitConverterSorting, + launcherIcon = launcherIcon ) } @@ -253,6 +258,17 @@ class UserPreferencesRepository @Inject constructor(private val dataStore: DataS } } + /** + * Update preference on custom color scheme. + * + * @param color New custom color value. + */ + suspend fun updateCustomColor(color: Color) { + dataStore.edit { preferences -> + preferences[PrefsKeys.CUSTOM_COLOR] = color.value.toLong() + } + } + /** * Update preference on starting screen route. * @@ -335,4 +351,15 @@ class UserPreferencesRepository @Inject constructor(private val dataStore: DataS preferences[PrefsKeys.UNIT_CONVERTER_SORTING] = sorting.name } } + + /** + * Update [UserPreferences.launcherIcon]. + * + * @see UserPreferences.launcherIcon + */ + suspend fun updateLauncherIcon(icon: LauncherIcon) { + dataStore.edit { preferences -> + preferences[PrefsKeys.LAUNCHER_ICON] = icon.name + } + } } diff --git a/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/AboutScreen.kt b/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/AboutScreen.kt index 95d49580..7e9fd9e3 100644 --- a/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/AboutScreen.kt +++ b/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/AboutScreen.kt @@ -75,7 +75,7 @@ internal fun AboutScreen( stringResource(R.string.currency_rates_note_setting) ) }, - headlineText = { Text(stringResource(R.string.currency_rates_note_setting)) }, + headlineContent = { Text(stringResource(R.string.currency_rates_note_setting)) }, modifier = Modifier.clickable { showDialog = true } ) } @@ -89,7 +89,7 @@ internal fun AboutScreen( stringResource(R.string.terms_and_conditions) ) }, - headlineText = { Text(stringResource(R.string.terms_and_conditions)) }, + headlineContent = { Text(stringResource(R.string.terms_and_conditions)) }, modifier = Modifier.clickable { openLink( mContext, @@ -108,7 +108,7 @@ internal fun AboutScreen( stringResource(R.string.privacy_policy) ) }, - headlineText = { Text(stringResource(R.string.privacy_policy)) }, + headlineContent = { Text(stringResource(R.string.privacy_policy)) }, modifier = Modifier.clickable { openLink( mContext, @@ -127,7 +127,7 @@ internal fun AboutScreen( stringResource(R.string.open_source) ) }, - headlineText = { Text(stringResource(R.string.open_source)) }, + headlineContent = { Text(stringResource(R.string.open_source)) }, modifier = Modifier.clickable { openLink( mContext, @@ -146,8 +146,8 @@ internal fun AboutScreen( stringResource(R.string.translate_app) ) }, - headlineText = { Text(stringResource(R.string.translate_app)) }, - supportingText = { Text(stringResource(R.string.translate_app_support)) }, + headlineContent = { Text(stringResource(R.string.translate_app)) }, + supportingContent = { Text(stringResource(R.string.translate_app_support)) }, modifier = Modifier.clickable { openLink( mContext, @@ -166,7 +166,7 @@ internal fun AboutScreen( stringResource(R.string.third_party_licenses) ) }, - headlineText = { Text(stringResource(R.string.third_party_licenses)) }, + headlineContent = { Text(stringResource(R.string.third_party_licenses)) }, modifier = Modifier.clickable { navigateToThirdParty() } ) } @@ -180,8 +180,8 @@ internal fun AboutScreen( stringResource(R.string.app_version_name_setting) ) }, - headlineText = { Text(stringResource(R.string.app_version_name_setting)) }, - supportingText = { Text("${BuildConfig.APP_NAME} (${BuildConfig.APP_CODE})") }, + headlineContent = { Text(stringResource(R.string.app_version_name_setting)) }, + supportingContent = { Text("${BuildConfig.APP_NAME} (${BuildConfig.APP_CODE})") }, modifier = Modifier.combinedClickable { if (userPrefs.value.enableToolsExperiment) { Toast.makeText(mContext, "Tools already enabled!", Toast.LENGTH_LONG).show() diff --git a/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/SettingsScreen.kt b/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/SettingsScreen.kt index 4b287ed9..ece6aa4b 100644 --- a/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/SettingsScreen.kt +++ b/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/SettingsScreen.kt @@ -88,8 +88,8 @@ internal fun SettingsScreen( stringResource(R.string.theme_setting), ) }, - headlineText = { Text(stringResource(R.string.theme_setting)) }, - supportingText = { Text(stringResource(R.string.theme_setting_support)) }, + headlineContent = { Text(stringResource(R.string.theme_setting)) }, + supportingContent = { Text(stringResource(R.string.theme_setting_support)) }, modifier = Modifier.clickable { navControllerAction(themesRoute) } ) } @@ -103,8 +103,8 @@ internal fun SettingsScreen( stringResource(R.string.starting_screen_setting), ) }, - headlineText = { Text(stringResource(R.string.starting_screen_setting)) }, - supportingText = { Text(stringResource(R.string.starting_screen_setting_support)) }, + headlineContent = { Text(stringResource(R.string.starting_screen_setting)) }, + supportingContent = { Text(stringResource(R.string.starting_screen_setting_support)) }, modifier = Modifier.clickable { dialogState = DialogState.START_SCREEN } ) } @@ -121,8 +121,8 @@ internal fun SettingsScreen( stringResource(R.string.precision_setting), ) }, - headlineText = { Text(stringResource(R.string.precision_setting)) }, - supportingText = { Text(stringResource(R.string.precision_setting_support)) }, + headlineContent = { Text(stringResource(R.string.precision_setting)) }, + supportingContent = { Text(stringResource(R.string.precision_setting_support)) }, modifier = Modifier.clickable { dialogState = DialogState.PRECISION } ) } @@ -130,8 +130,8 @@ internal fun SettingsScreen( // SEPARATOR item { ListItem( - headlineText = { Text(stringResource(R.string.separator_setting)) }, - supportingText = { Text(stringResource(R.string.separator_setting_support)) }, + headlineContent = { Text(stringResource(R.string.separator_setting)) }, + supportingContent = { Text(stringResource(R.string.separator_setting_support)) }, modifier = Modifier .clickable { dialogState = DialogState.SEPARATOR } .padding(start = 40.dp) @@ -141,8 +141,8 @@ internal fun SettingsScreen( // OUTPUT FORMAT item { ListItem( - headlineText = { Text(stringResource(R.string.output_format_setting)) }, - supportingText = { Text(stringResource(R.string.output_format_setting_support)) }, + headlineContent = { Text(stringResource(R.string.output_format_setting)) }, + supportingContent = { Text(stringResource(R.string.output_format_setting_support)) }, modifier = Modifier .clickable { dialogState = DialogState.OUTPUT_FORMAT } .padding(start = 40.dp) @@ -161,8 +161,8 @@ internal fun SettingsScreen( stringResource(R.string.disable_unit_group_description), ) }, - headlineText = { Text(stringResource(R.string.unit_groups_setting)) }, - supportingText = { Text(stringResource(R.string.unit_groups_support)) }, + headlineContent = { Text(stringResource(R.string.unit_groups_setting)) }, + supportingContent = { Text(stringResource(R.string.unit_groups_support)) }, modifier = Modifier.clickable { navControllerAction(unitsGroupRoute) } ) } @@ -176,8 +176,8 @@ internal fun SettingsScreen( stringResource(R.string.units_sorting) ) }, - headlineText = { Text(stringResource(R.string.units_sorting)) }, - supportingText = { Text(stringResource(R.string.units_sorting_support)) }, + headlineContent = { Text(stringResource(R.string.units_sorting)) }, + supportingContent = { Text(stringResource(R.string.units_sorting_support)) }, modifier = Modifier.clickable { dialogState = DialogState.UNIT_LIST_SORTING } ) } @@ -192,7 +192,7 @@ internal fun SettingsScreen( stringResource(R.string.format_time) ) }, - supportText = stringResource(R.string.format_time_support), + supportContent = stringResource(R.string.format_time_support), switchState = userPrefs.value.unitConverterFormatTime, onSwitchChange = viewModel::updateUnitConverterFormatTime ) @@ -211,7 +211,7 @@ internal fun SettingsScreen( stringResource(R.string.enable_vibrations) ) }, - supportText = stringResource(R.string.enable_vibrations_support), + supportContent = stringResource(R.string.enable_vibrations_support), switchState = userPrefs.value.enableVibrations, onSwitchChange = viewModel::updateVibrations ) @@ -227,7 +227,7 @@ internal fun SettingsScreen( stringResource(R.string.rate_this_app), ) }, - headlineText = { Text(stringResource(R.string.rate_this_app)) }, + headlineContent = { Text(stringResource(R.string.rate_this_app)) }, modifier = Modifier.clickable { openLink(mContext, BuildConfig.STORE_LINK) } ) } @@ -242,8 +242,8 @@ internal fun SettingsScreen( stringResource(R.string.about_unitto), ) }, - headlineText = { Text(stringResource(R.string.about_unitto)) }, - supportingText = { Text(stringResource(R.string.about_unitto_support)) }, + headlineContent = { Text(stringResource(R.string.about_unitto)) }, + supportingContent = { Text(stringResource(R.string.about_unitto_support)) }, modifier = Modifier.clickable { navControllerAction(aboutRoute) } ) } diff --git a/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/SettingsViewModel.kt b/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/SettingsViewModel.kt index 6f4ebfc4..c38fc7fa 100644 --- a/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/SettingsViewModel.kt +++ b/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/SettingsViewModel.kt @@ -18,12 +18,15 @@ package com.sadellie.unitto.feature.settings +import androidx.compose.ui.graphics.Color import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.sadellie.unitto.core.ui.Formatter +import com.sadellie.unitto.data.model.LauncherIcon import com.sadellie.unitto.data.model.UnitGroup import com.sadellie.unitto.data.model.UnitsListSorting import com.sadellie.unitto.data.unitgroups.UnitGroupsRepository +import com.sadellie.unitto.data.userprefs.UserPreferences import com.sadellie.unitto.data.userprefs.UserPreferencesRepository import dagger.hilt.android.lifecycle.HiltViewModel import io.github.sadellie.themmo.ThemingMode @@ -40,10 +43,10 @@ class SettingsViewModel @Inject constructor( private val userPrefsRepository: UserPreferencesRepository, private val unitGroupsRepository: UnitGroupsRepository, ) : ViewModel() { - var userPrefs = userPrefsRepository.userPreferencesFlow + val userPrefs = userPrefsRepository.userPreferencesFlow .onEach { Formatter.setSeparator(it.separator) } .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), - com.sadellie.unitto.data.userprefs.UserPreferences() + UserPreferences() ) val shownUnitGroups = unitGroupsRepository.shownUnitGroups val hiddenUnitGroups = unitGroupsRepository.hiddenUnitGroups @@ -75,6 +78,15 @@ class SettingsViewModel @Inject constructor( } } + /** + * @see UserPreferencesRepository.updateCustomColor + */ + fun updateCustomColor(color: Color) { + viewModelScope.launch { + userPrefsRepository.updateCustomColor(color) + } + } + /** * @see UserPreferencesRepository.updateDigitsPrecision */ @@ -187,6 +199,16 @@ class SettingsViewModel @Inject constructor( } } + /** + * @see UserPreferencesRepository.updateLauncherIcon + */ + fun updateLauncherIcon(icon: LauncherIcon, finished: () -> Unit?) { + viewModelScope.launch { + userPrefsRepository.updateLauncherIcon(icon) + finished() + } + } + /** * Prevent from dragging over non-draggable items (headers and hidden) * diff --git a/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/ThemesScreen.kt b/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/ThemesScreen.kt index d233f7b1..6e693873 100644 --- a/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/ThemesScreen.kt +++ b/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/ThemesScreen.kt @@ -18,83 +18,228 @@ package com.sadellie.unitto.feature.settings +import android.app.Activity +import android.content.ComponentName +import android.content.Context +import android.content.pm.PackageManager import android.os.Build import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.animateColorAsState import androidx.compose.animation.expandVertically import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.shrinkVertically +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Colorize import androidx.compose.material.icons.filled.DarkMode +import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.Palette +import androidx.compose.material.icons.filled.Warning +import androidx.compose.material3.AlertDialog +import androidx.compose.material3.FilledTonalButton import androidx.compose.material3.Icon +import androidx.compose.material3.ListItem +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable +import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.sadellie.unitto.core.ui.R +import com.sadellie.unitto.core.ui.common.Header import com.sadellie.unitto.core.ui.common.NavigateUpButton +import com.sadellie.unitto.core.ui.common.SegmentedButton +import com.sadellie.unitto.core.ui.common.SegmentedButtonRow import com.sadellie.unitto.core.ui.common.UnittoListItem import com.sadellie.unitto.core.ui.common.UnittoScreenWithLargeTopBar +import com.sadellie.unitto.data.model.LauncherIcon +import com.sadellie.unitto.feature.settings.components.ColorSelector +import com.sadellie.unitto.feature.settings.components.IconsSelector import io.github.sadellie.themmo.ThemingMode import io.github.sadellie.themmo.ThemmoController +private val colorSchemes: List by lazy { + listOf( + Color(0xFFE91E63), + Color(0xFFFF9800), + Color(0xFF4CAF50), + Color(0xFF2196F3), + Color(0xFF9C27B0), + Color(0xFF5C76AA), + Color(0xFF756FAA), + Color(0xFF9E6C2A), + ) +} + @Composable -internal fun ThemesScreen( +internal fun ThemesRoute( navigateUpAction: () -> Unit = {}, themmoController: ThemmoController, viewModel: SettingsViewModel ) { + val userPrefs = viewModel.userPrefs.collectAsStateWithLifecycle() + + ThemesScreen( + navigateUpAction = navigateUpAction, + currentThemingMode = themmoController.currentThemingMode, + onThemeChange = { + themmoController.setThemingMode(it) + viewModel.updateThemingMode(it) + }, + isDynamicThemeEnabled = themmoController.isDynamicThemeEnabled, + onDynamicThemeChange = { + themmoController.enableDynamicTheme(it) + viewModel.updateDynamicTheme(it) + }, + isAmoledThemeEnabled = themmoController.isAmoledThemeEnabled, + onAmoledThemeChange = { + themmoController.enableAmoledTheme(it) + viewModel.updateAmoledTheme(it) + }, + selectedColor = themmoController.currentCustomColor, + onColorChange = { + themmoController.setCustomColor(it) + viewModel.updateCustomColor(it) + }, + currentIcon = userPrefs.value.launcherIcon, + onIconChange = { newValue, callback -> + viewModel.updateLauncherIcon(newValue, callback) + }, + ) +} + +@Composable +private fun ThemesScreen( + navigateUpAction: () -> Unit, + currentThemingMode: ThemingMode, + onThemeChange: (ThemingMode) -> Unit, + isDynamicThemeEnabled: Boolean, + onDynamicThemeChange: (Boolean) -> Unit, + isAmoledThemeEnabled: Boolean, + onAmoledThemeChange: (Boolean) -> Unit, + selectedColor: Color, + onColorChange: (Color) -> Unit, + currentIcon: LauncherIcon, + onIconChange: (LauncherIcon, () -> Unit) -> Unit +) { + val mContext = LocalContext.current + val themingModes by remember { + mutableStateOf( + mapOf( + ThemingMode.AUTO to R.string.force_auto_mode, + ThemingMode.FORCE_LIGHT to R.string.force_light_mode, + ThemingMode.FORCE_DARK to R.string.force_dark_mode + ) + ) + } + var showIconChangeWarning: Boolean by rememberSaveable { mutableStateOf(false) } + + var selectedLauncherIcon: LauncherIcon by remember { mutableStateOf(currentIcon) } + var selectedLauncherIconColor: Color by remember { mutableStateOf(Color(currentIcon.backgroundColor)) } + val selectedLauncherIconColorAnim = animateColorAsState(targetValue = selectedLauncherIconColor) + val launcherIcons: List by remember(selectedLauncherIcon) { + derivedStateOf { + LauncherIcon + .values() + .toList() + .filter { Color(it.backgroundColor) == selectedLauncherIconColor } + } + } + UnittoScreenWithLargeTopBar( title = stringResource(R.string.theme_setting), navigationIcon = { NavigateUpButton(navigateUpAction) } ) { paddingValues -> LazyColumn(contentPadding = paddingValues) { + item { - UnittoListItem( + ListItem( + headlineContent = { Text(stringResource(R.string.selected_color)) }, + supportingContent = { + ColorSelector( + modifier = Modifier.padding(top = 12.dp), + selected = selectedLauncherIconColor, + onItemClick = { + selectedLauncherIconColor = it + }, + colorSchemes = remember { + LauncherIcon.values().map { Color(it.backgroundColor) } + .distinct() + }, + ) + }, + modifier = Modifier.padding(start = 40.dp) + ) + } + + item { + ListItem( + headlineContent = { Text(stringResource(R.string.selected_launcher_icon)) }, + supportingContent = { + IconsSelector( + modifier = Modifier.padding(top = 12.dp), + selectedColor = selectedLauncherIconColorAnim.value, + icons = launcherIcons, + selectedIcon = selectedLauncherIcon, + onIconChange = { selectedLauncherIcon = it } + ) + }, + modifier = Modifier.padding(start = 40.dp) + ) + } + + item { + FilledTonalButton( + modifier = Modifier.padding(start = 56.dp), + enabled = currentIcon != selectedLauncherIcon, + onClick = { showIconChangeWarning = true }, + ) { + Text(stringResource(R.string.apply_label)) + } + } + + item { + ListItem( leadingContent = { Icon( Icons.Default.Palette, stringResource(R.string.color_theme), ) }, - label = stringResource(R.string.color_theme), - allOptions = mapOf( - ThemingMode.AUTO to stringResource(R.string.force_auto_mode), - ThemingMode.FORCE_LIGHT to stringResource(R.string.force_light_mode), - ThemingMode.FORCE_DARK to stringResource(R.string.force_dark_mode) - ), - selected = themmoController.currentThemingMode, - onSelectedChange = { - themmoController.setThemingMode(it) - viewModel.updateThemingMode(it) - } + headlineContent = { Text(stringResource(R.string.color_theme)) }, + supportingContent = { Text(stringResource(R.string.color_theme_support)) }, ) } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) { - item { - UnittoListItem( - leadingContent = { - Icon( - Icons.Default.Colorize, - stringResource(R.string.enable_dynamic_colors), - ) - }, - label = stringResource(R.string.enable_dynamic_colors), - supportText = stringResource(R.string.enable_dynamic_colors_support), - switchState = themmoController.isDynamicThemeEnabled, - onSwitchChange = { - themmoController.enableDynamicTheme(it) - viewModel.updateDynamicTheme(it) - } - ) + item { + SegmentedButtonRow( + modifier = Modifier.padding(56.dp, 8.dp, 24.dp, 2.dp) + ) { + themingModes.forEach { (mode, stringRes) -> + SegmentedButton( + onClick = { onThemeChange(mode) }, + selected = currentThemingMode == mode, + content = { Text(stringResource(stringRes)) } + ) + } } } item { AnimatedVisibility( - visible = (themmoController.currentThemingMode != ThemingMode.FORCE_LIGHT), + visible = currentThemingMode != ThemingMode.FORCE_LIGHT, enter = expandVertically() + fadeIn(), exit = shrinkVertically() + fadeOut(), ) { @@ -106,15 +251,128 @@ internal fun ThemesScreen( ) }, label = stringResource(R.string.force_amoled_mode), - supportText = stringResource(R.string.force_amoled_mode_support), - switchState = themmoController.isAmoledThemeEnabled, - onSwitchChange = { - themmoController.enableAmoledTheme(it) - viewModel.updateAmoledTheme(it) - } + supportContent = stringResource(R.string.force_amoled_mode_support), + switchState = isAmoledThemeEnabled, + onSwitchChange = onAmoledThemeChange + ) + } + } + + item { Header(stringResource(R.string.color_scheme)) } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) { + item { + UnittoListItem( + leadingContent = { + Icon( + Icons.Default.Colorize, + stringResource(R.string.enable_dynamic_colors), + ) + }, + label = stringResource(R.string.enable_dynamic_colors), + supportContent = stringResource(R.string.enable_dynamic_colors_support), + switchState = isDynamicThemeEnabled, + onSwitchChange = onDynamicThemeChange + ) + } + } + + item { + AnimatedVisibility( + visible = !isDynamicThemeEnabled, + enter = expandVertically() + fadeIn(), + exit = shrinkVertically() + fadeOut(), + ) { + ListItem( + headlineContent = { Text(stringResource(R.string.selected_color)) }, + supportingContent = { + ColorSelector( + modifier = Modifier.padding(top = 12.dp), + selected = selectedColor, + onItemClick = onColorChange, + colorSchemes = colorSchemes, + defaultColor = Color(0xFF186c31) + ) + }, + modifier = Modifier.padding(start = 40.dp) ) } } } } + + if (showIconChangeWarning) { + AlertDialog( + icon = { + Icon(Icons.Default.Warning, stringResource(R.string.warning_label)) + }, + title = { + Text(stringResource(R.string.warning_label)) + }, + text = { + Text( + stringResource(R.string.icon_change_warning) + ) + }, + confirmButton = { + TextButton( + onClick = { + onIconChange(selectedLauncherIcon) { + mContext.changeIcon(selectedLauncherIcon) + (mContext as Activity).finish() + } + showIconChangeWarning = false + } + ) { + Text(stringResource(R.string.apply_label)) + } + }, + dismissButton = { + TextButton( + onClick = { showIconChangeWarning = false } + ) { + Text(stringResource(R.string.cancel_label)) + } + }, + onDismissRequest = { showIconChangeWarning = false } + ) + } +} + +private fun Context.changeIcon(newIcon: LauncherIcon) { + // Enable new icon + packageManager.setComponentEnabledSetting( + ComponentName(this, newIcon.component), + PackageManager.COMPONENT_ENABLED_STATE_ENABLED, + PackageManager.DONT_KILL_APP + ) + + val packages = LauncherIcon.values().toList() - newIcon + + // We make sure that other icons are disabled to avoid bugs. + packages.forEach { + packageManager.setComponentEnabledSetting( + ComponentName(this, it.component), + PackageManager.COMPONENT_ENABLED_STATE_DISABLED, + PackageManager.DONT_KILL_APP + ) + } +} + +@Preview +@Composable +private fun Preview() { + ThemesScreen( + navigateUpAction = {}, + currentThemingMode = ThemingMode.AUTO, + onThemeChange = {}, + isDynamicThemeEnabled = false, + onDynamicThemeChange = {}, + isAmoledThemeEnabled = false, + onAmoledThemeChange = {}, + selectedColor = Color.Unspecified, + onColorChange = {}, + currentIcon = LauncherIcon.MAIN_DEFAULT, + onIconChange = {_,_->} + ) } diff --git a/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/UnitGroupsScreen.kt b/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/UnitGroupsScreen.kt index f2834887..ed93cd2e 100644 --- a/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/UnitGroupsScreen.kt +++ b/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/UnitGroupsScreen.kt @@ -100,7 +100,7 @@ internal fun UnitGroupsScreen( } ListItem( - headlineText = { Text(stringResource(item.res)) }, + headlineContent = { Text(stringResource(item.res)) }, modifier = Modifier .padding(horizontal = itemPadding) .clip(CircleShape) @@ -153,7 +153,7 @@ internal fun UnitGroupsScreen( .background(MaterialTheme.colorScheme.surface) .clickable { viewModel.returnUnitGroup(it) } .animateItemPlacement(), - headlineText = { Text(stringResource(it.res)) }, + headlineContent = { Text(stringResource(it.res)) }, trailingContent = { Icon( Icons.Default.AddCircleOutline, diff --git a/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/components/ColorCheckbox.kt b/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/components/ColorCheckbox.kt new file mode 100644 index 00000000..4a38d6d3 --- /dev/null +++ b/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/components/ColorCheckbox.kt @@ -0,0 +1,122 @@ +/* + * Unitto is a unit converter for Android + * Copyright (c) 2023 Elshan Agaev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sadellie.unitto.feature.settings.components + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.core.tween +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.scaleIn +import androidx.compose.animation.scaleOut +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Check +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.surfaceColorAtElevation +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.luminance +import androidx.compose.ui.unit.dp + +@Composable +internal fun ColorSelector( + modifier: Modifier = Modifier, + selected: Color, + onItemClick: (Color) -> Unit, + colorSchemes: List, + defaultColor: Color? = null +) { + LazyRow( + modifier = modifier, + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + if (defaultColor != null) { + // Default, Unitto colors + item { + ColorCheckbox( + color = defaultColor, + selected = Color.Unspecified == selected, + onClick = { onItemClick(Color.Unspecified) } + ) + } + } + + colorSchemes.forEach { + item { + ColorCheckbox( + color = it, + selected = it == selected, + onClick = { onItemClick(it) } + ) + } + } + } +} + +@Composable +private fun ColorCheckbox( + color: Color, + selected: Boolean, + onClick: () -> Unit +) { + Box( + modifier = Modifier + .width(72.dp) + .clip(RoundedCornerShape(25)) + .clickable(onClick = onClick) + .background(MaterialTheme.colorScheme.surfaceColorAtElevation(2.dp)), + contentAlignment = Alignment.Center + ) { + Box( + modifier = Modifier + .fillMaxSize() + .aspectRatio(1f) + .padding(8.dp) + .clip(CircleShape) + .background(color) + .border(1.dp, Color.Black.copy(0.5f), CircleShape), + ) + AnimatedVisibility( + visible = selected, + enter = fadeIn(tween(250)) + scaleIn(tween(150)), + exit = fadeOut(tween(250)) + scaleOut(tween(150)), + ) { + Icon( + imageVector = Icons.Default.Check, + contentDescription = null, + tint = if (color.luminance() > 0.5) Color.Black else Color.White, + ) + } + } +} diff --git a/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/components/IconSelector.kt b/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/components/IconSelector.kt new file mode 100644 index 00000000..24744a47 --- /dev/null +++ b/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/components/IconSelector.kt @@ -0,0 +1,144 @@ +/* + * Unitto is a unit converter for Android + * Copyright (c) 2023 Elshan Agaev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sadellie.unitto.feature.settings.components + +import androidx.annotation.DrawableRes +import androidx.annotation.StringRes +import androidx.compose.animation.core.tween +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.scaleIn +import androidx.compose.animation.scaleOut +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Check +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.surfaceColorAtElevation +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.scale +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.luminance +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import com.sadellie.unitto.data.model.LauncherIcon + + +@Composable +internal fun IconsSelector( + modifier: Modifier, + selectedColor: Color, + icons: List, + selectedIcon: LauncherIcon, + onIconChange: (LauncherIcon) -> Unit +) { + LazyRow( + modifier = modifier, + horizontalArrangement = Arrangement.spacedBy(8.dp)) { + items(icons) { + IconCheckbox( + iconRes = it.foregroundDrawable, + foregroundColor = Color(it.foregroundColor), + backGroundColor = selectedColor, + selected = it == selectedIcon, + onClick = { onIconChange(it) }, + label = it.labelString + ) + } + } +} + +@Composable +private fun IconCheckbox( + @DrawableRes iconRes: Int, + foregroundColor: Color, + backGroundColor: Color, + @StringRes label: Int, + selected: Boolean, + onClick: () -> Unit +) { + Column( + modifier = Modifier + .width(72.dp) + .clip(RoundedCornerShape(25)) + .clickable(onClick = onClick) + .background(MaterialTheme.colorScheme.surfaceColorAtElevation(2.dp)) + .padding(bottom = 8.dp) + , + horizontalAlignment = Alignment.CenterHorizontally + ) { + Box( + modifier = Modifier + .fillMaxSize() + .aspectRatio(1f) + .padding(8.dp) + .clip(CircleShape) + .background(backGroundColor) + .border(1.dp, Color.Black.copy(0.5f), CircleShape), + contentAlignment = Alignment.Center + ) { + Icon( + painter = painterResource(iconRes), + contentDescription = null, + tint = foregroundColor, + modifier = Modifier.scale(1.5f) + ) + + // bug in language, need to call it like this + androidx.compose.animation.AnimatedVisibility( + visible = selected, + enter = fadeIn(tween(250)) + scaleIn(tween(150)), + exit = fadeOut(tween(250)) + scaleOut(tween(150)), + ) { + Box( + modifier = Modifier + .background(MaterialTheme.colorScheme.scrim.copy(0.5f)) + .fillMaxSize(), + contentAlignment = Alignment.Center + ) { + Icon( + imageVector = Icons.Default.Check, + contentDescription = null, + tint = if (backGroundColor.luminance() > 0.5) Color.Black else Color.White, + ) + } + } + } + + Text(stringResource(label), style = MaterialTheme.typography.labelSmall) + } +} diff --git a/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/navigation/SettingsNavigation.kt b/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/navigation/SettingsNavigation.kt index 9949afb9..cc2a874e 100644 --- a/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/navigation/SettingsNavigation.kt +++ b/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/navigation/SettingsNavigation.kt @@ -28,7 +28,7 @@ import com.sadellie.unitto.core.base.TopLevelDestinations import com.sadellie.unitto.feature.settings.AboutScreen import com.sadellie.unitto.feature.settings.SettingsScreen import com.sadellie.unitto.feature.settings.SettingsViewModel -import com.sadellie.unitto.feature.settings.ThemesScreen +import com.sadellie.unitto.feature.settings.ThemesRoute import com.sadellie.unitto.feature.settings.ThirdPartyLicensesScreen import com.sadellie.unitto.feature.settings.UnitGroupsScreen import io.github.sadellie.themmo.ThemmoController @@ -63,7 +63,7 @@ fun NavGraphBuilder.settingGraph( } composable(themesRoute) { - ThemesScreen( + ThemesRoute( navigateUpAction = { navController.navigateUp() }, themmoController = themmoController, viewModel = settingsViewModel diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3bf68e0a..0fe6b065 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,31 +2,31 @@ appCode = "19" appName = "Jazzberry jam" kotlin = "1.8.10" -androidxCore = "1.9.0" -androidGradlePlugin = "7.4.1" +androidxCore = "1.10.0" +androidGradlePlugin = "7.4.2" orgJetbrainsKotlinxCoroutinesTest = "1.6.4" -androidxCompose = "1.4.0-beta01" -androidxComposeCompiler = "1.4.2" -androidxComposeUi = "1.4.0-beta01" -androidxComposeMaterial3 = "1.1.0-alpha06" +androidxCompose = "1.5.0-alpha02" +androidxComposeCompiler = "1.4.4" +androidxComposeUi = "1.5.0-alpha02" +androidxComposeMaterial3 = "1.1.0-beta02" androidxNavigation = "2.5.3" -androidxLifecycleRuntimeCompose = "2.6.0-beta01" +androidxLifecycleRuntimeCompose = "2.6.1" androidxHilt = "1.0.0" -comGoogleDagger = "2.44.2" -androidxComposeMaterialIconsExtended = "1.4.0-alpha04" +comGoogleDagger = "2.45" +androidxComposeMaterialIconsExtended = "1.5.0-alpha02" androidxDatastore = "1.0.0" -comGoogleAccompanist = "0.27.1" -androidxRoom = "2.4.3" +comGoogleAccompanist = "0.30.1" +androidxRoom = "2.5.1" comSquareupMoshi = "1.14.0" comSquareupRetrofit2 = "2.9.0" -comGithubSadellieThemmo = "cf6be7e592" +comGithubSadellieThemmo = "3e34a0dcfe" orgBurnoutcrewComposereorderable = "0.9.6" comGithubSadellieExprk = "e55cba8f41" mxParser = "5.2.1" junit = "4.13.2" androidxTest = "1.5.0" androidxTestExt = "1.1.4" -androidDesugarJdkLibs = "2.0.2" +androidDesugarJdkLibs = "2.0.3" androidxTestRunner = "1.5.1" androidxTestRules = "1.5.0" orgRobolectric = "4.9"