From 73c87aca56903ad34bd6f910319377326ea1f1c1 Mon Sep 17 00:00:00 2001 From: FunkyMuse Date: Mon, 26 Jun 2023 19:22:56 +0200 Subject: [PATCH] wip: migrate settings to compose --- app/build.gradle | 73 --------- app/build.gradle.kts | 110 +++++++++++++ .../calculator/activities/MainActivity.kt | 102 ++++++------ .../calculator/activities/SettingsActivity.kt | 147 ++++++++++++------ .../activities/WidgetConfigureActivity.kt | 47 +++--- .../calculator/adapters/HistoryAdapter.kt | 20 ++- .../BooleanPreviewParameterProvider.kt | 8 + .../compose/extensions/PreviewExtensions.kt | 28 ++++ .../compose/screens/SettingsScreen.kt | 88 +++++++++++ .../settings/SettingsCheckBoxComponent.kt | 75 +++++++++ .../compose/settings/SettingsGroup.kt | 64 ++++++++ .../settings/SettingsPreferenceComponent.kt | 68 ++++++++ .../settings/SettingsTitleTextComponent.kt | 38 +++++ .../calculator/compose/theme/Theme.kt | 103 ++++++++++++ .../calculator/dialogs/HistoryDialog.kt | 13 +- .../calculator/extensions/Binding.kt | 10 ++ .../calculator/helpers/CalculatorImpl.kt | 4 +- build.gradle | 29 ---- build.gradle.kts | 5 + gradle.properties | 30 ++-- gradle/libs.versions.toml | 93 +++++++++++ gradle/wrapper/gradle-wrapper.properties | 2 +- settings.gradle | 1 - settings.gradle.kts | 16 ++ 24 files changed, 918 insertions(+), 256 deletions(-) delete mode 100644 app/build.gradle create mode 100644 app/build.gradle.kts create mode 100644 app/src/main/kotlin/com/simplemobiletools/calculator/compose/extensions/BooleanPreviewParameterProvider.kt create mode 100644 app/src/main/kotlin/com/simplemobiletools/calculator/compose/extensions/PreviewExtensions.kt create mode 100644 app/src/main/kotlin/com/simplemobiletools/calculator/compose/screens/SettingsScreen.kt create mode 100644 app/src/main/kotlin/com/simplemobiletools/calculator/compose/settings/SettingsCheckBoxComponent.kt create mode 100644 app/src/main/kotlin/com/simplemobiletools/calculator/compose/settings/SettingsGroup.kt create mode 100644 app/src/main/kotlin/com/simplemobiletools/calculator/compose/settings/SettingsPreferenceComponent.kt create mode 100644 app/src/main/kotlin/com/simplemobiletools/calculator/compose/settings/SettingsTitleTextComponent.kt create mode 100644 app/src/main/kotlin/com/simplemobiletools/calculator/compose/theme/Theme.kt create mode 100644 app/src/main/kotlin/com/simplemobiletools/calculator/extensions/Binding.kt delete mode 100644 build.gradle create mode 100644 build.gradle.kts create mode 100644 gradle/libs.versions.toml delete mode 100644 settings.gradle create mode 100644 settings.gradle.kts diff --git a/app/build.gradle b/app/build.gradle deleted file mode 100644 index 2a70628d..00000000 --- a/app/build.gradle +++ /dev/null @@ -1,73 +0,0 @@ -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply plugin: 'kotlin-android-extensions' -apply plugin: 'kotlin-kapt' - -def keystorePropertiesFile = rootProject.file("keystore.properties") -def keystoreProperties = new Properties() -if (keystorePropertiesFile.exists()) { - keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) -} - -android { - compileSdkVersion 33 - - defaultConfig { - applicationId "com.simplemobiletools.calculator" - minSdkVersion 23 - targetSdkVersion 33 - versionCode 60 - versionName "5.11.3" - setProperty("archivesBaseName", "calculator") - } - - signingConfigs { - if (keystorePropertiesFile.exists()) { - release { - keyAlias keystoreProperties['keyAlias'] - keyPassword keystoreProperties['keyPassword'] - storeFile file(keystoreProperties['storeFile']) - storePassword keystoreProperties['storePassword'] - } - } - } - - buildTypes { - debug { - applicationIdSuffix ".debug" - } - release { - minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - if (keystorePropertiesFile.exists()) { - signingConfig signingConfigs.release - } - } - } - - flavorDimensions "variants" - productFlavors { - core {} - fdroid {} - prepaid {} - } - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - - lintOptions { - checkReleaseBuilds false - abortOnError false - } -} - -dependencies { - implementation 'com.github.SimpleMobileTools:Simple-Commons:4c83ec8740' - implementation 'me.grantland:autofittextview:0.2.1' - implementation 'net.objecthunter:exp4j:0.4.8' - - kapt 'androidx.room:room-compiler:2.5.1' - implementation 'androidx.room:room-runtime:2.5.1' - annotationProcessor 'androidx.room:room-compiler:2.5.1' -} diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 00000000..6d48d33b --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,110 @@ +import java.io.FileInputStream +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile +import org.jetbrains.kotlin.konan.properties.Properties + +plugins { + alias(libs.plugins.android) + alias(libs.plugins.kotlinAndroid) + alias(libs.plugins.ksp) +} + +val keystorePropertiesFile: File = rootProject.file("keystore.properties") +val keystoreProperties = Properties() +if (keystorePropertiesFile.exists()) { + keystoreProperties.load(FileInputStream(keystorePropertiesFile)) +} + +android { + compileSdk = project.libs.versions.app.build.compileSDKVersion.get().toInt() + + defaultConfig { + minSdk = project.libs.versions.app.build.minimumSDK.get().toInt() + targetSdk = project.libs.versions.app.build.targetSDK.get().toInt() + versionName = project.libs.versions.app.version.versionName.get() + versionCode = project.libs.versions.app.version.versionCode.get().toInt() + setProperty("archivesBaseName", "calculator") + } + + signingConfigs { + if (keystorePropertiesFile.exists()) { + register("release") { + keyAlias = keystoreProperties.getProperty("keyAlias") + keyPassword = keystoreProperties.getProperty("keyPassword") + storeFile = file(keystoreProperties.getProperty("storeFile")) + storePassword = keystoreProperties.getProperty("storePassword") + } + } + } + + buildTypes { + debug { + applicationIdSuffix = ".debug" + } + release { + isMinifyEnabled = true + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + if (keystorePropertiesFile.exists()) { + signingConfig = signingConfigs.getByName("release") + } + } + } + + buildFeatures { + viewBinding = true + compose = true + } + + composeOptions { + kotlinCompilerExtensionVersion = libs.versions.composeCompiler.get() + } + + flavorDimensions.add("variants") + productFlavors { + register("core") + register("fdroid") + register("prepaid") + } + + compileOptions { + val currentJavaVersionFromLibs = JavaVersion.valueOf(libs.versions.app.build.javaVersion.get().toString()) + sourceCompatibility = currentJavaVersionFromLibs + targetCompatibility = currentJavaVersionFromLibs + } + + tasks.withType { + kotlinOptions.jvmTarget = project.libs.versions.app.build.kotlinJVMTarget.get() + kotlinOptions.freeCompilerArgs = listOf( + "-opt-in=kotlin.RequiresOptIn", + "-opt-in=androidx.compose.material3.ExperimentalMaterial3Api", + "-opt-in=androidx.compose.material.ExperimentalMaterialApi", + "-opt-in=androidx.compose.foundation.ExperimentalFoundationApi", + "-Xcontext-receivers" + ) + } + + sourceSets { + getByName("main").java.srcDirs("src/main/kotlin") + } + + lint { + checkReleaseBuilds = false + abortOnError = false + } +} + +dependencies { + implementation(libs.simple.tools.commons) + implementation(libs.auto.fit.text.view) + implementation(libs.exp4j) + + implementation(libs.bundles.compose) + implementation(libs.bundles.accompanist) + implementation(libs.bundles.compose.preview) + + implementation(libs.bundles.room) + ksp(libs.androidx.room.compiler) + +} diff --git a/app/src/main/kotlin/com/simplemobiletools/calculator/activities/MainActivity.kt b/app/src/main/kotlin/com/simplemobiletools/calculator/activities/MainActivity.kt index cff7c9de..38146f6d 100644 --- a/app/src/main/kotlin/com/simplemobiletools/calculator/activities/MainActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/calculator/activities/MainActivity.kt @@ -9,6 +9,7 @@ import androidx.core.content.res.ResourcesCompat import com.simplemobiletools.calculator.BuildConfig import com.simplemobiletools.calculator.R import com.simplemobiletools.calculator.databases.CalculatorDatabase +import com.simplemobiletools.calculator.databinding.ActivityMainBinding import com.simplemobiletools.calculator.dialogs.HistoryDialog import com.simplemobiletools.calculator.extensions.config import com.simplemobiletools.calculator.extensions.updateViewColors @@ -20,7 +21,6 @@ import com.simplemobiletools.commons.helpers.LOWER_ALPHA_INT import com.simplemobiletools.commons.helpers.MEDIUM_ALPHA_INT import com.simplemobiletools.commons.models.FAQItem import com.simplemobiletools.commons.models.Release -import kotlinx.android.synthetic.main.activity_main.* import me.grantland.widget.AutofitHelper class MainActivity : SimpleActivity(), Calculator { @@ -32,48 +32,50 @@ class MainActivity : SimpleActivity(), Calculator { private var saveCalculatorState: String = "" private lateinit var calc: CalculatorImpl + private val binding by lazy(LazyThreadSafetyMode.NONE) { ActivityMainBinding.inflate(layoutInflater) } + override fun onCreate(savedInstanceState: Bundle?) { isMaterialActivity = true super.onCreate(savedInstanceState) - setContentView(R.layout.activity_main) + setContentView(binding.root) appLaunched(BuildConfig.APPLICATION_ID) setupOptionsMenu() refreshMenuItems() - updateMaterialActivityViews(main_coordinator, null, useTransparentNavigation = false, useTopSearchMenu = false) - setupMaterialScrollListener(main_nested_scrollview, main_toolbar) + updateMaterialActivityViews(binding.mainCoordinator, null, useTransparentNavigation = false, useTopSearchMenu = false) + setupMaterialScrollListener(binding.mainNestedScrollview, binding.mainToolbar) if (savedInstanceState != null) { saveCalculatorState = savedInstanceState.getCharSequence(CALCULATOR_STATE) as String } calc = CalculatorImpl(this, applicationContext, decimalSeparator, groupingSeparator, saveCalculatorState) - btn_plus.setOnClickOperation(PLUS) - btn_minus.setOnClickOperation(MINUS) - btn_multiply.setOnClickOperation(MULTIPLY) - btn_divide.setOnClickOperation(DIVIDE) - btn_percent.setOnClickOperation(PERCENT) - btn_power.setOnClickOperation(POWER) - btn_root.setOnClickOperation(ROOT) - btn_minus.setOnLongClickListener { calc.turnToNegative() } - btn_clear.setVibratingOnClickListener { calc.handleClear() } - btn_clear.setOnLongClickListener { + binding.btnPlus?.setOnClickOperation(PLUS) + binding.btnMinus?.setOnClickOperation(MINUS) + binding.btnMultiply?.setOnClickOperation(MULTIPLY) + binding.btnDivide?.setOnClickOperation(DIVIDE) + binding.btnPercent?.setOnClickOperation(PERCENT) + binding.btnPower?.setOnClickOperation(POWER) + binding.btnRoot?.setOnClickOperation(ROOT) + binding.btnMinus?.setOnLongClickListener { calc.turnToNegative() } + binding.btnClear?.setVibratingOnClickListener { calc.handleClear() } + binding.btnClear?.setOnLongClickListener { calc.handleReset() true } getButtonIds().forEach { - it.setVibratingOnClickListener { view -> + it?.setVibratingOnClickListener { view -> calc.numpadClicked(view.id) } } - btn_equals.setVibratingOnClickListener { calc.handleEquals() } - formula.setOnLongClickListener { copyToClipboard(false) } - result.setOnLongClickListener { copyToClipboard(true) } - AutofitHelper.create(result) - AutofitHelper.create(formula) + binding.btnEquals?.setVibratingOnClickListener { calc.handleEquals() } + binding.formula?.setOnLongClickListener { copyToClipboard(false) } + binding.result?.setOnLongClickListener { copyToClipboard(true) } + AutofitHelper.create(binding.result) + AutofitHelper.create(binding.formula) storeStateVariables() - updateViewColors(calculator_holder, getProperTextColor()) + binding.calculatorHolder?.let { updateViewColors(it, getProperTextColor()) } setupDecimalSeparator() checkWhatsNewDialog() checkAppOnSDCard() @@ -81,9 +83,9 @@ class MainActivity : SimpleActivity(), Calculator { override fun onResume() { super.onResume() - setupToolbar(main_toolbar) + setupToolbar(binding.mainToolbar) if (storedTextColor != config.textColor) { - updateViewColors(calculator_holder, getProperTextColor()) + binding.calculatorHolder?.let { updateViewColors(it, getProperTextColor()) } } if (config.preventPhoneFromSleeping) { @@ -97,14 +99,16 @@ class MainActivity : SimpleActivity(), Calculator { vibrateOnButtonPress = config.vibrateOnButtonPress - arrayOf(btn_percent, btn_power, btn_root, btn_clear, btn_reset, btn_divide, btn_multiply, btn_plus, btn_minus, btn_equals, btn_decimal).forEach { - it.background = ResourcesCompat.getDrawable(resources, R.drawable.pill_background, theme) - it.background?.alpha = MEDIUM_ALPHA_INT - } + binding.apply { + arrayOf(btnPercent, btnPower, btnRoot, btnClear, btnReset, btnDivide, btnMultiply, btnPlus, btnMinus, btnEquals, btnDecimal).forEach { + it?.background = ResourcesCompat.getDrawable(resources, com.simplemobiletools.commons.R.drawable.pill_background, theme) + it?.background?.alpha = MEDIUM_ALPHA_INT + } - arrayOf(btn_0, btn_1, btn_2, btn_3, btn_4, btn_5, btn_6, btn_7, btn_8, btn_9).forEach { - it.background = ResourcesCompat.getDrawable(resources, R.drawable.pill_background, theme) - it.background?.alpha = LOWER_ALPHA_INT + arrayOf(btn0, btn1, btn2, btn3, btn4, btn5, btn6, btn7, btn8, btn9).forEach { + it?.background = ResourcesCompat.getDrawable(resources, com.simplemobiletools.commons.R.drawable.pill_background, theme) + it?.background?.alpha = LOWER_ALPHA_INT + } } } @@ -129,7 +133,7 @@ class MainActivity : SimpleActivity(), Calculator { } private fun setupOptionsMenu() { - main_toolbar.setOnMenuItemClickListener { menuItem -> + binding.mainToolbar.setOnMenuItemClickListener { menuItem -> when (menuItem.itemId) { R.id.history -> showHistory() R.id.more_apps_from_us -> launchMoreAppsFromUsIntent() @@ -142,8 +146,8 @@ class MainActivity : SimpleActivity(), Calculator { } private fun refreshMenuItems() { - main_toolbar.menu.apply { - findItem(R.id.more_apps_from_us).isVisible = !resources.getBoolean(R.bool.hide_google_relations) + binding.mainToolbar.menu.apply { + findItem(R.id.more_apps_from_us).isVisible = !resources.getBoolean(com.simplemobiletools.commons.R.bool.hide_google_relations) } } @@ -163,7 +167,7 @@ class MainActivity : SimpleActivity(), Calculator { private fun showHistory() { HistoryHelper(this).getHistory { if (it.isEmpty()) { - toast(R.string.history_empty) + toast(com.simplemobiletools.calculator.R.string.history_empty) } else { HistoryDialog(this, it, calc) } @@ -180,27 +184,29 @@ class MainActivity : SimpleActivity(), Calculator { val faqItems = arrayListOf( FAQItem(R.string.faq_1_title, R.string.faq_1_text), - FAQItem(R.string.faq_1_title_commons, R.string.faq_1_text_commons), - FAQItem(R.string.faq_4_title_commons, R.string.faq_4_text_commons) + FAQItem(com.simplemobiletools.commons.R.string.faq_1_title_commons, com.simplemobiletools.commons.R.string.faq_1_text_commons), + FAQItem(com.simplemobiletools.commons.R.string.faq_4_title_commons, com.simplemobiletools.commons.R.string.faq_4_text_commons) ) - if (!resources.getBoolean(R.bool.hide_google_relations)) { - faqItems.add(FAQItem(R.string.faq_2_title_commons, R.string.faq_2_text_commons)) - faqItems.add(FAQItem(R.string.faq_6_title_commons, R.string.faq_6_text_commons)) + if (!resources.getBoolean(com.simplemobiletools.commons.R.bool.hide_google_relations)) { + faqItems.add(FAQItem(com.simplemobiletools.commons.R.string.faq_2_title_commons, com.simplemobiletools.commons.R.string.faq_2_text_commons)) + faqItems.add(FAQItem(com.simplemobiletools.commons.R.string.faq_6_title_commons, com.simplemobiletools.commons.R.string.faq_6_text_commons)) } startAboutActivity(R.string.app_name, licenses, BuildConfig.VERSION_NAME, faqItems, true) } - private fun getButtonIds() = arrayOf(btn_decimal, btn_0, btn_1, btn_2, btn_3, btn_4, btn_5, btn_6, btn_7, btn_8, btn_9) + private fun getButtonIds() = binding.run { + arrayOf(btnDecimal, btn0, btn1, btn2, btn3, btn4, btn5, btn6, btn7, btn8, btn9) + } private fun copyToClipboard(copyResult: Boolean): Boolean { - var value = formula.value + var value = binding.formula?.value if (copyResult) { - value = result.value + value = binding.result?.value } - return if (value.isEmpty()) { + return if (value.isNullOrEmpty()) { false } else { copyToClipboard(value) @@ -209,19 +215,19 @@ class MainActivity : SimpleActivity(), Calculator { } override fun showNewResult(value: String, context: Context) { - result.text = value + binding.result?.text = value } private fun checkWhatsNewDialog() { arrayListOf().apply { - add(Release(18, R.string.release_18)) - add(Release(28, R.string.release_28)) + add(Release(18, com.simplemobiletools.calculator.R.string.release_18)) + add(Release(28, com.simplemobiletools.calculator.R.string.release_28)) checkWhatsNew(this, BuildConfig.VERSION_CODE) } } override fun showNewFormula(value: String, context: Context) { - formula.text = value + binding.formula?.text = value } private fun setupDecimalSeparator() { @@ -234,7 +240,7 @@ class MainActivity : SimpleActivity(), Calculator { groupingSeparator = COMMA } calc.updateSeparators(decimalSeparator, groupingSeparator) - btn_decimal.text = decimalSeparator + binding.btnDecimal?.text = decimalSeparator } private fun View.setVibratingOnClickListener(callback: (view: View) -> Unit) { diff --git a/app/src/main/kotlin/com/simplemobiletools/calculator/activities/SettingsActivity.kt b/app/src/main/kotlin/com/simplemobiletools/calculator/activities/SettingsActivity.kt index 201745ed..10760b58 100644 --- a/app/src/main/kotlin/com/simplemobiletools/calculator/activities/SettingsActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/calculator/activities/SettingsActivity.kt @@ -1,33 +1,82 @@ package com.simplemobiletools.calculator.activities +import android.app.ActivityManager import android.content.Intent +import android.os.Build import android.os.Bundle -import com.simplemobiletools.calculator.R +import android.view.View +import androidx.activity.compose.setContent +import androidx.appcompat.app.AppCompatActivity +import com.simplemobiletools.calculator.compose.screens.SettingsScreen +import com.simplemobiletools.calculator.compose.theme.AppThemeSurface +import com.simplemobiletools.calculator.compose.theme.Theme +import com.simplemobiletools.calculator.databinding.ActivitySettingsBinding import com.simplemobiletools.calculator.extensions.calculatorDB import com.simplemobiletools.calculator.extensions.config import com.simplemobiletools.calculator.extensions.updateWidgets +import com.simplemobiletools.calculator.extensions.viewBinding +import com.simplemobiletools.commons.activities.CustomizationActivity import com.simplemobiletools.commons.extensions.* -import com.simplemobiletools.commons.helpers.IS_CUSTOMIZING_COLORS -import com.simplemobiletools.commons.helpers.NavigationIcon -import com.simplemobiletools.commons.helpers.ensureBackgroundThread -import com.simplemobiletools.commons.helpers.isTiramisuPlus -import kotlinx.android.synthetic.main.activity_settings.* -import java.util.* +import com.simplemobiletools.commons.helpers.* +import java.util.Locale import kotlin.system.exitProcess -class SettingsActivity : SimpleActivity() { - override fun onCreate(savedInstanceState: Bundle?) { - isMaterialActivity = true - super.onCreate(savedInstanceState) - setContentView(R.layout.activity_settings) +class SettingsActivity : AppCompatActivity() { - updateMaterialActivityViews(settings_coordinator, settings_holder, useTransparentNavigation = true, useTopSearchMenu = false) - setupMaterialScrollListener(settings_nested_scrollview, settings_toolbar) + private val binding by viewBinding(ActivitySettingsBinding::inflate) + private val preferences by lazy { config } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContent { + AppThemeSurface { + SettingsScreen( + customizeColors = ::handleCustomizeColorsClick, goBack = ::finish, + backgroundColor = getProperBackgroundColor() + ) + } + } + val backgroundColor = getProperBackgroundColor() + updateStatusbarColor(backgroundColor) + updateActionbarColor(backgroundColor) + + //updateMaterialActivityViews(binding.settingsCoordinator, binding.settingsHolder, useTransparentNavigation = true, useTopSearchMenu = false) + //setupMaterialScrollListener(binding.settingsNestedScrollview, binding.settingsToolbar) + } + + fun updateStatusbarColor(color: Int) { + window.statusBarColor = color + + if (color.getContrastColor() == DARK_GREY) { + window.decorView.systemUiVisibility = window.decorView.systemUiVisibility.addBit(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) + } else { + window.decorView.systemUiVisibility = window.decorView.systemUiVisibility.removeBit(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) + } + } + + fun updateActionbarColor(color: Int = getProperStatusBarColor()) { + updateStatusbarColor(color) + setTaskDescription(ActivityManager.TaskDescription(null, null, color)) + } + + fun updateNavigationBarColor(color: Int) { + window.navigationBarColor = color + updateNavigationBarButtons(color) + } + + fun updateNavigationBarButtons(color: Int) { + if (isOreoPlus()) { + if (color.getContrastColor() == DARK_GREY) { + window.decorView.systemUiVisibility = window.decorView.systemUiVisibility.addBit(View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR) + } else { + window.decorView.systemUiVisibility = window.decorView.systemUiVisibility.removeBit(View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR) + } + } } override fun onResume() { super.onResume() - setupToolbar(settings_toolbar, NavigationIcon.Arrow) + /*setupToolbar(binding.settingsToolbar, NavigationIcon.Arrow) setupPurchaseThankYou() setupCustomizeColors() @@ -37,66 +86,76 @@ class SettingsActivity : SimpleActivity() { setupPreventPhoneFromSleeping() setupUseCommaAsDecimalMark() setupCustomizeWidgetColors() - updateTextColors(settings_nested_scrollview) + updateTextColors(binding.settingsNestedScrollview) - arrayOf(settings_color_customization_section_label, settings_general_settings_label).forEach { + arrayOf(binding.settingsColorCustomizationSectionLabel, binding.settingsGeneralSettingsLabel).forEach { it.setTextColor(getProperPrimaryColor()) - } + }*/ } private fun setupPurchaseThankYou() { - settings_purchase_thank_you_holder.beGoneIf(isOrWasThankYouInstalled()) - settings_purchase_thank_you_holder.setOnClickListener { + binding.settingsPurchaseThankYouHolder.beGoneIf(isOrWasThankYouInstalled()) + binding.settingsPurchaseThankYouHolder.setOnClickListener { launchPurchaseThankYouIntent() } } private fun setupCustomizeColors() { - settings_color_customization_label.text = getCustomizeColorsString() - settings_color_customization_holder.setOnClickListener { + binding.settingsWidgetColorCustomizationLabel.text = getCustomizeColorsString() + binding.settingsWidgetColorCustomizationHolder.setOnClickListener { handleCustomizeColorsClick() } } + private fun handleCustomizeColorsClick() { + Intent(applicationContext, CustomizationActivity::class.java).apply { + /*putExtra(APP_ICON_IDS, getAppIconIDs()) + putExtra(APP_LAUNCHER_NAME, getAppLauncherName())*/ + startActivity(this) + } + } + private fun setupUseEnglish() { - settings_use_english_holder.beVisibleIf((config.wasUseEnglishToggled || Locale.getDefault().language != "en") && !isTiramisuPlus()) - settings_use_english.isChecked = config.useEnglish - settings_use_english_holder.setOnClickListener { - settings_use_english.toggle() - config.useEnglish = settings_use_english.isChecked + binding.settingsUseEnglishHolder.beVisibleIf((preferences.wasUseEnglishToggled || Locale.getDefault().language != "en") && !isTiramisuPlus()) + binding.settingsUseEnglish.isChecked = preferences.useEnglish + binding.settingsUseEnglishHolder.setOnClickListener { + binding.settingsUseEnglish.toggle() + preferences.useEnglish = binding.settingsUseEnglish.isChecked exitProcess(0) } } private fun setupLanguage() { - settings_language.text = Locale.getDefault().displayLanguage - settings_language_holder.beVisibleIf(isTiramisuPlus()) - settings_language_holder.setOnClickListener { - launchChangeAppLanguageIntent() + binding.settingsLanguage.text = Locale.getDefault().displayLanguage + binding.settingsLanguageHolder.beVisibleIf(isTiramisuPlus()) + binding.settingsLanguageHolder.setOnClickListener { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + // launchChangeAppLanguageIntent() + } } } private fun setupVibrate() { - settings_vibrate.isChecked = config.vibrateOnButtonPress - settings_vibrate_holder.setOnClickListener { - settings_vibrate.toggle() - config.vibrateOnButtonPress = settings_vibrate.isChecked + binding.settingsVibrate.isChecked = preferences.vibrateOnButtonPress + binding.settingsVibrateHolder.setOnClickListener { + binding.settingsVibrate.toggle() + preferences.vibrateOnButtonPress = binding.settingsVibrate.isChecked } } private fun setupPreventPhoneFromSleeping() { - settings_prevent_phone_from_sleeping.isChecked = config.preventPhoneFromSleeping - settings_prevent_phone_from_sleeping_holder.setOnClickListener { - settings_prevent_phone_from_sleeping.toggle() - config.preventPhoneFromSleeping = settings_prevent_phone_from_sleeping.isChecked + binding.settingsPreventPhoneFromSleeping.isChecked = preferences.preventPhoneFromSleeping + binding.settingsPreventPhoneFromSleepingHolder.setOnClickListener { + binding.settingsPreventPhoneFromSleeping.toggle() + preferences.preventPhoneFromSleeping = binding.settingsPreventPhoneFromSleeping.isChecked } } private fun setupUseCommaAsDecimalMark() { - settings_use_comma_as_decimal_mark.isChecked = config.useCommaAsDecimalMark - settings_use_comma_as_decimal_mark_holder.setOnClickListener { - settings_use_comma_as_decimal_mark.toggle() - config.useCommaAsDecimalMark = settings_use_comma_as_decimal_mark.isChecked + binding.settingsUseCommaAsDecimalMark.isChecked = preferences.useCommaAsDecimalMark + binding.settingsUseCommaAsDecimalMark.setOnClickListener { + binding.settingsUseCommaAsDecimalMark.toggle() + preferences.useCommaAsDecimalMark = binding.settingsUseCommaAsDecimalMark.isChecked updateWidgets() ensureBackgroundThread { applicationContext.calculatorDB.deleteHistory() @@ -105,7 +164,7 @@ class SettingsActivity : SimpleActivity() { } private fun setupCustomizeWidgetColors() { - settings_widget_color_customization_holder.setOnClickListener { + binding.settingsWidgetColorCustomizationHolder.setOnClickListener { Intent(this, WidgetConfigureActivity::class.java).apply { putExtra(IS_CUSTOMIZING_COLORS, true) startActivity(this) diff --git a/app/src/main/kotlin/com/simplemobiletools/calculator/activities/WidgetConfigureActivity.kt b/app/src/main/kotlin/com/simplemobiletools/calculator/activities/WidgetConfigureActivity.kt index 724f0a31..0fca9887 100644 --- a/app/src/main/kotlin/com/simplemobiletools/calculator/activities/WidgetConfigureActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/calculator/activities/WidgetConfigureActivity.kt @@ -10,14 +10,14 @@ import android.widget.RemoteViews import android.widget.SeekBar import android.widget.TextView import com.simplemobiletools.calculator.R +import com.simplemobiletools.calculator.databinding.WidgetConfigBinding import com.simplemobiletools.calculator.extensions.config +import com.simplemobiletools.calculator.extensions.viewBinding import com.simplemobiletools.calculator.helpers.MyWidgetProvider import com.simplemobiletools.commons.dialogs.ColorPickerDialog import com.simplemobiletools.commons.dialogs.FeatureLockedDialog import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.helpers.IS_CUSTOMIZING_COLORS -import kotlinx.android.synthetic.main.activity_main.* -import kotlinx.android.synthetic.main.widget_config.* class WidgetConfigureActivity : SimpleActivity() { private var mBgAlpha = 0f @@ -27,11 +27,13 @@ class WidgetConfigureActivity : SimpleActivity() { private var mBgColorWithoutTransparency = 0 private var mFeatureLockedDialog: FeatureLockedDialog? = null + private val binding by viewBinding(WidgetConfigBinding::inflate) + public override fun onCreate(savedInstanceState: Bundle?) { useDynamicTheme = false super.onCreate(savedInstanceState) setResult(Activity.RESULT_CANCELED) - setContentView(R.layout.widget_config) + setContentView(binding.root) initVariables() val isCustomizingColors = intent.extras?.getBoolean(IS_CUSTOMIZING_COLORS) ?: false @@ -41,12 +43,12 @@ class WidgetConfigureActivity : SimpleActivity() { finish() } - config_save.setOnClickListener { saveConfig() } - config_bg_color.setOnClickListener { pickBackgroundColor() } - config_text_color.setOnClickListener { pickTextColor() } + binding.configSave.setOnClickListener { saveConfig() } + binding.configBgColor.setOnClickListener { pickBackgroundColor() } + binding.configTextColor.setOnClickListener { pickTextColor() } val primaryColor = getProperPrimaryColor() - config_bg_seekbar.setColors(mTextColor, primaryColor, primaryColor) + binding.configBgSeekbar.setColors(mTextColor, primaryColor, primaryColor) if (!isCustomizingColors && !isOrWasThankYouInstalled()) { mFeatureLockedDialog = FeatureLockedDialog(this) { @@ -70,27 +72,27 @@ class WidgetConfigureActivity : SimpleActivity() { mBgColor = config.widgetBgColor mBgAlpha = Color.alpha(mBgColor) / 255.toFloat() - btn_reset.beVisible() + binding.configCalc.btnReset.beVisible() mBgColorWithoutTransparency = Color.rgb(Color.red(mBgColor), Color.green(mBgColor), Color.blue(mBgColor)) - config_bg_seekbar.setOnSeekBarChangeListener(seekbarChangeListener) - config_bg_seekbar.progress = (mBgAlpha * 100).toInt() + binding.configBgSeekbar.setOnSeekBarChangeListener(seekbarChangeListener) + binding.configBgSeekbar.progress = (mBgAlpha * 100).toInt() updateBackgroundColor() mTextColor = config.widgetTextColor - if (mTextColor == resources.getColor(R.color.default_widget_text_color) && config.isUsingSystemTheme) { - mTextColor = resources.getColor(R.color.you_primary_color, theme) + if (mTextColor == resources.getColor(com.simplemobiletools.commons.R.color.default_widget_text_color, theme) && config.isUsingSystemTheme) { + mTextColor = resources.getColor(com.simplemobiletools.commons.R.color.you_primary_color, theme) } updateTextColor() - formula.text = "15,937*5" - result.text = "79,685" + binding.configCalc.formula.text = "15,937*5" + binding.configCalc.result.text = "79,685" } private fun saveConfig() { val appWidgetManager = AppWidgetManager.getInstance(this) ?: return val views = RemoteViews(packageName, R.layout.widget).apply { - applyColorFilter(R.id.widget_background, mBgColor) + applyColorFilter(binding.widgetBackground.id, mBgColor) } appWidgetManager.updateAppWidget(mWidgetId, views) @@ -121,13 +123,13 @@ class WidgetConfigureActivity : SimpleActivity() { private fun updateBackgroundColor() { mBgColor = mBgColorWithoutTransparency.adjustAlpha(mBgAlpha) - widget_background.applyColorFilter(mBgColor) - config_bg_color.setFillWithStroke(mBgColor, mBgColor) - config_save.backgroundTintList = ColorStateList.valueOf(getProperPrimaryColor()) + binding.widgetBackground.applyColorFilter(mBgColor) + binding.configBgColor.setFillWithStroke(mBgColor, mBgColor) + binding.configSave.backgroundTintList = ColorStateList.valueOf(getProperPrimaryColor()) } private fun updateTextColor() { - config_text_color.setFillWithStroke(mTextColor, mTextColor) + binding.configTextColor.setFillWithStroke(mTextColor, mTextColor) val viewIds = intArrayOf( R.id.btn_0, R.id.btn_1, R.id.btn_2, R.id.btn_3, R.id.btn_4, R.id.btn_5, R.id.btn_6, R.id.btn_7, R.id.btn_8, @@ -135,9 +137,10 @@ class WidgetConfigureActivity : SimpleActivity() { R.id.btn_minus, R.id.btn_plus, R.id.btn_decimal, R.id.btn_equals ) - result.setTextColor(mTextColor) - formula.setTextColor(mTextColor) - config_save.setTextColor(getProperPrimaryColor().getContrastColor()) + + binding.configCalc.result.setTextColor(mTextColor) + binding.configCalc.formula.setTextColor(mTextColor) + binding.configSave.setTextColor(getProperPrimaryColor().getContrastColor()) viewIds.forEach { (findViewById(it)).setTextColor(mTextColor) diff --git a/app/src/main/kotlin/com/simplemobiletools/calculator/adapters/HistoryAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/calculator/adapters/HistoryAdapter.kt index 1d2d468e..51b85202 100644 --- a/app/src/main/kotlin/com/simplemobiletools/calculator/adapters/HistoryAdapter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/calculator/adapters/HistoryAdapter.kt @@ -3,23 +3,21 @@ package com.simplemobiletools.calculator.adapters import android.view.View import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView -import com.simplemobiletools.calculator.R import com.simplemobiletools.calculator.activities.SimpleActivity +import com.simplemobiletools.calculator.databinding.HistoryViewBinding import com.simplemobiletools.calculator.helpers.CalculatorImpl import com.simplemobiletools.calculator.models.History import com.simplemobiletools.commons.extensions.copyToClipboard import com.simplemobiletools.commons.extensions.getProperTextColor -import kotlinx.android.synthetic.main.history_view.view.* class HistoryAdapter(val activity: SimpleActivity, val items: List, val calc: CalculatorImpl, val itemClick: () -> Unit) : RecyclerView.Adapter() { private var textColor = activity.getProperTextColor() - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { - val view = activity.layoutInflater.inflate(R.layout.history_view, parent, false) - return ViewHolder(view) - } + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder = + ViewHolder(HistoryViewBinding.inflate(activity.layoutInflater, parent, false)) + override fun onBindViewHolder(holder: ViewHolder, position: Int) { val item = items[position] @@ -28,13 +26,13 @@ class HistoryAdapter(val activity: SimpleActivity, val items: List, val override fun getItemCount() = items.size - inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) { + inner class ViewHolder(private val binding: HistoryViewBinding) : RecyclerView.ViewHolder(binding.root) { fun bindView(item: History): View { itemView.apply { - item_formula.text = item.formula - item_result.text = item.result - item_formula.setTextColor(textColor) - item_result.setTextColor(textColor) + binding.itemFormula.text = item.formula + binding.itemResult.text = item.result + binding.itemFormula.setTextColor(textColor) + binding.itemResult.setTextColor(textColor) setOnClickListener { calc.addNumberToFormula(item.result) diff --git a/app/src/main/kotlin/com/simplemobiletools/calculator/compose/extensions/BooleanPreviewParameterProvider.kt b/app/src/main/kotlin/com/simplemobiletools/calculator/compose/extensions/BooleanPreviewParameterProvider.kt new file mode 100644 index 00000000..1933640c --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/calculator/compose/extensions/BooleanPreviewParameterProvider.kt @@ -0,0 +1,8 @@ +package com.simplemobiletools.calculator.compose.extensions + +import androidx.compose.ui.tooling.preview.PreviewParameterProvider + +class BooleanPreviewParameterProvider : PreviewParameterProvider { + override val values: Sequence + get() = sequenceOf(false, true) +} diff --git a/app/src/main/kotlin/com/simplemobiletools/calculator/compose/extensions/PreviewExtensions.kt b/app/src/main/kotlin/com/simplemobiletools/calculator/compose/extensions/PreviewExtensions.kt new file mode 100644 index 00000000..e685cbc8 --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/calculator/compose/extensions/PreviewExtensions.kt @@ -0,0 +1,28 @@ +package com.simplemobiletools.calculator.compose.extensions + +import android.content.res.Configuration +import androidx.compose.ui.tooling.preview.Devices +import androidx.compose.ui.tooling.preview.Preview + +const val LIGHT = "Light" +const val DARK = "Dark" + +@MyDevicesDarkOnly +@MyDevicesLightOnly +annotation class MyDevices + +@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES, device = Devices.PIXEL_4_XL, name = "6.3 inches dark", group = DARK) +@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES, device = Devices.PIXEL_2, name = "5.0 inches dark", group = DARK) +@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES, device = Devices.PIXEL_2_XL, name = "6.0 inches dark", group = DARK) +@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES, device = Devices.PIXEL_4_XL, name = "5.5 inches dark", group = DARK) +@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES, device = Devices.PIXEL_4, name = "5.7 inches dark", group = DARK) +@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES, device = Devices.TABLET, name = "Tablet", group = DARK) +annotation class MyDevicesDarkOnly + +@Preview(showBackground = true, device = Devices.PIXEL_4_XL, name = "6.3 inches light", group = LIGHT) +@Preview(showBackground = true, device = Devices.PIXEL_2, name = "5.0 inches light", group = LIGHT) +@Preview(showBackground = true, device = Devices.PIXEL_2_XL, name = "6.0 inches light", group = LIGHT) +@Preview(showBackground = true, device = Devices.PIXEL_XL, name = "5.5 inches light", group = LIGHT) +@Preview(showBackground = true, device = Devices.PIXEL_4, name = "5.7 inches light", group = LIGHT) +@Preview(showBackground = true, device = Devices.TABLET, name = "Tablet", group = DARK) +annotation class MyDevicesLightOnly diff --git a/app/src/main/kotlin/com/simplemobiletools/calculator/compose/screens/SettingsScreen.kt b/app/src/main/kotlin/com/simplemobiletools/calculator/compose/screens/SettingsScreen.kt new file mode 100644 index 00000000..424b8309 --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/calculator/compose/screens/SettingsScreen.kt @@ -0,0 +1,88 @@ +package com.simplemobiletools.calculator.compose.screens + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material3.* +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.toArgb +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.core.graphics.toColor +import com.simplemobiletools.calculator.compose.extensions.MyDevices +import com.simplemobiletools.calculator.compose.settings.SettingsCheckBoxComponent +import com.simplemobiletools.calculator.compose.settings.SettingsGroup +import com.simplemobiletools.calculator.compose.settings.SettingsPreferenceComponent +import com.simplemobiletools.calculator.compose.settings.SettingsTitleTextComponent +import com.simplemobiletools.calculator.compose.theme.AppThemeSurface +import com.simplemobiletools.commons.R + +@Composable +fun SettingsScreen( + goBack: () -> Unit, + customizeColors: () -> Unit, + backgroundColor: Int +) { + Scaffold( + modifier = Modifier + .fillMaxSize() + .background(Color(backgroundColor)), + topBar = { + TopAppBar( + title = { + Text( + text = stringResource(id = R.string.settings), + modifier = Modifier + .padding(start = 16.dp) + .fillMaxWidth() + ) + }, + navigationIcon = { + Icon( + imageVector = Icons.Filled.ArrowBack, contentDescription = stringResource(id = R.string.back), + modifier = Modifier + .clickable { goBack() } + .padding(start = 8.dp) + ) + } + ) + } + ) { paddingValues -> + Column( + Modifier + .padding(paddingValues) + .verticalScroll(rememberScrollState()) + ) { + SettingsGroup(title = { + SettingsTitleTextComponent(text = stringResource(id = R.string.color_customization)) + }) { + SettingsPreferenceComponent(preferenceTitle = stringResource(id = R.string.customize_colors), doOnPreferenceClick = customizeColors) + SettingsPreferenceComponent(preferenceTitle = stringResource(id = R.string.customize_widget_colors)) + Spacer(modifier = Modifier.padding(bottom = 16.dp)) + } + Divider() + SettingsGroup(title = { + SettingsTitleTextComponent(text = stringResource(id = R.string.general_settings)) + }) { + SettingsPreferenceComponent(preferenceTitle = stringResource(id = R.string.purchase_simple_thank_you)) + SettingsCheckBoxComponent(title = stringResource(id = R.string.use_english_language)) + SettingsPreferenceComponent(preferenceTitle = stringResource(id = R.string.language), preferenceSummary = "English") + SettingsCheckBoxComponent(title = stringResource(id = R.string.vibrate_on_button_press)) + SettingsCheckBoxComponent(title = stringResource(id = R.string.prevent_phone_from_sleeping)) + SettingsCheckBoxComponent(title = stringResource(id = com.simplemobiletools.calculator.R.string.use_comma_as_decimal_mark)) + } + } + } +} + +@MyDevices +@Composable +private fun SettingsScreenPreview() { + AppThemeSurface { SettingsScreen(goBack = {}, customizeColors = {}, backgroundColor = MaterialTheme.colorScheme.background.toArgb()) } +} diff --git a/app/src/main/kotlin/com/simplemobiletools/calculator/compose/settings/SettingsCheckBoxComponent.kt b/app/src/main/kotlin/com/simplemobiletools/calculator/compose/settings/SettingsCheckBoxComponent.kt new file mode 100644 index 00000000..285013b4 --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/calculator/compose/settings/SettingsCheckBoxComponent.kt @@ -0,0 +1,75 @@ +package com.simplemobiletools.calculator.compose.settings + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Checkbox +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.simplemobiletools.calculator.compose.extensions.MyDevices +import com.simplemobiletools.calculator.compose.theme.AppThemeSurface +import com.simplemobiletools.calculator.compose.theme.preferenceSummaryColor +import com.simplemobiletools.calculator.compose.theme.preferenceTitleColor + +@Composable +fun SettingsCheckBoxComponent( + modifier: Modifier = Modifier, + title: String, + summary: String? = null, + initialValue: Boolean = false, + isPreferenceEnabled: Boolean = true, + onChange: ((Boolean) -> Unit)? = null, +) { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = modifier + .fillMaxWidth() + .padding(vertical = 14.dp, horizontal = 16.dp), + ) { + Column( + modifier = Modifier.weight(1f), + ) { + Text( + modifier = Modifier + .fillMaxWidth() + .padding(end = 16.dp), + text = title, + fontSize = 16.sp, + color = preferenceTitleColor(isEnabled = isPreferenceEnabled), + ) + AnimatedVisibility(visible = !summary.isNullOrBlank()) { + Text( + text = summary.toString(), + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 4.dp) + .padding(end = 16.dp), + fontSize = 14.sp, + color = preferenceSummaryColor(isEnabled = isPreferenceEnabled), + ) + } + } + Checkbox( + checked = initialValue, + onCheckedChange = { onChange?.invoke(it) }, + enabled = isPreferenceEnabled, + ) + } +} + +@MyDevices +@Composable +private fun SettingsCheckBoxComponentPreview() { + AppThemeSurface { + SettingsCheckBoxComponent( + title = "Some title", + summary = "Some summary", + ) + } +} diff --git a/app/src/main/kotlin/com/simplemobiletools/calculator/compose/settings/SettingsGroup.kt b/app/src/main/kotlin/com/simplemobiletools/calculator/compose/settings/SettingsGroup.kt new file mode 100644 index 00000000..890db51f --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/calculator/compose/settings/SettingsGroup.kt @@ -0,0 +1,64 @@ +package com.simplemobiletools.calculator.compose.settings + +import androidx.compose.foundation.layout.* +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.ProvideTextStyle +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import com.simplemobiletools.calculator.compose.extensions.MyDevices + +@Composable +fun SettingsGroup( + modifier: Modifier = Modifier, + title: @Composable (() -> Unit)? = null, + content: @Composable ColumnScope.() -> Unit, +) { + Surface { + Column( + modifier = modifier.fillMaxWidth(), + ) { + if (title != null) { + SettingsGroupTitle(title) + } + content() + } + } +} + +@Composable +internal fun SettingsGroupTitle(title: @Composable () -> Unit) { + Box( + modifier = Modifier + .fillMaxWidth() + .height(64.dp) + .padding(horizontal = 16.dp), + contentAlignment = Alignment.CenterStart + ) { + val primary = MaterialTheme.colorScheme.primary + val titleStyle = MaterialTheme.typography.headlineMedium.copy(color = primary) + ProvideTextStyle(value = titleStyle) { title() } + } +} + +@MyDevices +@Composable +private fun SettingsGroupPreview() { + MaterialTheme { + SettingsGroup( + title = { Text(text = "Title") } + ) { + Box( + modifier = Modifier + .height(64.dp) + .fillMaxWidth(), + contentAlignment = Alignment.Center, + ) { + Text(text = "Settings group") + } + } + } +} diff --git a/app/src/main/kotlin/com/simplemobiletools/calculator/compose/settings/SettingsPreferenceComponent.kt b/app/src/main/kotlin/com/simplemobiletools/calculator/compose/settings/SettingsPreferenceComponent.kt new file mode 100644 index 00000000..819c9ec9 --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/calculator/compose/settings/SettingsPreferenceComponent.kt @@ -0,0 +1,68 @@ +package com.simplemobiletools.calculator.compose.settings + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.combinedClickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.simplemobiletools.calculator.compose.extensions.MyDevices +import com.simplemobiletools.calculator.compose.theme.AppThemeSurface +import com.simplemobiletools.calculator.compose.theme.preferenceSummaryColor +import com.simplemobiletools.calculator.compose.theme.preferenceTitleColor +import com.simplemobiletools.commons.R + +@Composable +fun SettingsPreferenceComponent( + modifier: Modifier = Modifier, + preferenceTitle: String, + preferenceSummary: String? = null, + isPreferenceEnabled: Boolean = true, + doOnPreferenceLongClick: (() -> Unit)? = null, + doOnPreferenceClick: (() -> Unit)? = null, +) { + Column( + modifier = modifier + .fillMaxWidth() + .combinedClickable( + enabled = isPreferenceEnabled, + onClick = { doOnPreferenceClick?.invoke() }, + onLongClick = { doOnPreferenceLongClick?.invoke() }, + ) + .padding(vertical = 14.dp, horizontal = 16.dp), + ) { + Text( + text = preferenceTitle, + modifier = Modifier.fillMaxWidth(), + fontSize = 16.sp, + color = preferenceTitleColor(isEnabled = isPreferenceEnabled), + ) + AnimatedVisibility(visible = !preferenceSummary.isNullOrBlank()) { + Text( + text = preferenceSummary.toString(), + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 4.dp), + fontSize = 14.sp, + color = preferenceSummaryColor(isEnabled = isPreferenceEnabled), + ) + } + } +} + +@MyDevices +@Composable +private fun SettingsPreferencePreview() { + AppThemeSurface { + SettingsPreferenceComponent( + preferenceTitle = stringResource(id = R.string.language), + preferenceSummary = stringResource(id = R.string.translation_english), + isPreferenceEnabled = true, + ) + } +} diff --git a/app/src/main/kotlin/com/simplemobiletools/calculator/compose/settings/SettingsTitleTextComponent.kt b/app/src/main/kotlin/com/simplemobiletools/calculator/compose/settings/SettingsTitleTextComponent.kt new file mode 100644 index 00000000..47cb0548 --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/calculator/compose/settings/SettingsTitleTextComponent.kt @@ -0,0 +1,38 @@ +package com.simplemobiletools.calculator.compose.settings + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.res.dimensionResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import com.simplemobiletools.calculator.compose.extensions.MyDevices +import com.simplemobiletools.calculator.compose.theme.AppThemeSurface + +@Composable +fun SettingsTitleTextComponent( + modifier: Modifier = Modifier, + text: String, +) { + Box(modifier = Modifier.padding(top = 24.dp, bottom = 8.dp)) { + Text( + text = text.uppercase(), + modifier = modifier, + fontWeight = FontWeight(300), + color = MaterialTheme.colorScheme.primary, + fontSize = with(LocalDensity.current) { + dimensionResource(id = com.simplemobiletools.commons.R.dimen.normal_text_size).toSp() + }, + ) + } +} + +@MyDevices +@Composable +private fun SettingsTitleTextComponentPreview() = AppThemeSurface { + SettingsTitleTextComponent(text = "Color customization") +} diff --git a/app/src/main/kotlin/com/simplemobiletools/calculator/compose/theme/Theme.kt b/app/src/main/kotlin/com/simplemobiletools/calculator/compose/theme/Theme.kt new file mode 100644 index 00000000..86d29369 --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/calculator/compose/theme/Theme.kt @@ -0,0 +1,103 @@ +package com.simplemobiletools.calculator.compose.theme + +import androidx.compose.foundation.background +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.ReadOnlyComposable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.toArgb +import androidx.compose.ui.platform.LocalContext +import com.google.accompanist.systemuicontroller.rememberSystemUiController +import com.simplemobiletools.commons.extensions.* +import com.simplemobiletools.commons.helpers.HIGHER_ALPHA + + +val primaryColor = Color(0xFFF57C00) +val secondaryColor = Color(0xFFD76D00) +val tertiaryColor = primaryColor + + +private val DarkColorScheme = darkColorScheme( + primary = primaryColor, + secondary = secondaryColor, + tertiary = tertiaryColor, +) + +private val LightColorScheme = lightColorScheme( + primary = primaryColor, + secondary = secondaryColor, + tertiary = tertiaryColor, +) + +@get:ReadOnlyComposable +val disabledTextColor @Composable get() = if (isSystemInDarkTheme()) Color.DarkGray else Color.LightGray + +@get:ReadOnlyComposable +val textSubTitleColor + @Composable get() = if (isSystemInDarkTheme()) { + Color.White.copy(0.5f) + } else { + Color.Black.copy( + 0.5f, + ) + } + + +@Composable +fun preferenceSummaryColor(isEnabled: Boolean) = + if (isEnabled) textSubTitleColor else disabledTextColor + +@Composable +fun preferenceTitleColor(isEnabled: Boolean) = if (isEnabled) Color.Unspecified else disabledTextColor + +@Composable +fun Theme( + useTransparentNavigation: Boolean = true, + properBackgroundColor: Int, + content: @Composable () -> Unit, + statusBarColor: Int, +) { + //todo + val context = LocalContext.current + val systemUiController = rememberSystemUiController() + LaunchedEffect(Unit) { + if (context.navigationBarHeight > 0 || context.isUsingGestureNavigation() && useTransparentNavigation) { + systemUiController.isNavigationBarVisible = false + } + systemUiController.setStatusBarColor( + color = Color(statusBarColor) + ) + systemUiController.setNavigationBarColor(Color(properBackgroundColor.adjustAlpha(HIGHER_ALPHA))) + } + + MaterialTheme( + colorScheme = DarkColorScheme, + content = content, + ) +} + +@Composable +fun AppThemeSurface( + modifier: Modifier = Modifier, + properBackgroundColor: Int = LocalContext.current.getProperBackgroundColor(), + backgroundColor: Int = MaterialTheme.colorScheme.background.toArgb(), + statusBarColor: Int = LocalContext.current.getProperStatusBarColor(), + content: @Composable () -> Unit, +) { + Theme(properBackgroundColor = properBackgroundColor, content = { + Surface( + modifier = modifier + .fillMaxSize() + .background(Color(backgroundColor)) + ) { + content() + } + }, statusBarColor = statusBarColor) +} diff --git a/app/src/main/kotlin/com/simplemobiletools/calculator/dialogs/HistoryDialog.kt b/app/src/main/kotlin/com/simplemobiletools/calculator/dialogs/HistoryDialog.kt index bba3242f..41121a95 100644 --- a/app/src/main/kotlin/com/simplemobiletools/calculator/dialogs/HistoryDialog.kt +++ b/app/src/main/kotlin/com/simplemobiletools/calculator/dialogs/HistoryDialog.kt @@ -4,6 +4,7 @@ import androidx.appcompat.app.AlertDialog import com.simplemobiletools.calculator.R import com.simplemobiletools.calculator.activities.SimpleActivity import com.simplemobiletools.calculator.adapters.HistoryAdapter +import com.simplemobiletools.calculator.databinding.DialogHistoryBinding import com.simplemobiletools.calculator.extensions.calculatorDB import com.simplemobiletools.calculator.helpers.CalculatorImpl import com.simplemobiletools.calculator.models.History @@ -11,28 +12,28 @@ import com.simplemobiletools.commons.extensions.getAlertDialogBuilder import com.simplemobiletools.commons.extensions.setupDialogStuff import com.simplemobiletools.commons.extensions.toast import com.simplemobiletools.commons.helpers.ensureBackgroundThread -import kotlinx.android.synthetic.main.dialog_history.view.* class HistoryDialog(activity: SimpleActivity, items: List, calculator: CalculatorImpl) { - var dialog: AlertDialog? = null + private var dialog: AlertDialog? = null init { - val view = activity.layoutInflater.inflate(R.layout.dialog_history, null) + + val view = DialogHistoryBinding.inflate(activity.layoutInflater, null, false) activity.getAlertDialogBuilder() - .setPositiveButton(R.string.ok, null) + .setPositiveButton(com.simplemobiletools.commons.R.string.ok, null) .setNeutralButton(R.string.clear_history) { _, _ -> ensureBackgroundThread { activity.applicationContext.calculatorDB.deleteHistory() activity.toast(R.string.history_cleared) } }.apply { - activity.setupDialogStuff(view, this, R.string.history) { alertDialog -> + activity.setupDialogStuff(view.root, this, R.string.history) { alertDialog -> dialog = alertDialog } } - view.history_list.adapter = HistoryAdapter(activity, items, calculator) { + view.historyList.adapter = HistoryAdapter(activity, items, calculator) { dialog?.dismiss() } } diff --git a/app/src/main/kotlin/com/simplemobiletools/calculator/extensions/Binding.kt b/app/src/main/kotlin/com/simplemobiletools/calculator/extensions/Binding.kt new file mode 100644 index 00000000..98a4ea20 --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/calculator/extensions/Binding.kt @@ -0,0 +1,10 @@ +package com.simplemobiletools.calculator.extensions + +import android.app.Activity +import android.view.LayoutInflater +import androidx.viewbinding.ViewBinding + +inline fun Activity.viewBinding(crossinline bindingInflater: (LayoutInflater) -> T) = + lazy(LazyThreadSafetyMode.NONE) { + bindingInflater.invoke(layoutInflater) + } diff --git a/app/src/main/kotlin/com/simplemobiletools/calculator/helpers/CalculatorImpl.kt b/app/src/main/kotlin/com/simplemobiletools/calculator/helpers/CalculatorImpl.kt index 480978ea..0d71b41a 100644 --- a/app/src/main/kotlin/com/simplemobiletools/calculator/helpers/CalculatorImpl.kt +++ b/app/src/main/kotlin/com/simplemobiletools/calculator/helpers/CalculatorImpl.kt @@ -281,7 +281,7 @@ class CalculatorImpl( } if (result.isInfinite() || result.isNaN()) { - context.toast(R.string.unknown_error_occurred) + context.toast(com.simplemobiletools.commons.R.string.unknown_error_occurred) return } @@ -295,7 +295,7 @@ class CalculatorImpl( inputDisplayedFormula = result.format() baseValue = result } catch (e: Exception) { - context.toast(R.string.unknown_error_occurred) + context.toast(com.simplemobiletools.commons.R.string.unknown_error_occurred) } } } diff --git a/build.gradle b/build.gradle deleted file mode 100644 index 2d1ded29..00000000 --- a/build.gradle +++ /dev/null @@ -1,29 +0,0 @@ -// Top-level build file where you can add configuration options common to all sub-projects/modules. - -buildscript { - ext.kotlin_version = '1.7.10' - repositories { - google() - mavenCentral() - } - - dependencies { - classpath 'com.android.tools.build:gradle:7.3.1' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - - // NOTE: Do not place your application dependencies here; they belong - // in the individual module build.gradle files - } -} - -allprojects { - repositories { - google() - mavenCentral() - maven { url "https://jitpack.io" } - } -} - -task clean(type: Delete) { - delete rootProject.buildDir -} diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 00000000..9a736eea --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,5 @@ +plugins { + alias(libs.plugins.android).apply(false) + alias(libs.plugins.kotlinAndroid).apply(false) + alias(libs.plugins.ksp).apply(false) +} diff --git a/gradle.properties b/gradle.properties index 915f0e66..ea724e7b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,20 +1,12 @@ -# Project-wide Gradle settings. - -# IDE (e.g. Android Studio) users: -# Gradle settings configured through the IDE *will override* -# any settings specified in this file. - -# For more details on how to configure your build environment visit -# http://www.gradle.org/docs/current/userguide/build_environment.html - -# Specifies the JVM arguments used for the daemon process. -# The setting is particularly useful for tweaking memory settings. -# Default value: -Xmx10248m -XX:MaxPermSize=256m -# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 - -# When configured, Gradle will run in incubating parallel mode. -# This option should only be used with decoupled projects. More details, visit -# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects -# org.gradle.parallel=true +org.gradle.jvmargs=-Xmx4g -XX:+UseGCOverheadLimit -XX:GCTimeLimit=10 -Dfile.encoding=UTF-8 -XX:+UseParallelGC +org.gradle.workers.max=8 +kotlin.code.style=official +android.useAndroidX=true android.enableJetifier=true -android.useAndroidX=true \ No newline at end of file +org.gradle.parallel=true +org.gradle.caching=true +org.gradle.vfs.watch=true +org.gradle.configureondemand=true +org.gradle.unsafe.configuration-cache=true +org.gradle.unsafe.configuration-cache-problems=warn +android.nonTransitiveRClass=true diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 00000000..fae96648 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,93 @@ +[versions] +#jetbrains +kotlin = "1.8.21" +#KSP +ksp = "1.8.21-1.0.11" +#Androidx +androidx-customView = "1.2.0-alpha02" +androidx-customViewPooling = "1.0.0" +#Compose +composeActivity = "1.8.0-alpha06" +compose = "1.6.0-alpha01" +composeCompiler = "1.4.7" +composeMaterial3 = "1.2.0-alpha03" +accompanist = "0.31.4-beta" +#AutoFitTextView +autofittextview = "0.2.1" +#exp4j +exp4j = "0.4.8" +#Room +room = "2.5.2" +#Simple tools +simple-commons = "4c83ec8740" +#Gradle +gradlePlugins-agp = "7.3.1" +#build +app-build-compileSDKVersion = "34" +app-build-targetSDK = "33" +app-build-minimumSDK = "23" +app-build-javaVersion = "VERSION_17" +app-build-kotlinJVMTarget = "17" +#versioning +app-version-appId = "com.simplemobiletools.calculator" +app-version-versionCode = "60" +app-version-versionName = "5.11.3" + +[libraries] +#Android X +androidx-customView = { module = "androidx.customview:customview", version.ref = "androidx-customView" } +androidx-customViewPooling = { module = "androidx.customview:customview-poolingcontainer", version.ref = "androidx-customViewPooling" } +#Room +androidx-room-runtime = { module = "androidx.room:room-runtime", version.ref = "room" } +androidx-room-ktx = { module = "androidx.room:room-ktx", version.ref = "room" } +androidx-room-compiler = { module = "androidx.room:room-compiler", version.ref = "room" } +#Compose +compose-compiler = { module = "androidx.compose.compiler:compiler", version.ref = "composeCompiler" } +compose-foundation = { module = "androidx.compose.foundation:foundation", version.ref = "compose" } +compose-material3 = { module = "androidx.compose.material3:material3", version.ref = "composeMaterial3" } +compose-material2 = { module = "androidx.compose.material:material", version.ref = "compose" } +compose-material-icons = { module = "androidx.compose.material:material-icons-extended", version.ref = "compose" } +compose-animation = { module = "androidx.compose.animation:animation", version.ref = "compose" } +compose-activity = { module = "androidx.activity:activity-compose", version.ref = "composeActivity" } +compose-ui = { module = "androidx.compose.ui:ui", version.ref = "compose" } +compose-runtime = { module = "androidx.compose.runtime:runtime", version.ref = "compose" } +compose-uiTooling-debug = { module = "androidx.compose.ui:ui-tooling", version.ref = "compose" } +compose-uiTooling-preview = { module = "androidx.compose.ui:ui-tooling-preview", version.ref = "compose" } +#UI +auto-fit-text-view = { module = "me.grantland:autofittextview", version.ref = "autofittextview" } +#Simple Mobile Tools +simple-tools-commons = { module = "com.github.SimpleMobileTools:Simple-Commons", version.ref = "simple-commons" } +#Exp4j +exp4j = { module = "net.objecthunter:exp4j", version.ref = "exp4j" } +#Accompanist +accompanist-systemuicontroller = { module = "com.google.accompanist:accompanist-systemuicontroller", version.ref = "accompanist" } +[bundles] +compose = [ + "compose-activity", + "compose-animation", + "compose-compiler", + "compose-foundation", + "compose-material-icons", + "compose-material3", + "compose-runtime", + "compose-ui", + "compose-uiTooling-preview", +] +compose-preview = [ + "androidx-customView", + "androidx-customViewPooling", + "compose-uiTooling-debug", +] +room = [ + "androidx-room-ktx", + "androidx-room-runtime", +] +accompanist = [ + "accompanist-systemuicontroller", +] + +[plugins] +android = { id = "com.android.application", version.ref = "gradlePlugins-agp" } +ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } +kotlinAndroid = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } + diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index aa8192b8..3ecd7f43 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index e7b4def4..00000000 --- a/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -include ':app' diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 00000000..45478cbe --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,16 @@ +pluginManagement { + repositories { + gradlePluginPortal() + google() + mavenCentral() + } +} +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + maven { setUrl("https://jitpack.io") } + } +} +include(":app")