From 6e5e5c944f26b06c4a0c7f9feaf0da70b20cff72 Mon Sep 17 00:00:00 2001 From: fgerber Date: Wed, 17 Jan 2024 22:47:22 +0100 Subject: [PATCH] Push the long-awaited changes - Apply consistent blue theming, including setting to switch between dark/light modes - Hide edit button and all checkboxes in front of continents - Use material design for clickable buttons and checkboxes - Show percentages of visited countries per continent (possibly enable/disable in settings?) --- app/build.gradle | 4 +- app/src/main/AndroidManifest.xml | 13 +++- .../beendroid/activity/FoldingListAdapter.kt | 44 ++++++++++--- .../helcel/beendroid/activity/MainActivity.kt | 63 ++++++++++++++++++- .../beendroid/activity/SettingsActivity.kt | 39 ++++++++++++ .../beendroid/activity/SettingsFragment.kt | 54 ++++++++++++++++ .../net/helcel/beendroid/countries/Visited.kt | 6 +- .../net/helcel/beendroid/svg/CSSWrapper.kt | 7 ++- .../net/helcel/beendroid/svg/PSVGWrapper.kt | 29 +++++++-- .../{chevron_right_solid.xml => chevron.xml} | 2 +- app/src/main/res/drawable/edit.xml | 3 +- app/src/main/res/drawable/palette.xml | 11 ++++ app/src/main/res/layout/activity_main.xml | 47 ++------------ app/src/main/res/layout/activity_settings.xml | 16 +++++ app/src/main/res/layout/item_list.xml | 63 +++++++++---------- app/src/main/res/menu/menu_main.xml | 11 +++- app/src/main/res/values-night/themes.xml | 8 ++- app/src/main/res/values/arrays.xml | 8 +++ app/src/main/res/values/colors.xml | 13 ++++ app/src/main/res/values/en.xml | 6 +- app/src/main/res/values/themes.xml | 15 ++--- app/src/main/res/xml/fragment_settings.xml | 17 +++++ 22 files changed, 361 insertions(+), 118 deletions(-) create mode 100644 app/src/main/java/net/helcel/beendroid/activity/SettingsActivity.kt create mode 100644 app/src/main/java/net/helcel/beendroid/activity/SettingsFragment.kt rename app/src/main/res/drawable/{chevron_right_solid.xml => chevron.xml} (89%) create mode 100644 app/src/main/res/drawable/palette.xml create mode 100644 app/src/main/res/layout/activity_settings.xml create mode 100644 app/src/main/res/values/arrays.xml create mode 100644 app/src/main/res/values/colors.xml create mode 100644 app/src/main/res/xml/fragment_settings.xml diff --git a/app/build.gradle b/app/build.gradle index 245a569..4c65cee 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,12 +5,12 @@ plugins { android { namespace 'net.helcel.beendroid' - compileSdk 33 + compileSdk 34 defaultConfig { applicationId 'net.helcel.beendroid' minSdk 28 - targetSdk 33 + targetSdk 34 versionCode 1 versionName "1.0" diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 13b483f..805e8eb 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -16,14 +16,21 @@ > + android:exported="true" > - + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/net/helcel/beendroid/activity/FoldingListAdapter.kt b/app/src/main/java/net/helcel/beendroid/activity/FoldingListAdapter.kt index 42f4914..a1e0b6c 100644 --- a/app/src/main/java/net/helcel/beendroid/activity/FoldingListAdapter.kt +++ b/app/src/main/java/net/helcel/beendroid/activity/FoldingListAdapter.kt @@ -1,15 +1,20 @@ package net.helcel.beendroid.activity import android.content.Context +import android.graphics.Color import android.graphics.Typeface +import android.graphics.drawable.ColorDrawable +import android.util.Log +import android.util.TypedValue import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.ImageView import android.widget.TextView -import androidx.appcompat.content.res.AppCompatResources +import androidx.appcompat.content.res.AppCompatResources.getDrawable import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView +import com.google.android.material.button.MaterialButton import com.google.android.material.checkbox.MaterialCheckBox import net.helcel.beendroid.R import net.helcel.beendroid.countries.GeoLoc @@ -63,15 +68,14 @@ class FoldingListAdapter( private val visited: Visited, ) : RecyclerView.ViewHolder(itemView) { private val textView: TextView - private val expand: ImageView + //private val expand: MaterialButton private val checkBox: MaterialCheckBox private val subItemView: View private val list: RecyclerView init { textView = itemView.findViewById(R.id.textView) - expand = itemView.findViewById(R.id.expand) - expand.setImageDrawable(AppCompatResources.getDrawable(ctx,R.drawable.chevron_right_solid)) + //expand = itemView.findViewById(R.id.expand) checkBox = itemView.findViewById(R.id.checkBox) subItemView = itemView.findViewById(R.id.sub_item) list = itemView.findViewById(R.id.list_list) @@ -79,13 +83,39 @@ class FoldingListAdapter( } fun bind(el: Pair, parentLambda: () -> Unit) { - expand.rotation = if(el.second) 90f else 0f + //expand.rotation = if(el.second) 90f else 0f subItemView.visibility = if (el.second) View.VISIBLE else View.GONE - expand.visibility = if(!el.first.isEnd) View.VISIBLE else View.INVISIBLE + //expand.visibility = if(!el.first.isEnd) View.VISIBLE else View.INVISIBLE textView.text = el.first.fullName if (el.first.type == LocType.GROUP) { textView.setTypeface(null, Typeface.BOLD) + + val colorGrayTyped = TypedValue() + ctx.theme.resolveAttribute(android.R.attr.textColorTertiary, colorGrayTyped, true) + val color = Color.valueOf(colorGrayTyped.data) + textView.setBackgroundColor(Color.valueOf(color.red(), color.green(), color.blue(), 0.5f).toArgb()) + checkBox.visibility = View.INVISIBLE + + el.first.children.apply { + val nbCountries = this.size + val nbVisited = this.map { if (visited.visited(it)) 1 else 0 }.reduce{ a, b -> (a + b) } + val ratio = nbVisited.toFloat() / nbCountries.toFloat() + val percentage = (ratio * 100).toInt() + textView.text = "${textView.text as String} (${percentage}%)" + } + } else { + val colorBackgroundTyped = TypedValue() + ctx.theme.resolveAttribute(android.R.attr.colorBackground, colorBackgroundTyped, true) + textView.backgroundTintList = null + textView.background = ColorDrawable(colorBackgroundTyped.data) + textView.isActivated = false + + val layoutParam = checkBox.layoutParams + layoutParam.width = 125 + checkBox.layoutParams = layoutParam + + checkBox.visibility = View.VISIBLE } checkBox.checkedState = if (visited.visited(el.first)) MaterialCheckBox.STATE_CHECKED @@ -104,7 +134,7 @@ class FoldingListAdapter( } //textView.setOnLongClickListener{ checkBox.toggle(); true } - expand.setOnClickListener { expandLambda() } + //expand.setOnClickListener { expandLambda() } } } diff --git a/app/src/main/java/net/helcel/beendroid/activity/MainActivity.kt b/app/src/main/java/net/helcel/beendroid/activity/MainActivity.kt index a45386b..853cea5 100644 --- a/app/src/main/java/net/helcel/beendroid/activity/MainActivity.kt +++ b/app/src/main/java/net/helcel/beendroid/activity/MainActivity.kt @@ -1,9 +1,20 @@ package net.helcel.beendroid.activity +import android.content.Intent +import android.content.SharedPreferences import android.graphics.Bitmap import android.graphics.Canvas +import android.graphics.Color +import android.graphics.drawable.ColorDrawable import android.os.Bundle +import android.util.Log +import android.util.TypedValue +import android.view.Menu +import android.view.MenuInflater +import android.view.MenuItem import androidx.appcompat.app.AppCompatActivity +import androidx.core.view.MenuProvider +import androidx.preference.PreferenceManager import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.caverock.androidsvg.RenderOptions @@ -17,6 +28,8 @@ import net.helcel.beendroid.svg.PSVGWrapper class MainActivity : AppCompatActivity() { + private lateinit var sharedPreferences: SharedPreferences + private lateinit var map : SVGImageView private lateinit var list : RecyclerView @@ -30,26 +43,70 @@ class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - canvas.drawRGB(255, 255, 255) + // Create action bar + val colorPrimaryTyped = TypedValue() + theme.resolveAttribute(android.R.attr.colorPrimary, colorPrimaryTyped, true) + supportActionBar?.setBackgroundDrawable(ColorDrawable(colorPrimaryTyped.data)) + // Fetch shared preferences to restore app theme upon startup + sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this) + SettingsFragment.setTheme(this, sharedPreferences.getString(getString(R.string.key_theme), getString(R.string.system))) + + // Create menu in action bar + addMenuProvider(object : MenuProvider { + override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) { + menuInflater.inflate(R.menu.menu_main, menu) + } + + override fun onMenuItemSelected(menuItem: MenuItem): Boolean { + return when (menuItem.itemId) { + R.id.action_edit -> { + // TODO: Enable editing selected countries + true + } + R.id.action_settings -> { + // Open settings + startActivity(Intent(this@MainActivity, SettingsActivity::class.java)) + true + } + else -> { + false + } + } + } + + }) + + // Restore visited countries visited = Visited(this) visited.load() + // Wrap lists of countries psvg = PSVGWrapper(this) css = CSSWrapper(visited) + // Populate map from list of countries setContentView(R.layout.activity_main) map = findViewById(R.id.map) map.setImageBitmap(bitmap) - refreshMap() + // Populate list below the map list = findViewById(R.id.list) list.layoutManager = LinearLayoutManager(this, RecyclerView.VERTICAL, false) list.adapter = FoldingListAdapter(this, World.WWW.children, visited) { refreshMap() } } private fun refreshMap(){ - psvg.get().renderToCanvas(canvas,RenderOptions.create().css(css.get())) + // Set or reset background (replaces canvas.drawColor(0, 0, 0)) + val colorBackgroundTyped = TypedValue() + theme.resolveAttribute(android.R.attr.colorBackground, colorBackgroundTyped, true) + canvas.drawColor(colorBackgroundTyped.data) + + // Render all countries and visited ones + psvg.getFill().renderToCanvas(canvas, RenderOptions.create().css(css.get())) + + // Render all contours in the same color as the background to make them much clearer + psvg.getDraw().renderToCanvas(canvas) } } \ No newline at end of file diff --git a/app/src/main/java/net/helcel/beendroid/activity/SettingsActivity.kt b/app/src/main/java/net/helcel/beendroid/activity/SettingsActivity.kt new file mode 100644 index 0000000..168899b --- /dev/null +++ b/app/src/main/java/net/helcel/beendroid/activity/SettingsActivity.kt @@ -0,0 +1,39 @@ +package net.helcel.beendroid.activity + +import android.graphics.drawable.ColorDrawable +import android.content.Intent +import android.os.Bundle +import android.os.PersistableBundle +import android.util.TypedValue +import android.view.MenuItem +import androidx.activity.addCallback +import androidx.appcompat.app.AppCompatActivity +import net.helcel.beendroid.R + +class SettingsActivity: AppCompatActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + // Bind activity to XML layout with fragment view + setContentView(R.layout.activity_settings) + + // Create action bar + val colorPrimaryTyped = TypedValue() + theme.resolveAttribute(android.R.attr.colorPrimary, colorPrimaryTyped, true) + supportActionBar?.setBackgroundDrawable(ColorDrawable(colorPrimaryTyped.data)) + supportActionBar?.title = getString(R.string.action_settings) + supportActionBar?.setDisplayHomeAsUpEnabled(true) + + // Populate activity with settings fragment + supportFragmentManager.beginTransaction() + .replace(R.id.fragment_view, SettingsFragment()) + .commit() + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + // Configure on back pressed + finish() + return super.onOptionsItemSelected(item) + } +} \ No newline at end of file diff --git a/app/src/main/java/net/helcel/beendroid/activity/SettingsFragment.kt b/app/src/main/java/net/helcel/beendroid/activity/SettingsFragment.kt new file mode 100644 index 0000000..ba3c155 --- /dev/null +++ b/app/src/main/java/net/helcel/beendroid/activity/SettingsFragment.kt @@ -0,0 +1,54 @@ +package net.helcel.beendroid.activity + +import android.content.Context +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.util.TypedValue +import androidx.appcompat.app.AppCompatDelegate +import androidx.preference.ListPreference +import androidx.preference.PreferenceFragmentCompat +import net.helcel.beendroid.R + + +class SettingsFragment: PreferenceFragmentCompat() { + private lateinit var themePreference: ListPreference + + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { + setPreferencesFromResource(R.xml.fragment_settings, rootKey) + + // Select Light/Dark/System Mode + themePreference = findPreference(getString(R.string.key_theme))!! + themePreference.setOnPreferenceChangeListener { _, key -> + setTheme(requireContext(), key as String) + } + + } + + companion object { + fun setTheme(context: Context, key: String?): Boolean { + when (key) { + context.getString(R.string.system) -> { + // Set SYSTEM Theme + AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM) + return true + } + + context.getString(R.string.light) -> { + // Set LIGHT Theme + AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO) + return true + } + + context.getString(R.string.dark) -> { + // Set DARK Theme + AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES) + return true + } + + else -> { + return false + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/net/helcel/beendroid/countries/Visited.kt b/app/src/main/java/net/helcel/beendroid/countries/Visited.kt index 07c1a97..b7513fa 100644 --- a/app/src/main/java/net/helcel/beendroid/countries/Visited.kt +++ b/app/src/main/java/net/helcel/beendroid/countries/Visited.kt @@ -10,13 +10,13 @@ class Visited(ctx: Context) { fun load() { - Group.values().forEach { + Group.entries.forEach { locs[it] = pref.getBoolean(it.code, false) } - Country.values().forEach { + Country.entries.forEach { locs[it] = pref.getBoolean(it.code, false) } - State.values().forEach { + State.entries.forEach { locs[it] = pref.getBoolean(it.code, false) } editor.apply() diff --git a/app/src/main/java/net/helcel/beendroid/svg/CSSWrapper.kt b/app/src/main/java/net/helcel/beendroid/svg/CSSWrapper.kt index d5705ec..e95e26e 100644 --- a/app/src/main/java/net/helcel/beendroid/svg/CSSWrapper.kt +++ b/app/src/main/java/net/helcel/beendroid/svg/CSSWrapper.kt @@ -1,20 +1,23 @@ package net.helcel.beendroid.svg +import android.util.TypedValue import net.helcel.beendroid.countries.Visited import net.helcel.beendroid.countries.World class CSSWrapper(private val visited: Visited) { + private val colorPrimary = "#0187FF" + fun get() : String { return listOf(World.WWW.children .filter { visited.visited(it)} - .map { ".${it.code}{fill:blue;}"} + .map { ".${it.code}{fill:$colorPrimary;}"} .fold(""){acc, s-> acc + s}, World.WWW.children .filter { !visited.visited(it) } .map { cg -> cg.children .filter { visited.visited(it) } - .map { ".${it.code}{fill:blue;}"} + .map { ".${it.code}{fill:$colorPrimary;}"} .fold(""){acc, s-> acc + s} }.fold(""){acc,s->acc+s}, ).fold(""){acc,s-> acc+s} diff --git a/app/src/main/java/net/helcel/beendroid/svg/PSVGWrapper.kt b/app/src/main/java/net/helcel/beendroid/svg/PSVGWrapper.kt index 30b5f11..0afbdcd 100644 --- a/app/src/main/java/net/helcel/beendroid/svg/PSVGWrapper.kt +++ b/app/src/main/java/net/helcel/beendroid/svg/PSVGWrapper.kt @@ -1,7 +1,12 @@ package net.helcel.beendroid.svg import android.content.Context +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.util.Log +import android.util.TypedValue import com.caverock.androidsvg.SVG +import net.helcel.beendroid.R import net.helcel.beendroid.countries.Country import net.helcel.beendroid.countries.GeoLoc import net.helcel.beendroid.countries.World @@ -11,8 +16,20 @@ class PSVGWrapper(ctx: Context) { private val cm = HashMap() private var fm = "" + private val colorForeground: String + private val colorBackground: String + init { - Country.values().forEach { + val colorSecondaryTyped = TypedValue() + ctx.theme.resolveAttribute(android.R.attr.textColorTertiary, colorSecondaryTyped, true) + colorForeground = "\"#${Integer.toHexString(colorSecondaryTyped.data).subSequence(2, 8)}\"" + + val colorBackgroundTyped = TypedValue() + ctx.theme.resolveAttribute(android.R.attr.colorBackground, colorBackgroundTyped, true) + colorBackground = "\"#${Integer.toHexString(colorBackgroundTyped.data).subSequence(2, 8)}\"" + + + Country.entries.forEach { cm[it] = PSVGLoader(ctx, it, Level.ZERO).load() } build() @@ -31,12 +48,12 @@ class PSVGWrapper(ctx: Context) { }.fold("") { acc, e -> acc + e } } - fun get(): SVG { - return SVG.getFromString("$fm") + fun getFill(): SVG { + return SVG.getFromString("$fm") } - - - + fun getDraw(): SVG { + return SVG.getFromString("$fm") + } } \ No newline at end of file diff --git a/app/src/main/res/drawable/chevron_right_solid.xml b/app/src/main/res/drawable/chevron.xml similarity index 89% rename from app/src/main/res/drawable/chevron_right_solid.xml rename to app/src/main/res/drawable/chevron.xml index a66bef1..6d21775 100644 --- a/app/src/main/res/drawable/chevron_right_solid.xml +++ b/app/src/main/res/drawable/chevron.xml @@ -4,6 +4,6 @@ android:viewportWidth="320" android:viewportHeight="512"> diff --git a/app/src/main/res/drawable/edit.xml b/app/src/main/res/drawable/edit.xml index a4df5f3..5cd1ea2 100644 --- a/app/src/main/res/drawable/edit.xml +++ b/app/src/main/res/drawable/edit.xml @@ -1,11 +1,10 @@ diff --git a/app/src/main/res/drawable/palette.xml b/app/src/main/res/drawable/palette.xml new file mode 100644 index 0000000..e9875e0 --- /dev/null +++ b/app/src/main/res/drawable/palette.xml @@ -0,0 +1,11 @@ + + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 30c760d..bd4166a 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -2,49 +2,9 @@ - - - - - - - - - - - - - + android:theme="@style/Theme.Beendroid" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_list.xml b/app/src/main/res/layout/item_list.xml index 2bbd2bc..b5f2bfa 100644 --- a/app/src/main/res/layout/item_list.xml +++ b/app/src/main/res/layout/item_list.xml @@ -9,49 +9,48 @@ android:layout_width="match_parent" android:layout_height="wrap_content"> - - - + + + app:layout_constraintTop_toBottomOf="@id/checkBox"> + tools:context="net.helcel.beendroid.activity.MainActivity" > + + + - - \ No newline at end of file + diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml new file mode 100644 index 0000000..f5052d1 --- /dev/null +++ b/app/src/main/res/values/arrays.xml @@ -0,0 +1,8 @@ + + + + @string/system + @string/light + @string/dark + + diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..ac343a4 --- /dev/null +++ b/app/src/main/res/values/colors.xml @@ -0,0 +1,13 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03AFFF + #FF0187FF + #FFFFDD00 + #FF000000 + #FF555555 + #FFBBBBBB + #FFFFFFFF + diff --git a/app/src/main/res/values/en.xml b/app/src/main/res/values/en.xml index a6fbca8..e75bafd 100644 --- a/app/src/main/res/values/en.xml +++ b/app/src/main/res/values/en.xml @@ -2,7 +2,11 @@ BeenDroid Settings - + Edit Welcome! Change language + App theme + Same as system + Light theme + Dark theme \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 89c86e9..cfa9139 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -1,14 +1,9 @@ - - - - -