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.res.use
import androidx.core.graphics.drawable.toBitmap
import androidx.core.view.isInvisible
import androidx.core.view.isVisible
import androidx.core.view.size
import androidx.lifecycle.observe
import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.chip.Chip
import com.google.android.material.snackbar.Snackbar
import dagger.hilt.android.AndroidEntryPoint
import emu.skyline.adapter.AppViewItem
@ -33,6 +36,7 @@ import emu.skyline.data.AppItem
import emu.skyline.data.DataItem
import emu.skyline.data.HeaderItem
import emu.skyline.databinding.MainActivityBinding
import emu.skyline.loader.AppEntry
import emu.skyline.loader.LoaderResult
import emu.skyline.loader.RomFormat
import emu.skyline.utils.Settings
@ -41,6 +45,10 @@ import kotlin.math.ceil
@AndroidEntryPoint
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) }
@Inject
@ -54,16 +62,32 @@ class MainActivity : AppCompatActivity() {
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)
override fun onCreate(savedInstanceState : Bundle?) {
// Need to create new instance of settings, dependency injection happens
AppCompatDelegate.setDefaultNightMode(when ((Settings(this).appTheme.toInt())) {
0 -> AppCompatDelegate.MODE_NIGHT_NO
1 -> AppCompatDelegate.MODE_NIGHT_YES
2 -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
else -> AppCompatDelegate.MODE_NIGHT_UNSPECIFIED
})
AppCompatDelegate.setDefaultNightMode(
when ((Settings(this).appTheme.toInt())) {
0 -> AppCompatDelegate.MODE_NIGHT_NO
1 -> AppCompatDelegate.MODE_NIGHT_YES
2 -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
else -> AppCompatDelegate.MODE_NIGHT_UNSPECIFIED
}
)
super.onCreate(savedInstanceState)
setContentView(binding.root)
@ -79,13 +103,26 @@ class MainActivity : AppCompatActivity() {
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)
loadRoms(!settings.refreshRequired)
binding.searchBar.apply {
setLogIconListener { startActivity(Intent(context, LogActivity::class.java)) }
setSettingsIconListener { startActivityForResult(Intent(context, SettingsActivity::class.java), 3) }
setRefreshIconListener { loadRoms(false) }
binding.logIcon.setOnClickListener { startActivity(Intent(context, LogActivity::class.java)) }
binding.settingsIcon.setOnClickListener { startActivityForResult(Intent(context, SettingsActivity::class.java), 3) }
binding.refreshIcon.setOnClickListener { loadRoms(false) }
addTextChangedListener(afterTextChanged = { editable ->
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 ->
binding.searchBar.refreshIconVisible = !isInTouchMode
refreshIconVisible = !isInTouchMode
}
}
@ -184,32 +221,38 @@ class MainActivity : AppCompatActivity() {
binding.appList.layoutManager = CustomLayoutManager(gridSpan)
setAppListDecoration()
if (settings.searchLocation.isEmpty()) {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
intent.flags = Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION or Intent.FLAG_GRANT_PREFIX_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION
if (settings.searchLocation.isEmpty()) startActivityForResult(Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).apply {
flags = Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION or
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) {
MainState.Loading -> {
binding.searchBar.animateRefreshIcon()
binding.refreshIcon.animate().rotationBy(-180f)
binding.swipeRefreshLayout.isRefreshing = true
}
is MainState.Loaded -> {
binding.swipeRefreshLayout.isRefreshing = false
val formatOrder = arrayOf(RomFormat.NSP, RomFormat.NRO, RomFormat.NSO, RomFormat.NCA)
val items = mutableListOf<DataItem>()
for (format in formatOrder) {
state.items[format]?.let {
items.add(HeaderItem(format.name))
it.forEach { entry -> items.add(AppItem(entry)) }
}
}
populateAdapter(items)
appEntries = state.items
populateAdapter()
}
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
}
private fun populateAdapter(items : List<DataItem>) {
private fun populateAdapter() {
val items = getDataItems()
adapter.setItems(items.map {
when (it) {
is HeaderItem -> HeaderViewItem(it.title)

View File

@ -15,8 +15,9 @@ import emu.skyline.utils.toFile
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.io.File
import java.io.IOException
import java.util.*
import javax.inject.Inject
import kotlin.collections.HashMap
sealed class MainState {
object Loading : MainState()
@ -50,7 +51,7 @@ class MainViewModel @Inject constructor(private val romProvider : RomProvider) :
val romsFile = File(context.filesDir.canonicalPath + "/roms.bin")
viewModelScope.launch(Dispatchers.IO) {
if (loadFromFile) {
if (loadFromFile && romsFile.exists()) {
try {
state = MainState.Loaded(fromFile(romsFile))
return@launch
@ -59,14 +60,19 @@ class MainViewModel @Inject constructor(private val romProvider : RomProvider) :
}
}
val romElements = romProvider.loadRoms(searchLocation)
try {
romElements.toFile(romsFile)
} catch (e : IOException) {
Log.w(TAG, "Ran into exception while saving: ${e.message}")
state = if (searchLocation.toString().isEmpty()) {
@Suppress("ReplaceWithEnumMap")
MainState.Loaded(HashMap())
} else {
try {
val romElements = romProvider.loadRoms(searchLocation)
romElements.toFile(romsFile)
MainState.Loaded(romElements)
} catch (e : Exception) {
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
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.Filter
import android.widget.Filterable
@ -101,7 +100,7 @@ class GenericAdapter : RecyclerView.Adapter<GenericViewHolder<ViewBinding>>(), F
val avgScore = topResults.sumByDouble { it.score } / topResults.size
for (result in topResults)
if (result.score > avgScore) filterData.add(result.item)
if (result.score >= avgScore) filterData.add(result.item)
results.values = filterData
results.count = filterData.size

View File

@ -4,15 +4,10 @@ import android.content.Context
import android.text.Editable
import android.text.TextWatcher
import android.util.AttributeSet
import android.util.TypedValue
import android.view.LayoutInflater
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 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) {
private val binding = ViewSearchBarBinding.inflate(LayoutInflater.from(context), this)
@ -21,32 +16,6 @@ class SearchBarView @JvmOverloads constructor(context : Context, attrs : Attribu
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
get() = binding.searchField.text
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(
beforeTextChanged : (
text : CharSequence?,

View File

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

View File

@ -1,55 +1,55 @@
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:foreground="?attr/selectableItemBackground"
android:orientation="vertical">
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:foreground="?attr/selectableItemBackground"
android:orientation="vertical">
<com.google.android.material.card.MaterialCardView
android:id="@+id/item_click_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginTop="12dp"
android:layout_marginEnd="12dp"
android:layout_marginBottom="12dp"
app:cardCornerRadius="16dp"
app:cardElevation="4dp">
android:id="@+id/item_click_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="14dp"
android:layout_marginTop="14dp"
android:layout_marginEnd="14dp"
android:layout_marginBottom="14dp"
app:cardCornerRadius="16dp"
app:cardElevation="2dp">
<ImageView
android:id="@+id/icon"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:contentDescription="@string/icon"
tools:src="@drawable/default_icon" />
android:id="@+id/icon"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:contentDescription="@string/icon"
tools:src="@drawable/default_icon" />
</com.google.android.material.card.MaterialCardView>
<TextView
android:id="@+id/text_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
android:singleLine="true"
android:textColor="?android:attr/textColorPrimary"
android:textSize="12sp"
tools:text="Title" />
android:id="@+id/text_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
android:singleLine="true"
android:textColor="?android:attr/textColorPrimary"
android:textSize="12sp"
tools:text="Title" />
<TextView
android:id="@+id/text_subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:layout_marginBottom="16dp"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
android:singleLine="true"
android:textSize="12sp"
tools:text="Subtitle" />
android:id="@+id/text_subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:layout_marginBottom="16dp"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
android:singleLine="true"
android:textSize="12sp"
tools:text="Subtitle" />
</LinearLayout>

View File

@ -1,81 +1,80 @@
<?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:id="@+id/button_layout"
android:layout_width="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/button_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:animateLayoutChanges="true"
android:defaultFocusHighlightEnabled="false"
android:focusable="true"
android:focusableInTouchMode="true"
android:focusedByDefault="true"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:id="@+id/button_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:animateLayoutChanges="true"
android:defaultFocusHighlightEnabled="false"
android:focusable="true"
android:focusableInTouchMode="true"
android:focusedByDefault="true"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:id="@+id/button_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:animateLayoutChanges="true"
android:text="@string/use_button_axis"
android:textAlignment="center"
android:textAppearance="@style/TextAppearance.AppCompat.Display1"
android:textSize="16sp" />
android:text="@string/use_button_axis"
android:textAlignment="center"
android:textAppearance="@style/TextAppearance.AppCompat.Display1"
android:textSize="16sp" />
<RelativeLayout
android:id="@+id/button_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:animateLayoutChanges="true"
android:gravity="center">
android:id="@+id/button_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:animateLayoutChanges="true"
android:gravity="center">
<ImageView
android:id="@+id/button_icon"
android:layout_width="50dp"
android:layout_height="50dp"
android:contentDescription="@string/buttons"
android:outlineProvider="bounds"
android:src="@drawable/ic_button"
app:tint="?android:attr/textColorPrimary" />
android:id="@+id/button_icon"
android:layout_width="50dp"
android:layout_height="50dp"
android:contentDescription="@string/buttons"
android:outlineProvider="bounds"
android:src="@drawable/ic_button"
app:tint="?android:attr/textColorPrimary" />
<TextView
android:id="@+id/button_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignStart="@id/button_icon"
android:layout_alignTop="@id/button_icon"
android:layout_alignEnd="@id/button_icon"
android:layout_alignBottom="@id/button_icon"
android:alpha="0.25"
android:fontFamily="monospace"
android:gravity="center"
android:includeFontPadding="false"
android:textSize="27sp" />
android:id="@+id/button_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignStart="@id/button_icon"
android:layout_alignTop="@id/button_icon"
android:layout_alignEnd="@id/button_icon"
android:layout_alignBottom="@id/button_icon"
android:alpha="0.25"
android:fontFamily="monospace"
android:gravity="center"
android:includeFontPadding="false"
android:textSize="27sp" />
</RelativeLayout>
<SeekBar
android:id="@+id/button_seekbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:max="100"
android:progress="25"
android:secondaryProgressTint="@color/colorPrimaryDark"
android:secondaryProgressTintMode="screen"
android:visibility="gone" />
android:id="@+id/button_seekbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:max="100"
android:progress="25"
android:secondaryProgressTintMode="screen"
android:visibility="gone" />
<Button
android:id="@+id/button_reset"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_marginEnd="10dp"
android:text="@string/reset"
android:textColor="?attr/colorAccent" />
android:id="@+id/button_reset"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_marginEnd="10dp"
android:text="@string/reset"
android:textColor="?attr/colorAccent" />
</LinearLayout>

View File

@ -1,46 +1,153 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/app_bar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
android:fitsSystemWindows="true"
android:keyboardNavigationCluster="false"
android:touchscreenBlocksFocus="false"
app:elevation="0dp">
android:id="@+id/app_bar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
android:fitsSystemWindows="true"
android:keyboardNavigationCluster="false"
android:touchscreenBlocksFocus="false"
app:elevation="0dp">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="62dp"
android:fitsSystemWindows="true"
app:layout_scrollFlags="scroll">
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
app:layout_scrollFlags="scroll">
<emu.skyline.views.SearchBarView
<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
android:id="@+id/search_bar"
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.AppBarLayout>
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipe_refresh_layout"
android:id="@+id/swipe_refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="-4dp"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="-4dp"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
android:orientation="vertical">
<androidx.recyclerview.widget.RecyclerView
<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
android:id="@+id/app_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:paddingTop="4dp" />
</LinearLayout>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -1,130 +1,129 @@
<?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:id="@+id/stick_layout"
android:layout_width="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/stick_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:animateLayoutChanges="true"
android:defaultFocusHighlightEnabled="false"
android:focusable="true"
android:focusableInTouchMode="true"
android:focusedByDefault="true"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:id="@+id/stick_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start"
android:layout_marginBottom="10dp"
android:animateLayoutChanges="true"
android:text="@string/stick_button"
android:textAppearance="@style/TextAppearance.AppCompat.Display1"
android:textColor="?android:attr/textColorPrimary"
android:textSize="16sp" />
<TextView
android:id="@+id/stick_subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:animateLayoutChanges="true"
android:defaultFocusHighlightEnabled="false"
android:focusable="true"
android:focusableInTouchMode="true"
android:focusedByDefault="true"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:id="@+id/stick_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start"
android:layout_marginBottom="10dp"
android:animateLayoutChanges="true"
android:text="@string/stick_button"
android:textAppearance="@style/TextAppearance.AppCompat.Display1"
android:textColor="?android:attr/textColorPrimary"
android:textSize="16sp" />
<TextView
android:id="@+id/stick_subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:animateLayoutChanges="true"
android:text="@string/use_button_axis"
android:textAlignment="center"
android:textAppearance="@style/TextAppearance.AppCompat.Display1"
android:textSize="16sp" />
android:text="@string/use_button_axis"
android:textAlignment="center"
android:textAppearance="@style/TextAppearance.AppCompat.Display1"
android:textSize="16sp" />
<RelativeLayout
android:id="@+id/stick_circle_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:gravity="center">
android:id="@+id/stick_circle_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:gravity="center">
<ImageView
android:id="@+id/stick_circle_icon"
android:layout_width="80dp"
android:layout_height="80dp"
android:alpha="0.4"
android:contentDescription="@string/buttons"
android:outlineProvider="bounds"
android:src="@drawable/ic_button"
app:tint="?android:attr/textColorPrimary" />
android:id="@+id/stick_circle_icon"
android:layout_width="80dp"
android:layout_height="80dp"
android:alpha="0.4"
android:contentDescription="@string/buttons"
android:outlineProvider="bounds"
android:src="@drawable/ic_button"
app:tint="?android:attr/textColorPrimary" />
<RelativeLayout
android:id="@+id/stick_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignStart="@id/stick_circle_icon"
android:layout_alignTop="@id/stick_circle_icon"
android:layout_alignEnd="@id/stick_circle_icon"
android:layout_alignBottom="@id/stick_circle_icon">
android:id="@+id/stick_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignStart="@id/stick_circle_icon"
android:layout_alignTop="@id/stick_circle_icon"
android:layout_alignEnd="@id/stick_circle_icon"
android:layout_alignBottom="@id/stick_circle_icon">
<ImageView
android:id="@+id/stick_icon"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_margin="15dp"
android:alpha="0.4"
android:contentDescription="@string/buttons"
android:outlineProvider="bounds"
android:src="@drawable/ic_stick"
app:tint="?android:attr/textColorPrimary" />
android:id="@+id/stick_icon"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_margin="15dp"
android:alpha="0.4"
android:contentDescription="@string/buttons"
android:outlineProvider="bounds"
android:src="@drawable/ic_stick"
app:tint="?android:attr/textColorPrimary" />
<TextView
android:id="@+id/stick_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignStart="@id/stick_icon"
android:layout_alignTop="@id/stick_icon"
android:layout_alignEnd="@id/stick_icon"
android:layout_alignBottom="@id/stick_icon"
android:alpha="0.55"
android:fontFamily="monospace"
android:gravity="center"
android:includeFontPadding="false"
android:textColor="@android:color/white"
android:textSize="27sp" />
android:id="@+id/stick_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignStart="@id/stick_icon"
android:layout_alignTop="@id/stick_icon"
android:layout_alignEnd="@id/stick_icon"
android:layout_alignBottom="@id/stick_icon"
android:alpha="0.55"
android:fontFamily="monospace"
android:gravity="center"
android:includeFontPadding="false"
android:textColor="@android:color/white"
android:textSize="27sp" />
</RelativeLayout>
</RelativeLayout>
<SeekBar
android:id="@+id/stick_seekbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:max="100"
android:progress="25"
android:secondaryProgressTint="@color/colorPrimaryDark"
android:secondaryProgressTintMode="screen"
android:visibility="gone" />
android:id="@+id/stick_seekbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:max="100"
android:progress="25"
android:secondaryProgressTintMode="screen"
android:visibility="gone" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end">
<Button
android:id="@+id/stick_reset"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end">
android:layout_marginEnd="10dp"
android:text="@string/reset"
android:textColor="?attr/colorAccent" />
<Button
android:id="@+id/stick_reset"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
android:text="@string/reset"
android:textColor="?attr/colorAccent" />
<Button
android:id="@+id/stick_next"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/next"
android:textColor="?attr/colorAccent" />
android:id="@+id/stick_next"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/next"
android:textColor="?attr/colorAccent" />
</LinearLayout>
</LinearLayout>

View File

@ -1,107 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:parentTag="com.google.android.material.card.MaterialCardView">
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:parentTag="com.google.android.material.card.MaterialCardView">
<androidx.constraintlayout.motion.widget.MotionLayout
android:id="@+id/motion_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutDescription="@xml/view_search_bar_xml_constraintlayout_scene"
app:motionProgress="1"
tools:motionDebug="SHOW_ALL">
android:id="@+id/motion_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutDescription="@xml/view_search_bar_xml_constraintlayout_scene"
app:motionProgress="1"
tools:motionDebug="SHOW_ALL">
<ImageView
android:id="@+id/search_icon"
android:layout_width="22dp"
android:layout_height="22dp"
android:layout_gravity="center_vertical"
android:layout_marginStart="16dp"
android:contentDescription="@string/search"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_search"
app:tint="?android:attr/textColorSecondary" />
android:id="@+id/search_icon"
android:layout_width="22dp"
android:layout_height="22dp"
android:layout_gravity="center_vertical"
android:layout_marginStart="16dp"
android:contentDescription="@string/search"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_search"
app:tint="?android:attr/textColorSecondary" />
<EditText
android:id="@+id/search_field"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:background="@null"
android:focusedByDefault="false"
android:hint="@string/search"
android:importantForAutofill="no"
android:inputType="text"
android:singleLine="true"
android:textSize="16sp"
app:layout_constrainedWidth="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/refresh_icon"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintStart_toEndOf="@id/search_icon"
app:layout_constraintTop_toTopOf="parent"
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" />
android:id="@+id/search_field"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:background="@null"
android:focusedByDefault="false"
android:hint="@string/search"
android:importantForAutofill="no"
android:inputType="text"
android:singleLine="true"
android:textSize="16sp"
app:layout_constrainedWidth="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintStart_toEndOf="@id/search_icon"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="LabelFor" />
<TextView
android:id="@+id/skyline_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-medium"
android:text="@string/app_name"
android:textColor="?android:attr/textColorPrimary"
android:textSize="18sp" />
android:id="@+id/skyline_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-medium"
android:text="@string/app_name"
android:textColor="?android:attr/textColorPrimary"
android:textSize="18sp" />
</androidx.constraintlayout.motion.widget.MotionLayout>
</merge>

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"?>
<resources>
<color name="colorPrimary">#FF424242</color>
<color name="colorPrimaryDark">#FF121212</color>
<color name="colorPrimaryVariant">#FF121212</color>
</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"?>
<resources>
<declare-styleable name="CustomEditTextPreference">
<attr name="limit" format="integer"/>
<attr name="limit" format="integer" />
</declare-styleable>
<attr name="chipChoiceStyle" format="reference" />
</resources>

View File

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

View File

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

View File

@ -1,16 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<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">true</item>
</style>
<style name="AppTheme" parent="BaseAppTheme" />
<style name="roundedAppImage">
<style name="RoundedAppImage">
<item name="cornerFamily">rounded</item>
<item name="cornerSize">6dp</item>
</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>

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

View File

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