Merge branch 'feat/theme-settings'

This commit is contained in:
Sad Ellie 2023-04-20 11:56:18 +03:00
commit a55bf98ff5
83 changed files with 1322 additions and 154 deletions

View File

@ -5,7 +5,7 @@
<application
android:name=".UnittoApplication"
android:icon="@mipmap/ic_launcher"
android:icon="@mipmap/ic_launcher_1_green"
android:label="@string/app_name"
android:supportsRtl="true"
@ -25,6 +25,117 @@
<data android:scheme="app" android:host="com.sadellie.unitto" />
</intent-filter>
</activity>
<activity-alias
android:name=".custom.MainActivity2"
android:targetActivity=".MainActivity"
android:icon="@mipmap/ic_launcher_1_red"
android:enabled="false"
android:allowTaskReparenting="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<activity-alias
android:name=".custom.MainActivity3"
android:targetActivity=".MainActivity"
android:icon="@mipmap/ic_launcher_1_orange"
android:enabled="false"
android:allowTaskReparenting="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<activity-alias
android:name=".custom.MainActivity4"
android:targetActivity=".MainActivity"
android:icon="@mipmap/ic_launcher_2_green"
android:label="@string/calculator"
android:enabled="false"
android:allowTaskReparenting="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<activity-alias
android:name=".custom.MainActivity5"
android:targetActivity=".MainActivity"
android:icon="@mipmap/ic_launcher_2_red"
android:label="@string/calculator"
android:enabled="false"
android:allowTaskReparenting="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<activity-alias
android:name=".custom.MainActivity6"
android:targetActivity=".MainActivity"
android:icon="@mipmap/ic_launcher_2_orange"
android:label="@string/calculator"
android:enabled="false"
android:allowTaskReparenting="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<activity-alias
android:name=".custom.MainActivity7"
android:targetActivity=".MainActivity"
android:icon="@mipmap/ic_launcher_3_green"
android:label="@string/calculator"
android:enabled="false"
android:allowTaskReparenting="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<activity-alias
android:name=".custom.MainActivity8"
android:targetActivity=".MainActivity"
android:icon="@mipmap/ic_launcher_3_red"
android:label="@string/calculator"
android:enabled="false"
android:allowTaskReparenting="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<activity-alias
android:name=".custom.MainActivity9"
android:targetActivity=".MainActivity"
android:icon="@mipmap/ic_launcher_3_orange"
android:label="@string/calculator"
android:enabled="false"
android:allowTaskReparenting="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
</application>
</manifest>

View File

@ -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()

View File

@ -1,16 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<group android:scaleX="0.3559164"
android:scaleY="0.3559164"
android:translateX="37.271927"
android:translateY="24.247612">
<group android:translateY="133.59375">
<path android:pathData="M85.359375,-102L85.359375,-34.09375Q85.359375,-17.90625,74.90625,-8.453125Q64.46875,1,47.109375,1Q29.53125,1,19.1875,-8.3125Q8.859375,-17.625,8.859375,-34.171875L8.859375,-102L26.578125,-102L26.578125,-33.953125Q26.578125,-23.765625,31.78125,-18.375Q36.984375,-13,47.109375,-13Q67.640625,-13,67.640625,-34.515625L67.640625,-102L85.359375,-102Z"
android:fillColor="#186C31"/>
</group>
</group>
</vector>

View File

@ -1,16 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="72dp"
android:height="72dp"
android:viewportWidth="108"
android:viewportHeight="108">
<group android:scaleX="0.3559164"
android:scaleY="0.3559164"
android:translateX="37.271927"
android:translateY="24.247612">
<group android:translateY="133.59375">
<path android:pathData="M85.359375,-102L85.359375,-34.09375Q85.359375,-17.90625,74.90625,-8.453125Q64.46875,1,47.109375,1Q29.53125,1,19.1875,-8.3125Q8.859375,-17.625,8.859375,-34.171875L8.859375,-102L26.578125,-102L26.578125,-33.953125Q26.578125,-23.765625,31.78125,-18.375Q36.984375,-13,47.109375,-13Q67.640625,-13,67.640625,-34.515625L67.640625,-102L85.359375,-102Z"
android:fillColor="#186C31"/>
</group>
</group>
</vector>

View File

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
<!--suppress AndroidElementNotAllowed -->
<monochrome android:drawable="@drawable/ic_launcher_monochrome"/>
</adaptive-icon>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 883 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -0,0 +1,45 @@
<!--
~ 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 <https://www.gnu.org/licenses/>.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="66"
android:viewportHeight="66">
<group android:scaleX="0.396"
android:scaleY="0.396"
android:translateX="20.053"
android:translateY="20.174">
<path
android:pathData="M9,3.5L25,3.5A4.5,4.5 0,0 1,29.5 8L29.5,24A4.5,4.5 0,0 1,25 28.5L9,28.5A4.5,4.5 0,0 1,4.5 24L4.5,8A4.5,4.5 0,0 1,9 3.5z"
android:strokeWidth="3"
android:fillColor="#00000000"
android:strokeColor="#ffffff"/>
<path
android:pathData="M40,36.5L56,36.5A4.5,4.5 0,0 1,60.5 41L60.5,57A4.5,4.5 0,0 1,56 61.5L40,61.5A4.5,4.5 0,0 1,35.5 57L35.5,41A4.5,4.5 0,0 1,40 36.5z"
android:strokeWidth="3"
android:fillColor="#00000000"
android:strokeColor="#ffffff"/>
<path
android:pathData="M18.5,40C18.5,39.172 17.828,38.5 17,38.5C16.172,38.5 15.5,39.172 15.5,40H18.5ZM15.939,62.061C16.525,62.646 17.475,62.646 18.061,62.061L27.607,52.515C28.192,51.929 28.192,50.979 27.607,50.393C27.021,49.808 26.071,49.808 25.485,50.393L17,58.879L8.515,50.393C7.929,49.808 6.979,49.808 6.393,50.393C5.808,50.979 5.808,51.929 6.393,52.515L15.939,62.061ZM15.5,40L15.5,61H18.5V40H15.5Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M46.5,25C46.5,25.828 47.172,26.5 48,26.5C48.828,26.5 49.5,25.828 49.5,25L46.5,25ZM49.061,2.939C48.475,2.354 47.525,2.354 46.939,2.939L37.393,12.485C36.808,13.071 36.808,14.021 37.393,14.607C37.979,15.192 38.929,15.192 39.515,14.607L48,6.121L56.485,14.607C57.071,15.192 58.021,15.192 58.607,14.607C59.192,14.021 59.192,13.071 58.607,12.485L49.061,2.939ZM49.5,25L49.5,4L46.5,4L46.5,25L49.5,25Z"
android:fillColor="#ffffff"/>
</group>
</vector>

View File

@ -0,0 +1,33 @@
<!--
~ 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 <https://www.gnu.org/licenses/>.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="66"
android:viewportHeight="66">
<group android:scaleX="0.40408164"
android:scaleY="0.40408164"
android:translateX="19.665306"
android:translateY="19.665306">
<path
android:pathData="M20,38C20,36.343 21.343,35 23,35C24.657,35 26,36.343 26,38C26,39.657 24.657,41 23,41C21.343,41 20,39.657 20,38ZM30,38C30,36.343 31.343,35 33,35C34.657,35 36,36.343 36,38C36,39.657 34.657,41 33,41C31.343,41 30,39.657 30,38ZM40,38C40,36.343 41.343,35 43,35C44.657,35 46,36.343 46,38C46,39.657 44.657,41 43,41C41.343,41 40,39.657 40,38ZM33,43C34.657,43 36,44.343 36,46C36,47.657 34.657,49 33,49C31.343,49 30,47.657 30,46C30,44.343 31.343,43 33,43ZM43,43C41.343,43 40,44.343 40,46C40,47.657 41.343,49 43,49C44.657,49 46,47.657 46,46C46,44.343 44.657,43 43,43ZM23,43C21.343,43 20,44.343 20,46C20,47.657 21.343,49 23,49C24.657,49 26,47.657 26,46C26,44.343 24.657,43 23,43ZM36,54C36,52.343 34.657,51 33,51C31.343,51 30,52.343 30,54C30,55.657 31.343,57 33,57C34.657,57 36,55.657 36,54ZM46,54C46,52.343 44.657,51 43,51C41.343,51 40,52.343 40,54C40,55.657 41.343,57 43,57C44.657,57 46,55.657 46,54ZM20,54C20,52.343 21.343,51 23,51C24.657,51 26,52.343 26,54C26,55.657 24.657,57 23,57C21.343,57 20,55.657 20,54ZM18,3C14.686,3 12,5.686 12,9V57C12,60.314 14.686,63 18,63H48C51.314,63 54,60.314 54,57V9C54,5.686 51.314,3 48,3H18ZM17,13C17,10.791 18.791,9 21,9H45C47.209,9 49,10.791 49,13V25C49,27.209 47.209,29 45,29H21C18.791,29 17,27.209 17,25V13ZM38.172,13.465L41.354,16.646C41.549,16.842 41.549,17.158 41.354,17.354L38.172,20.535C37.976,20.731 37.66,20.731 37.465,20.535C37.269,20.34 37.269,20.024 37.465,19.828L39.793,17.5H32C31.724,17.5 31.5,17.276 31.5,17C31.5,16.724 31.724,16.5 32,16.5H39.793L37.465,14.172C37.269,13.976 37.269,13.66 37.465,13.465C37.66,13.269 37.976,13.269 38.172,13.465ZM24.646,21.354L27.828,24.535C28.024,24.731 28.34,24.731 28.535,24.535C28.731,24.34 28.731,24.024 28.535,23.828L26.207,21.5H34C34.276,21.5 34.5,21.276 34.5,21C34.5,20.724 34.276,20.5 34,20.5H26.207L28.535,18.172C28.731,17.976 28.731,17.66 28.535,17.465C28.34,17.269 28.024,17.269 27.828,17.465L24.646,20.646C24.451,20.842 24.451,21.158 24.646,21.354Z"
android:fillColor="#ffffff"
android:fillType="evenOdd"/>
</group>
</vector>

View File

@ -0,0 +1,45 @@
<!--
~ 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 <https://www.gnu.org/licenses/>.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="66"
android:viewportHeight="66">
<group android:scaleX="0.4125"
android:scaleY="0.4125"
android:translateX="19.3875"
android:translateY="19.3875">
<path
android:pathData="M42,36C38.686,36 36,38.686 36,42V56C36,59.314 38.686,62 42,62H56C59.314,62 62,59.314 62,56V42C62,38.686 59.314,36 56,36H42ZM49,41C47.895,41 47,41.895 47,43C47,44.105 47.895,45 49,45C50.105,45 51,44.105 51,43C51,41.895 50.105,41 49,41ZM42,47C40.895,47 40,47.895 40,49C40,50.105 40.895,51 42,51H56C57.105,51 58,50.105 58,49C58,47.895 57.105,47 56,47H42ZM47,55C47,53.895 47.895,53 49,53C50.105,53 51,53.895 51,55C51,56.105 50.105,57 49,57C47.895,57 47,56.105 47,55Z"
android:fillColor="#ffffff"
android:fillType="evenOdd"/>
<path
android:pathData="M10,36C6.686,36 4,38.686 4,42V56C4,59.314 6.686,62 10,62H24C27.314,62 30,59.314 30,56V42C30,38.686 27.314,36 24,36H10ZM9.929,41.929C10.71,41.148 11.976,41.148 12.757,41.929L17,46.172L21.243,41.929C22.024,41.148 23.29,41.148 24.071,41.929C24.852,42.71 24.852,43.976 24.071,44.757L19.828,49L24.071,53.243C24.852,54.024 24.852,55.29 24.071,56.071C23.29,56.852 22.024,56.852 21.243,56.071L17,51.828L12.757,56.071C11.976,56.852 10.71,56.852 9.929,56.071C9.148,55.29 9.148,54.024 9.929,53.243L14.172,49L9.929,44.757C9.148,43.976 9.148,42.71 9.929,41.929Z"
android:fillColor="#ffffff"
android:fillType="evenOdd"/>
<path
android:pathData="M42,4C38.686,4 36,6.686 36,10V24C36,27.314 38.686,30 42,30H56C59.314,30 62,27.314 62,24V10C62,6.686 59.314,4 56,4H42ZM42,15C40.895,15 40,15.895 40,17C40,18.105 40.895,19 42,19H56C57.105,19 58,18.105 58,17C58,15.895 57.105,15 56,15H42Z"
android:fillColor="#ffffff"
android:fillType="evenOdd"/>
<path
android:pathData="M10,4C6.686,4 4,6.686 4,10V24C4,27.314 6.686,30 10,30H24C27.314,30 30,27.314 30,24V10C30,6.686 27.314,4 24,4H10ZM17,8C18.105,8 19,8.895 19,10V15H24C25.105,15 26,15.895 26,17C26,18.105 25.105,19 24,19H19V24C19,25.105 18.105,26 17,26C15.895,26 15,25.105 15,24V19H10C8.895,19 8,18.105 8,17C8,15.895 8.895,15 10,15H15V10C15,8.895 15.895,8 17,8Z"
android:fillColor="#ffffff"
android:fillType="evenOdd"/>
</group>
</vector>

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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 <https://www.gnu.org/licenses/>.
-->
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_green_background"/>
<foreground android:drawable="@drawable/ic_launcher_1_foreground"/>
<monochrome android:drawable="@drawable/ic_launcher_1_foreground"/>
</adaptive-icon>

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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 <https://www.gnu.org/licenses/>.
-->
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_orange_background"/>
<foreground android:drawable="@drawable/ic_launcher_1_foreground"/>
<monochrome android:drawable="@drawable/ic_launcher_1_foreground"/>
</adaptive-icon>

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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 <https://www.gnu.org/licenses/>.
-->
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_red_background"/>
<foreground android:drawable="@drawable/ic_launcher_1_foreground"/>
<monochrome android:drawable="@drawable/ic_launcher_1_foreground"/>
</adaptive-icon>

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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 <https://www.gnu.org/licenses/>.
-->
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_green_background"/>
<foreground android:drawable="@drawable/ic_launcher_2_foreground"/>
<monochrome android:drawable="@drawable/ic_launcher_2_foreground"/>
</adaptive-icon>

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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 <https://www.gnu.org/licenses/>.
-->
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_orange_background"/>
<foreground android:drawable="@drawable/ic_launcher_2_foreground"/>
<monochrome android:drawable="@drawable/ic_launcher_2_foreground"/>
</adaptive-icon>

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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 <https://www.gnu.org/licenses/>.
-->
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_red_background"/>
<foreground android:drawable="@drawable/ic_launcher_2_foreground"/>
<monochrome android:drawable="@drawable/ic_launcher_2_foreground"/>
</adaptive-icon>

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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 <https://www.gnu.org/licenses/>.
-->
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_green_background"/>
<foreground android:drawable="@drawable/ic_launcher_3_foreground"/>
<monochrome android:drawable="@drawable/ic_launcher_3_foreground"/>
</adaptive-icon>

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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 <https://www.gnu.org/licenses/>.
-->
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_orange_background"/>
<foreground android:drawable="@drawable/ic_launcher_3_foreground"/>
<monochrome android:drawable="@drawable/ic_launcher_3_foreground"/>
</adaptive-icon>

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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 <https://www.gnu.org/licenses/>.
-->
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_red_background"/>
<foreground android:drawable="@drawable/ic_launcher_3_foreground"/>
<monochrome android:drawable="@drawable/ic_launcher_3_foreground"/>
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1015 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ 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 <https://www.gnu.org/licenses/>.
-->
<resources>
<color name="ic_launcher_green_background">#186C31</color>
<color name="ic_launcher_orange_background">#FF9800</color>
<color name="ic_launcher_red_background">#E91E63</color>
</resources>

View File

@ -1064,9 +1064,9 @@
<string name="ton_force_short">tf</string>
<string name="millinewton">Millinewton</string>
<string name="millinewton_short">mN</string>
<string name="attonewton">attonewton</string>
<string name="attonewton">Attonewton</string>
<string name="attonewton_short">aN</string>
<string name="dyne">dyne</string>
<string name="dyne">Dyne</string>
<string name="dyne_short">dyn</string>
<string name="joule_per_meter">Joule/meter</string>
<string name="joule_per_meter_short">J/m</string>
@ -1317,10 +1317,14 @@
<string name="force_light_mode">Light</string>
<string name="force_dark_mode">Dark</string>
<string name="color_theme">Color theme</string>
<string name="color_theme_support">Pick a theming mode</string>
<string name="force_amoled_mode">AMOLED Dark</string>
<string name="force_amoled_mode_support">Use black background for dark themes</string>
<string name="enable_dynamic_colors">Dynamic colors</string>
<string name="enable_dynamic_colors_support">Use colors from your wallpaper</string>
<string name="color_scheme">Color scheme</string>
<string name="selected_color">Selected color</string>
<string name="selected_launcher_icon">Selected icon</string>
<!--MISC.-->
<string name="loading_label">Loading…</string>
@ -1328,6 +1332,9 @@
<string name="copied">Copied %1$s!</string>
<string name="cancel_label">Cancel</string>
<string name="ok_label" translatable="false">OK</string>
<string name="apply_label">Apply</string>
<string name="warning_label">Warning!</string>
<string name="icon_change_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!</string>
<string name="search_bar_placeholder">Search units</string>
<string name="search_placeholder">No results found</string>
<string name="search_placeholder_button_label">Open settings</string>

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
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()
}
}

View File

@ -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 <T> 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 <T> 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(

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
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),
}

View File

@ -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<UserPreferences> = 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<UnitGroup> =
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
}
}
}

View File

@ -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()

View File

@ -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) }
)
}

View File

@ -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)
*

View File

@ -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<Color> 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<LauncherIcon> 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),
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)) }
)
},
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 {
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 = {_,_->}
)
}

View File

@ -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,

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
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<Color>,
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,
)
}
}
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
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<LauncherIcon>,
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)
}
}

View File

@ -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

View File

@ -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"