ui improvements

This commit is contained in:
izzy2lost
2025-12-18 01:41:02 -05:00
parent 497ecc6766
commit 883f63ddff
14 changed files with 503 additions and 115 deletions
+2 -1
View File
@@ -63,7 +63,8 @@ dependencies {
implementation("androidx.core:core-ktx:1.15.0")
implementation("androidx.appcompat:appcompat:1.7.0")
implementation("androidx.documentfile:documentfile:1.0.1")
implementation("com.google.android.material:material:1.12.0")
implementation("androidx.recyclerview:recyclerview:1.4.0")
implementation("com.google.android.material:material:1.14.0-alpha07")
}
kotlin {
@@ -3,27 +3,53 @@ package com.izzy2lost.super3
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.widget.*
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.GravityCompat
import androidx.core.widget.addTextChangedListener
import androidx.documentfile.provider.DocumentFile
import androidx.drawerlayout.widget.DrawerLayout
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.appbar.MaterialToolbar
import com.google.android.material.button.MaterialButton
import com.google.android.material.color.MaterialColors
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 kotlin.concurrent.thread
class MainActivity : AppCompatActivity() {
private val prefs by lazy { getSharedPreferences("super3_prefs", MODE_PRIVATE) }
private lateinit var drawerLayout: DrawerLayout
private lateinit var navigationView: NavigationView
private lateinit var toolbar: MaterialToolbar
private lateinit var searchBar: SearchBar
private lateinit var searchView: SearchView
private lateinit var gamesFolderText: TextView
private lateinit var userFolderText: TextView
private lateinit var gamesList: ListView
private lateinit var gamesList: RecyclerView
private lateinit var searchResultsList: RecyclerView
private lateinit var statusText: TextView
private lateinit var gamesAdapter: GamesAdapter
private var gamesTreeUri: Uri? = null
private var userTreeUri: Uri? = null
private var games: List<GameDef> = emptyList()
private var zipDocs: Map<String, DocumentFile> = emptyMap()
@Volatile
private var scanning = false
private val pickGamesFolder =
registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { uri ->
if (uri != null) {
@@ -49,28 +75,69 @@ class MainActivity : AppCompatActivity() {
applyImmersiveMode()
setContentView(R.layout.activity_main)
gamesFolderText = findViewById(R.id.games_folder_text)
userFolderText = findViewById(R.id.user_folder_text)
drawerLayout = findViewById(R.id.drawer_layout)
navigationView = findViewById(R.id.navigation_view)
toolbar = findViewById(R.id.toolbar)
searchBar = findViewById(R.id.search_bar)
searchView = findViewById(R.id.search_view)
gamesList = findViewById(R.id.games_list)
statusText = findViewById(R.id.status_text)
searchResultsList = findViewById(R.id.search_results_list)
findViewById<Button>(R.id.pick_games_folder).setOnClickListener { pickGamesFolder.launch(null) }
findViewById<Button>(R.id.pick_user_folder).setOnClickListener { pickUserFolder.launch(null) }
findViewById<Button>(R.id.rescan_button).setOnClickListener { refreshUi() }
// Get views from the navigation header
val headerView = navigationView.getHeaderView(0)
gamesFolderText = headerView.findViewById(R.id.games_folder_text)
userFolderText = headerView.findViewById(R.id.user_folder_text)
statusText = headerView.findViewById(R.id.status_text)
gamesList.onItemClickListener = AdapterView.OnItemClickListener { _, _, position, _ ->
val item = (gamesList.adapter as GameAdapter).getItem(position) ?: return@OnItemClickListener
val btnPickGamesFolder: MaterialButton = headerView.findViewById(R.id.btn_pick_games_folder)
val btnPickUserFolder: MaterialButton = headerView.findViewById(R.id.btn_pick_user_folder)
val btnRescan: MaterialButton = headerView.findViewById(R.id.btn_rescan)
gamesAdapter = GamesAdapter { item ->
if (!item.launchable) {
Toast.makeText(this, item.status, Toast.LENGTH_SHORT).show()
return@OnItemClickListener
return@GamesAdapter
}
launchGame(item.game)
}
gamesList.adapter = gamesAdapter
searchResultsList.adapter = gamesAdapter
toolbar.setNavigationOnClickListener {
drawerLayout.openDrawer(GravityCompat.START)
}
btnPickGamesFolder.setOnClickListener { pickGamesFolder.launch(null) }
btnPickUserFolder.setOnClickListener { pickUserFolder.launch(null) }
btnRescan.setOnClickListener { refreshUi() }
runCatching { searchView.setupWithSearchBar(searchBar) }
searchBar.setOnClickListener {
searchView.show()
searchView.requestFocusAndShowKeyboard()
}
searchView.setAutoShowKeyboard(true)
val onSurface = MaterialColors.getColor(searchView, com.google.android.material.R.attr.colorOnSurface)
val onSurfaceVariant =
MaterialColors.getColor(searchView, com.google.android.material.R.attr.colorOnSurfaceVariant)
searchView.editText.setTextColor(onSurface)
searchView.editText.setHintTextColor(onSurfaceVariant)
searchView.addTransitionListener { _, _, newState ->
val searchActive = newState != SearchView.TransitionState.HIDDEN
gamesList.visibility = if (searchActive) View.GONE else View.VISIBLE
if (newState == SearchView.TransitionState.SHOWING || newState == SearchView.TransitionState.SHOWN) {
searchView.requestFocusAndShowKeyboard()
}
}
searchView.editText.addTextChangedListener { editable ->
gamesAdapter.setFilter(editable?.toString().orEmpty())
}
loadPrefs()
games = GameXml.parseGamesXmlFromAssets(this)
// Ensure internal user root has the required files from APK assets (Config/Games.xml, Assets/, etc.).
AssetInstaller.ensureInstalled(this, internalUserRoot())
refreshUi()
@@ -87,7 +154,6 @@ class MainActivity : AppCompatActivity() {
}
private fun internalUserRoot(): File {
// Matches native default: <externalFiles>/super3
return File(getExternalFilesDir(null), "super3")
}
@@ -100,16 +166,29 @@ class MainActivity : AppCompatActivity() {
}
private fun refreshUi() {
gamesFolderText.text = gamesTreeUri?.toString() ?: "Not set"
userFolderText.text = userTreeUri?.toString() ?: "Not set"
gamesFolderText.text = "Games folder: ${gamesTreeUri?.toString() ?: "Not set"}"
userFolderText.text = "Data folder: ${userTreeUri?.toString() ?: "Not set"}"
val gamesUri = gamesTreeUri
if (gamesUri == null) {
zipDocs = emptyMap()
gamesAdapter.submitList(buildItems(games, zipDocs))
statusText.text = "Games folder not set. Tap \"Games folder\" to choose."
scanning = false
return
}
if (scanning) return
scanning = true
statusText.text = "Scanning…"
thread(name = "Super3Scanner") {
val zips = scanZipDocs(gamesTreeUri)
val zips = scanZipDocs(gamesUri)
val items = buildItems(games, zips)
runOnUiThread {
zipDocs = zips
gamesAdapter.submitList(items)
statusText.text = "Found ${zipDocs.size} ZIP(s). Tap a game to launch."
gamesList.adapter = GameAdapter(this, games, zipDocs)
scanning = false
}
}
}
@@ -141,7 +220,6 @@ class MainActivity : AppCompatActivity() {
val userUri = userTreeUri
if (userUri != null) {
// Pull saved NVRAM/Saves/Config from user folder into internal root before launch.
UserDataSync.syncFromTreeIntoInternal(this, userUri, internalRoot)
}
@@ -151,12 +229,15 @@ class MainActivity : AppCompatActivity() {
if (missing.isNotEmpty()) {
runOnUiThread {
statusText.text = "Missing required ZIP(s): ${missing.joinToString(", ")}"
Toast.makeText(this, "Missing required ZIP(s): ${missing.joinToString(", ")}", Toast.LENGTH_LONG).show()
Toast.makeText(
this,
"Missing required ZIP(s): ${missing.joinToString(", ")}",
Toast.LENGTH_LONG
).show()
}
return@thread
}
// Copy selected game zip + required parent chain zips into cacheDir so GameLoader can find them.
for (zipBase in required) {
val doc = zipDocs[zipBase] ?: continue
val ok = copyDocToCacheIfNeeded(doc, File(cacheDir, "$zipBase.zip"))
@@ -170,8 +251,6 @@ class MainActivity : AppCompatActivity() {
}
val romPath = File(cacheDir, "${game.name}.zip").absolutePath
// Ensure Games.xml exists on disk for the native loader.
val gamesXmlPath = File(internalRoot, "Config/Games.xml").absolutePath
val userDataRoot = internalRoot.absolutePath
@@ -210,8 +289,7 @@ class MainActivity : AppCompatActivity() {
if (outFile.exists() && expectedSize > 0 && outFile.length() == expectedSize) {
return true
}
val uri = doc.uri
val input = contentResolver.openInputStream(uri) ?: return false
val input = contentResolver.openInputStream(doc.uri) ?: return false
input.use { ins ->
outFile.outputStream().use { outs ->
ins.copyTo(outs)
@@ -221,25 +299,6 @@ class MainActivity : AppCompatActivity() {
}
}
private class GameAdapter(
context: MainActivity,
private val games: List<GameDef>,
zipDocs: Map<String, DocumentFile>,
) : ArrayAdapter<GameItem>(context, android.R.layout.simple_list_item_2, buildItems(games, zipDocs)) {
override fun getView(position: Int, convertView: android.view.View?, parent: android.view.ViewGroup): android.view.View {
val v = convertView ?: android.view.LayoutInflater.from(context)
.inflate(android.R.layout.simple_list_item_2, parent, false)
val item = getItem(position)!!
val t1 = v.findViewById<TextView>(android.R.id.text1)
val t2 = v.findViewById<TextView>(android.R.id.text2)
t1.text = item.game.displayName
t2.text = item.status
t1.isEnabled = item.launchable
t2.isEnabled = item.launchable
return v
}
}
private data class GameItem(val game: GameDef, val launchable: Boolean, val status: String)
private fun buildItems(games: List<GameDef>, zipDocs: Map<String, DocumentFile>): List<GameItem> {
@@ -263,14 +322,75 @@ private fun buildItems(games: List<GameDef>, zipDocs: Map<String, DocumentFile>)
val req = requiredZips(g)
val missing = req.filter { !zipDocs.containsKey(it) }
val launchable = missing.isEmpty() && zipDocs.containsKey(g.name)
val status = if (missing.isEmpty()) {
if (req.size == 1) "${g.name}.zip found"
else "needs ${req.joinToString(" + ") { "${it}.zip" }}"
} else {
"missing ${missing.joinToString(" + ") { "${it}.zip" }}"
}
val status =
if (missing.isEmpty()) {
if (req.size == 1) "${g.name}.zip found" else "needs ${req.joinToString(" + ") { "${it}.zip" }}"
} else {
"missing ${missing.joinToString(" + ") { "${it}.zip" }}"
}
GameItem(game = g, launchable = launchable, status = status)
}
return items.sortedWith(compareByDescending<GameItem> { it.launchable }.thenBy { it.game.displayName })
}
private class GamesAdapter(
private val onClick: (GameItem) -> Unit,
) : RecyclerView.Adapter<GamesAdapter.VH>() {
private var allItems: List<GameItem> = emptyList()
private var shownItems: List<GameItem> = emptyList()
private var filter: String = ""
fun submitList(items: List<GameItem>) {
allItems = items
applyFilter()
}
fun setFilter(query: String) {
val normalized = query.trim()
if (normalized == filter) return
filter = normalized
applyFilter()
}
private fun applyFilter() {
val q = filter.trim()
shownItems =
if (q.isBlank()) {
allItems
} else {
val needle = q.lowercase()
allItems.filter {
it.game.displayName.lowercase().contains(needle) || it.game.name.lowercase().contains(needle)
}
}
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VH {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_game, parent, false)
return VH(view)
}
override fun onBindViewHolder(holder: VH, position: Int) {
val item = shownItems[position]
holder.bind(item, onClick)
}
override fun getItemCount(): Int = shownItems.size
class VH(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val title: TextView = itemView.findViewById(R.id.game_title)
private val subtitle: TextView = itemView.findViewById(R.id.game_subtitle)
fun bind(item: GameItem, onClick: (GameItem) -> Unit) {
title.text = item.game.displayName
subtitle.text = item.status
itemView.isEnabled = item.launchable
title.isEnabled = item.launchable
subtitle.isEnabled = item.launchable
itemView.alpha = if (item.launchable) 1.0f else 0.5f
itemView.setOnClickListener { onClick(item) }
}
}
}
@@ -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="M200,840Q167,840 143.5,816.5Q120,793 120,760L120,200Q120,167 143.5,143.5Q167,120 200,120L760,120Q793,120 816.5,143.5Q840,167 840,200L840,760Q840,793 816.5,816.5Q793,840 760,840L200,840ZM200,333L760,333L760,200Q760,200 760,200Q760,200 760,200L200,200Q200,200 200,200Q200,200 200,200L200,333ZM200,547L760,547L760,413L200,413L200,547ZM200,760L760,760Q760,760 760,760Q760,760 760,760L760,627L200,627L200,760Q200,760 200,760Q200,760 200,760ZM240,306L240,226L320,226L320,306L240,306ZM240,520L240,440L320,440L320,520L240,520ZM240,734L240,654L320,654L320,734L240,734Z"/>
</vector>
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?attr/colorOnSurface"
android:pathData="M3,6h18v2H3zM3,11h18v2H3zM3,16h18v2H3z" />
</vector>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@color/md_theme_onSurface"
android:pathData="M17.65,6.35C16.2,4.9 14.21,4 12,4c-4.42,0 -7.99,3.58 -7.99,8s3.57,8 7.99,8c3.73,0 6.84,-2.55 7.73,-6h-2.08c-0.82,2.33 -3.04,4 -5.65,4 -3.31,0 -6,-2.69 -6,-6s2.69,-6 6,-6c1.66,0 3.14,0.69 4.22,1.78L13,11h7V4l-2.35,2.35z"/>
</vector>
File diff suppressed because one or more lines are too long
@@ -1,79 +1,94 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
android:layout_height="match_parent">
<TextView
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Games folder (SAF):"
android:textStyle="bold" />
android:layout_height="match_parent">
<TextView
android:id="@+id/games_folder_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Not set"
android:textSize="12sp"
android:maxLines="2" />
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/app_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:background="?attr/colorPrimary"
app:materialThemeOverlay="@style/ThemeOverlay.Material3Expressive.AppBarWithSearch"
app:elevation="8dp"
app:liftOnScroll="false">
<Button
android:id="@+id/pick_games_folder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Pick Games Folder" />
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
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">
<Space
android:layout_width="match_parent"
android:layout_height="8dp" />
<com.google.android.material.search.SearchBar
android:id="@+id/search_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:hint="Search games"
app:liftOnScroll="true"
app:liftOnScrollColor="?attr/colorSurfaceContainerHighest" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="User folder (SAF, optional):"
android:textStyle="bold" />
</com.google.android.material.appbar.MaterialToolbar>
<TextView
android:id="@+id/user_folder_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Not set"
android:textSize="12sp"
android:maxLines="2" />
</com.google.android.material.appbar.AppBarLayout>
<Button
android:id="@+id/pick_user_folder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Pick User Folder" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/games_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:background="?android:attr/colorBackground"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
<Space
android:layout_width="match_parent"
android:layout_height="8dp" />
<com.google.android.material.search.SearchView
android:id="@+id/search_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:hint="Search games"
android:elevation="16dp"
app:autoShowKeyboard="true"
app:layout_anchor="@id/search_bar">
<Button
android:id="@+id/rescan_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Rescan" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/search_results_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:background="?android:attr/colorBackground"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
<TextView
android:id="@+id/status_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="8dp"
android:text="Tap a game to launch"
android:textSize="12sp" />
</com.google.android.material.search.SearchView>
<ListView
android:id="@+id/games_list"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:divider="@android:color/darker_gray"
android:dividerHeight="1dp" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</LinearLayout>
<com.google.android.material.navigation.NavigationView
android:id="@+id/navigation_view"
android:layout_width="280dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
android:background="?attr/colorPrimary"
app:menu="@menu/drawer_menu"
app:headerLayout="@layout/nav_header"
app:itemTextColor="?attr/colorOnPrimary"
app:itemIconTint="?attr/colorOnPrimary" />
</androidx.drawerlayout.widget.DrawerLayout>
@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="12dp"
app:cardElevation="4dp"
app:strokeWidth="0dp"
app:cardCornerRadius="12dp"
app:cardBackgroundColor="?attr/colorSurface">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/game_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:textAppearance="?attr/textAppearanceHeadlineSmall"
android:textColor="?attr/colorOnSurface" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/game_subtitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:ellipsize="end"
android:maxLines="2"
android:textAppearance="?attr/textAppearanceBodyMedium"
android:textColor="?attr/colorOnSurfaceVariant" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
@@ -0,0 +1,75 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="24dp"
android:background="?attr/colorPrimary">
<ImageView
android:layout_width="180dp"
android:layout_height="180dp"
android:layout_gravity="center_horizontal"
android:contentDescription="Logo"
android:src="@drawable/logo" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/status_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="Tap a game to launch"
android:textAppearance="?attr/textAppearanceBodyMedium"
android:textColor="?attr/colorOnPrimary"
android:gravity="center"
android:visibility="gone" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_pick_games_folder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:text="Pick Games Folder"
app:icon="@drawable/stadia_controller_24px"
style="?attr/materialButtonElevatedStyle" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_pick_user_folder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="Pick Data Folder"
app:icon="@drawable/data_table_24px"
style="?attr/materialButtonElevatedStyle" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_rescan"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="Rescan"
app:icon="@drawable/refresh_24px"
style="?attr/materialButtonElevatedStyle" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/games_folder_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="Games folder: Not set"
android:textAppearance="?attr/textAppearanceBodySmall"
android:textColor="?attr/colorOnPrimary"
android:visibility="gone" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/user_folder_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Data folder: Not set"
android:textAppearance="?attr/textAppearanceBodySmall"
android:textColor="?attr/colorOnPrimary"
android:visibility="gone" />
</LinearLayout>
@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
</menu>
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Dark scheme -->
<color name="md_theme_primary">#3BC1FF</color>
<color name="md_theme_onPrimary">#003548</color>
<color name="md_theme_primaryContainer">#004C67</color>
<color name="md_theme_onPrimaryContainer">#BFE9FF</color>
<color name="md_theme_secondary">#AFC6FF</color>
<color name="md_theme_onSecondary">#152A5B</color>
<color name="md_theme_secondaryContainer">#2C4173</color>
<color name="md_theme_onSecondaryContainer">#DDE3FF</color>
<color name="md_theme_tertiary">#D8D6D7</color>
<color name="md_theme_onTertiary">#1C1C1C</color>
<color name="md_theme_background">#000000</color>
<color name="md_theme_onBackground">#E6E6E6</color>
<color name="md_theme_surface">#0A0B0D</color>
<color name="md_theme_onSurface">#E6E6E6</color>
<color name="md_theme_surfaceVariant">#1A2026</color>
<color name="md_theme_onSurfaceVariant">#C0C8CF</color>
<color name="md_theme_outline">#8A939B</color>
<color name="md_theme_outlineVariant">#3F484E</color>
</resources>
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Brand colors from logo.xml -->
<color name="brand_blue">#0297D6</color>
<color name="brand_blue_deep">#0843AF</color>
<color name="brand_silver">#D8D6D7</color>
<!-- Light scheme -->
<color name="md_theme_primary">@color/brand_blue</color>
<color name="md_theme_onPrimary">#FFFFFF</color>
<color name="md_theme_primaryContainer">#D2F2FE</color>
<color name="md_theme_onPrimaryContainer">#001E2A</color>
<color name="md_theme_secondary">@color/brand_blue_deep</color>
<color name="md_theme_onSecondary">#FFFFFF</color>
<color name="md_theme_secondaryContainer">#DDE3FF</color>
<color name="md_theme_onSecondaryContainer">#0A1636</color>
<color name="md_theme_tertiary">@color/brand_silver</color>
<color name="md_theme_onTertiary">#1C1C1C</color>
<color name="md_theme_background">#FBFCFF</color>
<color name="md_theme_onBackground">#0F1115</color>
<color name="md_theme_surface">#FBFCFF</color>
<color name="md_theme_onSurface">#0F1115</color>
<color name="md_theme_surfaceVariant">#EAF1F6</color>
<color name="md_theme_onSurfaceVariant">#3F484E</color>
<color name="md_theme_outline">#6F7880</color>
<color name="md_theme_outlineVariant">#C0C8CF</color>
</resources>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Widget.Super3.Button.ElevatedButton" parent="Widget.Material3Expressive.Button">
<item name="android:stateListAnimator">@animator/m3_btn_elevated_btn_state_list_anim</item>
<item name="elevation">@dimen/m3_comp_button_elevated_container_elevation</item>
<item name="materialThemeOverlay">@style/ThemeOverlay.Material3Expressive.Button.Elevated</item>
</style>
</resources>
+28 -2
View File
@@ -1,5 +1,31 @@
<resources>
<style name="Theme.Super3" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<!-- Customize your theme here. -->
<style name="Theme.Super3" parent="Theme.Material3.DayNight.NoActionBar">
<item name="colorPrimary">@color/md_theme_primary</item>
<item name="colorOnPrimary">@color/md_theme_onPrimary</item>
<item name="colorPrimaryContainer">@color/md_theme_primaryContainer</item>
<item name="colorOnPrimaryContainer">@color/md_theme_onPrimaryContainer</item>
<item name="colorSecondary">@color/md_theme_secondary</item>
<item name="colorOnSecondary">@color/md_theme_onSecondary</item>
<item name="colorSecondaryContainer">@color/md_theme_secondaryContainer</item>
<item name="colorOnSecondaryContainer">@color/md_theme_onSecondaryContainer</item>
<item name="colorTertiary">@color/md_theme_tertiary</item>
<item name="colorOnTertiary">@color/md_theme_onTertiary</item>
<item name="android:colorBackground">@color/md_theme_background</item>
<item name="colorSurface">@color/md_theme_surface</item>
<item name="colorOnSurface">@color/md_theme_onSurface</item>
<item name="colorSurfaceVariant">@color/md_theme_surfaceVariant</item>
<item name="colorOnSurfaceVariant">@color/md_theme_onSurfaceVariant</item>
<item name="colorOutline">@color/md_theme_outline</item>
<item name="colorOutlineVariant">@color/md_theme_outlineVariant</item>
<item name="materialSearchBarStyle">@style/Widget.Material3Expressive.SearchBar</item>
<item name="materialSearchViewStyle">@style/Widget.Material3Expressive.SearchView</item>
<item name="materialButtonStyle">@style/Widget.Material3Expressive.Button</item>
<item name="materialButtonElevatedStyle">@style/Widget.Super3.Button.ElevatedButton</item>
</style>
</resources>