Skip to content

Commit

Permalink
ui(refactor pt.1): Migrate base app theme, settingsAdapter, `MainAc…
Browse files Browse the repository at this point in the history
…tivity` to material3 (#25)

* Update main app style to material 3

* Migrate checkboxes to material switches

SettingsAdapter and RunningSettingsDialog only

* Move dialogs to Material3 Dialogs

* Update seekbars to Material3 Sliders

* Fix Mem1 and Mem2 sliders

* Update SettingsAdapter item and header styling

* Readd headerBar

* [WIP] Use Material3 Sliders on CheatsActivity

* Migrate to themes.xml

* androidManifest: use new theme

* Remove hardcoded colors

* Don't use accent color for status bar

* activity_main: fix light mode action bar

* fragment_convert: fix checkbox

* dialog_game_details: some fixes

* themes: remove redundant attrs

* build.gradle.kts: enable viewBinding

* Update MainActivity to material3

* Change app name and userDir name to dolphin-enhanced

* MainActivity: Remove Item Divider

* fix appBar height

* activity_main: Add fab to add games

* Move input bindings to seperate settings section

* Revert input bindings back to legacy dialog

* Improve MainActivity header

* Improve SettingsAdapter headerBar

* dialog_game_details: try to make it scrollable

* Readd `Run File` & `Clear Cache` action

* activity_editor: fix toolbar title color

* Fix editor icon

* Rework MainActivity itilebar layout

* Update activity_main.xml

* Rework icons on MainActivity header

* Small cleanup

* Cleanup & rework some stuff

* Minor rebrand to convert dialog

* MotionAlertDialog: migrate to MaterialAlertDialog

* wrage

* Update MotionAlertDialog.kt

* Update MotionAlertDialog.kt

* Update MotionAlertDialog.kt

* Update themes.xml

* Update themes.xml

* Update MotionAlertDialog.kt

* Limit the slider's input field value to match the sliders steps

* Fix invalid value string in dialogs and tweak padding

* Minor re-tick

---------

Co-authored-by: Ishan09811 <[email protected]>
Co-authored-by: Gamer64 <[email protected]>
  • Loading branch information
3 people authored Feb 7, 2025
1 parent c1efcbf commit 4a7d978
Show file tree
Hide file tree
Showing 44 changed files with 892 additions and 768 deletions.
1 change: 1 addition & 0 deletions Source/Android/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ android {

buildFeatures {
buildConfig = true
viewBinding = true
}

compileOptions {
Expand Down
12 changes: 4 additions & 8 deletions Source/Android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
<application
android:name=".DolphinApplication"
android:label="@string/app_name"
android:theme="@style/Theme.DolphinEmu.Main"
android:icon="@mipmap/ic_launcher"
android:requestLegacyExternalStorage="true"
android:networkSecurityConfig="@xml/network_security_config"
Expand All @@ -24,8 +25,7 @@
<meta-data android:name="android.max_aspect" android:value="2.1" />

<activity
android:name=".ui.main.MainActivity"
android:theme="@style/DolphinBase">
android:name=".ui.main.MainActivity">

<intent-filter>
<action android:name="android.intent.action.VIEW" />
Expand All @@ -41,25 +41,21 @@

<activity
android:name=".features.settings.ui.SettingsActivity"
android:theme="@style/DolphinSettingsBase"
android:label="@string/preferences_settings"/>

<activity
android:screenOrientation="userLandscape"
android:name=".activities.EmulationActivity"
android:theme="@style/DolphinEmulationBase"
android:preferMinimalPostProcessing="true"/>

<activity
android:name=".activities.EditorActivity"
android:label="@string/app_name"
android:windowSoftInputMode="adjustUnspecified|stateHidden"
android:configChanges="orientation|keyboardHidden"
android:theme="@style/DolphinBase"/>
android:configChanges="orientation|keyboardHidden"/>

<activity
android:name=".activities.ConvertActivity"
android:theme="@style/DolphinBase" />
android:name=".activities.ConvertActivity" />

<service android:name=".services.GameFileCacheService"/>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import java.io.IOException
import java.io.InputStreamReader
import java.io.StringReader
import java.lang.ref.WeakReference
import com.google.android.material.materialswitch.MaterialSwitch

class EditorActivity : AppCompatActivity() {
class CheatEntry {
Expand Down Expand Up @@ -278,7 +279,7 @@ class EditorActivity : AppCompatActivity() {
private val textName: TextView = itemView.findViewById(R.id.text_setting_name)
private val textDescription: TextView =
itemView.findViewById(R.id.text_setting_description)
private val checkbox: CheckBox = itemView.findViewById(R.id.checkbox)
private val switch: MaterialSwitch = itemView.findViewById(R.id.switch_widget)

init {
itemView.setOnClickListener(this)
Expand All @@ -288,12 +289,12 @@ class EditorActivity : AppCompatActivity() {
model = entry
textName.text = entry.name
textDescription.text = entry.info
checkbox.isChecked = entry.active
switch.isChecked = entry.active
}

override fun onClick(v: View) {
toggleCheatEntry(model!!)
checkbox.isChecked = model!!.active
switch.isChecked = model!!.active
}
}

Expand All @@ -302,7 +303,7 @@ class EditorActivity : AppCompatActivity() {

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CheatEntryViewHolder {
val inflater = LayoutInflater.from(parent.context)
val itemView = inflater.inflate(R.layout.list_item_setting_checkbox, parent, false)
val itemView = inflater.inflate(R.layout.list_item_setting_switch, parent, false)
return CheatEntryViewHolder(itemView)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package org.dolphinemu.dolphinemu.dialogs

import android.app.AlertDialog
import android.content.Context
import android.view.InputDevice
import android.view.InputDevice.MotionRange
import android.view.KeyEvent
import android.view.MotionEvent
import androidx.appcompat.app.AlertDialog
import org.dolphinemu.dolphinemu.features.settings.model.view.InputBindingSetting
import org.dolphinemu.dolphinemu.utils.ControllerMappingHelper
import org.dolphinemu.dolphinemu.utils.Log
Expand All @@ -24,7 +24,7 @@ class MotionAlertDialog
*/(
context: Context?, // The selected input preference
private val setting: InputBindingSetting
) : AlertDialog(context) {
) : AlertDialog(context!!) {
private val previousValues = ArrayList<Float>()
private var prevDeviceId = 0
private var waitingForEvent = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import android.preference.PreferenceManager
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.CheckBox
import android.widget.CompoundButton
import android.widget.RadioButton
import android.widget.RadioGroup
Expand All @@ -21,6 +20,7 @@ import androidx.fragment.app.DialogFragment
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.materialswitch.MaterialSwitch
import org.dolphinemu.dolphinemu.NativeLibrary
import org.dolphinemu.dolphinemu.R
import org.dolphinemu.dolphinemu.activities.EmulationActivity
Expand Down Expand Up @@ -154,23 +154,23 @@ class RunningSettingDialog : DialogFragment() {
CompoundButton.OnCheckedChangeListener {
var item: SettingsItem? = null
private var textSettingName: TextView? = null
private var checkbox: CheckBox? = null
private var switchWidget: MaterialSwitch? = null

override fun findViews(root: View) {
textSettingName = root.findViewById(R.id.text_setting_name)
checkbox = root.findViewById(R.id.checkbox)
checkbox!!.setOnCheckedChangeListener(this)
switchWidget = root.findViewById(R.id.switch_widget)
switchWidget!!.setOnCheckedChangeListener(this)
}

override fun bind(item: SettingsItem) {
this.item = item
textSettingName!!.text = item.name
checkbox!!.isChecked = this.item!!.value > 0
switchWidget!!.isChecked = this.item!!.value > 0
}

override fun onClick(clicked: View) {
checkbox!!.toggle()
item!!.value = if (checkbox!!.isChecked) 1 else 0
switchWidget!!.toggle()
item!!.value = if (switchWidget!!.isChecked) 1 else 0
}

override fun onCheckedChanged(view: CompoundButton, isChecked: Boolean) {
Expand Down Expand Up @@ -575,7 +575,7 @@ class RunningSettingDialog : DialogFragment() {
val inflater = LayoutInflater.from(parent.context)
when (viewType) {
TYPE_CHECKBOX -> {
itemView = inflater.inflate(R.layout.list_item_running_checkbox, parent, false)
itemView = inflater.inflate(R.layout.list_item_running_switch, parent, false)
return CheckBoxSettingViewHolder(itemView)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ import android.widget.SeekBar
import android.widget.SeekBar.OnSeekBarChangeListener
import androidx.appcompat.app.AlertDialog
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.textfield.TextInputEditText
import com.google.android.material.textfield.TextInputLayout
import com.google.android.material.slider.Slider
import org.dolphinemu.dolphinemu.R
import org.dolphinemu.dolphinemu.dialogs.MotionAlertDialog
import org.dolphinemu.dolphinemu.features.settings.model.Settings
Expand All @@ -27,7 +29,7 @@ import org.dolphinemu.dolphinemu.features.settings.model.view.SingleChoiceSettin
import org.dolphinemu.dolphinemu.features.settings.model.view.SliderSetting
import org.dolphinemu.dolphinemu.features.settings.model.view.StringSingleChoiceSetting
import org.dolphinemu.dolphinemu.features.settings.model.view.SubmenuSetting
import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.CheckBoxSettingViewHolder
import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.SwitchSettingViewHolder
import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.HeaderViewHolder
import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.InputBindingSettingViewHolder
import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.RumbleBindingViewHolder
Expand All @@ -49,6 +51,7 @@ class SettingsAdapter(private val activity: SettingsActivity) :
private var seekbarProgress = 0

private var dialog: AlertDialog? = null
private var inputDialog: MotionAlertDialog? = null
private var textSliderValue: TextInputEditText? = null
private var textInputLayout: TextInputLayout? = null

Expand All @@ -70,8 +73,8 @@ class SettingsAdapter(private val activity: SettingsActivity) :
}

SettingsItem.TYPE_CHECKBOX -> {
view = inflater.inflate(R.layout.list_item_setting_checkbox, parent, false)
return CheckBoxSettingViewHolder(
view = inflater.inflate(R.layout.list_item_setting_switch, parent, false)
return SwitchSettingViewHolder(
view,
this
)
Expand Down Expand Up @@ -152,7 +155,7 @@ class SettingsAdapter(private val activity: SettingsActivity) :
clickedPosition = position

val value = getSelectionForSingleChoiceValue(item)
val builder = AlertDialog.Builder(activity)
val builder = MaterialAlertDialogBuilder(activity)
builder.setTitle(item.nameId)
builder.setSingleChoiceItems(item.choicesId, value, this)
dialog = builder.show()
Expand All @@ -162,7 +165,7 @@ class SettingsAdapter(private val activity: SettingsActivity) :
clickedItem = item
clickedPosition = position

val builder = AlertDialog.Builder(activity)
val builder = MaterialAlertDialogBuilder(activity)
builder.setTitle(item.nameId)
builder.setSingleChoiceItems(item.choicesId, item.selectValueIndex, this)
dialog = builder.show()
Expand All @@ -180,17 +183,18 @@ class SettingsAdapter(private val activity: SettingsActivity) :
clickedItem = item
clickedPosition = position
seekbarProgress = item.selectedValue
val builder = AlertDialog.Builder(activity)

val builder = MaterialAlertDialogBuilder(activity)
val inflater = LayoutInflater.from(activity)
val view = inflater.inflate(R.layout.dialog_seekbar, null)
val seekbar = view.findViewById<SeekBar>(R.id.seekbar)
val view = inflater.inflate(R.layout.dialog_sliders, null)
val slider = view.findViewById<Slider>(R.id.slider)

builder.setTitle(item.nameId)
builder.setView(view)
builder.setPositiveButton(android.R.string.ok, this)
builder.setNeutralButton(R.string.slider_default) { dialog: DialogInterface?, which: Int ->
seekbar.progress = item.getDefaultValue()
slider.value = item.getDefaultValue().toFloat()
seekbarProgress = item.getDefaultValue()
onClick(dialog!!, which)
}
dialog = builder.show()
Expand All @@ -200,43 +204,43 @@ class SettingsAdapter(private val activity: SettingsActivity) :
textSliderValue!!.setText(seekbarProgress.toString())
textInputLayout!!.suffixText = item.units

seekbar.max = item.max
seekbar.progress = seekbarProgress
seekbar.keyProgressIncrement = 5
slider.valueFrom = 0f
slider.valueTo = item.max.toFloat()
slider.value = seekbarProgress.toFloat()

textSliderValue!!.addTextChangedListener( object : TextWatcher {
// 128 avoids 5 step skipping on MEM2 Size setting
slider.stepSize = when {
item.max > 128 -> 5f
else -> 1f
}

textSliderValue!!.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable) {
val textValue = s.toString().toIntOrNull();
val textValue = s.toString().toIntOrNull()
// workaround to maintain SDK 24 support
// we just use a 0 instead of seekbar.getMin()
if (textValue == null || textValue < 0 || textValue > item.max) {
textInputLayout!!.error = "Inappropriate value"
// we just use textValue < 0 instead of textValue < seekbar.getMin()
if (textValue == null || textValue < 0 || textValue > item.max || textValue % slider.stepSize.toInt() != 0) {
textInputLayout!!.error = activity.getString(R.string.invalid_value)
} else {
textInputLayout!!.error = null
seekbarProgress = textValue
if (slider.value.toInt() != textValue) {
slider.value = textValue.toFloat()
}
}
}
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
})

seekbar.setOnSeekBarChangeListener(object : OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
// seekBar.max > 128 avoids 5 step skipping for MEM1 & MEM2 Size settings
seekbarProgress = if (seekBar.max > 128) ((progress / 5) * 5) else progress

if (textSliderValue!!.text.toString() != seekBar.toString()) {
textSliderValue!!.setText(seekbarProgress.toString())
textSliderValue!!.setSelection(textSliderValue!!.length())
}
slider.addOnChangeListener { _, value, _ ->
val progress = value.toInt()
seekbarProgress = progress
if (textSliderValue!!.text.toString() != progress.toString()) {
textSliderValue!!.setText(progress.toString())
textSliderValue!!.setSelection(textSliderValue!!.length())
}

override fun onStartTrackingTouch(seekBar: SeekBar) {
}

override fun onStopTrackingTouch(seekBar: SeekBar) {
}
})
}
}

fun onSubmenuClick(item: SubmenuSetting) {
Expand All @@ -253,33 +257,34 @@ class SettingsAdapter(private val activity: SettingsActivity) :
clickedItem = item
clickedPosition = position

val dialog = MotionAlertDialog(activity, item)
dialog.setTitle(R.string.input_binding)
dialog.setMessage(
getFormatString(
if (item is RumbleBindingSetting) R.string.input_rumble_description else R.string.input_binding_description,
activity.getString(item.nameId)
inputDialog = MotionAlertDialog(activity, item).apply {
setTitle(R.string.input_binding)
setMessage(
getFormatString(
if (item is RumbleBindingSetting)
R.string.input_rumble_description
else
R.string.input_binding_description,
activity.getString(item.nameId)
)
)
)
dialog.setButton(
AlertDialog.BUTTON_NEGATIVE, activity.getString(android.R.string.cancel),
this
)
dialog.setButton(
AlertDialog.BUTTON_NEUTRAL, activity.getString(R.string.clear)
) { _: DialogInterface?, _: Int ->
val preferences =
PreferenceManager.getDefaultSharedPreferences(activity)
item.clearValue()
}
dialog.setOnDismissListener {
val setting = StringSetting(item.key, item.section, item.value)
notifyItemChanged(position)
activity.putSetting(setting)
activity.setSettingChanged()
setButton(DialogInterface.BUTTON_NEGATIVE,
activity.getString(android.R.string.cancel)) { dialog, _ ->
dialog.dismiss()
}
setButton(DialogInterface.BUTTON_NEUTRAL,
activity.getString(R.string.clear)) { _, _ ->
item.clearValue()
}
setOnDismissListener {
val setting = StringSetting(item.key, item.section, item.value)
notifyItemChanged(position)
activity.putSetting(setting)
activity.setSettingChanged()
}
setCanceledOnTouchOutside(false)
}
dialog.setCanceledOnTouchOutside(false)
dialog.show()
inputDialog?.show()
}

override fun onClick(dialog: DialogInterface, which: Int) {
Expand Down
Loading

0 comments on commit 4a7d978

Please sign in to comment.