3
0
Fork 0
forked from suyu/suyu

android: Use view binding

This commit is contained in:
Charles Lombardo 2023-03-20 00:21:52 -04:00 committed by bunnei
parent e49e6cac7e
commit 72679c7bae
16 changed files with 189 additions and 284 deletions

View file

@ -8,11 +8,9 @@ import android.content.DialogInterface
import android.content.Intent import android.content.Intent
import android.graphics.Rect import android.graphics.Rect
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater
import android.view.MotionEvent import android.view.MotionEvent
import android.view.View import android.view.View
import android.view.WindowManager import android.view.WindowManager
import android.widget.TextView
import androidx.activity.OnBackPressedCallback import androidx.activity.OnBackPressedCallback
import androidx.annotation.IntDef import androidx.annotation.IntDef
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
@ -21,10 +19,10 @@ import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.slider.Slider
import com.google.android.material.slider.Slider.OnChangeListener import com.google.android.material.slider.Slider.OnChangeListener
import org.yuzu.yuzu_emu.NativeLibrary import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.DialogSliderBinding
import org.yuzu.yuzu_emu.features.settings.model.Settings import org.yuzu.yuzu_emu.features.settings.model.Settings
import org.yuzu.yuzu_emu.fragments.EmulationFragment import org.yuzu.yuzu_emu.fragments.EmulationFragment
import org.yuzu.yuzu_emu.fragments.MenuFragment import org.yuzu.yuzu_emu.fragments.MenuFragment
@ -139,27 +137,22 @@ open class EmulationActivity : AppCompatActivity() {
} }
private fun adjustScale() { private fun adjustScale() {
val inflater = LayoutInflater.from(this) val sliderBinding = DialogSliderBinding.inflate(layoutInflater)
val view = inflater.inflate(R.layout.dialog_slider, null) sliderBinding.slider.valueTo = 150F
val slider = view.findViewById<Slider>(R.id.slider) sliderBinding.slider.value = PreferenceManager.getDefaultSharedPreferences(applicationContext)
val textValue = view.findViewById<TextView>(R.id.text_value)
val units = view.findViewById<TextView>(R.id.text_units)
slider.valueTo = 150F
slider.value = PreferenceManager.getDefaultSharedPreferences(applicationContext)
.getInt(Settings.PREF_CONTROL_SCALE, 50).toFloat() .getInt(Settings.PREF_CONTROL_SCALE, 50).toFloat()
slider.addOnChangeListener(OnChangeListener { _, value, _ -> sliderBinding.slider.addOnChangeListener(OnChangeListener { _, value, _ ->
textValue.text = value.toString() sliderBinding.textValue.text = value.toString()
setControlScale(value.toInt()) setControlScale(value.toInt())
}) })
textValue.text = slider.value.toString() sliderBinding.textValue.text = sliderBinding.slider.value.toString()
units.text = "%" sliderBinding.textUnits.text = "%"
MaterialAlertDialogBuilder(this) MaterialAlertDialogBuilder(this)
.setTitle(R.string.emulation_control_scale) .setTitle(R.string.emulation_control_scale)
.setView(view) .setView(sliderBinding.root)
.setNegativeButton(android.R.string.cancel, null) .setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(android.R.string.ok) { _: DialogInterface?, _: Int -> .setPositiveButton(android.R.string.ok) { _: DialogInterface?, _: Int ->
setControlScale(slider.value.toInt()) setControlScale(sliderBinding.slider.value.toInt())
} }
.setNeutralButton(R.string.slider_default) { _: DialogInterface?, _: Int -> .setNeutralButton(R.string.slider_default) { _: DialogInterface?, _: Int ->
setControlScale(50) setControlScale(50)

View file

@ -24,6 +24,8 @@ import kotlinx.coroutines.withContext
import org.yuzu.yuzu_emu.NativeLibrary import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.activities.EmulationActivity.Companion.launch import org.yuzu.yuzu_emu.activities.EmulationActivity.Companion.launch
import org.yuzu.yuzu_emu.databinding.CardGameBinding
import org.yuzu.yuzu_emu.model.Game
import org.yuzu.yuzu_emu.model.GameDatabase import org.yuzu.yuzu_emu.model.GameDatabase
import org.yuzu.yuzu_emu.utils.Log import org.yuzu.yuzu_emu.utils.Log
import org.yuzu.yuzu_emu.viewholders.GameViewHolder import org.yuzu.yuzu_emu.viewholders.GameViewHolder
@ -51,25 +53,24 @@ class GameAdapter(private val activity: AppCompatActivity) : RecyclerView.Adapte
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GameViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GameViewHolder {
// Create a new view. // Create a new view.
val gameCard = LayoutInflater.from(parent.context) val binding = CardGameBinding.inflate(LayoutInflater.from(parent.context))
.inflate(R.layout.card_game, parent, false) binding.root.setOnClickListener(this)
gameCard.setOnClickListener(this)
// Use that view to create a ViewHolder. // Use that view to create a ViewHolder.
return GameViewHolder(gameCard) return GameViewHolder(binding)
} }
override fun onBindViewHolder(holder: GameViewHolder, position: Int) { override fun onBindViewHolder(holder: GameViewHolder, position: Int) {
if (isDatasetValid) { if (isDatasetValid) {
if (cursor!!.moveToPosition(position)) { if (cursor!!.moveToPosition(position)) {
holder.imageIcon.scaleType = ImageView.ScaleType.CENTER_CROP holder.binding.imageGameScreen.scaleType = ImageView.ScaleType.CENTER_CROP
activity.lifecycleScope.launch { activity.lifecycleScope.launch {
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
val uri = val uri =
Uri.parse(cursor!!.getString(GameDatabase.GAME_COLUMN_PATH)).toString() Uri.parse(cursor!!.getString(GameDatabase.GAME_COLUMN_PATH)).toString()
val bitmap = decodeGameIcon(uri) val bitmap = decodeGameIcon(uri)
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
holder.imageIcon.load(bitmap) { holder.binding.imageGameScreen.load(bitmap) {
error(R.drawable.no_icon) error(R.drawable.no_icon)
crossfade(true) crossfade(true)
} }
@ -77,20 +78,23 @@ class GameAdapter(private val activity: AppCompatActivity) : RecyclerView.Adapte
} }
} }
holder.textGameTitle.text = holder.binding.textGameTitle.text =
cursor!!.getString(GameDatabase.GAME_COLUMN_TITLE) cursor!!.getString(GameDatabase.GAME_COLUMN_TITLE)
.replace("[\\t\\n\\r]+".toRegex(), " ") .replace("[\\t\\n\\r]+".toRegex(), " ")
holder.textGameCaption.text = cursor!!.getString(GameDatabase.GAME_COLUMN_CAPTION) holder.binding.textGameCaption.text = cursor!!.getString(GameDatabase.GAME_COLUMN_CAPTION)
// TODO These shouldn't be necessary once the move to a DB-based model is complete. // TODO These shouldn't be necessary once the move to a DB-based model is complete.
holder.gameId = cursor!!.getString(GameDatabase.GAME_COLUMN_GAME_ID) val game = Game(
holder.path = cursor!!.getString(GameDatabase.GAME_COLUMN_PATH) cursor!!.getString(GameDatabase.GAME_COLUMN_TITLE),
holder.title = cursor!!.getString(GameDatabase.GAME_COLUMN_TITLE) cursor!!.getString(GameDatabase.GAME_COLUMN_DESCRIPTION),
holder.description = cursor!!.getString(GameDatabase.GAME_COLUMN_DESCRIPTION) cursor!!.getString(GameDatabase.GAME_COLUMN_REGIONS),
holder.regions = cursor!!.getString(GameDatabase.GAME_COLUMN_REGIONS) cursor!!.getString(GameDatabase.GAME_COLUMN_PATH),
holder.company = cursor!!.getString(GameDatabase.GAME_COLUMN_CAPTION) cursor!!.getString(GameDatabase.GAME_COLUMN_GAME_ID),
cursor!!.getString(GameDatabase.GAME_COLUMN_CAPTION)
)
holder.game = game
val backgroundColorId = val backgroundColorId =
if (isValidGame(holder.path!!)) R.attr.colorSurface else R.attr.colorErrorContainer if (isValidGame(holder.game.path)) R.attr.colorSurface else R.attr.colorErrorContainer
val itemView = holder.itemView val itemView = holder.itemView
itemView.setBackgroundColor( itemView.setBackgroundColor(
MaterialColors.getColor( MaterialColors.getColor(
@ -177,7 +181,7 @@ class GameAdapter(private val activity: AppCompatActivity) : RecyclerView.Adapte
*/ */
override fun onClick(view: View) { override fun onClick(view: View) {
val holder = view.tag as GameViewHolder val holder = view.tag as GameViewHolder
launch((view.context as FragmentActivity), holder.path, holder.title) launch((view.context as FragmentActivity), holder.game.path, holder.game.title)
} }
private fun isValidGame(path: String): Boolean { private fun isValidGame(path: String): Boolean {

View file

@ -9,7 +9,6 @@ import android.content.IntentFilter
import android.os.Bundle import android.os.Bundle
import android.view.Menu import android.view.Menu
import android.view.View import android.view.View
import android.widget.FrameLayout
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
@ -18,11 +17,11 @@ import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding import androidx.core.view.updatePadding
import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.localbroadcastmanager.content.LocalBroadcastManager
import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.progressindicator.LinearProgressIndicator
import org.yuzu.yuzu_emu.NativeLibrary import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.ActivitySettingsBinding
import org.yuzu.yuzu_emu.databinding.DialogProgressBarBinding
import org.yuzu.yuzu_emu.features.settings.model.Settings import org.yuzu.yuzu_emu.features.settings.model.Settings
import org.yuzu.yuzu_emu.features.settings.ui.SettingsFragment.Companion.newInstance import org.yuzu.yuzu_emu.features.settings.ui.SettingsFragment.Companion.newInstance
import org.yuzu.yuzu_emu.utils.* import org.yuzu.yuzu_emu.utils.*
@ -31,11 +30,15 @@ class SettingsActivity : AppCompatActivity(), SettingsActivityView {
private val presenter = SettingsActivityPresenter(this) private val presenter = SettingsActivityPresenter(this)
private var dialog: AlertDialog? = null private var dialog: AlertDialog? = null
private lateinit var binding: ActivitySettingsBinding
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
ThemeHelper.setTheme(this) ThemeHelper.setTheme(this)
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_settings)
binding = ActivitySettingsBinding.inflate(layoutInflater)
setContentView(binding.root)
WindowCompat.setDecorFitsSystemWindows(window, false) WindowCompat.setDecorFitsSystemWindows(window, false)
@ -45,7 +48,7 @@ class SettingsActivity : AppCompatActivity(), SettingsActivityView {
presenter.onCreate(savedInstanceState, menuTag!!, gameID!!) presenter.onCreate(savedInstanceState, menuTag!!, gameID!!)
// Show "Back" button in the action bar for navigation // Show "Back" button in the action bar for navigation
setSupportActionBar(findViewById(R.id.toolbar_settings)) setSupportActionBar(binding.toolbarSettings)
supportActionBar!!.setDisplayHomeAsUpEnabled(true) supportActionBar!!.setDisplayHomeAsUpEnabled(true)
setInsets() setInsets()
@ -138,13 +141,12 @@ class SettingsActivity : AppCompatActivity(), SettingsActivityView {
override fun showLoading() { override fun showLoading() {
if (dialog == null) { if (dialog == null) {
val root = layoutInflater.inflate(R.layout.dialog_progress_bar, null) val loadingBinding = DialogProgressBarBinding.inflate(layoutInflater)
val progressBar = root.findViewById<LinearProgressIndicator>(R.id.progress_bar) loadingBinding.progressBar.isIndeterminate = true
progressBar.isIndeterminate = true
dialog = MaterialAlertDialogBuilder(this) dialog = MaterialAlertDialogBuilder(this)
.setTitle(R.string.load_settings) .setTitle(R.string.load_settings)
.setView(root) .setView(loadingBinding.root)
.setCancelable(false) .setCancelable(false)
.create() .create()
} }
@ -195,12 +197,10 @@ class SettingsActivity : AppCompatActivity(), SettingsActivityView {
get() = supportFragmentManager.findFragmentByTag(FRAGMENT_TAG) as SettingsFragment? get() = supportFragmentManager.findFragmentByTag(FRAGMENT_TAG) as SettingsFragment?
private fun setInsets() { private fun setInsets() {
val appBar = findViewById<AppBarLayout>(R.id.appbar_settings) ViewCompat.setOnApplyWindowInsetsListener(binding.frameContent) { view: View, windowInsets: WindowInsetsCompat ->
val frame = findViewById<FrameLayout>(R.id.frame_content)
ViewCompat.setOnApplyWindowInsetsListener(frame) { view: View, windowInsets: WindowInsetsCompat ->
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()) val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
view.updatePadding(left = insets.left, right = insets.right) view.updatePadding(left = insets.left, right = insets.right)
InsetsHelper.insetAppBar(insets, appBar) InsetsHelper.insetAppBar(insets, binding.appbarSettings)
windowInsets windowInsets
} }
} }

View file

@ -9,7 +9,6 @@ import android.icu.util.Calendar
import android.icu.util.TimeZone import android.icu.util.TimeZone
import android.text.format.DateFormat import android.text.format.DateFormat
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.TextView import android.widget.TextView
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
@ -20,6 +19,10 @@ import com.google.android.material.slider.Slider
import com.google.android.material.timepicker.MaterialTimePicker import com.google.android.material.timepicker.MaterialTimePicker
import com.google.android.material.timepicker.TimeFormat import com.google.android.material.timepicker.TimeFormat
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.DialogSliderBinding
import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
import org.yuzu.yuzu_emu.databinding.ListItemSettingSwitchBinding
import org.yuzu.yuzu_emu.databinding.ListItemSettingsHeaderBinding
import org.yuzu.yuzu_emu.features.settings.model.FloatSetting import org.yuzu.yuzu_emu.features.settings.model.FloatSetting
import org.yuzu.yuzu_emu.features.settings.model.view.* import org.yuzu.yuzu_emu.features.settings.model.view.*
import org.yuzu.yuzu_emu.features.settings.ui.viewholder.* import org.yuzu.yuzu_emu.features.settings.ui.viewholder.*
@ -43,37 +46,29 @@ class SettingsAdapter(
} }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SettingViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SettingViewHolder {
val view: View
val inflater = LayoutInflater.from(parent.context) val inflater = LayoutInflater.from(parent.context)
return when (viewType) { return when (viewType) {
SettingsItem.TYPE_HEADER -> { SettingsItem.TYPE_HEADER -> {
view = inflater.inflate(R.layout.list_item_settings_header, parent, false) HeaderViewHolder(ListItemSettingsHeaderBinding.inflate(inflater), this)
HeaderViewHolder(view, this)
} }
SettingsItem.TYPE_CHECKBOX -> { SettingsItem.TYPE_SWITCH -> {
view = inflater.inflate(R.layout.list_item_setting_switch, parent, false) SwitchSettingViewHolder(ListItemSettingSwitchBinding.inflate(inflater), this)
SwitchSettingViewHolder(view, this)
} }
SettingsItem.TYPE_SINGLE_CHOICE, SettingsItem.TYPE_STRING_SINGLE_CHOICE -> { SettingsItem.TYPE_SINGLE_CHOICE, SettingsItem.TYPE_STRING_SINGLE_CHOICE -> {
view = inflater.inflate(R.layout.list_item_setting, parent, false) SingleChoiceViewHolder(ListItemSettingBinding.inflate(inflater), this)
SingleChoiceViewHolder(view, this)
} }
SettingsItem.TYPE_SLIDER -> { SettingsItem.TYPE_SLIDER -> {
view = inflater.inflate(R.layout.list_item_setting, parent, false) SliderViewHolder(ListItemSettingBinding.inflate(inflater), this)
SliderViewHolder(view, this)
} }
SettingsItem.TYPE_SUBMENU -> { SettingsItem.TYPE_SUBMENU -> {
view = inflater.inflate(R.layout.list_item_setting, parent, false) SubmenuViewHolder(ListItemSettingBinding.inflate(inflater), this)
SubmenuViewHolder(view, this)
} }
SettingsItem.TYPE_DATETIME_SETTING -> { SettingsItem.TYPE_DATETIME_SETTING -> {
view = inflater.inflate(R.layout.list_item_setting, parent, false) DateTimeViewHolder(ListItemSettingBinding.inflate(inflater), this)
DateTimeViewHolder(view, this)
} }
else -> { else -> {
// TODO: Create an error view since we can't return null now // TODO: Create an error view since we can't return null now
view = inflater.inflate(R.layout.list_item_settings_header, parent, false) HeaderViewHolder(ListItemSettingsHeaderBinding.inflate(inflater), this)
HeaderViewHolder(view, this)
} }
} }
} }
@ -191,15 +186,13 @@ class SettingsAdapter(
sliderProgress = item.selectedValue sliderProgress = item.selectedValue
val inflater = LayoutInflater.from(context) val inflater = LayoutInflater.from(context)
val sliderLayout = inflater.inflate(R.layout.dialog_slider, null) val sliderBinding = DialogSliderBinding.inflate(inflater)
val sliderView = sliderLayout.findViewById<Slider>(R.id.slider)
textSliderValue = sliderLayout.findViewById(R.id.text_value) textSliderValue = sliderBinding.textValue
textSliderValue!!.text = sliderProgress.toString() textSliderValue!!.text = sliderProgress.toString()
val units = sliderLayout.findViewById<TextView>(R.id.text_units) sliderBinding.textUnits.text = item.units
units.text = item.units
sliderView.apply { sliderBinding.slider.apply {
valueFrom = item.min.toFloat() valueFrom = item.min.toFloat()
valueTo = item.max.toFloat() valueTo = item.max.toFloat()
value = sliderProgress.toFloat() value = sliderProgress.toFloat()
@ -211,11 +204,11 @@ class SettingsAdapter(
dialog = MaterialAlertDialogBuilder(context) dialog = MaterialAlertDialogBuilder(context)
.setTitle(item.nameId) .setTitle(item.nameId)
.setView(sliderLayout) .setView(sliderBinding.root)
.setPositiveButton(android.R.string.ok, this) .setPositiveButton(android.R.string.ok, this)
.setNegativeButton(android.R.string.cancel, defaultCancelListener) .setNegativeButton(android.R.string.cancel, defaultCancelListener)
.setNeutralButton(R.string.slider_default) { dialog: DialogInterface, which: Int -> .setNeutralButton(R.string.slider_default) { dialog: DialogInterface, which: Int ->
sliderView.value = item.defaultValue.toFloat() sliderBinding.slider.value = item.defaultValue.toFloat()
onClick(dialog, which) onClick(dialog, which)
} }
.show() .show()

View file

@ -14,9 +14,8 @@ import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.divider.MaterialDividerItemDecoration import com.google.android.material.divider.MaterialDividerItemDecoration
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.databinding.FragmentSettingsBinding
import org.yuzu.yuzu_emu.features.settings.model.Setting import org.yuzu.yuzu_emu.features.settings.model.Setting
import org.yuzu.yuzu_emu.features.settings.model.Settings import org.yuzu.yuzu_emu.features.settings.model.Settings
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
@ -26,9 +25,10 @@ class SettingsFragment : Fragment(), SettingsFragmentView {
private val presenter = SettingsFragmentPresenter(this) private val presenter = SettingsFragmentPresenter(this)
private var activityView: SettingsActivityView? = null private var activityView: SettingsActivityView? = null
private var adapter: SettingsAdapter? = null private var settingsAdapter: SettingsAdapter? = null
private lateinit var recyclerView: RecyclerView private var _binding: FragmentSettingsBinding? = null
private val binding get() = _binding!!
override fun onAttach(context: Context) { override fun onAttach(context: Context) {
super.onAttach(context) super.onAttach(context)
@ -41,7 +41,6 @@ class SettingsFragment : Fragment(), SettingsFragmentView {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
val menuTag = requireArguments().getString(ARGUMENT_MENU_TAG) val menuTag = requireArguments().getString(ARGUMENT_MENU_TAG)
val gameId = requireArguments().getString(ARGUMENT_GAME_ID) val gameId = requireArguments().getString(ARGUMENT_GAME_ID)
adapter = SettingsAdapter(this, requireActivity())
presenter.onCreate(menuTag!!, gameId!!) presenter.onCreate(menuTag!!, gameId!!)
} }
@ -49,18 +48,20 @@ class SettingsFragment : Fragment(), SettingsFragmentView {
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup?, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View? { ): View {
return inflater.inflate(R.layout.fragment_settings, container, false) _binding = FragmentSettingsBinding.inflate(layoutInflater)
return binding.root
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val manager = LinearLayoutManager(activity) settingsAdapter = SettingsAdapter(this, requireActivity())
recyclerView = view.findViewById(R.id.list_settings)
recyclerView.adapter = adapter
recyclerView.layoutManager = manager
val dividerDecoration = MaterialDividerItemDecoration(requireContext(), LinearLayoutManager.VERTICAL) val dividerDecoration = MaterialDividerItemDecoration(requireContext(), LinearLayoutManager.VERTICAL)
dividerDecoration.isLastItemDecorated = false dividerDecoration.isLastItemDecorated = false
recyclerView.addItemDecoration(dividerDecoration) binding.listSettings.apply {
adapter = settingsAdapter
layoutManager = LinearLayoutManager(activity)
addItemDecoration(dividerDecoration)
}
val activity = activity as SettingsActivityView? val activity = activity as SettingsActivityView?
presenter.onViewCreated(activity!!.settings) presenter.onViewCreated(activity!!.settings)
@ -70,8 +71,8 @@ class SettingsFragment : Fragment(), SettingsFragmentView {
override fun onDetach() { override fun onDetach() {
super.onDetach() super.onDetach()
activityView = null activityView = null
if (adapter != null) { if (settingsAdapter != null) {
adapter!!.closeDialog() settingsAdapter!!.closeDialog()
} }
} }
@ -86,7 +87,7 @@ class SettingsFragment : Fragment(), SettingsFragmentView {
} }
override fun showSettingsList(settingsList: ArrayList<SettingsItem>) { override fun showSettingsList(settingsList: ArrayList<SettingsItem>) {
adapter!!.setSettings(settingsList) settingsAdapter!!.setSettings(settingsList)
} }
override fun loadDefaultSettings() { override fun loadDefaultSettings() {
@ -114,7 +115,7 @@ class SettingsFragment : Fragment(), SettingsFragmentView {
} }
private fun setInsets() { private fun setInsets() {
ViewCompat.setOnApplyWindowInsetsListener(recyclerView) { view: View, windowInsets: WindowInsetsCompat -> ViewCompat.setOnApplyWindowInsetsListener(binding.listSettings) { view: View, windowInsets: WindowInsetsCompat ->
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()) val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
view.updatePadding(bottom = insets.bottom) view.updatePadding(bottom = insets.bottom)
windowInsets windowInsets

View file

@ -4,31 +4,23 @@
package org.yuzu.yuzu_emu.features.settings.ui.viewholder package org.yuzu.yuzu_emu.features.settings.ui.viewholder
import android.view.View import android.view.View
import android.widget.TextView import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.features.settings.model.view.DateTimeSetting import org.yuzu.yuzu_emu.features.settings.model.view.DateTimeSetting
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
class DateTimeViewHolder(itemView: View, adapter: SettingsAdapter) : class DateTimeViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
SettingViewHolder(itemView, adapter) { SettingViewHolder(binding.root, adapter) {
private lateinit var item: DateTimeSetting private lateinit var item: DateTimeSetting
private lateinit var textSettingName: TextView
private lateinit var textSettingDescription: TextView
override fun findViews(root: View) {
textSettingName = root.findViewById(R.id.text_setting_name)
textSettingDescription = root.findViewById(R.id.text_setting_description)
}
override fun bind(item: SettingsItem) { override fun bind(item: SettingsItem) {
this.item = item as DateTimeSetting this.item = item as DateTimeSetting
textSettingName.setText(item.nameId) binding.textSettingName.setText(item.nameId)
if (item.descriptionId!! > 0) { if (item.descriptionId!! > 0) {
textSettingDescription.setText(item.descriptionId) binding.textSettingDescription.setText(item.descriptionId)
textSettingDescription.visibility = View.VISIBLE binding.textSettingDescription.visibility = View.VISIBLE
} else { } else {
textSettingDescription.visibility = View.GONE binding.textSettingDescription.visibility = View.GONE
} }
} }

View file

@ -4,25 +4,19 @@
package org.yuzu.yuzu_emu.features.settings.ui.viewholder package org.yuzu.yuzu_emu.features.settings.ui.viewholder
import android.view.View import android.view.View
import android.widget.TextView import org.yuzu.yuzu_emu.databinding.ListItemSettingsHeaderBinding
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
class HeaderViewHolder(itemView: View, adapter: SettingsAdapter) : class HeaderViewHolder(val binding: ListItemSettingsHeaderBinding, adapter: SettingsAdapter) :
SettingViewHolder(itemView, adapter) { SettingViewHolder(binding.root, adapter) {
private lateinit var headerName: TextView
init { init {
itemView.setOnClickListener(null) itemView.setOnClickListener(null)
} }
override fun findViews(root: View) {
headerName = root.findViewById(R.id.text_header_name)
}
override fun bind(item: SettingsItem) { override fun bind(item: SettingsItem) {
headerName.setText(item.nameId) binding.textHeaderName.setText(item.nameId)
} }
override fun onClick(clicked: View) { override fun onClick(clicked: View) {

View file

@ -13,16 +13,8 @@ abstract class SettingViewHolder(itemView: View, protected val adapter: Settings
init { init {
itemView.setOnClickListener(this) itemView.setOnClickListener(this)
findViews(itemView)
} }
/**
* Gets handles to all this ViewHolder's child views using their XML-defined identifiers.
*
* @param root The newly inflated top-level view.
*/
protected abstract fun findViews(root: View)
/** /**
* Called by the adapter to set this ViewHolder's child views to display the list item * Called by the adapter to set this ViewHolder's child views to display the list item
* it must now represent. * it must now represent.

View file

@ -4,40 +4,32 @@
package org.yuzu.yuzu_emu.features.settings.ui.viewholder package org.yuzu.yuzu_emu.features.settings.ui.viewholder
import android.view.View import android.view.View
import android.widget.TextView import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.model.view.SingleChoiceSetting import org.yuzu.yuzu_emu.features.settings.model.view.SingleChoiceSetting
import org.yuzu.yuzu_emu.features.settings.model.view.StringSingleChoiceSetting import org.yuzu.yuzu_emu.features.settings.model.view.StringSingleChoiceSetting
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
class SingleChoiceViewHolder(itemView: View, adapter: SettingsAdapter) : class SingleChoiceViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
SettingViewHolder(itemView, adapter) { SettingViewHolder(binding.root, adapter) {
private lateinit var item: SettingsItem private lateinit var item: SettingsItem
private lateinit var textSettingName: TextView
private lateinit var textSettingDescription: TextView
override fun findViews(root: View) {
textSettingName = root.findViewById(R.id.text_setting_name)
textSettingDescription = root.findViewById(R.id.text_setting_description)
}
override fun bind(item: SettingsItem) { override fun bind(item: SettingsItem) {
this.item = item this.item = item
textSettingName.setText(item.nameId) binding.textSettingName.setText(item.nameId)
textSettingDescription.visibility = View.VISIBLE binding.textSettingDescription.visibility = View.VISIBLE
if (item.descriptionId!! > 0) { if (item.descriptionId!! > 0) {
textSettingDescription.setText(item.descriptionId) binding.textSettingDescription.setText(item.descriptionId)
} else if (item is SingleChoiceSetting) { } else if (item is SingleChoiceSetting) {
val resMgr = textSettingDescription.context.resources val resMgr = binding.textSettingDescription.context.resources
val values = resMgr.getIntArray(item.valuesId) val values = resMgr.getIntArray(item.valuesId)
for (i in values.indices) { for (i in values.indices) {
if (values[i] == item.selectedValue) { if (values[i] == item.selectedValue) {
textSettingDescription.text = resMgr.getStringArray(item.choicesId)[i] binding.textSettingDescription.text = resMgr.getStringArray(item.choicesId)[i]
} }
} }
} else { } else {
textSettingDescription.visibility = View.GONE binding.textSettingDescription.visibility = View.GONE
} }
} }

View file

@ -4,30 +4,23 @@
package org.yuzu.yuzu_emu.features.settings.ui.viewholder package org.yuzu.yuzu_emu.features.settings.ui.viewholder
import android.view.View import android.view.View
import android.widget.TextView import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
class SliderViewHolder(itemView: View, adapter: SettingsAdapter) : SettingViewHolder(itemView, adapter) { class SliderViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
SettingViewHolder(binding.root, adapter) {
private lateinit var item: SliderSetting private lateinit var item: SliderSetting
private lateinit var textSettingName: TextView
private lateinit var textSettingDescription: TextView
override fun findViews(root: View) {
textSettingName = root.findViewById(R.id.text_setting_name)
textSettingDescription = root.findViewById(R.id.text_setting_description)
}
override fun bind(item: SettingsItem) { override fun bind(item: SettingsItem) {
this.item = item as SliderSetting this.item = item as SliderSetting
textSettingName.setText(item.nameId) binding.textSettingName.setText(item.nameId)
if (item.descriptionId!! > 0) { if (item.descriptionId!! > 0) {
textSettingDescription.setText(item.descriptionId) binding.textSettingDescription.setText(item.descriptionId)
textSettingDescription.visibility = View.VISIBLE binding.textSettingDescription.visibility = View.VISIBLE
} else { } else {
textSettingDescription.visibility = View.GONE binding.textSettingDescription.visibility = View.GONE
} }
} }

View file

@ -4,31 +4,23 @@
package org.yuzu.yuzu_emu.features.settings.ui.viewholder package org.yuzu.yuzu_emu.features.settings.ui.viewholder
import android.view.View import android.view.View
import android.widget.TextView import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.model.view.SubmenuSetting import org.yuzu.yuzu_emu.features.settings.model.view.SubmenuSetting
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
class SubmenuViewHolder(itemView: View, adapter: SettingsAdapter) : class SubmenuViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
SettingViewHolder(itemView, adapter) { SettingViewHolder(binding.root, adapter) {
private lateinit var item: SubmenuSetting private lateinit var item: SubmenuSetting
private lateinit var textSettingName: TextView
private lateinit var textSettingDescription: TextView
override fun findViews(root: View) {
textSettingName = root.findViewById(R.id.text_setting_name)
textSettingDescription = root.findViewById(R.id.text_setting_description)
}
override fun bind(item: SettingsItem) { override fun bind(item: SettingsItem) {
this.item = item as SubmenuSetting this.item = item as SubmenuSetting
textSettingName.setText(item.nameId) binding.textSettingName.setText(item.nameId)
if (item.descriptionId!! > 0) { if (item.descriptionId!! > 0) {
textSettingDescription.setText(item.descriptionId) binding.textSettingDescription.setText(item.descriptionId)
textSettingDescription.visibility = View.VISIBLE binding.textSettingDescription.visibility = View.VISIBLE
} else { } else {
textSettingDescription.visibility = View.GONE binding.textSettingDescription.visibility = View.GONE
} }
} }

View file

@ -5,43 +5,31 @@ package org.yuzu.yuzu_emu.features.settings.ui.viewholder
import android.view.View import android.view.View
import android.widget.CompoundButton import android.widget.CompoundButton
import android.widget.TextView import org.yuzu.yuzu_emu.databinding.ListItemSettingSwitchBinding
import com.google.android.material.materialswitch.MaterialSwitch
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.features.settings.model.view.SwitchSetting import org.yuzu.yuzu_emu.features.settings.model.view.SwitchSetting
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
class SwitchSettingViewHolder(itemView: View, adapter: SettingsAdapter) : class SwitchSettingViewHolder(val binding: ListItemSettingSwitchBinding, adapter: SettingsAdapter) :
SettingViewHolder(itemView, adapter) { SettingViewHolder(binding.root, adapter) {
private lateinit var item: SwitchSetting
private lateinit var textSettingName: TextView
private lateinit var textSettingDescription: TextView
private lateinit var switch: MaterialSwitch
override fun findViews(root: View) {
textSettingName = root.findViewById(R.id.text_setting_name)
textSettingDescription = root.findViewById(R.id.text_setting_description)
switch = root.findViewById(R.id.switch_widget)
}
override fun bind(item: SettingsItem) { override fun bind(item: SettingsItem) {
this.item = item as SwitchSetting val setting = item as SwitchSetting
textSettingName.setText(item.nameId) binding.textSettingName.setText(item.nameId)
if (item.descriptionId!! > 0) { if (item.descriptionId!! > 0) {
textSettingDescription.setText(item.descriptionId) binding.textSettingDescription.setText(item.descriptionId)
textSettingDescription.visibility = View.VISIBLE binding.textSettingDescription.visibility = View.VISIBLE
} else { } else {
textSettingDescription.text = "" binding.textSettingDescription.text = ""
textSettingDescription.visibility = View.GONE binding.textSettingDescription.visibility = View.GONE
} }
switch.isChecked = this.item.isChecked binding.switchWidget.isChecked = setting.isChecked
switch.setOnCheckedChangeListener { _: CompoundButton, _: Boolean -> binding.switchWidget.setOnCheckedChangeListener { _: CompoundButton, _: Boolean ->
adapter.onBooleanClick(item, bindingAdapterPosition, switch.isChecked) adapter.onBooleanClick(item, bindingAdapterPosition, binding.switchWidget.isChecked)
} }
} }
override fun onClick(clicked: View) { override fun onClick(clicked: View) {
switch.toggle() binding.switchWidget.toggle()
} }
} }

View file

@ -10,8 +10,6 @@ import android.graphics.Color
import android.os.Bundle import android.os.Bundle
import android.os.Handler import android.os.Handler
import android.view.* import android.view.*
import android.widget.Button
import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.localbroadcastmanager.content.LocalBroadcastManager
@ -20,8 +18,8 @@ import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.YuzuApplication import org.yuzu.yuzu_emu.YuzuApplication
import org.yuzu.yuzu_emu.activities.EmulationActivity import org.yuzu.yuzu_emu.activities.EmulationActivity
import org.yuzu.yuzu_emu.databinding.FragmentEmulationBinding
import org.yuzu.yuzu_emu.features.settings.model.Settings import org.yuzu.yuzu_emu.features.settings.model.Settings
import org.yuzu.yuzu_emu.overlay.InputOverlay
import org.yuzu.yuzu_emu.utils.DirectoryInitialization import org.yuzu.yuzu_emu.utils.DirectoryInitialization
import org.yuzu.yuzu_emu.utils.DirectoryInitialization.DirectoryInitializationState import org.yuzu.yuzu_emu.utils.DirectoryInitialization.DirectoryInitializationState
import org.yuzu.yuzu_emu.utils.DirectoryStateReceiver import org.yuzu.yuzu_emu.utils.DirectoryStateReceiver
@ -29,13 +27,14 @@ import org.yuzu.yuzu_emu.utils.Log
class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.FrameCallback { class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.FrameCallback {
private lateinit var preferences: SharedPreferences private lateinit var preferences: SharedPreferences
private var inputOverlay: InputOverlay? = null
private lateinit var emulationState: EmulationState private lateinit var emulationState: EmulationState
private var directoryStateReceiver: DirectoryStateReceiver? = null private var directoryStateReceiver: DirectoryStateReceiver? = null
private var emulationActivity: EmulationActivity? = null private var emulationActivity: EmulationActivity? = null
private lateinit var perfStats: TextView
private var perfStatsUpdater: (() -> Unit)? = null private var perfStatsUpdater: (() -> Unit)? = null
private var _binding: FragmentEmulationBinding? = null
private val binding get() = _binding!!
override fun onAttach(context: Context) { override fun onAttach(context: Context) {
super.onAttach(context) super.onAttach(context)
if (context is EmulationActivity) { if (context is EmulationActivity) {
@ -66,22 +65,19 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup?, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View? { ): View {
val contents = inflater.inflate(R.layout.fragment_emulation, container, false) _binding = FragmentEmulationBinding.inflate(layoutInflater)
val surfaceView = contents.findViewById<SurfaceView>(R.id.surface_emulation) return binding.root
surfaceView.holder.addCallback(this) }
inputOverlay = contents.findViewById(R.id.surface_input_overlay)
perfStats = contents.findViewById(R.id.show_fps_text) override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
perfStats.setTextColor(Color.YELLOW) binding.surfaceEmulation.holder.addCallback(this)
val doneButton = contents.findViewById<Button>(R.id.done_control_config) binding.showFpsText.setTextColor(Color.YELLOW)
doneButton?.setOnClickListener { stopConfiguringControls() } binding.doneControlConfig.setOnClickListener { stopConfiguringControls() }
// Setup overlay. // Setup overlay.
resetInputOverlay() resetInputOverlay()
updateShowFpsOverlay() updateShowFpsOverlay()
// The new Surface created here will get passed to the native code via onSurfaceChanged.
return contents
} }
override fun onResume() { override fun onResume() {
@ -108,6 +104,11 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
super.onPause() super.onPause()
} }
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
override fun onDetach() { override fun onDetach() {
NativeLibrary.clearEmulationActivity() NativeLibrary.clearEmulationActivity()
super.onDetach() super.onDetach()
@ -144,7 +145,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
} }
fun refreshInputOverlay() { fun refreshInputOverlay() {
inputOverlay!!.refreshControls() binding.surfaceInputOverlay.refreshControls()
} }
fun resetInputOverlay() { fun resetInputOverlay() {
@ -152,7 +153,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
preferences.edit() preferences.edit()
.putInt(Settings.PREF_CONTROL_SCALE, 50) .putInt(Settings.PREF_CONTROL_SCALE, 50)
.apply() .apply()
inputOverlay!!.resetButtonPlacement() binding.surfaceInputOverlay.resetButtonPlacement()
} }
private fun updateShowFpsOverlay() { private fun updateShowFpsOverlay() {
@ -165,17 +166,17 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
perfStatsUpdater = { perfStatsUpdater = {
val perfStats = NativeLibrary.GetPerfStats() val perfStats = NativeLibrary.GetPerfStats()
if (perfStats[FPS] > 0) { if (perfStats[FPS] > 0) {
this.perfStats.text = String.format("FPS: %.1f", perfStats[FPS]) binding.showFpsText.text = String.format("FPS: %.1f", perfStats[FPS])
} }
perfStatsUpdateHandler.postDelayed(perfStatsUpdater!!, 100) perfStatsUpdateHandler.postDelayed(perfStatsUpdater!!, 100)
} }
perfStatsUpdateHandler.post(perfStatsUpdater!!) perfStatsUpdateHandler.post(perfStatsUpdater!!)
perfStats.visibility = View.VISIBLE binding.showFpsText.visibility = View.VISIBLE
} else { } else {
if (perfStatsUpdater != null) { if (perfStatsUpdater != null) {
perfStatsUpdateHandler.removeCallbacks(perfStatsUpdater!!) perfStatsUpdateHandler.removeCallbacks(perfStatsUpdater!!)
} }
perfStats.visibility = View.GONE binding.showFpsText.visibility = View.GONE
} }
} }
@ -203,18 +204,17 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
} }
fun startConfiguringControls() { fun startConfiguringControls() {
requireView().findViewById<View>(R.id.done_control_config).visibility = binding.doneControlConfig.visibility = View.VISIBLE
View.VISIBLE binding.surfaceInputOverlay.setIsInEditMode(true)
inputOverlay!!.setIsInEditMode(true)
} }
fun stopConfiguringControls() { fun stopConfiguringControls() {
requireView().findViewById<View>(R.id.done_control_config).visibility = View.GONE binding.doneControlConfig.visibility = View.GONE
inputOverlay!!.setIsInEditMode(false) binding.surfaceInputOverlay.setIsInEditMode(false)
} }
val isConfiguringControls: Boolean val isConfiguringControls: Boolean
get() = inputOverlay!!.isInEditMode get() = binding.surfaceInputOverlay.isInEditMode
private class EmulationState(private val mGamePath: String?) { private class EmulationState(private val mGamePath: String?) {
private var state: State private var state: State

View file

@ -10,30 +10,29 @@ import android.os.Bundle
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import android.widget.FrameLayout
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding import androidx.core.view.updatePadding
import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.yuzu.yuzu_emu.NativeLibrary import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.activities.EmulationActivity import org.yuzu.yuzu_emu.activities.EmulationActivity
import org.yuzu.yuzu_emu.databinding.ActivityMainBinding
import org.yuzu.yuzu_emu.features.settings.ui.SettingsActivity import org.yuzu.yuzu_emu.features.settings.ui.SettingsActivity
import org.yuzu.yuzu_emu.model.GameProvider import org.yuzu.yuzu_emu.model.GameProvider
import org.yuzu.yuzu_emu.ui.platform.PlatformGamesFragment import org.yuzu.yuzu_emu.ui.platform.PlatformGamesFragment
import org.yuzu.yuzu_emu.utils.* import org.yuzu.yuzu_emu.utils.*
class MainActivity : AppCompatActivity(), MainView { class MainActivity : AppCompatActivity(), MainView {
private lateinit var toolbar: Toolbar
private var platformGamesFragment: PlatformGamesFragment? = null private var platformGamesFragment: PlatformGamesFragment? = null
private val presenter = MainPresenter(this) private val presenter = MainPresenter(this)
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
val splashScreen = installSplashScreen() val splashScreen = installSplashScreen()
splashScreen.setKeepOnScreenCondition { !DirectoryInitialization.areDirectoriesReady() } splashScreen.setKeepOnScreenCondition { !DirectoryInitialization.areDirectoriesReady() }
@ -41,12 +40,13 @@ class MainActivity : AppCompatActivity(), MainView {
ThemeHelper.setTheme(this) ThemeHelper.setTheme(this)
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
WindowCompat.setDecorFitsSystemWindows(window, false) WindowCompat.setDecorFitsSystemWindows(window, false)
findViews() setSupportActionBar(binding.toolbarMain)
setSupportActionBar(toolbar)
presenter.onCreate() presenter.onCreate()
if (savedInstanceState == null) { if (savedInstanceState == null) {
StartupHandler.handleInit(this) StartupHandler.handleInit(this)
@ -81,11 +81,6 @@ class MainActivity : AppCompatActivity(), MainView {
presenter.addDirIfNeeded(AddDirectoryHelper(this)) presenter.addDirIfNeeded(AddDirectoryHelper(this))
} }
// TODO: Replace with view binding
private fun findViews() {
toolbar = findViewById(R.id.toolbar_main)
}
override fun onCreateOptionsMenu(menu: Menu): Boolean { override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_game_grid, menu) menuInflater.inflate(R.menu.menu_game_grid, menu)
return true return true
@ -95,7 +90,7 @@ class MainActivity : AppCompatActivity(), MainView {
* MainView * MainView
*/ */
override fun setVersionString(version: String) { override fun setVersionString(version: String) {
toolbar.subtitle = version binding.toolbarMain.subtitle = version
} }
override fun refresh() { override fun refresh() {
@ -247,12 +242,10 @@ class MainActivity : AppCompatActivity(), MainView {
} }
private fun setInsets() { private fun setInsets() {
val appBar = findViewById<AppBarLayout>(R.id.appbar_main) ViewCompat.setOnApplyWindowInsetsListener(binding.gamesPlatformFrame) { view: View, windowInsets: WindowInsetsCompat ->
val frame = findViewById<FrameLayout>(R.id.games_platform_frame)
ViewCompat.setOnApplyWindowInsetsListener(frame) { view: View, windowInsets: WindowInsetsCompat ->
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()) val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
view.updatePadding(left = insets.left, right = insets.right) view.updatePadding(left = insets.left, right = insets.right)
InsetsHelper.insetAppBar(insets, appBar) InsetsHelper.insetAppBar(insets, binding.appbarMain)
windowInsets windowInsets
} }
} }

View file

@ -9,35 +9,33 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.ViewTreeObserver.OnGlobalLayoutListener import android.view.ViewTreeObserver.OnGlobalLayoutListener
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import com.google.android.material.color.MaterialColors import com.google.android.material.color.MaterialColors
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.YuzuApplication import org.yuzu.yuzu_emu.YuzuApplication
import org.yuzu.yuzu_emu.adapters.GameAdapter import org.yuzu.yuzu_emu.adapters.GameAdapter
import org.yuzu.yuzu_emu.databinding.FragmentGridBinding
class PlatformGamesFragment : Fragment(), PlatformGamesView { class PlatformGamesFragment : Fragment(), PlatformGamesView {
private val presenter = PlatformGamesPresenter(this) private val presenter = PlatformGamesPresenter(this)
private var adapter: GameAdapter? = null private var adapter: GameAdapter? = null
private lateinit var recyclerView: RecyclerView
private lateinit var textView: TextView private var _binding: FragmentGridBinding? = null
private val binding get() = _binding!!
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup?, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View? { ): View {
val rootView = inflater.inflate(R.layout.fragment_grid, container, false)
findViews(rootView)
presenter.onCreateView() presenter.onCreateView()
return rootView _binding = FragmentGridBinding.inflate(inflater)
return binding.root
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@ -58,30 +56,34 @@ class PlatformGamesFragment : Fragment(), PlatformGamesView {
} }
view.viewTreeObserver.removeOnGlobalLayoutListener(this) view.viewTreeObserver.removeOnGlobalLayoutListener(this)
val layoutManager = GridLayoutManager(activity, columns) val layoutManager = GridLayoutManager(activity, columns)
recyclerView.layoutManager = layoutManager binding.gridGames.layoutManager = layoutManager
recyclerView.adapter = adapter binding.gridGames.adapter = adapter
} }
}) })
} }
// Add swipe down to refresh gesture // Add swipe down to refresh gesture
val pullToRefresh = view.findViewById<SwipeRefreshLayout>(R.id.swipe_refresh) binding.swipeRefresh.setOnRefreshListener {
pullToRefresh.setOnRefreshListener {
refresh() refresh()
pullToRefresh.isRefreshing = false binding.swipeRefresh.isRefreshing = false
} }
// Set theme color to the refresh animation's background // Set theme color to the refresh animation's background
pullToRefresh.setProgressBackgroundColorSchemeColor( binding.swipeRefresh.setProgressBackgroundColorSchemeColor(
MaterialColors.getColor(pullToRefresh, R.attr.colorPrimary) MaterialColors.getColor(binding.swipeRefresh, R.attr.colorPrimary)
) )
pullToRefresh.setColorSchemeColors( binding.swipeRefresh.setColorSchemeColors(
MaterialColors.getColor(pullToRefresh, R.attr.colorOnPrimary) MaterialColors.getColor(binding.swipeRefresh, R.attr.colorOnPrimary)
) )
setInsets() setInsets()
} }
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
override fun refresh() { override fun refresh() {
val databaseHelper = YuzuApplication.databaseHelper val databaseHelper = YuzuApplication.databaseHelper
databaseHelper!!.scanLibrary(databaseHelper.writableDatabase) databaseHelper!!.scanLibrary(databaseHelper.writableDatabase)
@ -97,17 +99,12 @@ class PlatformGamesFragment : Fragment(), PlatformGamesView {
} }
private fun updateTextView() { private fun updateTextView() {
textView.visibility = binding.gamelistEmptyText.visibility =
if (adapter!!.itemCount == 0) View.VISIBLE else View.GONE if (adapter!!.itemCount == 0) View.VISIBLE else View.GONE
} }
private fun findViews(root: View) {
recyclerView = root.findViewById(R.id.grid_games)
textView = root.findViewById(R.id.gamelist_empty_text)
}
private fun setInsets() { private fun setInsets() {
ViewCompat.setOnApplyWindowInsetsListener(recyclerView) { view: View, windowInsets: WindowInsetsCompat -> ViewCompat.setOnApplyWindowInsetsListener(binding.gridGames) { view: View, windowInsets: WindowInsetsCompat ->
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()) val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
view.updatePadding(bottom = insets.bottom) view.updatePadding(bottom = insets.bottom)
windowInsets windowInsets

View file

@ -3,33 +3,14 @@
package org.yuzu.yuzu_emu.viewholders package org.yuzu.yuzu_emu.viewholders
import android.view.View
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.databinding.CardGameBinding
import org.yuzu.yuzu_emu.model.Game
/** class GameViewHolder(val binding: CardGameBinding) : RecyclerView.ViewHolder(binding.root) {
* A simple class that stores references to views so that the GameAdapter doesn't need to lateinit var game: Game
* keep calling findViewById(), which is expensive.
*/
class GameViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var imageIcon: ImageView
var textGameTitle: TextView
var textGameCaption: TextView
var gameId: String? = null
// TODO Not need any of this stuff. Currently only the properties dialog needs it.
var path: String? = null
var title: String? = null
var description: String? = null
var regions: String? = null
var company: String? = null
init { init {
itemView.tag = this itemView.tag = this
imageIcon = itemView.findViewById(R.id.image_game_screen)
textGameTitle = itemView.findViewById(R.id.text_game_title)
textGameCaption = itemView.findViewById(R.id.text_game_caption)
} }
} }