diff --git a/.idea/androidTestResultsUserPreferences.xml b/.idea/androidTestResultsUserPreferences.xml new file mode 100644 index 0000000..1ff8cba --- /dev/null +++ b/.idea/androidTestResultsUserPreferences.xml @@ -0,0 +1,48 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts index f3c1f83..01d3b93 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,6 +1,7 @@ plugins { alias(libs.plugins.androidApplication) alias(libs.plugins.jetbrainsKotlinAndroid) + } android { @@ -43,6 +44,9 @@ android { androidResources { generateLocaleConfig = true } + buildFeatures{ + viewBinding = true + } } dependencies { @@ -68,6 +72,8 @@ dependencies { implementation(libs.androidx.annotation) implementation(libs.androidx.lifecycle.livedata.ktx) implementation(libs.androidx.lifecycle.viewmodel.ktx) + implementation(libs.androidx.datastore.rxjava3) + implementation(libs.androidx.datastore.preferences) testImplementation(libs.junit) diff --git a/app/src/androidTest/java/uk/kagurach/android101/TestColorHelper.kt b/app/src/androidTest/java/uk/kagurach/android101/TestColorHelper.kt new file mode 100644 index 0000000..817d96a --- /dev/null +++ b/app/src/androidTest/java/uk/kagurach/android101/TestColorHelper.kt @@ -0,0 +1,31 @@ +package uk.kagurach.android101 + +import org.junit.Assert +import org.junit.Test +import uk.kagurach.android101.helper.ColorHelper +import org.junit.runner.RunWith + + +class TestColorHelper { + val colorHelper = ColorHelper() + + @Test + fun Test_toColorInt(){ + Assert.assertEquals(0,colorHelper.toColorInt(0, 0, 0)) + Assert.assertEquals(0xfffffe,colorHelper.toColorInt(255, 0xff, 254)) + } + + @Test(expected = Exception::class) + fun Test_error(){ + val wtf1 = colorHelper.toColorInt(-1,256,1) + } + @Test + fun Test_toString(){ + Assert.assertEquals("$000000",colorHelper.toString(0,"$")) + Assert.assertEquals("#ffffff",colorHelper.toString(0xffffff)) + Assert.assertEquals("#ABCD12",colorHelper.toString(0xabcd12, upperCase = true)) + + + } + +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 08b5324..c5955c9 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,7 +2,6 @@ - + - + diff --git a/app/src/main/java/uk/kagurach/android101/KaBaseActivity.kt b/app/src/main/java/uk/kagurach/android101/KaBaseActivity.kt new file mode 100644 index 0000000..aa21f22 --- /dev/null +++ b/app/src/main/java/uk/kagurach/android101/KaBaseActivity.kt @@ -0,0 +1,14 @@ +package uk.kagurach.android101 + +import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity +import kotlinx.coroutines.runBlocking + + +open class KaBaseActivity : AppCompatActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + val storage = SettingStorage(this) + this.setTheme(runBlocking { storage.getDefaultTheme() }) + } +} \ No newline at end of file diff --git a/app/src/main/java/uk/kagurach/android101/MainActivity.java b/app/src/main/java/uk/kagurach/android101/MainActivity.java index 15707d5..96724b6 100644 --- a/app/src/main/java/uk/kagurach/android101/MainActivity.java +++ b/app/src/main/java/uk/kagurach/android101/MainActivity.java @@ -27,7 +27,7 @@ import java.util.Arrays; import uk.kagurach.android101.helper.PageHelper; -public class MainActivity extends AppCompatActivity { +public class MainActivity extends KaBaseActivity { PageHelper pageHelper; @Override @@ -62,7 +62,7 @@ public class MainActivity extends AppCompatActivity { 101); } textViewAppendString(tv, "Check Finished"); - textViewAppendString(tv, "提示:常桉有惊喜"); + textViewAppendString(tv, "提示:常按有惊喜"); } textViewAppendString(tv, "*************************\nfinished"); @@ -73,6 +73,9 @@ public class MainActivity extends AppCompatActivity { button.setEnabled(true); button.setOnClickListener(pageHelper.pageButtonHandler); button.setOnLongClickListener(new LongClickHandler(this)); + + Button SettingPageButton = findViewById(R.id.P1OpenAppSettingsLayout); + SettingPageButton.setOnClickListener(new SettingPageHandler()); } private void textViewAppendString(@NonNull TextView tv, String s) { @@ -121,4 +124,15 @@ public class MainActivity extends AppCompatActivity { return false; } } + + private final class SettingPageHandler implements View.OnClickListener { + + @Override + public void onClick(View v) { + Intent intent = new Intent(v.getContext(),SettingPage.class); + intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + startActivity(intent); + finish(); + } + } } \ No newline at end of file diff --git a/app/src/main/java/uk/kagurach/android101/MainActivity2.java b/app/src/main/java/uk/kagurach/android101/MainActivity2.java index d5b4b03..ca234f9 100644 --- a/app/src/main/java/uk/kagurach/android101/MainActivity2.java +++ b/app/src/main/java/uk/kagurach/android101/MainActivity2.java @@ -21,10 +21,11 @@ import androidx.core.graphics.Insets; import androidx.core.view.ViewCompat; import androidx.core.view.WindowInsetsCompat; +import uk.kagurach.android101.helper.ColorHelper; import uk.kagurach.android101.helper.PageHelper; import uk.kagurach.android101.helper.ToastHelper; -public class MainActivity2 extends AppCompatActivity { +public class MainActivity2 extends KaBaseActivity { PageHelper pageHelper; @@ -159,9 +160,8 @@ public class MainActivity2 extends AppCompatActivity { private void updateCurrentSettingShower(){ TextView tv = findViewById(R.id.P2SettingResult); - String sb = "Color = #" + - String.format("%6s",Integer.toString(_text_color&0xffffff, 16)) - .replace(" ","0") + + String sb = "Color = " + + new ColorHelper().toString(_text_color,"#",false) + "; TextSize = " + _text_size + "." + diff --git a/app/src/main/java/uk/kagurach/android101/Page3.java b/app/src/main/java/uk/kagurach/android101/Page3.java index bbf10df..de9fac9 100644 --- a/app/src/main/java/uk/kagurach/android101/Page3.java +++ b/app/src/main/java/uk/kagurach/android101/Page3.java @@ -16,7 +16,7 @@ import androidx.core.view.WindowInsetsCompat; import uk.kagurach.android101.helper.PageHelper; -public class Page3 extends AppCompatActivity { +public class Page3 extends KaBaseActivity { PageHelper pageHelper; diff --git a/app/src/main/java/uk/kagurach/android101/Page4.java b/app/src/main/java/uk/kagurach/android101/Page4.java index 78c5152..c890ec5 100644 --- a/app/src/main/java/uk/kagurach/android101/Page4.java +++ b/app/src/main/java/uk/kagurach/android101/Page4.java @@ -22,7 +22,7 @@ import androidx.core.view.WindowInsetsCompat; import uk.kagurach.android101.helper.PageHelper; import uk.kagurach.android101.misc.vibrationBroadcastReceiver.vibrationBroadcastReceiver; -public class Page4 extends AppCompatActivity { +public class Page4 extends KaBaseActivity { PageHelper pageHelper; ActivityResultLauncher mLauncher; diff --git a/app/src/main/java/uk/kagurach/android101/Page5.java b/app/src/main/java/uk/kagurach/android101/Page5.java index dfa70a7..0c20a9f 100644 --- a/app/src/main/java/uk/kagurach/android101/Page5.java +++ b/app/src/main/java/uk/kagurach/android101/Page5.java @@ -25,7 +25,7 @@ import uk.kagurach.android101.helper.PageHelper; import uk.kagurach.android101.helper.ToastHelper; import uk.kagurach.android101.helper.AutoCompleHelper.AnimalTypeAutoCompleteHelper; -public class Page5 extends AppCompatActivity { +public class Page5 extends KaBaseActivity { AnimalTypeAutoCompleteHelper completeHelper = null; final AnimalDatabaseHelper dbHelper = new AnimalDatabaseHelper(this); diff --git a/app/src/main/java/uk/kagurach/android101/SettingPage.kt b/app/src/main/java/uk/kagurach/android101/SettingPage.kt new file mode 100644 index 0000000..2e7a6c8 --- /dev/null +++ b/app/src/main/java/uk/kagurach/android101/SettingPage.kt @@ -0,0 +1,88 @@ +package uk.kagurach.android101 + +import android.content.Context +import android.content.Intent +import android.os.Bundle +import android.util.Log +import android.view.View +import android.widget.ImageButton +import androidx.activity.enableEdgeToEdge +import androidx.appcompat.app.AppCompatActivity +import androidx.core.view.ViewCompat +import androidx.core.view.WindowInsetsCompat +import androidx.datastore.preferences.core.edit +import androidx.datastore.preferences.core.intPreferencesKey +import androidx.datastore.preferences.preferencesDataStore +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.runBlocking +import uk.kagurach.android101.databinding.ActivitySettingPageBinding + +import uk.kagurach.android101.helper.ColorHelper + +val Context.datastore by preferencesDataStore(name = "settings") +val DefaultColor = intPreferencesKey("default_color") + +class SettingPage : KaBaseActivity() { + lateinit var binding: ActivitySettingPageBinding + lateinit var settingStorage: SettingStorage + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_setting_page) + ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets -> + val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) + v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom) + insets + } + binding = ActivitySettingPageBinding.inflate(layoutInflater) + setContentView(binding.root) + + settingStorage = SettingStorage(this) + + binding.ThemeRed.setOnClickListener(SetColorHandler()) + binding.ThemeBlue.setOnClickListener(SetColorHandler()) + binding.ThemeCyan.setOnClickListener(SetColorHandler()) + binding.ThemePink.setOnClickListener(SetColorHandler()) + binding.ThemeGreen.setOnClickListener(SetColorHandler()) + + binding.SettingPageSubmit.setOnClickListener(FinishButtonHandler()) + } + + + inner class SetColorHandler: View.OnClickListener { + override fun onClick(v: View?) { + if (v == null){ + return + } + + val colorTheme = when(v.id){ + R.id.ThemeBlue -> R.style.Theme_Blue + R.id.ThemeGreen -> R.style.Theme_Green + R.id.ThemeRed -> R.style.Theme_Red + R.id.ThemeCyan -> R.style.Theme_Cyan + R.id.ThemePink -> R.style.Theme_Pink + else -> {throw RuntimeException("Impossible branch met!")} + } + + runBlocking { + settingStorage.setDefaultTheme(colorTheme) + } + + val intent = Intent(v.context,this@SettingPage::class.java) + startActivity(intent) + finish() + } + } + + inner class FinishButtonHandler: View.OnClickListener{ + override fun onClick(v: View?) { + val intent = Intent(v!!.context,MainActivity::class.java) + startActivity(intent) + finish() + } + + } + + +} \ No newline at end of file diff --git a/app/src/main/java/uk/kagurach/android101/SettingStorage.kt b/app/src/main/java/uk/kagurach/android101/SettingStorage.kt new file mode 100644 index 0000000..0ed7eb4 --- /dev/null +++ b/app/src/main/java/uk/kagurach/android101/SettingStorage.kt @@ -0,0 +1,28 @@ +package uk.kagurach.android101 + +import android.content.Context +import androidx.datastore.preferences.core.edit +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.map + +class SettingStorage(val context: Context) { + + suspend fun getDefaultTheme(): Int { + return getDefaultColorFlow.first() + } + suspend fun setDefaultTheme(newValue: Int) { + context.datastore.edit { + preferences -> + preferences[DefaultColor] = newValue + } + } + + + private val getDefaultColorFlow: Flow = + context.datastore.data + .map { + preferences -> + preferences[DefaultColor] ?: R.id.ThemeBlue + } +} \ No newline at end of file diff --git a/app/src/main/java/uk/kagurach/android101/helper/ColorHelper.kt b/app/src/main/java/uk/kagurach/android101/helper/ColorHelper.kt new file mode 100644 index 0000000..2be9a97 --- /dev/null +++ b/app/src/main/java/uk/kagurach/android101/helper/ColorHelper.kt @@ -0,0 +1,23 @@ +package uk.kagurach.android101.helper + +import android.graphics.Color +import androidx.compose.ui.util.fastJoinToString + +class ColorHelper { + fun toColorInt(r: Int, g: Int, b: Int): Int { + if (r !in 0..255 || g !in 0..255 || b !in 0..255) { + throw Exception("RGB not in range") + } + return Color.rgb(r, g, b).and(0xffffff) // Preserve only low 48 bit + } + + @OptIn(ExperimentalStdlibApi::class) + fun toString(colorInt: Int, start: String = "#", upperCase: Boolean = false): String { + val colorInt = colorInt.and(0xffffff) // Keep only low six digit + val colorString = colorInt.toHexString( + if (upperCase) { HexFormat.UpperCase } + else{ HexFormat.Default } + ).drop(2) + return "$start$colorString" + } +} \ No newline at end of file diff --git a/app/src/main/java/uk/kagurach/android101/misc/Kaculate.kt b/app/src/main/java/uk/kagurach/android101/misc/Kaculate.kt index dac3337..85cd971 100644 --- a/app/src/main/java/uk/kagurach/android101/misc/Kaculate.kt +++ b/app/src/main/java/uk/kagurach/android101/misc/Kaculate.kt @@ -9,15 +9,15 @@ fun Kaculate(src: String, ctx: Context): String { return src } - val OpList = charArrayOf('+', '-', 'x', '/', '^') + val opList = charArrayOf('+', '-', 'x', '/', '^') var numStack = floatArrayOf() var opStack = charArrayOf() var _curnum = "" // Fix for expression starts with operator - val src = if (src[0] in OpList){ - "0" + src + val src = if (src[0] in opList){ + "0$src" }else{ src } @@ -25,7 +25,7 @@ fun Kaculate(src: String, ctx: Context): String { for (i in src.indices) { if (src[i] in '0'..'9' || src[i] == '.') { _curnum += src[i] - } else if (src[i] in OpList) { + } else if (src[i] in opList) { try { numStack += _curnum.toFloat() _curnum = "" diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index f925424..c585eab 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -4,25 +4,51 @@ android:id="@+id/main" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context=".MainActivity"> + tools:context=".MainActivity" + tools:viewBindingIgnore="true"> + android:orientation="vertical" + android:layout_marginHorizontal="15dp" + android:layout_marginVertical="10dp" + > - + android:layout_height="wrap_content" + android:minHeight="500dp" + > + + + + +