diff --git a/Source/Android/app/build.gradle.kts b/Source/Android/app/build.gradle.kts index 1818fa50..dea6300f 100644 --- a/Source/Android/app/build.gradle.kts +++ b/Source/Android/app/build.gradle.kts @@ -9,6 +9,7 @@ android { buildFeatures { buildConfig = true + viewBinding = true } compileOptions { diff --git a/Source/Android/app/src/main/AndroidManifest.xml b/Source/Android/app/src/main/AndroidManifest.xml index dde254da..76e04636 100644 --- a/Source/Android/app/src/main/AndroidManifest.xml +++ b/Source/Android/app/src/main/AndroidManifest.xml @@ -14,6 +14,7 @@ + android:name=".ui.main.MainActivity"> @@ -41,25 +41,21 @@ + android:configChanges="orientation|keyboardHidden"/> + android:name=".activities.ConvertActivity" /> diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EditorActivity.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EditorActivity.kt index e5b5f00a..77517ebc 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EditorActivity.kt +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EditorActivity.kt @@ -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 { @@ -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) @@ -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 } } @@ -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) } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/MotionAlertDialog.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/MotionAlertDialog.kt index 728dc328..2efdc2aa 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/MotionAlertDialog.kt +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/MotionAlertDialog.kt @@ -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 @@ -24,7 +24,7 @@ class MotionAlertDialog */( context: Context?, // The selected input preference private val setting: InputBindingSetting -) : AlertDialog(context) { +) : AlertDialog(context!!) { private val previousValues = ArrayList() private var prevDeviceId = 0 private var waitingForEvent = true diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/RunningSettingDialog.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/RunningSettingDialog.kt index 4cc0ff59..34f56034 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/RunningSettingDialog.kt +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/RunningSettingDialog.kt @@ -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 @@ -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 @@ -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) { @@ -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) } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsAdapter.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsAdapter.kt index 826b0090..784e0197 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsAdapter.kt +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsAdapter.kt @@ -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 @@ -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 @@ -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 @@ -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 ) @@ -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() @@ -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() @@ -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(R.id.seekbar) + val view = inflater.inflate(R.layout.dialog_sliders, null) + val slider = view.findViewById(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() @@ -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) { @@ -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) { diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragment.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragment.kt index 0a98100f..6c9455e8 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragment.kt +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragment.kt @@ -10,6 +10,7 @@ import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager.SpanSizeLookup import androidx.recyclerview.widget.RecyclerView +import com.google.android.material.appbar.MaterialToolbar import org.dolphinemu.dolphinemu.R import org.dolphinemu.dolphinemu.features.settings.model.Settings import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem @@ -52,11 +53,15 @@ class SettingsFragment : Fragment(), SettingsFragmentView { val args = arguments val menuTag = args!!.getSerializable(ARGUMENT_MENU_TAG) as MenuTag? + val toolbar = view.findViewById(R.id.toolbar_settings) if (titles.containsKey(menuTag)) { - requireActivity().setTitle(titles[menuTag]!!) + toolbar.title = getString(titles[menuTag]!!) + } + + toolbar.setNavigationOnClickListener { + requireActivity().onBackPressed() } - //LinearLayoutManager manager = new LinearLayoutManager(mActivity); val recyclerView = view.findViewById(R.id.list_settings) val mgr = GridLayoutManager(settingsActivity, 2) @@ -74,12 +79,6 @@ class SettingsFragment : Fragment(), SettingsFragmentView { recyclerView.adapter = adapter recyclerView.layoutManager = mgr - recyclerView.addItemDecoration( - DividerItemDecoration( - requireContext(), - DividerItemDecoration.VERTICAL - ) - ) showSettingsList(settingsActivity!!.getSettings()) } @@ -125,7 +124,7 @@ class SettingsFragment : Fragment(), SettingsFragmentView { titles[MenuTag.GCPAD_TYPE] = R.string.grid_menu_gcpad_settings titles[MenuTag.GRAPHICS] = - R.string.grid_menu_graphics_settings + R.string.graphics_submenu titles[MenuTag.HACKS] = R.string.hacks_submenu titles[MenuTag.DEBUG] = R.string.debug_submenu titles[MenuTag.ENHANCEMENTS] = R.string.enhancements_submenu diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.kt index a9fa8bb8..92026a5c 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.kt +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.kt @@ -105,18 +105,10 @@ class SettingsFragmentPresenter private fun addConfigSettings(sl: ArrayList) { sl.add(SubmenuSetting(null, null, R.string.general_submenu, 0, MenuTag.CONFIG_GENERAL)) - sl.add( - SubmenuSetting( - null, - null, - R.string.grid_menu_graphics_settings, - 0, - MenuTag.GRAPHICS - ) - ) + sl.add(SubmenuSetting(null, null, R.string.interface_submenu, 0, MenuTag.CONFIG_INTERFACE)) + sl.add(SubmenuSetting(null, null, R.string.graphics_submenu, 0, MenuTag.GRAPHICS)) sl.add(SubmenuSetting(null, null, R.string.enhancements_submenu, 0, MenuTag.ENHANCEMENTS)) sl.add(SubmenuSetting(null, null, R.string.hacks_submenu, 0, MenuTag.HACKS)) - sl.add(SubmenuSetting(null, null, R.string.interface_submenu, 0, MenuTag.CONFIG_INTERFACE)) sl.add(SubmenuSetting(null, null, R.string.gamecube_submenu, 0, MenuTag.CONFIG_GAME_CUBE)) sl.add(SubmenuSetting(null, null, R.string.wii_submenu, 0, MenuTag.CONFIG_WII)) sl.add(SubmenuSetting(null, null, R.string.debug_submenu, 0, MenuTag.DEBUG)) diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/CheckBoxSettingViewHolder.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/SwitchSettingViewHolder.kt similarity index 72% rename from Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/CheckBoxSettingViewHolder.kt rename to Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/SwitchSettingViewHolder.kt index 4a1538e9..7c593918 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/CheckBoxSettingViewHolder.kt +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/SwitchSettingViewHolder.kt @@ -1,26 +1,25 @@ package org.dolphinemu.dolphinemu.features.settings.ui.viewholder import android.view.View -import android.widget.CheckBox import android.widget.TextView +import com.google.android.material.materialswitch.MaterialSwitch import org.dolphinemu.dolphinemu.R import org.dolphinemu.dolphinemu.features.settings.model.view.CheckBoxSetting import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter -class CheckBoxSettingViewHolder(itemView: View, adapter: SettingsAdapter) : +class SwitchSettingViewHolder(itemView: View, adapter: SettingsAdapter) : SettingViewHolder(itemView, adapter) { private var item: CheckBoxSetting? = null private var textSettingName: TextView? = null private var textSettingDescription: 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) textSettingDescription = root.findViewById(R.id.text_setting_description) - checkbox = root.findViewById(R.id.checkbox) + switchWidget = root.findViewById(R.id.switch_widget) } override fun bind(item: SettingsItem) { @@ -29,11 +28,11 @@ class CheckBoxSettingViewHolder(itemView: View, adapter: SettingsAdapter) : if (item.getDescriptionId() > 0) { textSettingDescription!!.setText(item.getDescriptionId()) } - checkbox!!.isChecked = this.item!!.isChecked + switchWidget!!.isChecked = this.item!!.isChecked } override fun onClick(clicked: View) { - checkbox!!.toggle() - adapter.onBooleanClick(item!!, adapterPosition, checkbox!!.isChecked) + switchWidget!!.toggle() + adapter.onBooleanClick(item!!, adapterPosition, switchWidget!!.isChecked) } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.kt index e64016d5..e22d75bb 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.kt +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.kt @@ -8,7 +8,10 @@ import android.content.pm.PackageManager import android.os.Bundle import android.preference.PreferenceManager import android.view.Menu +import android.view.View import android.view.MenuItem +import android.view.ViewGroup.MarginLayoutParams +import android.widget.PopupMenu import android.widget.Toast import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity @@ -17,6 +20,10 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.RecyclerView +import androidx.core.view.ViewCompat +import androidx.core.view.WindowCompat +import androidx.core.view.WindowInsetsCompat +import androidx.core.view.updatePadding import org.dolphinemu.dolphinemu.R import org.dolphinemu.dolphinemu.activities.EmulationActivity.Companion.launch import org.dolphinemu.dolphinemu.adapters.GameAdapter @@ -30,6 +37,7 @@ import org.dolphinemu.dolphinemu.utils.FileBrowserHelper import org.dolphinemu.dolphinemu.utils.PermissionsHandler import org.dolphinemu.dolphinemu.utils.StartupHandler import org.dolphinemu.dolphinemu.utils.ThemeUtil +import org.dolphinemu.dolphinemu.databinding.ActivityMainBinding import java.io.File import java.util.Arrays @@ -38,10 +46,8 @@ import java.util.Arrays * individually display a grid of available games for each Fragment, in a tabbed layout. */ class MainActivity : AppCompatActivity() { - private var divider: DividerItemDecoration? = null - private var gameList: RecyclerView? = null - private var adapter: GameAdapter? = null - private var toolbar: Toolbar? = null + private val binding by lazy { ActivityMainBinding.inflate(layoutInflater) } + private var adapter: GameAdapter? = GameAdapter() private var broadcastReceiver: BroadcastReceiver? = null private var dirToAdd: String? = null @@ -49,11 +55,24 @@ class MainActivity : AppCompatActivity() { ThemeUtil.applyTheme() super.onCreate(savedInstanceState) - setContentView(R.layout.activity_main) + setContentView(binding.root) - findViews() - setSupportActionBar(toolbar) - title = String(TITLE_BYTES) + WindowCompat.setDecorFitsSystemWindows(window, false) + + setInsets() + + val pref = PreferenceManager.getDefaultSharedPreferences(this) + binding.gridGames.setAdapter(adapter) + refreshGameList(pref.getBoolean(PREF_GAMELIST, true)) + + binding.appBarLayout.apply { + binding.listingType.setOnClickListener { toggleGameList() } + binding.settingsIcon.setOnClickListener { launchSettingsActivity(MenuTag.CONFIG) } + binding.moreOptions.setOnClickListener { showMoreOptions(it) } + } + + // TODO: make it to add games instead of folders + binding.add.setOnClickListener { launchFileListActivity() } val filter = IntentFilter() filter.addAction(GameFileCacheService.BROADCAST_ACTION) @@ -89,17 +108,6 @@ class MainActivity : AppCompatActivity() { ) } - // TODO: Replace with a ButterKnife injection. - private fun findViews() { - val pref = PreferenceManager.getDefaultSharedPreferences(this) - divider = DividerItemDecoration(this, DividerItemDecoration.VERTICAL) - toolbar = findViewById(R.id.toolbar_main) - gameList = findViewById(R.id.grid_games) - adapter = GameAdapter() - gameList!!.setAdapter(adapter) - refreshGameList(pref.getBoolean(PREF_GAMELIST, true)) - } - private fun refreshGameList(flag: Boolean) { val resourceId: Int var columns = resources.getInteger(R.integer.game_grid_columns) @@ -107,15 +115,13 @@ class MainActivity : AppCompatActivity() { if (flag) { resourceId = R.layout.card_game layoutManager = GridLayoutManager(this, columns) - gameList!!.addItemDecoration(divider!!) } else { columns = columns * 2 + 1 resourceId = R.layout.card_game2 layoutManager = GridLayoutManager(this, columns) - gameList!!.removeItemDecoration(divider!!) } adapter!!.setResourceId(resourceId) - gameList!!.layoutManager = layoutManager + binding.gridGames.layoutManager = layoutManager } private fun toggleGameList() { @@ -125,58 +131,35 @@ class MainActivity : AppCompatActivity() { refreshGameList(flag) } - override fun onCreateOptionsMenu(menu: Menu): Boolean { - val inflater = menuInflater - inflater.inflate(R.menu.menu_game_grid, menu) - return true - } - - override fun onOptionsItemSelected(item: MenuItem): Boolean { - when (item.itemId) { - R.id.menu_add_directory -> { - launchFileListActivity() - return true - } - - R.id.menu_toggle_list -> { - toggleGameList() - return true - } - - R.id.menu_settings_core -> { - launchSettingsActivity(MenuTag.CONFIG) - return true - } - - R.id.menu_settings_gcpad -> { - launchSettingsActivity(MenuTag.GCPAD_TYPE) - return true - } - - R.id.menu_settings_wiimote -> { - launchSettingsActivity(MenuTag.WIIMOTE) - return true - } - - R.id.menu_clear_data -> { - clearGameData(this) - return true - } - - R.id.menu_refresh -> { - GameFileCacheService.startRescan(this) - return true - } - - R.id.menu_open_file -> { - launchOpenFileActivity() - return true - } + private fun setInsets() = + ViewCompat.setOnApplyWindowInsetsListener( + binding.root + ) { _: View, windowInsets: WindowInsetsCompat -> + val barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()) + val cutoutInsets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout()) + val leftInsets = barInsets.left + cutoutInsets.left + val rightInsets = barInsets.right + cutoutInsets.right + + val appBar = binding.appBarLayout.layoutParams as MarginLayoutParams + appBar.leftMargin = leftInsets + appBar.rightMargin = rightInsets + binding.appBarLayout.layoutParams = appBar + + binding.gridGames.updatePadding( + left = leftInsets, + right = rightInsets, + bottom = barInsets.bottom + ) + val fab = binding.add.layoutParams as MarginLayoutParams + val fabPadding = resources.getDimensionPixelSize(R.dimen.spacing_large) + fab.leftMargin = leftInsets + fabPadding + fab.bottomMargin = barInsets.bottom + fabPadding + fab.rightMargin = rightInsets + fabPadding + binding.add.layoutParams = fab + + windowInsets } - return false - } - private fun launchSettingsActivity(menuTag: MenuTag?) { SettingsActivity.launch(this, menuTag, "") } @@ -303,28 +286,43 @@ class MainActivity : AppCompatActivity() { adapter!!.swapDataSet(GameFileCacheService.getAllGameFiles()) } + private fun showMoreOptions(view: View) { + PopupMenu(this, view).apply { + menuInflater.inflate(R.menu.menu_main_more, menu) + setOnMenuItemClickListener { item -> + when (item.itemId) { + R.id.menu_settings_gcpad -> { + launchSettingsActivity(MenuTag.GCPAD_TYPE) + true + } + R.id.menu_settings_wiimote -> { + launchSettingsActivity(MenuTag.WIIMOTE) + true + } + R.id.menu_clear_data -> { + clearGameData(view.context) + true + } + R.id.menu_refresh -> { + GameFileCacheService.startRescan(view.context) + true + } + + R.id.menu_open_file -> { + launchOpenFileActivity() + true + } + else -> false + } + } + show() + } + } + companion object { const val REQUEST_ADD_DIRECTORY = 1 const val REQUEST_OPEN_FILE = 2 const val REQUEST_GPU_DRIVER = 3 private const val PREF_GAMELIST = "GAME_LIST_TYPE" - private val TITLE_BYTES = byteArrayOf( - 0x44, - 0x6f, - 0x6c, - 0x70, - 0x68, - 0x69, - 0x6e, - 0x20, - 0x35, - 0x2e, - 0x30, - 0x28, - 0x4d, - 0x4d, - 0x4a, - 0x29 - ) } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/DirectoryInitialization.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/DirectoryInitialization.java index 64c8fa50..16d31701 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/DirectoryInitialization.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/DirectoryInitialization.java @@ -96,7 +96,7 @@ private static boolean setDolphinUserDirectory(Context context) if (externalPath == null) return false; - File userPath = new File(externalPath, "dolphin-mmj"); + File userPath = new File(externalPath, "dolphin-enhanced"); if (!userPath.isDirectory() && !userPath.mkdir()) { return false; diff --git a/Source/Android/app/src/main/res/drawable-hdpi/ic_add.png b/Source/Android/app/src/main/res/drawable-hdpi/ic_add.png deleted file mode 100644 index 4006b497..00000000 Binary files a/Source/Android/app/src/main/res/drawable-hdpi/ic_add.png and /dev/null differ diff --git a/Source/Android/app/src/main/res/drawable-xhdpi/ic_add.png b/Source/Android/app/src/main/res/drawable-xhdpi/ic_add.png deleted file mode 100644 index eb6e9be6..00000000 Binary files a/Source/Android/app/src/main/res/drawable-xhdpi/ic_add.png and /dev/null differ diff --git a/Source/Android/app/src/main/res/drawable-xxhdpi/ic_add.png b/Source/Android/app/src/main/res/drawable-xxhdpi/ic_add.png deleted file mode 100644 index a82ed819..00000000 Binary files a/Source/Android/app/src/main/res/drawable-xxhdpi/ic_add.png and /dev/null differ diff --git a/Source/Android/app/src/main/res/drawable-xxxhdpi/ic_add.png b/Source/Android/app/src/main/res/drawable-xxxhdpi/ic_add.png deleted file mode 100644 index 21e9f6e0..00000000 Binary files a/Source/Android/app/src/main/res/drawable-xxxhdpi/ic_add.png and /dev/null differ diff --git a/Source/Android/app/src/main/res/drawable/ic_add.xml b/Source/Android/app/src/main/res/drawable/ic_add.xml new file mode 100644 index 00000000..c0a21e54 --- /dev/null +++ b/Source/Android/app/src/main/res/drawable/ic_add.xml @@ -0,0 +1,11 @@ + + + + diff --git a/Source/Android/app/src/main/res/drawable/ic_back.xml b/Source/Android/app/src/main/res/drawable/ic_back.xml new file mode 100644 index 00000000..dfae1514 --- /dev/null +++ b/Source/Android/app/src/main/res/drawable/ic_back.xml @@ -0,0 +1,10 @@ + + + + diff --git a/Source/Android/app/src/main/res/drawable/ic_grid.xml b/Source/Android/app/src/main/res/drawable/ic_grid.xml new file mode 100644 index 00000000..4ed5d1eb --- /dev/null +++ b/Source/Android/app/src/main/res/drawable/ic_grid.xml @@ -0,0 +1,10 @@ + + + diff --git a/Source/Android/app/src/main/res/drawable/ic_more.xml b/Source/Android/app/src/main/res/drawable/ic_more.xml new file mode 100644 index 00000000..fce2d499 --- /dev/null +++ b/Source/Android/app/src/main/res/drawable/ic_more.xml @@ -0,0 +1,10 @@ + + + + diff --git a/Source/Android/app/src/main/res/layout-w680dp-land/activity_convert.xml b/Source/Android/app/src/main/res/layout-w680dp-land/activity_convert.xml index ad419e68..bd37c3de 100644 --- a/Source/Android/app/src/main/res/layout-w680dp-land/activity_convert.xml +++ b/Source/Android/app/src/main/res/layout-w680dp-land/activity_convert.xml @@ -3,7 +3,6 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:fillViewport="true" - android:background="@color/dolphin_background" xmlns:app="http://schemas.android.com/apk/res-auto"> + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="match_parent"> @@ -57,8 +53,6 @@ android:text="@android:string/cancel" android:id="@+id/button_cancel" style="@style/Widget.MaterialComponents.Button.TextButton" - android:backgroundTint="@color/dolphin" - android:textColor="@android:color/white" android:textAllCaps="false" android:layout_width="match_parent" android:layout_height="wrap_content" @@ -70,8 +64,6 @@ android:text="@string/cheat_list" android:id="@+id/button_confirm" style="@style/Widget.MaterialComponents.Button.TextButton" - android:backgroundTint="@color/dolphin" - android:textColor="@android:color/white" android:textAllCaps="false" android:layout_width="match_parent" android:layout_height="wrap_content" diff --git a/Source/Android/app/src/main/res/layout/activity_main.xml b/Source/Android/app/src/main/res/layout/activity_main.xml index e9f372e2..9afbe30c 100644 --- a/Source/Android/app/src/main/res/layout/activity_main.xml +++ b/Source/Android/app/src/main/res/layout/activity_main.xml @@ -1,23 +1,131 @@ - - - + - + android:layout_height="match_parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + diff --git a/Source/Android/app/src/main/res/layout/activity_settings.xml b/Source/Android/app/src/main/res/layout/activity_settings.xml index 349a590e..492fbf04 100644 --- a/Source/Android/app/src/main/res/layout/activity_settings.xml +++ b/Source/Android/app/src/main/res/layout/activity_settings.xml @@ -2,5 +2,4 @@ + android:id="@+id/frame_content"/> diff --git a/Source/Android/app/src/main/res/layout/card_game.xml b/Source/Android/app/src/main/res/layout/card_game.xml index f48af4d7..3ebe6efc 100644 --- a/Source/Android/app/src/main/res/layout/card_game.xml +++ b/Source/Android/app/src/main/res/layout/card_game.xml @@ -4,17 +4,17 @@ xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content" + style="?attr/materialCardViewOutlinedStyle" android:transitionName="card_game" + android:layout_margin="8dp" android:focusable="true" android:clickable="true" - app:cardElevation="0dp" android:foreground="?android:attr/selectableItemBackground"> + android:layout_height="match_parent"> - - + android:layout_height="match_parent"> - - - - - - - + + + + + + - - + + + + + + + + + + + android:layout_alignBottom="@id/image_game_screen" + android:layout_marginTop="8dp" + android:layout_toEndOf="@id/image_game_screen" + android:orientation="horizontal"> + +