added dark/light button and other ui adjustments

This commit is contained in:
izzy2lost
2025-12-28 06:50:14 -05:00
parent 392360f8c3
commit 613a68d209
6 changed files with 201 additions and 23 deletions
@@ -3,8 +3,10 @@ package com.izzy2lost.super3
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.content.res.Configuration
import android.text.method.LinkMovementMethod
import android.text.util.Linkify
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@@ -13,6 +15,8 @@ import android.widget.TextView
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import androidx.appcompat.content.res.AppCompatResources
import androidx.core.view.GravityCompat
import androidx.core.widget.addTextChangedListener
import androidx.documentfile.provider.DocumentFile
@@ -27,6 +31,7 @@ import com.google.android.material.navigation.NavigationView
import com.google.android.material.search.SearchBar
import com.google.android.material.search.SearchView
import java.io.File
import java.util.ArrayDeque
import kotlin.math.max
import kotlin.math.min
import kotlin.concurrent.thread
@@ -41,7 +46,9 @@ class MainActivity : AppCompatActivity() {
private lateinit var toolbar: MaterialToolbar
private lateinit var searchBar: SearchBar
private lateinit var searchView: SearchView
private lateinit var btnOpenDrawer: ImageButton
private lateinit var btnViewMode: ImageButton
private lateinit var btnThemeToggle: ImageButton
private lateinit var btnAbout: MaterialButton
private lateinit var gamesFolderText: TextView
@@ -119,6 +126,7 @@ class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
applyThemeFromPrefs()
if (!prefs.getBoolean("setup_complete", false)) {
val hasGames = prefs.getString("gamesTreeUri", null) != null
val hasData = prefs.getString("userTreeUri", null) != null
@@ -138,7 +146,9 @@ class MainActivity : AppCompatActivity() {
toolbar = findViewById(R.id.toolbar)
searchBar = findViewById(R.id.search_bar)
searchView = findViewById(R.id.search_view)
btnOpenDrawer = findViewById(R.id.btn_open_drawer)
btnViewMode = findViewById(R.id.btn_view_mode)
btnThemeToggle = findViewById(R.id.btn_theme_toggle)
gamesList = findViewById(R.id.games_list)
searchResultsList = findViewById(R.id.search_results_list)
@@ -170,7 +180,7 @@ class MainActivity : AppCompatActivity() {
gamesList.adapter = gamesAdapter
searchResultsList.adapter = gamesAdapter
toolbar.setNavigationOnClickListener {
btnOpenDrawer.setOnClickListener {
drawerLayout.openDrawer(GravityCompat.START)
}
@@ -208,6 +218,7 @@ class MainActivity : AppCompatActivity() {
}
runCatching { searchView.setupWithSearchBar(searchBar) }
styleSearchBarText()
searchBar.setOnClickListener {
searchView.show()
searchView.requestFocusAndShowKeyboard()
@@ -242,6 +253,9 @@ class MainActivity : AppCompatActivity() {
applyViewMode(viewMode)
}
updateThemeToggleIcon()
btnThemeToggle.setOnClickListener { toggleTheme() }
loadPrefs()
games = GameXml.parseGamesXmlFromAssets(this)
@@ -253,6 +267,77 @@ class MainActivity : AppCompatActivity() {
refreshUi()
}
private fun applyThemeFromPrefs() {
val mode =
when (prefs.getString("theme_mode", null)) {
"light" -> AppCompatDelegate.MODE_NIGHT_NO
"dark" -> AppCompatDelegate.MODE_NIGHT_YES
else -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
}
if (AppCompatDelegate.getDefaultNightMode() != mode) {
AppCompatDelegate.setDefaultNightMode(mode)
}
}
private fun toggleTheme() {
val currentlyDark = isNightModeActive()
val mode =
if (currentlyDark) {
prefs.edit().putString("theme_mode", "light").apply()
AppCompatDelegate.MODE_NIGHT_NO
} else {
prefs.edit().putString("theme_mode", "dark").apply()
AppCompatDelegate.MODE_NIGHT_YES
}
AppCompatDelegate.setDefaultNightMode(mode)
recreate()
}
private fun isNightModeActive(): Boolean {
val mask = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
return mask == Configuration.UI_MODE_NIGHT_YES
}
private fun updateThemeToggleIcon() {
if (isNightModeActive()) {
btnThemeToggle.setImageResource(R.drawable.light_mode_24px)
btnThemeToggle.contentDescription = getString(R.string.theme_switch_to_light)
} else {
btnThemeToggle.setImageResource(R.drawable.dark_mode_24px)
btnThemeToggle.contentDescription = getString(R.string.theme_switch_to_dark)
}
}
private fun styleSearchBarText() {
val textView = findSearchBarTextView() ?: return
textView.gravity = Gravity.CENTER
textView.textAlignment = View.TEXT_ALIGNMENT_CENTER
val icon = AppCompatResources.getDrawable(this, R.drawable.search_24px) ?: return
val tint =
MaterialColors.getColor(
searchBar,
com.google.android.material.R.attr.colorOnSurfaceVariant,
)
icon.setTint(tint)
textView.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null)
textView.compoundDrawablePadding = (6 * resources.displayMetrics.density).toInt()
}
private fun findSearchBarTextView(): TextView? {
val queue = ArrayDeque<View>()
queue.add(searchBar)
while (queue.isNotEmpty()) {
val view = queue.removeFirst()
if (view is TextView) return view
if (view is ViewGroup) {
for (i in 0 until view.childCount) {
queue.add(view.getChildAt(i))
}
}
}
return null
}
private fun showAboutDialog() {
val view = layoutInflater.inflate(R.layout.dialog_about, null)
val aboutText: TextView = view.findViewById(R.id.about_text)
@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M480,840Q330,840 225,735Q120,630 120,480Q120,330 225,225Q330,120 480,120Q494,120 507.5,121Q521,122 534,124Q493,153 468.5,199.5Q444,246 444,300Q444,390 507,453Q570,516 660,516Q715,516 761,491.5Q807,467 836,426Q838,439 839,452.5Q840,466 840,480Q840,630 735,735Q630,840 480,840ZM480,760Q568,760 638,711.5Q708,663 740,585Q720,590 700,593Q680,596 660,596Q537,596 450.5,509.5Q364,423 364,300Q364,280 367,260Q370,240 375,220Q297,252 248.5,322Q200,392 200,480Q200,596 282,678Q364,760 480,760ZM470,490Q470,490 470,490Q470,490 470,490Q470,490 470,490Q470,490 470,490Q470,490 470,490Q470,490 470,490Q470,490 470,490Q470,490 470,490Q470,490 470,490Q470,490 470,490Q470,490 470,490Q470,490 470,490Z"/>
</vector>
@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M480,600Q530,600 565,565Q600,530 600,480Q600,430 565,395Q530,360 480,360Q430,360 395,395Q360,430 360,480Q360,530 395,565Q430,600 480,600ZM480,680Q397,680 338.5,621.5Q280,563 280,480Q280,397 338.5,338.5Q397,280 480,280Q563,280 621.5,338.5Q680,397 680,480Q680,563 621.5,621.5Q563,680 480,680ZM200,520L40,520L40,440L200,440L200,520ZM920,520L760,520L760,440L920,440L920,520ZM440,200L440,40L520,40L520,200L440,200ZM440,920L440,760L520,760L520,920L440,920ZM256,310L155,213L212,154L308,254L256,310ZM748,806L651,705L704,650L805,747L748,806ZM650,256L747,155L806,212L706,308L650,256ZM154,748L255,651L310,704L213,805L154,748ZM480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Z"/>
</vector>
@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M784,840L532,588Q502,612 463,626Q424,640 380,640Q271,640 195.5,564.5Q120,489 120,380Q120,271 195.5,195.5Q271,120 380,120Q489,120 564.5,195.5Q640,271 640,380Q640,424 626,463Q612,502 588,532L840,784L784,840ZM380,560Q455,560 507.5,507.5Q560,455 560,380Q560,305 507.5,252.5Q455,200 380,200Q305,200 252.5,252.5Q200,305 200,380Q200,455 252.5,507.5Q305,560 380,560Z"/>
</vector>
@@ -13,8 +13,10 @@
android:id="@+id/app_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:fitsSystemWindows="false"
android:background="?attr/colorPrimary"
android:paddingTop="0dp"
android:paddingBottom="0dp"
app:materialThemeOverlay="@style/ThemeOverlay.Material3Expressive.AppBarWithSearch"
app:elevation="8dp"
app:liftOnScroll="false">
@@ -24,35 +26,92 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
app:navigationIcon="@drawable/ic_menu_24"
app:navigationIconTint="?attr/colorOnPrimary">
android:minHeight="0dp"
android:paddingTop="0dp"
android:paddingBottom="0dp"
android:paddingStart="0dp"
android:paddingEnd="0dp"
app:contentInsetEnd="0dp"
app:contentInsetStart="0dp"
app:contentInsetStartWithNavigation="0dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp">
android:layout_marginEnd="8dp"
android:orientation="vertical">
<com.google.android.material.search.SearchBar
android:id="@+id/search_bar"
android:layout_width="0dp"
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="Search games"
app:liftOnScroll="true"
app:liftOnScrollColor="?attr/colorSurfaceContainerHighest" />
android:layout_marginTop="0dp"
android:layout_marginBottom="0dp">
<ImageButton
android:id="@+id/btn_view_mode"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginStart="8dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="Change view"
android:src="@drawable/view_list_24px"
android:tint="?attr/colorOnPrimary" />
<ImageView
android:id="@+id/app_logo"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_gravity="center"
android:contentDescription="@string/app_name"
android:src="@drawable/logo" />
<ImageButton
android:id="@+id/btn_theme_toggle"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="end|center_vertical"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/theme_toggle"
android:src="@drawable/dark_mode_24px"
android:tint="?attr/colorOnPrimary" />
</FrameLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="-50dp">
<ImageButton
android:id="@+id/btn_open_drawer"
android:layout_width="48dp"
android:layout_height="48dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/open_menu"
android:src="@drawable/ic_menu_24"
android:tint="?attr/colorOnPrimary"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.search.SearchBar
android:id="@+id/search_bar"
android:layout_width="0dp"
android:layout_height="38dp"
android:minHeight="38dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:hint="Search games"
app:liftOnScroll="true"
app:liftOnScrollColor="?attr/colorSurfaceContainerHighest"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintWidth_percent="0.72" />
<ImageButton
android:id="@+id/btn_view_mode"
android:layout_width="48dp"
android:layout_height="48dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="Change view"
android:src="@drawable/view_list_24px"
android:tint="?attr/colorOnPrimary"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
@@ -29,4 +29,8 @@
<string name="setup_not_set">Not set</string>
<string name="setup_games_folder_value">Games folder: %1$s</string>
<string name="setup_data_folder_value">Data folder: %1$s</string>
<string name="theme_toggle">Toggle theme</string>
<string name="theme_switch_to_light">Switch to light mode</string>
<string name="theme_switch_to_dark">Switch to dark mode</string>
<string name="open_menu">Open menu</string>
</resources>