Add filter and move search bar down

* Fix crashes
This commit is contained in:
Willi Ye 2021-02-08 18:41:49 +01:00 committed by ◱ Mark
parent 479209886b
commit 4db75022d2
22 changed files with 526 additions and 440 deletions

View File

@ -17,12 +17,15 @@ import androidx.appcompat.app.AppCompatDelegate
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.content.res.use import androidx.core.content.res.use
import androidx.core.graphics.drawable.toBitmap import androidx.core.graphics.drawable.toBitmap
import androidx.core.view.isInvisible
import androidx.core.view.isVisible
import androidx.core.view.size import androidx.core.view.size
import androidx.lifecycle.observe import androidx.lifecycle.observe
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.chip.Chip
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import emu.skyline.adapter.AppViewItem import emu.skyline.adapter.AppViewItem
@ -33,6 +36,7 @@ import emu.skyline.data.AppItem
import emu.skyline.data.DataItem import emu.skyline.data.DataItem
import emu.skyline.data.HeaderItem import emu.skyline.data.HeaderItem
import emu.skyline.databinding.MainActivityBinding import emu.skyline.databinding.MainActivityBinding
import emu.skyline.loader.AppEntry
import emu.skyline.loader.LoaderResult import emu.skyline.loader.LoaderResult
import emu.skyline.loader.RomFormat import emu.skyline.loader.RomFormat
import emu.skyline.utils.Settings import emu.skyline.utils.Settings
@ -41,6 +45,10 @@ import kotlin.math.ceil
@AndroidEntryPoint @AndroidEntryPoint
class MainActivity : AppCompatActivity() { class MainActivity : AppCompatActivity() {
companion object {
private val formatOrder = arrayOf(RomFormat.NSP, RomFormat.XCI, RomFormat.NRO, RomFormat.NSO, RomFormat.NCA)
}
private val binding by lazy { MainActivityBinding.inflate(layoutInflater) } private val binding by lazy { MainActivityBinding.inflate(layoutInflater) }
@Inject @Inject
@ -54,16 +62,32 @@ class MainActivity : AppCompatActivity() {
private val viewModel by viewModels<MainViewModel>() private val viewModel by viewModels<MainViewModel>()
private var formatFilter : RomFormat? = null
private var appEntries : Map<RomFormat, List<AppEntry>>? = null
private var refreshIconVisible = false
set(visible) {
field = visible
binding.refreshIcon.apply {
if (visible != isVisible) {
binding.refreshIcon.alpha = if (visible) 0f else 1f
animate().alpha(if (visible) 1f else 0f).withStartAction { isVisible = true }.withEndAction { isInvisible = !visible }.apply { duration = 500 }.start()
}
}
}
private fun AppItem.toViewItem() = AppViewItem(layoutType, this, missingIcon, ::selectStartGame, ::selectShowGameDialog) private fun AppItem.toViewItem() = AppViewItem(layoutType, this, missingIcon, ::selectStartGame, ::selectShowGameDialog)
override fun onCreate(savedInstanceState : Bundle?) { override fun onCreate(savedInstanceState : Bundle?) {
// Need to create new instance of settings, dependency injection happens // Need to create new instance of settings, dependency injection happens
AppCompatDelegate.setDefaultNightMode(when ((Settings(this).appTheme.toInt())) { AppCompatDelegate.setDefaultNightMode(
when ((Settings(this).appTheme.toInt())) {
0 -> AppCompatDelegate.MODE_NIGHT_NO 0 -> AppCompatDelegate.MODE_NIGHT_NO
1 -> AppCompatDelegate.MODE_NIGHT_YES 1 -> AppCompatDelegate.MODE_NIGHT_YES
2 -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM 2 -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
else -> AppCompatDelegate.MODE_NIGHT_UNSPECIFIED else -> AppCompatDelegate.MODE_NIGHT_UNSPECIFIED
}) }
)
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(binding.root) setContentView(binding.root)
@ -79,13 +103,26 @@ class MainActivity : AppCompatActivity() {
setOnRefreshListener { loadRoms(false) } setOnRefreshListener { loadRoms(false) }
} }
for (format in formatOrder) {
binding.chipGroup.addView(Chip(this, null, R.attr.chipChoiceStyle).apply { text = format.name })
}
binding.chipGroup.setOnCheckedChangeListener { group, checkedId ->
for (i in 0 until group.childCount) {
if (group.getChildAt(i).id == checkedId) {
formatFilter = if (i == 0) null else formatOrder[i - 1]
populateAdapter()
break
}
}
}
viewModel.stateData.observe(owner = this, onChanged = ::handleState) viewModel.stateData.observe(owner = this, onChanged = ::handleState)
loadRoms(!settings.refreshRequired) loadRoms(!settings.refreshRequired)
binding.searchBar.apply { binding.searchBar.apply {
setLogIconListener { startActivity(Intent(context, LogActivity::class.java)) } binding.logIcon.setOnClickListener { startActivity(Intent(context, LogActivity::class.java)) }
setSettingsIconListener { startActivityForResult(Intent(context, SettingsActivity::class.java), 3) } binding.settingsIcon.setOnClickListener { startActivityForResult(Intent(context, SettingsActivity::class.java), 3) }
setRefreshIconListener { loadRoms(false) } binding.refreshIcon.setOnClickListener { loadRoms(false) }
addTextChangedListener(afterTextChanged = { editable -> addTextChangedListener(afterTextChanged = { editable ->
editable?.let { text -> adapter.filter.filter(text.toString()) } editable?.let { text -> adapter.filter.filter(text.toString()) }
}) })
@ -95,7 +132,7 @@ class MainActivity : AppCompatActivity() {
} }
} }
window.decorView.findViewById<View>(android.R.id.content).viewTreeObserver.addOnTouchModeChangeListener { isInTouchMode -> window.decorView.findViewById<View>(android.R.id.content).viewTreeObserver.addOnTouchModeChangeListener { isInTouchMode ->
binding.searchBar.refreshIconVisible = !isInTouchMode refreshIconVisible = !isInTouchMode
} }
} }
@ -184,32 +221,38 @@ class MainActivity : AppCompatActivity() {
binding.appList.layoutManager = CustomLayoutManager(gridSpan) binding.appList.layoutManager = CustomLayoutManager(gridSpan)
setAppListDecoration() setAppListDecoration()
if (settings.searchLocation.isEmpty()) { if (settings.searchLocation.isEmpty()) startActivityForResult(Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).apply {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE) flags = Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION or
intent.flags = Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION or Intent.FLAG_GRANT_PREFIX_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION Intent.FLAG_GRANT_PREFIX_URI_PERMISSION or
Intent.FLAG_GRANT_READ_URI_PERMISSION
}, 1)
}
startActivityForResult(intent, 1) private fun getDataItems() = mutableListOf<DataItem>().apply {
appEntries?.let { entries ->
val formats = formatFilter?.let { arrayOf(it) } ?: formatOrder
for (format in formats) {
entries[format]?.let {
add(HeaderItem(format.name))
it.forEach { entry -> add(AppItem(entry)) }
}
}
} }
} }
private fun handleState(state : MainState) = when (state) { private fun handleState(state : MainState) = when (state) {
MainState.Loading -> { MainState.Loading -> {
binding.searchBar.animateRefreshIcon() binding.refreshIcon.animate().rotationBy(-180f)
binding.swipeRefreshLayout.isRefreshing = true binding.swipeRefreshLayout.isRefreshing = true
} }
is MainState.Loaded -> { is MainState.Loaded -> {
binding.swipeRefreshLayout.isRefreshing = false binding.swipeRefreshLayout.isRefreshing = false
val formatOrder = arrayOf(RomFormat.NSP, RomFormat.NRO, RomFormat.NSO, RomFormat.NCA) appEntries = state.items
val items = mutableListOf<DataItem>() populateAdapter()
for (format in formatOrder) {
state.items[format]?.let {
items.add(HeaderItem(format.name))
it.forEach { entry -> items.add(AppItem(entry)) }
}
}
populateAdapter(items)
} }
is MainState.Error -> Snackbar.make(findViewById(android.R.id.content), getString(R.string.error) + ": ${state.ex.localizedMessage}", Snackbar.LENGTH_SHORT).show() is MainState.Error -> Snackbar.make(findViewById(android.R.id.content), getString(R.string.error) + ": ${state.ex.localizedMessage}", Snackbar.LENGTH_SHORT).show()
} }
@ -233,7 +276,8 @@ class MainActivity : AppCompatActivity() {
settings.refreshRequired = false settings.refreshRequired = false
} }
private fun populateAdapter(items : List<DataItem>) { private fun populateAdapter() {
val items = getDataItems()
adapter.setItems(items.map { adapter.setItems(items.map {
when (it) { when (it) {
is HeaderItem -> HeaderViewItem(it.title) is HeaderItem -> HeaderViewItem(it.title)

View File

@ -15,8 +15,9 @@ import emu.skyline.utils.toFile
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.io.File import java.io.File
import java.io.IOException import java.util.*
import javax.inject.Inject import javax.inject.Inject
import kotlin.collections.HashMap
sealed class MainState { sealed class MainState {
object Loading : MainState() object Loading : MainState()
@ -50,7 +51,7 @@ class MainViewModel @Inject constructor(private val romProvider : RomProvider) :
val romsFile = File(context.filesDir.canonicalPath + "/roms.bin") val romsFile = File(context.filesDir.canonicalPath + "/roms.bin")
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
if (loadFromFile) { if (loadFromFile && romsFile.exists()) {
try { try {
state = MainState.Loaded(fromFile(romsFile)) state = MainState.Loaded(fromFile(romsFile))
return@launch return@launch
@ -59,14 +60,19 @@ class MainViewModel @Inject constructor(private val romProvider : RomProvider) :
} }
} }
val romElements = romProvider.loadRoms(searchLocation) state = if (searchLocation.toString().isEmpty()) {
@Suppress("ReplaceWithEnumMap")
MainState.Loaded(HashMap())
} else {
try { try {
val romElements = romProvider.loadRoms(searchLocation)
romElements.toFile(romsFile) romElements.toFile(romsFile)
} catch (e : IOException) { MainState.Loaded(romElements)
} catch (e : Exception) {
Log.w(TAG, "Ran into exception while saving: ${e.message}") Log.w(TAG, "Ran into exception while saving: ${e.message}")
MainState.Error(e)
}
} }
state = MainState.Loaded(romElements)
} }
} }
} }

View File

@ -5,7 +5,6 @@
package emu.skyline.adapter package emu.skyline.adapter
import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.Filter import android.widget.Filter
import android.widget.Filterable import android.widget.Filterable
@ -101,7 +100,7 @@ class GenericAdapter : RecyclerView.Adapter<GenericViewHolder<ViewBinding>>(), F
val avgScore = topResults.sumByDouble { it.score } / topResults.size val avgScore = topResults.sumByDouble { it.score } / topResults.size
for (result in topResults) for (result in topResults)
if (result.score > avgScore) filterData.add(result.item) if (result.score >= avgScore) filterData.add(result.item)
results.values = filterData results.values = filterData
results.count = filterData.size results.count = filterData.size

View File

@ -4,15 +4,10 @@ import android.content.Context
import android.text.Editable import android.text.Editable
import android.text.TextWatcher import android.text.TextWatcher
import android.util.AttributeSet import android.util.AttributeSet
import android.util.TypedValue
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.inputmethod.InputMethodManager import android.view.inputmethod.InputMethodManager
import androidx.core.view.MarginLayoutParamsCompat
import androidx.core.view.isInvisible
import androidx.core.view.isVisible
import com.google.android.material.card.MaterialCardView import com.google.android.material.card.MaterialCardView
import emu.skyline.databinding.ViewSearchBarBinding import emu.skyline.databinding.ViewSearchBarBinding
import kotlin.math.roundToInt
class SearchBarView @JvmOverloads constructor(context : Context, attrs : AttributeSet? = null, defStyleAttr : Int = com.google.android.material.R.attr.materialCardViewStyle) : MaterialCardView(context, attrs, defStyleAttr) { class SearchBarView @JvmOverloads constructor(context : Context, attrs : AttributeSet? = null, defStyleAttr : Int = com.google.android.material.R.attr.materialCardViewStyle) : MaterialCardView(context, attrs, defStyleAttr) {
private val binding = ViewSearchBarBinding.inflate(LayoutInflater.from(context), this) private val binding = ViewSearchBarBinding.inflate(LayoutInflater.from(context), this)
@ -21,32 +16,6 @@ class SearchBarView @JvmOverloads constructor(context : Context, attrs : Attribu
useCompatPadding = true useCompatPadding = true
} }
override fun onAttachedToWindow() {
super.onAttachedToWindow()
val margin = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 16f, context.resources.displayMetrics).roundToInt()
MarginLayoutParamsCompat.setMarginStart(layoutParams as MarginLayoutParams?, margin)
MarginLayoutParamsCompat.setMarginEnd(layoutParams as MarginLayoutParams?, margin)
radius = margin / 2f
cardElevation = radius / 2f
}
fun setRefreshIconListener(listener : OnClickListener) = binding.refreshIcon.setOnClickListener(listener)
fun setLogIconListener(listener : OnClickListener) = binding.logIcon.setOnClickListener(listener)
fun setSettingsIconListener(listener : OnClickListener) = binding.settingsIcon.setOnClickListener(listener)
var refreshIconVisible = false
set(visible) {
field = visible
binding.refreshIcon.apply {
if (visible != isVisible) {
binding.refreshIcon.alpha = if (visible) 0f else 1f
animate().alpha(if (visible) 1f else 0f).withStartAction { isVisible = true }.withEndAction { isInvisible = !visible }.apply { duration = 500 }.start()
}
}
}
var text : CharSequence var text : CharSequence
get() = binding.searchField.text get() = binding.searchField.text
set(value) = binding.searchField.setText(value) set(value) = binding.searchField.setText(value)
@ -65,10 +34,6 @@ class SearchBarView @JvmOverloads constructor(context : Context, attrs : Attribu
} }
} }
fun animateRefreshIcon() {
binding.refreshIcon.animate().rotationBy(-180f)
}
fun addTextChangedListener( fun addTextChangedListener(
beforeTextChanged : ( beforeTextChanged : (
text : CharSequence?, text : CharSequence?,

View File

@ -14,7 +14,7 @@
android:layout_height="150dp" android:layout_height="150dp"
android:contentDescription="@string/icon" android:contentDescription="@string/icon"
android:focusable="false" android:focusable="false"
app:shapeAppearanceOverlay="@style/roundedAppImage" app:shapeAppearanceOverlay="@style/RoundedAppImage"
tools:src="@drawable/default_icon" /> tools:src="@drawable/default_icon" />
<LinearLayout <LinearLayout

View File

@ -11,12 +11,12 @@
android:id="@+id/item_click_layout" android:id="@+id/item_click_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="12dp" android:layout_marginStart="14dp"
android:layout_marginTop="12dp" android:layout_marginTop="14dp"
android:layout_marginEnd="12dp" android:layout_marginEnd="14dp"
android:layout_marginBottom="12dp" android:layout_marginBottom="14dp"
app:cardCornerRadius="16dp" app:cardCornerRadius="16dp"
app:cardElevation="4dp"> app:cardElevation="2dp">
<ImageView <ImageView
android:id="@+id/icon" android:id="@+id/icon"

View File

@ -65,7 +65,6 @@
android:layout_marginBottom="10dp" android:layout_marginBottom="10dp"
android:max="100" android:max="100"
android:progress="25" android:progress="25"
android:secondaryProgressTint="@color/colorPrimaryDark"
android:secondaryProgressTintMode="screen" android:secondaryProgressTintMode="screen"
android:visibility="gone" /> android:visibility="gone" />

View File

@ -18,14 +18,88 @@
<com.google.android.material.appbar.CollapsingToolbarLayout <com.google.android.material.appbar.CollapsingToolbarLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="62dp" android:layout_height="wrap_content"
android:fitsSystemWindows="true" android:fitsSystemWindows="true"
app:layout_scrollFlags="scroll"> app:layout_scrollFlags="scroll">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:orientation="vertical">
<ImageView
android:id="@+id/refresh_icon"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_gravity="center_vertical"
android:layout_marginTop="16dp"
android:layout_marginEnd="4dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/refresh"
android:padding="5dp"
android:visibility="invisible"
app:layout_constraintEnd_toStartOf="@id/log_icon"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_refresh"
app:tint="?android:attr/textColorSecondary"
tools:visibility="visible" />
<ImageView
android:id="@+id/log_icon"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_gravity="center_vertical"
android:layout_marginTop="16dp"
android:layout_marginEnd="4dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/log"
android:padding="5dp"
app:layout_constraintEnd_toStartOf="@id/settings_icon"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_log"
app:tint="?android:attr/textColorSecondary" />
<ImageView
android:id="@+id/settings_icon"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_gravity="center_vertical"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/settings"
android:padding="5dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_settings"
app:tint="?android:attr/textColorSecondary" />
<TextView
android:id="@+id/title_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="18dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="18dp"
android:fontFamily="sans-serif-medium"
android:text="@string/app_name"
android:textColor="?android:attr/textColorPrimary"
android:textSize="32sp"
android:textStyle="bold"
app:layout_constraintTop_toBottomOf="@id/settings_icon" />
<emu.skyline.views.SearchBarView <emu.skyline.views.SearchBarView
android:id="@+id/search_bar" android:id="@+id/search_bar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" /> android:layout_height="64dp"
android:layout_marginStart="12dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="12dp"
app:cardCornerRadius="16dp"
app:cardElevation="2dp"
app:layout_constraintTop_toBottomOf="@id/title_text" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.appbar.CollapsingToolbarLayout> </com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout> </com.google.android.material.appbar.AppBarLayout>
@ -36,11 +110,44 @@
android:layout_marginTop="-4dp" android:layout_marginTop="-4dp"
app:layout_behavior="@string/appbar_scrolling_view_behavior"> app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="none">
<com.google.android.material.chip.ChipGroup
android:id="@+id/chip_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="18dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="18dp"
app:checkedChip="@id/all_chip"
app:chipSpacingHorizontal="16dp"
app:selectionRequired="true"
app:singleLine="true"
app:singleSelection="true">
<com.google.android.material.chip.Chip
android:id="@+id/all_chip"
style="?attr/chipChoiceStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/all" />
</com.google.android.material.chip.ChipGroup>
</HorizontalScrollView>
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/app_list" android:id="@+id/app_list"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:clipToPadding="false" android:clipToPadding="false"
android:paddingTop="4dp" /> android:paddingTop="4dp" />
</LinearLayout>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout> </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -101,7 +101,6 @@
android:layout_marginBottom="10dp" android:layout_marginBottom="10dp"
android:max="100" android:max="100"
android:progress="25" android:progress="25"
android:secondaryProgressTint="@color/colorPrimaryDark"
android:secondaryProgressTintMode="screen" android:secondaryProgressTintMode="screen"
android:visibility="gone" /> android:visibility="gone" />

View File

@ -42,59 +42,12 @@
android:textSize="16sp" android:textSize="16sp"
app:layout_constrainedWidth="true" app:layout_constrainedWidth="true"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/refresh_icon" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0" app:layout_constraintHorizontal_bias="0"
app:layout_constraintStart_toEndOf="@id/search_icon" app:layout_constraintStart_toEndOf="@id/search_icon"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
tools:ignore="LabelFor" /> tools:ignore="LabelFor" />
<ImageView
android:id="@+id/refresh_icon"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_gravity="center_vertical"
android:layout_marginEnd="4dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/refresh"
android:padding="5dp"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/log_icon"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_refresh"
app:tint="?android:attr/textColorSecondary"
tools:visibility="visible" />
<ImageView
android:id="@+id/log_icon"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_gravity="center_vertical"
android:layout_marginEnd="4dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/log"
android:padding="5dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/settings_icon"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_log"
app:tint="?android:attr/textColorSecondary" />
<ImageView
android:id="@+id/settings_icon"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_gravity="center_vertical"
android:layout_marginEnd="8dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/settings"
android:padding="5dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_settings"
app:tint="?android:attr/textColorSecondary" />
<TextView <TextView
android:id="@+id/skyline_text" android:id="@+id/skyline_text"
android:layout_width="wrap_content" android:layout_width="wrap_content"

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AppTheme" parent="BaseAppTheme">
<item name="android:windowLightNavigationBar">false</item>
<item name="android:navigationBarColor">@color/colorPrimaryDark</item>
</style>
</resources>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<color name="colorPrimary">#FF424242</color> <color name="colorPrimary">#FF424242</color>
<color name="colorPrimaryDark">#FF121212</color> <color name="colorPrimaryVariant">#FF121212</color>
</resources> </resources>

View File

@ -1,9 +0,0 @@
<resources>
<style name="BaseAppTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="android:windowLightStatusBar">false</item>
</style>
</resources>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools">
<style name="AppTheme" parent="BaseAppTheme">
<item name="android:windowLightNavigationBar" tools:targetApi="o_mr1">false</item>
<item name="android:windowLightStatusBar">false</item>
</style>
</resources>

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AppTheme" parent="BaseAppTheme">
<item name="android:windowLightNavigationBar">true</item>
<item name="android:navigationBarColor">@color/colorPrimaryDark</item>
</style>
</resources>

View File

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<declare-styleable name="CustomEditTextPreference"> <declare-styleable name="CustomEditTextPreference">
<attr name="limit" format="integer"/> <attr name="limit" format="integer" />
</declare-styleable> </declare-styleable>
<attr name="chipChoiceStyle" format="reference" />
</resources> </resources>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<color name="colorPrimary">@color/cardview_light_background</color> <color name="colorPrimary">@color/cardview_light_background</color>
<color name="colorPrimaryDark">@android:color/white</color> <color name="colorPrimaryVariant">@android:color/white</color>
<color name="colorAccent">#FFFF0000</color> <color name="colorOnPrimary">#FFFF0000</color>
</resources> </resources>

View File

@ -8,6 +8,7 @@
<string name="log">Logger</string> <string name="log">Logger</string>
<string name="refresh">Refresh</string> <string name="refresh">Refresh</string>
<!-- Main --> <!-- Main -->
<string name="all">All</string>
<string name="metadata_missing">Metadata Missing</string> <string name="metadata_missing">Metadata Missing</string>
<string name="icon">Icon</string> <string name="icon">Icon</string>
<string name="no_rom">Cannot find any ROMs</string> <string name="no_rom">Cannot find any ROMs</string>

View File

@ -1,16 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<style name="BaseAppTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar"> <style name="RoundedAppImage">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="android:windowLightStatusBar">true</item>
</style>
<style name="AppTheme" parent="BaseAppTheme" />
<style name="roundedAppImage">
<item name="cornerFamily">rounded</item> <item name="cornerFamily">rounded</item>
<item name="cornerSize">6dp</item> <item name="cornerSize">6dp</item>
</style> </style>
<style name="ChipChoice.Material">
<item name="colorPrimary">@color/colorOnPrimary</item>
<item name="colorOnPrimary">@color/colorPrimary</item>
</style>
<style name="ChipChoice" parent="Widget.MaterialComponents.Chip.Choice">
<item name="android:textAllCaps">true</item>
<item name="chipStartPadding">8dp</item>
<item name="chipEndPadding">8dp</item>
<item name="materialThemeOverlay">@style/ChipChoice.Material</item>
<item name="shapeAppearance">@style/ShapeAppearance.MaterialComponents.LargeComponent</item>
</style>
</resources> </resources>

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools">
<style name="BaseAppTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryVariant">@color/colorPrimaryVariant</item>
<item name="colorOnPrimary">@color/colorOnPrimary</item>
<item name="colorSecondary">@color/colorOnPrimary</item>
<item name="colorOnSecondary">@color/colorPrimary</item>
<item name="android:statusBarColor">@color/colorPrimaryVariant</item>
<item name="android:navigationBarColor">@color/colorPrimaryVariant</item>
<item name="chipChoiceStyle">@style/ChipChoice</item>
</style>
<style name="AppTheme" parent="BaseAppTheme">
<item name="android:windowLightNavigationBar" tools:targetApi="o_mr1">true</item>
<item name="android:windowLightStatusBar">true</item>
</style>
<style name="ToolbarTheme" parent="AppTheme">
<item name="colorPrimary">@color/colorPrimary</item>
</style>
</resources>

View File

@ -53,12 +53,12 @@
android:visibility="invisible" android:visibility="invisible"
motion:layout_constrainedWidth="true" motion:layout_constrainedWidth="true"
motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintEnd_toStartOf="@id/refresh_icon"
motion:layout_constraintHorizontal_bias="0" motion:layout_constraintHorizontal_bias="0"
motion:layout_constraintStart_toEndOf="@id/search_icon" motion:layout_constraintStart_toEndOf="@id/search_icon"
motion:layout_constraintTop_toTopOf="parent" motion:layout_constraintTop_toTopOf="parent"
motion:transitionEasing="linear" motion:transitionEasing="linear"
android:alpha="0" /> android:alpha="0"
motion:layout_constraintEnd_toEndOf="parent" />
</ConstraintSet> </ConstraintSet>
<ConstraintSet android:id="@+id/end"> <ConstraintSet android:id="@+id/end">
@ -83,10 +83,10 @@
android:visibility="visible" android:visibility="visible"
motion:layout_constrainedWidth="true" motion:layout_constrainedWidth="true"
motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintEnd_toStartOf="@id/refresh_icon"
motion:layout_constraintHorizontal_bias="0" motion:layout_constraintHorizontal_bias="0"
motion:layout_constraintStart_toEndOf="@id/search_icon" motion:layout_constraintStart_toEndOf="@id/search_icon"
motion:layout_constraintTop_toTopOf="parent" motion:layout_constraintTop_toTopOf="parent"
android:alpha="1" /> android:alpha="1"
motion:layout_constraintEnd_toEndOf="parent" />
</ConstraintSet> </ConstraintSet>
</MotionScene> </MotionScene>

View File

@ -1,7 +1,7 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules. // Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript { buildscript {
ext.kotlin_version = '1.4.21' ext.kotlin_version = '1.4.30'
ext.lifecycle_version = '2.2.0' ext.lifecycle_version = '2.2.0'
ext.hilt_version = '2.31.2-alpha' ext.hilt_version = '2.31.2-alpha'