Android: Use view binding

This commit is contained in:
Charles Lombardo 2022-09-23 19:55:52 -04:00
parent 063c2739b3
commit 5c30f65bbb
54 changed files with 815 additions and 949 deletions

View File

@ -4,6 +4,8 @@ android {
compileSdkVersion 33 compileSdkVersion 33
ndkVersion "25.0.8775105" ndkVersion "25.0.8775105"
viewBinding.enabled = true
compileOptions { compileOptions {
// Flag to enable support for the new language APIs // Flag to enable support for the new language APIs
coreLibraryDesugaringEnabled true coreLibraryDesugaringEnabled true

View File

@ -5,17 +5,12 @@ package org.dolphinemu.dolphinemu.activities;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.view.View;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.core.view.WindowCompat; import androidx.core.view.WindowCompat;
import androidx.core.widget.NestedScrollView;
import com.google.android.material.appbar.AppBarLayout;
import com.google.android.material.appbar.CollapsingToolbarLayout;
import com.google.android.material.appbar.MaterialToolbar;
import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.databinding.ActivityConvertBinding;
import org.dolphinemu.dolphinemu.fragments.ConvertFragment; import org.dolphinemu.dolphinemu.fragments.ConvertFragment;
import org.dolphinemu.dolphinemu.utils.InsetsHelper; import org.dolphinemu.dolphinemu.utils.InsetsHelper;
import org.dolphinemu.dolphinemu.utils.ThemeHelper; import org.dolphinemu.dolphinemu.utils.ThemeHelper;
@ -38,7 +33,8 @@ public class ConvertActivity extends AppCompatActivity
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_convert); ActivityConvertBinding binding = ActivityConvertBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
WindowCompat.setDecorFitsSystemWindows(getWindow(), false); WindowCompat.setDecorFitsSystemWindows(getWindow(), false);
@ -52,17 +48,13 @@ public class ConvertActivity extends AppCompatActivity
getSupportFragmentManager().beginTransaction().add(R.id.fragment_convert, fragment).commit(); getSupportFragmentManager().beginTransaction().add(R.id.fragment_convert, fragment).commit();
} }
MaterialToolbar tb = findViewById(R.id.toolbar_convert); binding.toolbarConvertLayout.setTitle(getString(R.string.convert_convert));
CollapsingToolbarLayout ctb = findViewById(R.id.toolbar_convert_layout); setSupportActionBar(binding.toolbarConvert);
ctb.setTitle(getString(R.string.convert_convert));
setSupportActionBar(tb);
getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setDisplayHomeAsUpEnabled(true);
AppBarLayout appBarLayout = findViewById(R.id.appbar_convert); InsetsHelper.setUpAppBarWithScrollView(this, binding.appbarConvert, binding.scrollViewConvert,
NestedScrollView scrollView = findViewById(R.id.scroll_view_convert); binding.workaroundView);
View workaroundView = findViewById(R.id.workaround_view); ThemeHelper.enableScrollTint(this, binding.toolbarConvert, binding.appbarConvert);
InsetsHelper.setUpAppBarWithScrollView(this, appBarLayout, scrollView, workaroundView);
ThemeHelper.enableScrollTint(this, tb, appBarLayout);
} }
@Override @Override

View File

@ -13,7 +13,6 @@ import android.preference.PreferenceManager;
import android.util.SparseIntArray; import android.util.SparseIntArray;
import android.view.InputDevice; import android.view.InputDevice;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.MotionEvent; import android.view.MotionEvent;
@ -33,6 +32,9 @@ import androidx.fragment.app.FragmentManager;
import org.dolphinemu.dolphinemu.NativeLibrary; import org.dolphinemu.dolphinemu.NativeLibrary;
import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.databinding.ActivityEmulationBinding;
import org.dolphinemu.dolphinemu.databinding.DialogInputAdjustBinding;
import org.dolphinemu.dolphinemu.databinding.DialogIrSensitivityBinding;
import org.dolphinemu.dolphinemu.features.settings.model.BooleanSetting; import org.dolphinemu.dolphinemu.features.settings.model.BooleanSetting;
import org.dolphinemu.dolphinemu.features.settings.model.IntSetting; import org.dolphinemu.dolphinemu.features.settings.model.IntSetting;
import org.dolphinemu.dolphinemu.features.settings.model.Settings; import org.dolphinemu.dolphinemu.features.settings.model.Settings;
@ -62,7 +64,6 @@ import java.util.List;
import static java.lang.annotation.RetentionPolicy.SOURCE; import static java.lang.annotation.RetentionPolicy.SOURCE;
import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.slider.LabelFormatter;
import com.google.android.material.slider.Slider; import com.google.android.material.slider.Slider;
public final class EmulationActivity extends AppCompatActivity implements ThemeProvider public final class EmulationActivity extends AppCompatActivity implements ThemeProvider
@ -338,7 +339,8 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP
Rumble.initRumble(this); Rumble.initRumble(this);
setContentView(R.layout.activity_emulation); ActivityEmulationBinding binding = ActivityEmulationBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
// Find or create the EmulationFragment // Find or create the EmulationFragment
mEmulationFragment = (EmulationFragment) getSupportFragmentManager() mEmulationFragment = (EmulationFragment) getSupportFragmentManager()
@ -905,11 +907,10 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP
private void adjustScale() private void adjustScale()
{ {
LayoutInflater inflater = LayoutInflater.from(this); DialogInputAdjustBinding dialogBinding = DialogInputAdjustBinding.inflate(getLayoutInflater());
View view = inflater.inflate(R.layout.dialog_input_adjust, null);
final Slider scaleSlider = view.findViewById(R.id.input_scale_slider); final Slider scaleSlider = dialogBinding.inputScaleSlider;
final TextView scaleValue = view.findViewById(R.id.input_scale_value); final TextView scaleValue = dialogBinding.inputScaleValue;
scaleSlider.setValueTo(150); scaleSlider.setValueTo(150);
scaleSlider.setValue(IntSetting.MAIN_CONTROL_SCALE.getInt(mSettings)); scaleSlider.setValue(IntSetting.MAIN_CONTROL_SCALE.getInt(mSettings));
scaleSlider.setStepSize(1); scaleSlider.setStepSize(1);
@ -918,8 +919,8 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP
scaleValue.setText(((int) scaleSlider.getValue() + 50) + "%"); scaleValue.setText(((int) scaleSlider.getValue() + 50) + "%");
// alpha // alpha
final Slider sliderOpacity = view.findViewById(R.id.input_opacity_slider); final Slider sliderOpacity = dialogBinding.inputOpacitySlider;
final TextView valueOpacity = view.findViewById(R.id.input_opacity_value); final TextView valueOpacity = dialogBinding.inputOpacityValue;
sliderOpacity.setValueTo(100); sliderOpacity.setValueTo(100);
sliderOpacity.setValue(IntSetting.MAIN_CONTROL_OPACITY.getInt(mSettings)); sliderOpacity.setValue(IntSetting.MAIN_CONTROL_OPACITY.getInt(mSettings));
sliderOpacity.setStepSize(1); sliderOpacity.setStepSize(1);
@ -927,10 +928,9 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP
(slider, progress, fromUser) -> valueOpacity.setText(((int) progress) + "%")); (slider, progress, fromUser) -> valueOpacity.setText(((int) progress) + "%"));
valueOpacity.setText(((int) sliderOpacity.getValue()) + "%"); valueOpacity.setText(((int) sliderOpacity.getValue()) + "%");
new MaterialAlertDialogBuilder(this) new MaterialAlertDialogBuilder(this)
.setTitle(R.string.emulation_control_adjustments) .setTitle(R.string.emulation_control_adjustments)
.setView(view) .setView(dialogBinding.getRoot())
.setPositiveButton(R.string.ok, (dialog, which) -> .setPositiveButton(R.string.ok, (dialog, which) ->
{ {
IntSetting.MAIN_CONTROL_SCALE.setInt(mSettings, (int) scaleSlider.getValue()); IntSetting.MAIN_CONTROL_SCALE.setInt(mSettings, (int) scaleSlider.getValue());
@ -1008,12 +1008,12 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP
int ir_pitch = ini.getInt(Settings.SECTION_CONTROLS, SettingsFile.KEY_WIIBIND_IR_PITCH, 20); int ir_pitch = ini.getInt(Settings.SECTION_CONTROLS, SettingsFile.KEY_WIIBIND_IR_PITCH, 20);
LayoutInflater inflater = LayoutInflater.from(this); DialogIrSensitivityBinding dialogBinding =
View view = inflater.inflate(R.layout.dialog_ir_sensitivity, null); DialogIrSensitivityBinding.inflate(getLayoutInflater());
TextView text_slider_value_pitch = view.findViewById(R.id.text_ir_pitch); TextView text_slider_value_pitch = dialogBinding.textIrPitch;
TextView units = view.findViewById(R.id.text_ir_pitch_units); TextView units = dialogBinding.textIrPitchUnits;
Slider slider_pitch = view.findViewById(R.id.slider_pitch); Slider slider_pitch = dialogBinding.sliderPitch;
text_slider_value_pitch.setText(String.valueOf(ir_pitch)); text_slider_value_pitch.setText(String.valueOf(ir_pitch));
units.setText(getString(R.string.pitch)); units.setText(getString(R.string.pitch));
@ -1026,9 +1026,9 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP
int ir_yaw = ini.getInt(Settings.SECTION_CONTROLS, SettingsFile.KEY_WIIBIND_IR_YAW, 25); int ir_yaw = ini.getInt(Settings.SECTION_CONTROLS, SettingsFile.KEY_WIIBIND_IR_YAW, 25);
TextView text_slider_value_yaw = view.findViewById(R.id.text_ir_yaw); TextView text_slider_value_yaw = dialogBinding.textIrYaw;
TextView units_yaw = view.findViewById(R.id.text_ir_yaw_units); TextView units_yaw = dialogBinding.textIrYawUnits;
Slider seekbar_yaw = view.findViewById(R.id.slider_width); Slider seekbar_yaw = dialogBinding.sliderYaw;
text_slider_value_yaw.setText(String.valueOf(ir_yaw)); text_slider_value_yaw.setText(String.valueOf(ir_yaw));
units_yaw.setText(getString(R.string.yaw)); units_yaw.setText(getString(R.string.yaw));
@ -1038,13 +1038,12 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP
seekbar_yaw.addOnChangeListener((slider, progress, fromUser) -> text_slider_value_yaw.setText( seekbar_yaw.addOnChangeListener((slider, progress, fromUser) -> text_slider_value_yaw.setText(
String.valueOf((int) progress))); String.valueOf((int) progress)));
int ir_vertical_offset = int ir_vertical_offset =
ini.getInt(Settings.SECTION_CONTROLS, SettingsFile.KEY_WIIBIND_IR_VERTICAL_OFFSET, 10); ini.getInt(Settings.SECTION_CONTROLS, SettingsFile.KEY_WIIBIND_IR_VERTICAL_OFFSET, 10);
TextView text_slider_value_vertical_offset = view.findViewById(R.id.text_ir_vertical_offset); TextView text_slider_value_vertical_offset = dialogBinding.textIrVerticalOffset;
TextView units_vertical_offset = view.findViewById(R.id.text_ir_vertical_offset_units); TextView units_vertical_offset = dialogBinding.textIrVerticalOffsetUnits;
Slider seekbar_vertical_offset = view.findViewById(R.id.slider_vertical_offset); Slider seekbar_vertical_offset = dialogBinding.sliderVerticalOffset;
text_slider_value_vertical_offset.setText(String.valueOf(ir_vertical_offset)); text_slider_value_vertical_offset.setText(String.valueOf(ir_vertical_offset));
units_vertical_offset.setText(getString(R.string.vertical_offset)); units_vertical_offset.setText(getString(R.string.vertical_offset));
@ -1057,7 +1056,7 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP
new MaterialAlertDialogBuilder(this) new MaterialAlertDialogBuilder(this)
.setTitle(getString(R.string.emulation_ir_sensitivity)) .setTitle(getString(R.string.emulation_ir_sensitivity))
.setView(view) .setView(dialogBinding.getRoot())
.setPositiveButton(R.string.ok, (dialogInterface, i) -> .setPositiveButton(R.string.ok, (dialogInterface, i) ->
{ {
ini.setString(Settings.SECTION_CONTROLS, SettingsFile.KEY_WIIBIND_IR_PITCH, ini.setString(Settings.SECTION_CONTROLS, SettingsFile.KEY_WIIBIND_IR_PITCH,

View File

@ -10,19 +10,15 @@ import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.view.View; import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.core.view.WindowCompat; import androidx.core.view.WindowCompat;
import androidx.core.widget.NestedScrollView;
import com.google.android.material.appbar.AppBarLayout;
import com.google.android.material.appbar.MaterialToolbar;
import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.databinding.ActivityUserDataBinding;
import org.dolphinemu.dolphinemu.utils.DirectoryInitialization; import org.dolphinemu.dolphinemu.utils.DirectoryInitialization;
import org.dolphinemu.dolphinemu.utils.InsetsHelper; import org.dolphinemu.dolphinemu.utils.InsetsHelper;
import org.dolphinemu.dolphinemu.utils.Log; import org.dolphinemu.dolphinemu.utils.Log;
@ -61,45 +57,36 @@ public class UserDataActivity extends AppCompatActivity
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_user_data); ActivityUserDataBinding binding = ActivityUserDataBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
WindowCompat.setDecorFitsSystemWindows(getWindow(), false); WindowCompat.setDecorFitsSystemWindows(getWindow(), false);
TextView textType = findViewById(R.id.text_type);
TextView textPath = findViewById(R.id.text_path);
TextView textAndroid11 = findViewById(R.id.text_android_11);
Button buttonOpenSystemFileManager = findViewById(R.id.button_open_system_file_manager);
Button buttonImportUserData = findViewById(R.id.button_import_user_data);
Button buttonExportUserData = findViewById(R.id.button_export_user_data);
boolean android_10 = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q; boolean android_10 = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q;
boolean android_11 = Build.VERSION.SDK_INT >= Build.VERSION_CODES.R; boolean android_11 = Build.VERSION.SDK_INT >= Build.VERSION_CODES.R;
boolean legacy = DirectoryInitialization.isUsingLegacyUserDirectory(); boolean legacy = DirectoryInitialization.isUsingLegacyUserDirectory();
int user_data_new_location = android_10 ? int user_data_new_location = android_10 ?
R.string.user_data_new_location_android_10 : R.string.user_data_new_location; R.string.user_data_new_location_android_10 : R.string.user_data_new_location;
textType.setText(legacy ? R.string.user_data_old_location : user_data_new_location); binding.textType.setText(legacy ? R.string.user_data_old_location : user_data_new_location);
textPath.setText(DirectoryInitialization.getUserDirectory()); binding.textPath.setText(DirectoryInitialization.getUserDirectory());
textAndroid11.setVisibility(android_11 && !legacy ? View.VISIBLE : View.GONE); binding.textAndroid11.setVisibility(android_11 && !legacy ? View.VISIBLE : View.GONE);
buttonOpenSystemFileManager.setVisibility(android_11 ? View.VISIBLE : View.GONE); binding.buttonOpenSystemFileManager.setVisibility(android_11 ? View.VISIBLE : View.GONE);
buttonOpenSystemFileManager.setOnClickListener(view -> openFileManager()); binding.buttonOpenSystemFileManager.setOnClickListener(view -> openFileManager());
buttonImportUserData.setOnClickListener(view -> importUserData()); binding.buttonImportUserData.setOnClickListener(view -> importUserData());
buttonExportUserData.setOnClickListener(view -> exportUserData()); binding.buttonExportUserData.setOnClickListener(view -> exportUserData());
MaterialToolbar tb = findViewById(R.id.toolbar_user_data); setSupportActionBar(binding.toolbarUserData);
setSupportActionBar(tb);
getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setDisplayHomeAsUpEnabled(true);
AppBarLayout appBarLayout = findViewById(R.id.appbar_user_data); InsetsHelper.setUpAppBarWithScrollView(this, binding.appbarUserData,
NestedScrollView scrollView = findViewById(R.id.scroll_view_user_data); binding.scrollViewUserData, binding.workaroundView);
View workaroundView = findViewById(R.id.workaround_view); ThemeHelper.enableScrollTint(this, binding.toolbarUserData, binding.appbarUserData);
InsetsHelper.setUpAppBarWithScrollView(this, appBarLayout, scrollView, workaroundView);
ThemeHelper.enableScrollTint(this, tb, appBarLayout);
} }
@Override @Override

View File

@ -3,7 +3,6 @@
package org.dolphinemu.dolphinemu.adapters; package org.dolphinemu.dolphinemu.adapters;
import android.content.Context; import android.content.Context;
import android.graphics.Rect;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
@ -14,16 +13,16 @@ import androidx.recyclerview.widget.RecyclerView;
import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.activities.EmulationActivity; import org.dolphinemu.dolphinemu.activities.EmulationActivity;
import org.dolphinemu.dolphinemu.databinding.CardGameBinding;
import org.dolphinemu.dolphinemu.dialogs.GamePropertiesDialog; import org.dolphinemu.dolphinemu.dialogs.GamePropertiesDialog;
import org.dolphinemu.dolphinemu.model.GameFile; import org.dolphinemu.dolphinemu.model.GameFile;
import org.dolphinemu.dolphinemu.services.GameFileCacheManager; import org.dolphinemu.dolphinemu.services.GameFileCacheManager;
import org.dolphinemu.dolphinemu.utils.GlideUtils; import org.dolphinemu.dolphinemu.utils.GlideUtils;
import org.dolphinemu.dolphinemu.viewholders.GameViewHolder;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public final class GameAdapter extends RecyclerView.Adapter<GameViewHolder> implements public final class GameAdapter extends RecyclerView.Adapter<GameAdapter.GameViewHolder> implements
View.OnClickListener, View.OnClickListener,
View.OnLongClickListener View.OnLongClickListener
{ {
@ -45,18 +44,17 @@ public final class GameAdapter extends RecyclerView.Adapter<GameViewHolder> impl
* @param viewType Not used here, but useful when more than one type of child will be used in the RecyclerView. * @param viewType Not used here, but useful when more than one type of child will be used in the RecyclerView.
* @return The created ViewHolder with references to all the child view's members. * @return The created ViewHolder with references to all the child view's members.
*/ */
@NonNull
@Override @Override
public GameViewHolder onCreateViewHolder(ViewGroup parent, int viewType) public GameViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{ {
// Create a new view. CardGameBinding binding = CardGameBinding.inflate(LayoutInflater.from(parent.getContext()));
View gameCard = LayoutInflater.from(parent.getContext())
.inflate(R.layout.card_game, parent, false);
gameCard.setOnClickListener(this); binding.getRoot().setOnClickListener(this);
gameCard.setOnLongClickListener(this); binding.getRoot().setOnLongClickListener(this);
// Use that view to create a ViewHolder. // Use that view to create a ViewHolder.
return new GameViewHolder(gameCard); return new GameViewHolder(binding);
} }
/** /**
@ -72,21 +70,34 @@ public final class GameAdapter extends RecyclerView.Adapter<GameViewHolder> impl
{ {
Context context = holder.itemView.getContext(); Context context = holder.itemView.getContext();
GameFile gameFile = mGameFiles.get(position); GameFile gameFile = mGameFiles.get(position);
GlideUtils.loadGameCover(holder, holder.imageScreenshot, gameFile); GlideUtils.loadGameCover(holder, holder.binding.imageGameScreen, gameFile);
if (GameFileCacheManager.findSecondDisc(gameFile) != null) if (GameFileCacheManager.findSecondDisc(gameFile) != null)
{ {
holder.textGameCaption holder.binding.textGameCaption
.setText(context.getString(R.string.disc_number, gameFile.getDiscNumber() + 1)); .setText(context.getString(R.string.disc_number, gameFile.getDiscNumber() + 1));
} }
else else
{ {
holder.textGameCaption.setText(gameFile.getCompany()); holder.binding.textGameCaption.setText(gameFile.getCompany());
} }
holder.gameFile = gameFile; holder.gameFile = gameFile;
} }
public static class GameViewHolder extends RecyclerView.ViewHolder
{
public GameFile gameFile;
public CardGameBinding binding;
public GameViewHolder(@NonNull CardGameBinding binding)
{
super(binding.getRoot());
binding.getRoot().setTag(this);
this.binding = binding;
}
}
/** /**
* Called by the LayoutManager to find out how much data we have. * Called by the LayoutManager to find out how much data we have.
* *

View File

@ -5,16 +5,15 @@ package org.dolphinemu.dolphinemu.dialogs;
import android.app.Dialog; import android.app.Dialog;
import android.os.Bundle; import android.os.Bundle;
import android.view.View; import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.fragment.app.DialogFragment; import androidx.fragment.app.DialogFragment;
import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.dolphinemu.dolphinemu.NativeLibrary; import org.dolphinemu.dolphinemu.NativeLibrary;
import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.databinding.DialogGameDetailsBinding;
import org.dolphinemu.dolphinemu.model.GameFile; import org.dolphinemu.dolphinemu.model.GameFile;
import org.dolphinemu.dolphinemu.services.GameFileCacheManager; import org.dolphinemu.dolphinemu.services.GameFileCacheManager;
import org.dolphinemu.dolphinemu.utils.GlideUtils; import org.dolphinemu.dolphinemu.utils.GlideUtils;
@ -34,90 +33,72 @@ public final class GameDetailsDialog extends DialogFragment
return fragment; return fragment;
} }
@NonNull
@Override @Override
public Dialog onCreateDialog(Bundle savedInstanceState) public Dialog onCreateDialog(Bundle savedInstanceState)
{ {
GameFile gameFile = GameFileCacheManager.addOrGet(getArguments().getString(ARG_GAME_PATH)); GameFile gameFile = GameFileCacheManager.addOrGet(getArguments().getString(ARG_GAME_PATH));
ViewGroup contents = (ViewGroup) getActivity().getLayoutInflater() DialogGameDetailsBinding binding = DialogGameDetailsBinding.inflate(getLayoutInflater());
.inflate(R.layout.dialog_game_details, null);
ImageView banner = contents.findViewById(R.id.banner);
TextView textTitle = contents.findViewById(R.id.text_game_title);
TextView textDescription = contents.findViewById(R.id.text_description);
TextView textCountry = contents.findViewById(R.id.text_country);
TextView textCompany = contents.findViewById(R.id.text_company);
TextView textGameId = contents.findViewById(R.id.text_game_id);
TextView textRevision = contents.findViewById(R.id.text_revision);
TextView textFileFormat = contents.findViewById(R.id.text_file_format);
TextView textCompression = contents.findViewById(R.id.text_compression);
TextView textBlockSize = contents.findViewById(R.id.text_block_size);
TextView labelFileFormat = contents.findViewById(R.id.label_file_format);
TextView labelCompression = contents.findViewById(R.id.label_compression);
TextView labelBlockSize = contents.findViewById(R.id.label_block_size);
String country = getResources().getStringArray(R.array.countryNames)[gameFile.getCountry()]; String country = getResources().getStringArray(R.array.countryNames)[gameFile.getCountry()];
String description = gameFile.getDescription(); String description = gameFile.getDescription();
String fileSize = NativeLibrary.FormatSize(gameFile.getFileSize(), 2); String fileSize = NativeLibrary.FormatSize(gameFile.getFileSize(), 2);
textTitle.setText(gameFile.getTitle()); binding.textGameTitle.setText(gameFile.getTitle());
textDescription.setText(gameFile.getDescription()); binding.textDescription.setText(gameFile.getDescription());
if (description.isEmpty()) if (description.isEmpty())
{ {
textDescription.setVisibility(View.GONE); binding.textDescription.setVisibility(View.GONE);
} }
textCountry.setText(country); binding.textCountry.setText(country);
textCompany.setText(gameFile.getCompany()); binding.textCompany.setText(gameFile.getCompany());
textGameId.setText(gameFile.getGameId()); binding.textGameId.setText(gameFile.getGameId());
textRevision.setText(String.valueOf(gameFile.getRevision())); binding.textRevision.setText(String.valueOf(gameFile.getRevision()));
if (!gameFile.shouldShowFileFormatDetails()) if (!gameFile.shouldShowFileFormatDetails())
{ {
labelFileFormat.setText(R.string.game_details_file_size); binding.labelFileFormat.setText(R.string.game_details_file_size);
textFileFormat.setText(fileSize); binding.textFileFormat.setText(fileSize);
labelCompression.setVisibility(View.GONE); binding.labelCompression.setVisibility(View.GONE);
textCompression.setVisibility(View.GONE); binding.textCompression.setVisibility(View.GONE);
labelBlockSize.setVisibility(View.GONE); binding.labelBlockSize.setVisibility(View.GONE);
textBlockSize.setVisibility(View.GONE); binding.textBlockSize.setVisibility(View.GONE);
} }
else else
{ {
long blockSize = gameFile.getBlockSize(); long blockSize = gameFile.getBlockSize();
String compression = gameFile.getCompressionMethod(); String compression = gameFile.getCompressionMethod();
textFileFormat.setText(getResources().getString(R.string.game_details_size_and_format, binding.textFileFormat.setText(getResources().getString(R.string.game_details_size_and_format,
gameFile.getFileFormatName(), fileSize)); gameFile.getFileFormatName(), fileSize));
if (compression.isEmpty()) if (compression.isEmpty())
{ {
textCompression.setText(R.string.game_details_no_compression); binding.textCompression.setText(R.string.game_details_no_compression);
} }
else else
{ {
textCompression.setText(gameFile.getCompressionMethod()); binding.textCompression.setText(gameFile.getCompressionMethod());
} }
if (blockSize > 0) if (blockSize > 0)
{ {
textBlockSize.setText(NativeLibrary.FormatSize(blockSize, 0)); binding.textBlockSize.setText(NativeLibrary.FormatSize(blockSize, 0));
} }
else else
{ {
labelBlockSize.setVisibility(View.GONE); binding.labelBlockSize.setVisibility(View.GONE);
textBlockSize.setVisibility(View.GONE); binding.textBlockSize.setVisibility(View.GONE);
} }
} }
GlideUtils.loadGameBanner(banner, gameFile); GlideUtils.loadGameBanner(binding.banner, gameFile);
return new MaterialAlertDialogBuilder(requireActivity()) return new MaterialAlertDialogBuilder(requireActivity())
.setView(contents) .setView(binding.getRoot())
.create(); .create();
} }
} }

View File

@ -9,6 +9,7 @@ import androidx.annotation.NonNull;
import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelProvider;
import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.databinding.ListItemSubmenuBinding;
import org.dolphinemu.dolphinemu.features.cheats.model.ARCheat; import org.dolphinemu.dolphinemu.features.cheats.model.ARCheat;
import org.dolphinemu.dolphinemu.features.cheats.model.CheatsViewModel; import org.dolphinemu.dolphinemu.features.cheats.model.CheatsViewModel;
import org.dolphinemu.dolphinemu.features.cheats.model.GeckoCheat; import org.dolphinemu.dolphinemu.features.cheats.model.GeckoCheat;
@ -23,13 +24,13 @@ public class ActionViewHolder extends CheatItemViewHolder implements View.OnClic
private int mString; private int mString;
private int mPosition; private int mPosition;
public ActionViewHolder(@NonNull View itemView) public ActionViewHolder(@NonNull ListItemSubmenuBinding binding)
{ {
super(itemView); super(binding.getRoot());
mName = itemView.findViewById(R.id.text_setting_name); mName = binding.textSettingName;
itemView.setOnClickListener(this); binding.getRoot().setOnClickListener(this);
} }
public void bind(CheatsActivity activity, CheatItem item, int position) public void bind(CheatsActivity activity, CheatItem item, int position)

View File

@ -6,8 +6,6 @@ import android.os.Bundle;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ScrollView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
@ -15,78 +13,57 @@ import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelProvider;
import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.textfield.TextInputEditText;
import com.google.android.material.textfield.TextInputLayout;
import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.databinding.FragmentCheatDetailsBinding;
import org.dolphinemu.dolphinemu.features.cheats.model.Cheat; import org.dolphinemu.dolphinemu.features.cheats.model.Cheat;
import org.dolphinemu.dolphinemu.features.cheats.model.CheatsViewModel; import org.dolphinemu.dolphinemu.features.cheats.model.CheatsViewModel;
public class CheatDetailsFragment extends Fragment public class CheatDetailsFragment extends Fragment
{ {
private View mRoot;
private ScrollView mScrollView;
private TextInputLayout mEditNameLayout;
private TextInputEditText mEditName;
private TextInputLayout mEditCreatorLayout;
private TextInputEditText mEditCreator;
private TextInputLayout mEditNotesLayout;
private TextInputEditText mEditNotes;
private TextInputLayout mEditCodeLayout;
private TextInputEditText mEditCode;
private Button mButtonDelete;
private Button mButtonEdit;
private Button mButtonCancel;
private Button mButtonOk;
private CheatsViewModel mViewModel; private CheatsViewModel mViewModel;
private Cheat mCheat; private Cheat mCheat;
private FragmentCheatDetailsBinding mBinding;
@Nullable @Nullable
@Override @Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) @Nullable Bundle savedInstanceState)
{ {
return inflater.inflate(R.layout.fragment_cheat_details, container, false); mBinding = FragmentCheatDetailsBinding.inflate(inflater, container, false);
return mBinding.getRoot();
} }
@Override @Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState)
{ {
mRoot = view.findViewById(R.id.root);
mScrollView = view.findViewById(R.id.scroll_view);
mEditNameLayout = view.findViewById(R.id.edit_name);
mEditName = view.findViewById(R.id.edit_name_input);
mEditCreatorLayout = view.findViewById(R.id.edit_creator);
mEditCreator = view.findViewById(R.id.edit_creator_input);
mEditNotesLayout = view.findViewById(R.id.edit_notes);
mEditNotes = view.findViewById(R.id.edit_notes_input);
mEditCodeLayout = view.findViewById(R.id.edit_code);
mEditCode = view.findViewById(R.id.edit_code_input);
mButtonDelete = view.findViewById(R.id.button_delete);
mButtonEdit = view.findViewById(R.id.button_edit);
mButtonCancel = view.findViewById(R.id.button_cancel);
mButtonOk = view.findViewById(R.id.button_ok);
CheatsActivity activity = (CheatsActivity) requireActivity(); CheatsActivity activity = (CheatsActivity) requireActivity();
mViewModel = new ViewModelProvider(activity).get(CheatsViewModel.class); mViewModel = new ViewModelProvider(activity).get(CheatsViewModel.class);
mViewModel.getSelectedCheat().observe(getViewLifecycleOwner(), this::onSelectedCheatUpdated); mViewModel.getSelectedCheat().observe(getViewLifecycleOwner(), this::onSelectedCheatUpdated);
mViewModel.getIsEditing().observe(getViewLifecycleOwner(), this::onIsEditingUpdated); mViewModel.getIsEditing().observe(getViewLifecycleOwner(), this::onIsEditingUpdated);
mButtonDelete.setOnClickListener(this::onDeleteClicked); mBinding.buttonDelete.setOnClickListener(this::onDeleteClicked);
mButtonEdit.setOnClickListener(this::onEditClicked); mBinding.buttonEdit.setOnClickListener(this::onEditClicked);
mButtonCancel.setOnClickListener(this::onCancelClicked); mBinding.buttonCancel.setOnClickListener(this::onCancelClicked);
mButtonOk.setOnClickListener(this::onOkClicked); mBinding.buttonOk.setOnClickListener(this::onOkClicked);
CheatsActivity.setOnFocusChangeListenerRecursively(view, CheatsActivity.setOnFocusChangeListenerRecursively(view,
(v, hasFocus) -> activity.onDetailsViewFocusChange(hasFocus)); (v, hasFocus) -> activity.onDetailsViewFocusChange(hasFocus));
} }
@Override
public void onDestroyView()
{
super.onDestroyView();
mBinding = null;
}
private void clearEditErrors() private void clearEditErrors()
{ {
mEditNameLayout.setError(null); mBinding.editName.setError(null);
mEditCodeLayout.setError(null); mBinding.editCode.setError(null);
} }
private void onDeleteClicked(View view) private void onDeleteClicked(View view)
@ -101,22 +78,24 @@ public class CheatDetailsFragment extends Fragment
private void onEditClicked(View view) private void onEditClicked(View view)
{ {
mViewModel.setIsEditing(true); mViewModel.setIsEditing(true);
mButtonOk.requestFocus(); mBinding.buttonOk.requestFocus();
} }
private void onCancelClicked(View view) private void onCancelClicked(View view)
{ {
mViewModel.setIsEditing(false); mViewModel.setIsEditing(false);
onSelectedCheatUpdated(mCheat); onSelectedCheatUpdated(mCheat);
mButtonDelete.requestFocus(); mBinding.buttonDelete.requestFocus();
} }
private void onOkClicked(View view) private void onOkClicked(View view)
{ {
clearEditErrors(); clearEditErrors();
int result = mCheat.trySet(mEditName.getText().toString(), mEditCreator.getText().toString(), int result = mCheat.trySet(mBinding.editNameInput.getText().toString(),
mEditNotes.getText().toString(), mEditCode.getText().toString()); mBinding.editCreatorInput.getText().toString(),
mBinding.editNotesInput.getText().toString(),
mBinding.editCodeInput.getText().toString());
switch (result) switch (result)
{ {
@ -131,23 +110,23 @@ public class CheatDetailsFragment extends Fragment
mViewModel.notifySelectedCheatChanged(); mViewModel.notifySelectedCheatChanged();
mViewModel.setIsEditing(false); mViewModel.setIsEditing(false);
} }
mButtonEdit.requestFocus(); mBinding.buttonEdit.requestFocus();
break; break;
case Cheat.TRY_SET_FAIL_NO_NAME: case Cheat.TRY_SET_FAIL_NO_NAME:
mEditNameLayout.setError(getString(R.string.cheats_error_no_name)); mBinding.editName.setError(getString(R.string.cheats_error_no_name));
mScrollView.smoothScrollTo(0, mEditName.getTop()); mBinding.scrollView.smoothScrollTo(0, mBinding.editNameInput.getTop());
break; break;
case Cheat.TRY_SET_FAIL_NO_CODE_LINES: case Cheat.TRY_SET_FAIL_NO_CODE_LINES:
mEditCodeLayout.setError(getString(R.string.cheats_error_no_code_lines)); mBinding.editCode.setError(getString(R.string.cheats_error_no_code_lines));
mScrollView.smoothScrollTo(0, mEditCode.getBottom()); mBinding.scrollView.smoothScrollTo(0, mBinding.editCodeInput.getBottom());
break; break;
case Cheat.TRY_SET_FAIL_CODE_MIXED_ENCRYPTION: case Cheat.TRY_SET_FAIL_CODE_MIXED_ENCRYPTION:
mEditCodeLayout.setError(getString(R.string.cheats_error_mixed_encryption)); mBinding.editCode.setError(getString(R.string.cheats_error_mixed_encryption));
mScrollView.smoothScrollTo(0, mEditCode.getBottom()); mBinding.scrollView.smoothScrollTo(0, mBinding.editCodeInput.getBottom());
break; break;
default: default:
mEditCodeLayout.setError(getString(R.string.cheats_error_on_line, result)); mBinding.editCode.setError(getString(R.string.cheats_error_on_line, result));
mScrollView.smoothScrollTo(0, mEditCode.getBottom()); mBinding.scrollView.smoothScrollTo(0, mBinding.editCodeInput.getBottom());
break; break;
} }
} }
@ -156,18 +135,18 @@ public class CheatDetailsFragment extends Fragment
{ {
clearEditErrors(); clearEditErrors();
mRoot.setVisibility(cheat == null ? View.GONE : View.VISIBLE); mBinding.root.setVisibility(cheat == null ? View.GONE : View.VISIBLE);
int creatorVisibility = cheat != null && cheat.supportsCreator() ? View.VISIBLE : View.GONE; int creatorVisibility = cheat != null && cheat.supportsCreator() ? View.VISIBLE : View.GONE;
int notesVisibility = cheat != null && cheat.supportsNotes() ? View.VISIBLE : View.GONE; int notesVisibility = cheat != null && cheat.supportsNotes() ? View.VISIBLE : View.GONE;
int codeVisibility = cheat != null && cheat.supportsCode() ? View.VISIBLE : View.GONE; int codeVisibility = cheat != null && cheat.supportsCode() ? View.VISIBLE : View.GONE;
mEditCreatorLayout.setVisibility(creatorVisibility); mBinding.editCreator.setVisibility(creatorVisibility);
mEditNotesLayout.setVisibility(notesVisibility); mBinding.editNotes.setVisibility(notesVisibility);
mEditCodeLayout.setVisibility(codeVisibility); mBinding.editCode.setVisibility(codeVisibility);
boolean userDefined = cheat != null && cheat.getUserDefined(); boolean userDefined = cheat != null && cheat.getUserDefined();
mButtonDelete.setEnabled(userDefined); mBinding.buttonDelete.setEnabled(userDefined);
mButtonEdit.setEnabled(userDefined); mBinding.buttonEdit.setEnabled(userDefined);
// If the fragment was recreated while editing a cheat, it's vital that we // If the fragment was recreated while editing a cheat, it's vital that we
// don't repopulate the fields, otherwise the user's changes will be lost // don't repopulate the fields, otherwise the user's changes will be lost
@ -175,10 +154,10 @@ public class CheatDetailsFragment extends Fragment
if (!isEditing && cheat != null) if (!isEditing && cheat != null)
{ {
mEditName.setText(cheat.getName()); mBinding.editNameInput.setText(cheat.getName());
mEditCreator.setText(cheat.getCreator()); mBinding.editCreatorInput.setText(cheat.getCreator());
mEditNotes.setText(cheat.getNotes()); mBinding.editNotesInput.setText(cheat.getNotes());
mEditCode.setText(cheat.getCode()); mBinding.editCodeInput.setText(cheat.getCode());
} }
mCheat = cheat; mCheat = cheat;
@ -186,14 +165,14 @@ public class CheatDetailsFragment extends Fragment
private void onIsEditingUpdated(boolean isEditing) private void onIsEditingUpdated(boolean isEditing)
{ {
mEditName.setEnabled(isEditing); mBinding.editNameInput.setEnabled(isEditing);
mEditCreator.setEnabled(isEditing); mBinding.editCreatorInput.setEnabled(isEditing);
mEditNotes.setEnabled(isEditing); mBinding.editNotesInput.setEnabled(isEditing);
mEditCode.setEnabled(isEditing); mBinding.editCodeInput.setEnabled(isEditing);
mButtonDelete.setVisibility(isEditing ? View.GONE : View.VISIBLE); mBinding.buttonDelete.setVisibility(isEditing ? View.GONE : View.VISIBLE);
mButtonEdit.setVisibility(isEditing ? View.GONE : View.VISIBLE); mBinding.buttonEdit.setVisibility(isEditing ? View.GONE : View.VISIBLE);
mButtonCancel.setVisibility(isEditing ? View.VISIBLE : View.GONE); mBinding.buttonCancel.setVisibility(isEditing ? View.VISIBLE : View.GONE);
mButtonOk.setVisibility(isEditing ? View.VISIBLE : View.GONE); mBinding.buttonOk.setVisibility(isEditing ? View.VISIBLE : View.GONE);
} }
} }

View File

@ -12,40 +12,47 @@ import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelProvider;
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.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.databinding.FragmentCheatListBinding;
import org.dolphinemu.dolphinemu.features.cheats.model.CheatsViewModel; import org.dolphinemu.dolphinemu.features.cheats.model.CheatsViewModel;
import org.dolphinemu.dolphinemu.utils.InsetsHelper; import org.dolphinemu.dolphinemu.utils.InsetsHelper;
public class CheatListFragment extends Fragment public class CheatListFragment extends Fragment
{ {
private FragmentCheatListBinding mBinding;
@Nullable @Nullable
@Override @Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) @Nullable Bundle savedInstanceState)
{ {
return inflater.inflate(R.layout.fragment_cheat_list, container, false); mBinding = FragmentCheatListBinding.inflate(inflater, container, false);
return mBinding.getRoot();
} }
@Override @Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState)
{ {
RecyclerView recyclerView = view.findViewById(R.id.cheat_list);
CheatsActivity activity = (CheatsActivity) requireActivity(); CheatsActivity activity = (CheatsActivity) requireActivity();
CheatsViewModel viewModel = new ViewModelProvider(activity).get(CheatsViewModel.class); CheatsViewModel viewModel = new ViewModelProvider(activity).get(CheatsViewModel.class);
recyclerView.setAdapter(new CheatsAdapter(activity, viewModel)); mBinding.cheatList.setAdapter(new CheatsAdapter(activity, viewModel));
recyclerView.setLayoutManager(new LinearLayoutManager(activity)); mBinding.cheatList.setLayoutManager(new LinearLayoutManager(activity));
MaterialDividerItemDecoration divider = MaterialDividerItemDecoration divider =
new MaterialDividerItemDecoration(requireActivity(), LinearLayoutManager.VERTICAL); new MaterialDividerItemDecoration(requireActivity(), LinearLayoutManager.VERTICAL);
divider.setLastItemDecorated(false); divider.setLastItemDecorated(false);
recyclerView.addItemDecoration(divider); mBinding.cheatList.addItemDecoration(divider);
InsetsHelper.setUpList(getContext(), recyclerView); InsetsHelper.setUpList(getContext(), mBinding.cheatList);
}
@Override
public void onDestroyView()
{
super.onDestroyView();
mBinding = null;
} }
} }

View File

@ -10,43 +10,38 @@ import android.widget.TextView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelProvider;
import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.databinding.ListItemCheatBinding;
import org.dolphinemu.dolphinemu.features.cheats.model.Cheat; import org.dolphinemu.dolphinemu.features.cheats.model.Cheat;
import org.dolphinemu.dolphinemu.features.cheats.model.CheatsViewModel; import org.dolphinemu.dolphinemu.features.cheats.model.CheatsViewModel;
public class CheatViewHolder extends CheatItemViewHolder public class CheatViewHolder extends CheatItemViewHolder
implements View.OnClickListener, CompoundButton.OnCheckedChangeListener implements View.OnClickListener, CompoundButton.OnCheckedChangeListener
{ {
private final View mRoot; private final ListItemCheatBinding mBinding;
private final TextView mName;
private final CheckBox mCheckbox;
private CheatsViewModel mViewModel; private CheatsViewModel mViewModel;
private Cheat mCheat; private Cheat mCheat;
private int mPosition; private int mPosition;
public CheatViewHolder(@NonNull View itemView) public CheatViewHolder(@NonNull ListItemCheatBinding binding)
{ {
super(itemView); super(binding.getRoot());
mBinding = binding;
mRoot = itemView.findViewById(R.id.root);
mName = itemView.findViewById(R.id.text_name);
mCheckbox = itemView.findViewById(R.id.checkbox);
} }
public void bind(CheatsActivity activity, CheatItem item, int position) public void bind(CheatsActivity activity, CheatItem item, int position)
{ {
mCheckbox.setOnCheckedChangeListener(null); mBinding.checkbox.setOnCheckedChangeListener(null);
mViewModel = new ViewModelProvider(activity).get(CheatsViewModel.class); mViewModel = new ViewModelProvider(activity).get(CheatsViewModel.class);
mCheat = item.getCheat(); mCheat = item.getCheat();
mPosition = position; mPosition = position;
mName.setText(mCheat.getName()); mBinding.textName.setText(mCheat.getName());
mCheckbox.setChecked(mCheat.getEnabled()); mBinding.checkbox.setChecked(mCheat.getEnabled());
mRoot.setOnClickListener(this); mBinding.root.setOnClickListener(this);
mCheckbox.setOnCheckedChangeListener(this); mBinding.checkbox.setOnCheckedChangeListener(this);
} }
public void onClick(View root) public void onClick(View root)

View File

@ -19,12 +19,11 @@ import androidx.core.view.WindowCompat;
import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelProvider;
import androidx.slidingpanelayout.widget.SlidingPaneLayout; import androidx.slidingpanelayout.widget.SlidingPaneLayout;
import com.google.android.material.appbar.AppBarLayout;
import com.google.android.material.appbar.MaterialToolbar;
import com.google.android.material.color.MaterialColors; import com.google.android.material.color.MaterialColors;
import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.databinding.ActivityCheatsBinding;
import org.dolphinemu.dolphinemu.features.cheats.model.Cheat; import org.dolphinemu.dolphinemu.features.cheats.model.Cheat;
import org.dolphinemu.dolphinemu.features.cheats.model.CheatsViewModel; import org.dolphinemu.dolphinemu.features.cheats.model.CheatsViewModel;
import org.dolphinemu.dolphinemu.features.cheats.model.GeckoCheat; import org.dolphinemu.dolphinemu.features.cheats.model.GeckoCheat;
@ -48,13 +47,11 @@ public class CheatsActivity extends AppCompatActivity
private boolean mIsWii; private boolean mIsWii;
private CheatsViewModel mViewModel; private CheatsViewModel mViewModel;
private SlidingPaneLayout mSlidingPaneLayout;
private View mCheatList;
private View mCheatDetails;
private View mCheatListLastFocus; private View mCheatListLastFocus;
private View mCheatDetailsLastFocus; private View mCheatDetailsLastFocus;
private ActivityCheatsBinding mBinding;
public static void launch(Context context, String gameId, String gameTdbId, int revision, public static void launch(Context context, String gameId, String gameTdbId, int revision,
boolean isWii) boolean isWii)
{ {
@ -86,38 +83,34 @@ public class CheatsActivity extends AppCompatActivity
mViewModel = new ViewModelProvider(this).get(CheatsViewModel.class); mViewModel = new ViewModelProvider(this).get(CheatsViewModel.class);
mViewModel.load(mGameId, mRevision); mViewModel.load(mGameId, mRevision);
setContentView(R.layout.activity_cheats); mBinding = ActivityCheatsBinding.inflate(getLayoutInflater());
setContentView(mBinding.getRoot());
WindowCompat.setDecorFitsSystemWindows(getWindow(), false); WindowCompat.setDecorFitsSystemWindows(getWindow(), false);
mSlidingPaneLayout = findViewById(R.id.sliding_pane_layout); mCheatListLastFocus = mBinding.cheatList;
mCheatList = findViewById(R.id.cheat_list); mCheatDetailsLastFocus = mBinding.cheatDetails;
mCheatDetails = findViewById(R.id.cheat_details);
mCheatListLastFocus = mCheatList; mBinding.slidingPaneLayout.addPanelSlideListener(this);
mCheatDetailsLastFocus = mCheatDetails;
mSlidingPaneLayout.addPanelSlideListener(this);
getOnBackPressedDispatcher().addCallback(this, getOnBackPressedDispatcher().addCallback(this,
new TwoPaneOnBackPressedCallback(mSlidingPaneLayout)); new TwoPaneOnBackPressedCallback(mBinding.slidingPaneLayout));
mViewModel.getSelectedCheat().observe(this, this::onSelectedCheatChanged); mViewModel.getSelectedCheat().observe(this, this::onSelectedCheatChanged);
onSelectedCheatChanged(mViewModel.getSelectedCheat().getValue()); onSelectedCheatChanged(mViewModel.getSelectedCheat().getValue());
mViewModel.getOpenDetailsViewEvent().observe(this, this::openDetailsView); mViewModel.getOpenDetailsViewEvent().observe(this, this::openDetailsView);
MaterialToolbar tb = findViewById(R.id.toolbar_cheats); setSupportActionBar(mBinding.toolbarCheats);
setSupportActionBar(tb);
getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setDisplayHomeAsUpEnabled(true);
View workaroundView = findViewById(R.id.workaround_view); InsetsHelper.setUpCheatsLayout(this, mBinding.appbarCheats, mBinding.slidingPaneLayout,
AppBarLayout appBarLayout = findViewById(R.id.appbar_cheats); mBinding.cheatDetails,
InsetsHelper.setUpCheatsLayout(this, appBarLayout, mSlidingPaneLayout, mCheatDetails, mBinding.workaroundView);
workaroundView);
@ColorInt int color = MaterialColors.getColor(tb, R.attr.colorSurfaceVariant); @ColorInt int color =
tb.setBackgroundColor(color); MaterialColors.getColor(mBinding.toolbarCheats, R.attr.colorSurfaceVariant);
mBinding.toolbarCheats.setBackgroundColor(color);
ThemeHelper.setStatusBarColor(this, color); ThemeHelper.setStatusBarColor(this, color);
} }
@ -161,10 +154,10 @@ public class CheatsActivity extends AppCompatActivity
{ {
boolean cheatSelected = selectedCheat != null; boolean cheatSelected = selectedCheat != null;
if (!cheatSelected && mSlidingPaneLayout.isOpen()) if (!cheatSelected && mBinding.slidingPaneLayout.isOpen())
mSlidingPaneLayout.close(); mBinding.slidingPaneLayout.close();
mSlidingPaneLayout.setLockMode(cheatSelected ? mBinding.slidingPaneLayout.setLockMode(cheatSelected ?
SlidingPaneLayout.LOCK_MODE_UNLOCKED : SlidingPaneLayout.LOCK_MODE_LOCKED_CLOSED); SlidingPaneLayout.LOCK_MODE_UNLOCKED : SlidingPaneLayout.LOCK_MODE_LOCKED_CLOSED);
} }
@ -172,11 +165,11 @@ public class CheatsActivity extends AppCompatActivity
{ {
if (hasFocus) if (hasFocus)
{ {
mCheatListLastFocus = mCheatList.findFocus(); mCheatListLastFocus = mBinding.cheatList.findFocus();
if (mCheatListLastFocus == null) if (mCheatListLastFocus == null)
throw new NullPointerException(); throw new NullPointerException();
mSlidingPaneLayout.close(); mBinding.slidingPaneLayout.close();
} }
} }
@ -184,11 +177,11 @@ public class CheatsActivity extends AppCompatActivity
{ {
if (hasFocus) if (hasFocus)
{ {
mCheatDetailsLastFocus = mCheatDetails.findFocus(); mCheatDetailsLastFocus = mBinding.cheatDetails.findFocus();
if (mCheatDetailsLastFocus == null) if (mCheatDetailsLastFocus == null)
throw new NullPointerException(); throw new NullPointerException();
mSlidingPaneLayout.open(); mBinding.slidingPaneLayout.open();
} }
} }
@ -202,7 +195,7 @@ public class CheatsActivity extends AppCompatActivity
private void openDetailsView(boolean open) private void openDetailsView(boolean open)
{ {
if (open) if (open)
mSlidingPaneLayout.open(); mBinding.slidingPaneLayout.open();
} }
public Settings loadGameSpecificSettings() public Settings loadGameSpecificSettings()

View File

@ -10,6 +10,9 @@ import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.databinding.ListItemCheatBinding;
import org.dolphinemu.dolphinemu.databinding.ListItemHeaderBinding;
import org.dolphinemu.dolphinemu.databinding.ListItemSubmenuBinding;
import org.dolphinemu.dolphinemu.features.cheats.model.ARCheat; import org.dolphinemu.dolphinemu.features.cheats.model.ARCheat;
import org.dolphinemu.dolphinemu.features.cheats.model.CheatsViewModel; import org.dolphinemu.dolphinemu.features.cheats.model.CheatsViewModel;
import org.dolphinemu.dolphinemu.features.cheats.model.GeckoCheat; import org.dolphinemu.dolphinemu.features.cheats.model.GeckoCheat;
@ -66,17 +69,17 @@ public class CheatsAdapter extends RecyclerView.Adapter<CheatItemViewHolder>
switch (viewType) switch (viewType)
{ {
case CheatItem.TYPE_CHEAT: case CheatItem.TYPE_CHEAT:
View cheatView = inflater.inflate(R.layout.list_item_cheat, parent, false); ListItemCheatBinding listItemCheatBinding = ListItemCheatBinding.inflate(inflater);
addViewListeners(cheatView); addViewListeners(listItemCheatBinding.getRoot());
return new CheatViewHolder(cheatView); return new CheatViewHolder(listItemCheatBinding);
case CheatItem.TYPE_HEADER: case CheatItem.TYPE_HEADER:
View headerView = inflater.inflate(R.layout.list_item_header, parent, false); ListItemHeaderBinding listItemHeaderBinding = ListItemHeaderBinding.inflate(inflater);
addViewListeners(headerView); addViewListeners(listItemHeaderBinding.getRoot());
return new HeaderViewHolder(headerView); return new HeaderViewHolder(listItemHeaderBinding);
case CheatItem.TYPE_ACTION: case CheatItem.TYPE_ACTION:
View actionView = inflater.inflate(R.layout.list_item_submenu, parent, false); ListItemSubmenuBinding listItemSubmenuBinding = ListItemSubmenuBinding.inflate(inflater);
addViewListeners(actionView); addViewListeners(listItemSubmenuBinding.getRoot());
return new ActionViewHolder(actionView); return new ActionViewHolder(listItemSubmenuBinding);
default: default:
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }

View File

@ -8,16 +8,17 @@ import android.widget.TextView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.databinding.ListItemHeaderBinding;
public class HeaderViewHolder extends CheatItemViewHolder public class HeaderViewHolder extends CheatItemViewHolder
{ {
private TextView mHeaderName; private TextView mHeaderName;
public HeaderViewHolder(@NonNull View itemView) public HeaderViewHolder(@NonNull ListItemHeaderBinding binding)
{ {
super(itemView); super(binding.getRoot());
mHeaderName = itemView.findViewById(R.id.text_header_name); mHeaderName = binding.textHeaderName;
} }
public void bind(CheatsActivity activity, CheatItem item, int position) public void bind(CheatsActivity activity, CheatItem item, int position)

View File

@ -6,14 +6,12 @@ import android.os.Bundle;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.databinding.FragmentCheatWarningBinding;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractBooleanSetting; import org.dolphinemu.dolphinemu.features.settings.model.AbstractBooleanSetting;
import org.dolphinemu.dolphinemu.features.settings.model.Settings; import org.dolphinemu.dolphinemu.features.settings.model.Settings;
import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag; import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag;
@ -28,6 +26,8 @@ public abstract class SettingDisabledWarningFragment extends Fragment
private final MenuTag mSettingShortcut; private final MenuTag mSettingShortcut;
private final int mText; private final int mText;
private FragmentCheatWarningBinding mBinding;
public SettingDisabledWarningFragment(AbstractBooleanSetting setting, MenuTag settingShortcut, public SettingDisabledWarningFragment(AbstractBooleanSetting setting, MenuTag settingShortcut,
int text) int text)
{ {
@ -38,10 +38,11 @@ public abstract class SettingDisabledWarningFragment extends Fragment
@Nullable @Nullable
@Override @Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) @Nullable Bundle savedInstanceState)
{ {
return inflater.inflate(R.layout.fragment_cheat_warning, container, false); mBinding = FragmentCheatWarningBinding.inflate(inflater, container, false);
return mBinding.getRoot();
} }
@Override @Override
@ -49,11 +50,8 @@ public abstract class SettingDisabledWarningFragment extends Fragment
{ {
mView = view; mView = view;
TextView textView = view.findViewById(R.id.text_warning); mBinding.textWarning.setText(mText);
textView.setText(mText); mBinding.buttonSettings.setOnClickListener(this);
Button settingsButton = view.findViewById(R.id.button_settings);
settingsButton.setOnClickListener(this);
CheatsActivity activity = (CheatsActivity) requireActivity(); CheatsActivity activity = (CheatsActivity) requireActivity();
CheatsActivity.setOnFocusChangeListenerRecursively(view, CheatsActivity.setOnFocusChangeListenerRecursively(view,
@ -73,6 +71,13 @@ public abstract class SettingDisabledWarningFragment extends Fragment
} }
} }
@Override
public void onDestroyView()
{
super.onDestroyView();
mBinding = null;
}
public void onClick(View view) public void onClick(View view)
{ {
SettingsActivity.launch(requireContext(), mSettingShortcut); SettingsActivity.launch(requireContext(), mSettingShortcut);

View File

@ -9,7 +9,7 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.databinding.ListItemRiivolutionBinding;
import org.dolphinemu.dolphinemu.features.riivolution.model.RiivolutionPatches; import org.dolphinemu.dolphinemu.features.riivolution.model.RiivolutionPatches;
import java.util.ArrayList; import java.util.ArrayList;
@ -48,8 +48,8 @@ public class RiivolutionAdapter extends RecyclerView.Adapter<RiivolutionViewHold
public RiivolutionViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) public RiivolutionViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType)
{ {
LayoutInflater inflater = LayoutInflater.from(parent.getContext()); LayoutInflater inflater = LayoutInflater.from(parent.getContext());
return new RiivolutionViewHolder( ListItemRiivolutionBinding binding = ListItemRiivolutionBinding.inflate(inflater);
inflater.inflate(R.layout.list_item_riivolution, parent, false)); return new RiivolutionViewHolder(binding.getRoot(), binding);
} }
@Override @Override

View File

@ -5,22 +5,14 @@ package org.dolphinemu.dolphinemu.features.riivolution.ui;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.core.view.WindowCompat; import androidx.core.view.WindowCompat;
import androidx.core.widget.NestedScrollView;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.appbar.AppBarLayout;
import com.google.android.material.appbar.CollapsingToolbarLayout;
import com.google.android.material.appbar.MaterialToolbar;
import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.activities.EmulationActivity; import org.dolphinemu.dolphinemu.activities.EmulationActivity;
import org.dolphinemu.dolphinemu.databinding.ActivityRiivolutionBootBinding;
import org.dolphinemu.dolphinemu.features.riivolution.model.RiivolutionPatches; import org.dolphinemu.dolphinemu.features.riivolution.model.RiivolutionPatches;
import org.dolphinemu.dolphinemu.features.settings.model.StringSetting; import org.dolphinemu.dolphinemu.features.settings.model.StringSetting;
import org.dolphinemu.dolphinemu.utils.DirectoryInitialization; import org.dolphinemu.dolphinemu.utils.DirectoryInitialization;
@ -36,6 +28,8 @@ public class RiivolutionBootActivity extends AppCompatActivity
private RiivolutionPatches mPatches; private RiivolutionPatches mPatches;
private ActivityRiivolutionBootBinding mBinding;
public static void launch(Context context, String gamePath, String gameId, int revision, public static void launch(Context context, String gamePath, String gameId, int revision,
int discNumber) int discNumber)
{ {
@ -54,7 +48,8 @@ public class RiivolutionBootActivity extends AppCompatActivity
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_riivolution_boot); mBinding = ActivityRiivolutionBootBinding.inflate(getLayoutInflater());
setContentView(mBinding.getRoot());
WindowCompat.setDecorFitsSystemWindows(getWindow(), false); WindowCompat.setDecorFitsSystemWindows(getWindow(), false);
@ -69,11 +64,9 @@ public class RiivolutionBootActivity extends AppCompatActivity
if (loadPath.isEmpty()) if (loadPath.isEmpty())
loadPath = DirectoryInitialization.getUserDirectory() + "/Load"; loadPath = DirectoryInitialization.getUserDirectory() + "/Load";
TextView textSdRoot = findViewById(R.id.text_sd_root); mBinding.textSdRoot.setText(getString(R.string.riivolution_sd_root, loadPath + "/Riivolution"));
textSdRoot.setText(getString(R.string.riivolution_sd_root, loadPath + "/Riivolution"));
Button buttonStart = findViewById(R.id.button_start); mBinding.buttonStart.setOnClickListener((v) ->
buttonStart.setOnClickListener((v) ->
{ {
if (mPatches != null) if (mPatches != null)
mPatches.saveConfig(); mPatches.saveConfig();
@ -88,17 +81,13 @@ public class RiivolutionBootActivity extends AppCompatActivity
runOnUiThread(() -> populateList(patches)); runOnUiThread(() -> populateList(patches));
}).start(); }).start();
MaterialToolbar tb = findViewById(R.id.toolbar_riivolution); mBinding.toolbarRiivolutionLayout.setTitle(getString(R.string.riivolution_riivolution));
CollapsingToolbarLayout ctb = findViewById(R.id.toolbar_riivolution_layout); setSupportActionBar(mBinding.toolbarRiivolution);
ctb.setTitle(getString(R.string.riivolution_riivolution));
setSupportActionBar(tb);
getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setDisplayHomeAsUpEnabled(true);
AppBarLayout appBarLayout = findViewById(R.id.appbar_riivolution); InsetsHelper.setUpAppBarWithScrollView(this, mBinding.appbarRiivolution,
NestedScrollView scrollView = findViewById(R.id.scroll_view_riivolution); mBinding.scrollViewRiivolution, mBinding.workaroundView);
View workaroundView = findViewById(R.id.workaround_view); ThemeHelper.enableScrollTint(this, mBinding.toolbarRiivolution, mBinding.appbarRiivolution);
InsetsHelper.setUpAppBarWithScrollView(this, appBarLayout, scrollView, workaroundView);
ThemeHelper.enableScrollTint(this, tb, appBarLayout);
} }
@Override @Override
@ -121,9 +110,7 @@ public class RiivolutionBootActivity extends AppCompatActivity
{ {
mPatches = patches; mPatches = patches;
RecyclerView recyclerView = findViewById(R.id.recycler_view); mBinding.recyclerView.setAdapter(new RiivolutionAdapter(this, patches));
mBinding.recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(new RiivolutionAdapter(this, patches));
recyclerView.setLayoutManager(new LinearLayoutManager(this));
} }
} }

View File

@ -6,60 +6,53 @@ import android.content.Context;
import android.view.View; import android.view.View;
import android.widget.AdapterView; import android.widget.AdapterView;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import android.widget.TextView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.textfield.MaterialAutoCompleteTextView;
import com.google.android.material.textfield.TextInputLayout;
import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.databinding.ListItemRiivolutionBinding;
import org.dolphinemu.dolphinemu.features.riivolution.model.RiivolutionPatches; import org.dolphinemu.dolphinemu.features.riivolution.model.RiivolutionPatches;
public class RiivolutionViewHolder extends RecyclerView.ViewHolder public class RiivolutionViewHolder extends RecyclerView.ViewHolder
implements AdapterView.OnItemClickListener implements AdapterView.OnItemClickListener
{ {
private final TextView mTextView; private final ListItemRiivolutionBinding mBinding;
private final TextInputLayout mChoiceLayout;
private final MaterialAutoCompleteTextView mChoiceDropdown;
private RiivolutionPatches mPatches; private RiivolutionPatches mPatches;
private RiivolutionItem mItem; private RiivolutionItem mItem;
public RiivolutionViewHolder(@NonNull View itemView) public RiivolutionViewHolder(@NonNull View itemView, ListItemRiivolutionBinding binding)
{ {
super(itemView); super(itemView);
mBinding = binding;
mTextView = itemView.findViewById(R.id.text_name);
mChoiceLayout = itemView.findViewById(R.id.layout_choice);
mChoiceDropdown = itemView.findViewById(R.id.dropdown_choice);
} }
public void bind(Context context, RiivolutionPatches patches, RiivolutionItem item) public void bind(Context context, RiivolutionPatches patches, RiivolutionItem item)
{ {
// TODO: Remove workaround for text filtering issue in material components when fixed // TODO: Remove workaround for text filtering issue in material components when fixed
// https://github.com/material-components/material-components-android/issues/1464 // https://github.com/material-components/material-components-android/issues/1464
mChoiceDropdown.setSaveEnabled(false); mBinding.dropdownChoice.setSaveEnabled(false);
String text; String text;
if (item.mOptionIndex != -1) if (item.mOptionIndex != -1)
{ {
mTextView.setVisibility(View.GONE); mBinding.textName.setVisibility(View.GONE);
text = patches.getOptionName(item.mDiscIndex, item.mSectionIndex, item.mOptionIndex); text = patches.getOptionName(item.mDiscIndex, item.mSectionIndex, item.mOptionIndex);
mChoiceLayout.setHint(text); mBinding.layoutChoice.setHint(text);
} }
else if (item.mSectionIndex != -1) else if (item.mSectionIndex != -1)
{ {
mTextView.setTextAppearance(context, R.style.TextAppearance_AppCompat_Medium); mBinding.textName.setTextAppearance(context, R.style.TextAppearance_AppCompat_Medium);
mChoiceLayout.setVisibility(View.GONE); mBinding.layoutChoice.setVisibility(View.GONE);
text = patches.getSectionName(item.mDiscIndex, item.mSectionIndex); text = patches.getSectionName(item.mDiscIndex, item.mSectionIndex);
} }
else else
{ {
mChoiceLayout.setVisibility(View.GONE); mBinding.layoutChoice.setVisibility(View.GONE);
text = patches.getDiscName(item.mDiscIndex); text = patches.getDiscName(item.mDiscIndex);
} }
mTextView.setText(text); mBinding.textName.setText(text);
if (item.mOptionIndex != -1) if (item.mOptionIndex != -1)
{ {
@ -78,11 +71,11 @@ public class RiivolutionViewHolder extends RecyclerView.ViewHolder
i)); i));
} }
mChoiceDropdown.setAdapter(adapter); mBinding.dropdownChoice.setAdapter(adapter);
mChoiceDropdown.setText(adapter.getItem( mBinding.dropdownChoice.setText(adapter.getItem(
patches.getSelectedChoice(mItem.mDiscIndex, mItem.mSectionIndex, mItem.mOptionIndex)), patches.getSelectedChoice(mItem.mDiscIndex, mItem.mSectionIndex, mItem.mOptionIndex)),
false); false);
mChoiceDropdown.setOnItemClickListener(this); mBinding.dropdownChoice.setOnItemClickListener(this);
} }
} }

View File

@ -28,6 +28,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.dolphinemu.dolphinemu.NativeLibrary; import org.dolphinemu.dolphinemu.NativeLibrary;
import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.databinding.ActivitySettingsBinding;
import org.dolphinemu.dolphinemu.ui.main.MainPresenter; import org.dolphinemu.dolphinemu.ui.main.MainPresenter;
import org.dolphinemu.dolphinemu.utils.FileBrowserHelper; import org.dolphinemu.dolphinemu.utils.FileBrowserHelper;
import org.dolphinemu.dolphinemu.utils.InsetsHelper; import org.dolphinemu.dolphinemu.utils.InsetsHelper;
@ -81,7 +82,8 @@ public final class SettingsActivity extends AppCompatActivity implements Setting
MainPresenter.skipRescanningLibrary(); MainPresenter.skipRescanningLibrary();
} }
setContentView(R.layout.activity_settings); ActivitySettingsBinding binding = ActivitySettingsBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
WindowCompat.setDecorFitsSystemWindows(getWindow(), false); WindowCompat.setDecorFitsSystemWindows(getWindow(), false);
@ -96,21 +98,17 @@ public final class SettingsActivity extends AppCompatActivity implements Setting
mPresenter = new SettingsActivityPresenter(this, getSettings()); mPresenter = new SettingsActivityPresenter(this, getSettings());
mPresenter.onCreate(savedInstanceState, menuTag, gameID, revision, isWii, this); mPresenter.onCreate(savedInstanceState, menuTag, gameID, revision, isWii, this);
MaterialToolbar tb = findViewById(R.id.toolbar_settings); mToolbarLayout = binding.toolbarSettingsLayout;
mToolbarLayout = findViewById(R.id.toolbar_settings_layout); setSupportActionBar(binding.toolbarSettings);
setSupportActionBar(tb);
getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setDisplayHomeAsUpEnabled(true);
AppBarLayout appBarLayout = findViewById(R.id.appbar_settings);
FrameLayout frameLayout = findViewById(R.id.frame_content_settings);
// TODO: Remove this when CollapsingToolbarLayouts are fixed by Google // TODO: Remove this when CollapsingToolbarLayouts are fixed by Google
// https://github.com/material-components/material-components-android/issues/1310 // https://github.com/material-components/material-components-android/issues/1310
ViewCompat.setOnApplyWindowInsetsListener(mToolbarLayout, null); ViewCompat.setOnApplyWindowInsetsListener(mToolbarLayout, null);
View workaroundView = findViewById(R.id.workaround_view); InsetsHelper.setUpSettingsLayout(this, binding.appbarSettings, binding.frameContentSettings,
InsetsHelper.setUpSettingsLayout(this, appBarLayout, frameLayout, workaroundView); binding.workaroundView);
ThemeHelper.enableScrollTint(this, tb, appBarLayout); ThemeHelper.enableScrollTint(this, binding.toolbarSettings, binding.appbarSettings);
} }
@Override @Override

View File

@ -8,7 +8,6 @@ import android.content.Intent;
import android.os.Build; import android.os.Build;
import android.provider.DocumentsContract; import android.provider.DocumentsContract;
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;
@ -21,6 +20,12 @@ import com.google.android.material.slider.Slider;
import com.google.android.material.textfield.TextInputEditText; import com.google.android.material.textfield.TextInputEditText;
import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.databinding.DialogInputStringBinding;
import org.dolphinemu.dolphinemu.databinding.DialogSliderBinding;
import org.dolphinemu.dolphinemu.databinding.ListItemHeaderBinding;
import org.dolphinemu.dolphinemu.databinding.ListItemSettingBinding;
import org.dolphinemu.dolphinemu.databinding.ListItemSettingCheckboxBinding;
import org.dolphinemu.dolphinemu.databinding.ListItemSubmenuBinding;
import org.dolphinemu.dolphinemu.dialogs.MotionAlertDialog; import org.dolphinemu.dolphinemu.dialogs.MotionAlertDialog;
import org.dolphinemu.dolphinemu.features.settings.model.Settings; import org.dolphinemu.dolphinemu.features.settings.model.Settings;
import org.dolphinemu.dolphinemu.features.settings.model.view.CheckBoxSetting; import org.dolphinemu.dolphinemu.features.settings.model.view.CheckBoxSetting;
@ -79,59 +84,50 @@ public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolde
mClickedPosition = -1; mClickedPosition = -1;
} }
@NonNull
@Override @Override
public SettingViewHolder onCreateViewHolder(ViewGroup parent, int viewType) public SettingViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType)
{ {
View view;
LayoutInflater inflater = LayoutInflater.from(parent.getContext()); LayoutInflater inflater = LayoutInflater.from(parent.getContext());
switch (viewType) switch (viewType)
{ {
case SettingsItem.TYPE_HEADER: case SettingsItem.TYPE_HEADER:
view = inflater.inflate(R.layout.list_item_header, parent, false); return new HeaderViewHolder(ListItemHeaderBinding.inflate(inflater), this);
return new HeaderViewHolder(view, this);
case SettingsItem.TYPE_CHECKBOX: case SettingsItem.TYPE_CHECKBOX:
view = inflater.inflate(R.layout.list_item_setting_checkbox, parent, false); return new CheckBoxSettingViewHolder(ListItemSettingCheckboxBinding.inflate(inflater),
return new CheckBoxSettingViewHolder(view, this); this);
case SettingsItem.TYPE_STRING_SINGLE_CHOICE: case SettingsItem.TYPE_STRING_SINGLE_CHOICE:
case SettingsItem.TYPE_SINGLE_CHOICE_DYNAMIC_DESCRIPTIONS: case SettingsItem.TYPE_SINGLE_CHOICE_DYNAMIC_DESCRIPTIONS:
case SettingsItem.TYPE_SINGLE_CHOICE: case SettingsItem.TYPE_SINGLE_CHOICE:
view = inflater.inflate(R.layout.list_item_setting, parent, false); return new SingleChoiceViewHolder(ListItemSettingBinding.inflate(inflater), this);
return new SingleChoiceViewHolder(view, this);
case SettingsItem.TYPE_SLIDER: case SettingsItem.TYPE_SLIDER:
view = inflater.inflate(R.layout.list_item_setting, parent, false); return new SliderViewHolder(ListItemSettingBinding.inflate(inflater), this, mContext);
return new SliderViewHolder(view, this, mContext);
case SettingsItem.TYPE_SUBMENU: case SettingsItem.TYPE_SUBMENU:
view = inflater.inflate(R.layout.list_item_submenu, parent, false); return new SubmenuViewHolder(ListItemSubmenuBinding.inflate(inflater), this);
return new SubmenuViewHolder(view, this);
case SettingsItem.TYPE_INPUT_BINDING: case SettingsItem.TYPE_INPUT_BINDING:
view = inflater.inflate(R.layout.list_item_setting, parent, false); return new InputBindingSettingViewHolder(ListItemSettingBinding.inflate(inflater), this,
return new InputBindingSettingViewHolder(view, this, mContext); mContext);
case SettingsItem.TYPE_RUMBLE_BINDING: case SettingsItem.TYPE_RUMBLE_BINDING:
view = inflater.inflate(R.layout.list_item_setting, parent, false); return new RumbleBindingViewHolder(ListItemSettingBinding.inflate(inflater), this,
return new RumbleBindingViewHolder(view, this, mContext); mContext);
case SettingsItem.TYPE_FILE_PICKER: case SettingsItem.TYPE_FILE_PICKER:
view = inflater.inflate(R.layout.list_item_setting, parent, false); return new FilePickerViewHolder(ListItemSettingBinding.inflate(inflater), this);
return new FilePickerViewHolder(view, this);
case SettingsItem.TYPE_RUN_RUNNABLE: case SettingsItem.TYPE_RUN_RUNNABLE:
view = inflater.inflate(R.layout.list_item_setting, parent, false); return new RunRunnableViewHolder(ListItemSettingBinding.inflate(inflater), this, mContext);
return new RunRunnableViewHolder(view, this, mContext);
case SettingsItem.TYPE_STRING: case SettingsItem.TYPE_STRING:
view = inflater.inflate(R.layout.list_item_setting, parent, false); return new InputStringSettingViewHolder(ListItemSettingBinding.inflate(inflater), this);
return new InputStringSettingViewHolder(view, this);
case SettingsItem.TYPE_HYPERLINK_HEADER: case SettingsItem.TYPE_HYPERLINK_HEADER:
view = inflater.inflate(R.layout.list_item_header, parent, false); return new HeaderHyperLinkViewHolder(ListItemHeaderBinding.inflate(inflater), this);
return new HeaderHyperLinkViewHolder(view, this, mContext);
default: default:
throw new IllegalArgumentException("Invalid view type: " + viewType); throw new IllegalArgumentException("Invalid view type: " + viewType);
@ -139,7 +135,7 @@ public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolde
} }
@Override @Override
public void onBindViewHolder(SettingViewHolder holder, int position) public void onBindViewHolder(@NonNull SettingViewHolder holder, int position)
{ {
holder.bind(getItem(position)); holder.bind(getItem(position));
} }
@ -206,12 +202,12 @@ public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolde
{ {
LayoutInflater inflater = LayoutInflater.from(mContext); LayoutInflater inflater = LayoutInflater.from(mContext);
View dialogView = inflater.inflate(R.layout.dialog_input_string, null); DialogInputStringBinding binding = DialogInputStringBinding.inflate(inflater);
TextInputEditText input = dialogView.findViewById(R.id.input); TextInputEditText input = binding.input;
input.setText(item.getSelectedValue(getSettings())); input.setText(item.getSelectedValue(getSettings()));
mDialog = new MaterialAlertDialogBuilder(mView.getActivity()) mDialog = new MaterialAlertDialogBuilder(mView.getActivity())
.setView(dialogView) .setView(binding.getRoot())
.setMessage(item.getDescription()) .setMessage(item.getDescription())
.setPositiveButton(R.string.ok, (dialogInterface, i) -> .setPositiveButton(R.string.ok, (dialogInterface, i) ->
{ {
@ -275,26 +271,25 @@ public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolde
mSeekbarProgress = item.getSelectedValue(getSettings()); mSeekbarProgress = item.getSelectedValue(getSettings());
LayoutInflater inflater = LayoutInflater.from(mView.getActivity()); LayoutInflater inflater = LayoutInflater.from(mView.getActivity());
View view = inflater.inflate(R.layout.dialog_slider, null); DialogSliderBinding binding = DialogSliderBinding.inflate(inflater);
mDialog = new MaterialAlertDialogBuilder(mView.getActivity()) mTextSliderValue = binding.textValue;
.setTitle(item.getName())
.setView(view)
.setPositiveButton(R.string.ok, this)
.show();
mTextSliderValue = view.findViewById(R.id.text_value);
mTextSliderValue.setText(String.valueOf(mSeekbarProgress)); mTextSliderValue.setText(String.valueOf(mSeekbarProgress));
TextView units = view.findViewById(R.id.text_units); binding.textUnits.setText(item.getUnits());
units.setText(item.getUnits());
Slider slider = view.findViewById(R.id.slider); Slider slider = binding.slider;
slider.setValueFrom(item.getMin()); slider.setValueFrom(item.getMin());
slider.setValueTo(item.getMax()); slider.setValueTo(item.getMax());
slider.setValue(mSeekbarProgress); slider.setValue(mSeekbarProgress);
slider.setStepSize(1); slider.setStepSize(1);
slider.addOnChangeListener(this); slider.addOnChangeListener(this);
mDialog = new MaterialAlertDialogBuilder(mView.getActivity())
.setTitle(item.getName())
.setView(binding.getRoot())
.setPositiveButton(R.string.ok, this)
.show();
} }
public void onSubmenuClick(SubmenuSetting item) public void onSubmenuClick(SubmenuSetting item)

View File

@ -17,6 +17,7 @@ import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.divider.MaterialDividerItemDecoration; import com.google.android.material.divider.MaterialDividerItemDecoration;
import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.databinding.FragmentSettingsBinding;
import org.dolphinemu.dolphinemu.features.settings.model.Settings; import org.dolphinemu.dolphinemu.features.settings.model.Settings;
import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem; import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem;
import org.dolphinemu.dolphinemu.utils.InsetsHelper; import org.dolphinemu.dolphinemu.utils.InsetsHelper;
@ -74,6 +75,8 @@ public final class SettingsFragment extends Fragment implements SettingsFragment
titles.put(MenuTag.WIIMOTE_EXTENSION_4, R.string.wiimote_extension_7); titles.put(MenuTag.WIIMOTE_EXTENSION_4, R.string.wiimote_extension_7);
} }
private FragmentSettingsBinding mBinding;
public static Fragment newInstance(MenuTag menuTag, String gameId, Bundle extras) public static Fragment newInstance(MenuTag menuTag, String gameId, Bundle extras)
{ {
SettingsFragment fragment = new SettingsFragment(); SettingsFragment fragment = new SettingsFragment();
@ -114,12 +117,13 @@ public final class SettingsFragment extends Fragment implements SettingsFragment
mPresenter.onCreate(menuTag, gameId, args); mPresenter.onCreate(menuTag, gameId, args);
} }
@Nullable @NonNull
@Override @Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) @Nullable Bundle savedInstanceState)
{ {
return inflater.inflate(R.layout.fragment_settings, container, false); mBinding = FragmentSettingsBinding.inflate(inflater, container, false);
return mBinding.getRoot();
} }
@Override @Override
@ -135,7 +139,7 @@ public final class SettingsFragment extends Fragment implements SettingsFragment
LinearLayoutManager manager = new LinearLayoutManager(getActivity()); LinearLayoutManager manager = new LinearLayoutManager(getActivity());
RecyclerView recyclerView = view.findViewById(R.id.list_settings); RecyclerView recyclerView = mBinding.listSettings;
recyclerView.setAdapter(mAdapter); recyclerView.setAdapter(mAdapter);
recyclerView.setLayoutManager(manager); recyclerView.setLayoutManager(manager);
@ -151,6 +155,13 @@ public final class SettingsFragment extends Fragment implements SettingsFragment
mPresenter.onViewCreated(menuTag, activity.getSettings()); mPresenter.onViewCreated(menuTag, activity.getSettings());
} }
@Override
public void onDestroyView()
{
super.onDestroyView();
mBinding = null;
}
@Override @Override
public void onDetach() public void onDetach()
{ {

View File

@ -3,12 +3,10 @@
package org.dolphinemu.dolphinemu.features.settings.ui.viewholder; package org.dolphinemu.dolphinemu.features.settings.ui.viewholder;
import android.view.View; import android.view.View;
import android.widget.CheckBox;
import android.widget.TextView;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.databinding.ListItemSettingCheckboxBinding;
import org.dolphinemu.dolphinemu.features.settings.model.view.CheckBoxSetting; import org.dolphinemu.dolphinemu.features.settings.model.view.CheckBoxSetting;
import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem; import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter; import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
@ -17,22 +15,12 @@ public final class CheckBoxSettingViewHolder extends SettingViewHolder
{ {
private CheckBoxSetting mItem; private CheckBoxSetting mItem;
private TextView mTextSettingName; private final ListItemSettingCheckboxBinding mBinding;
private TextView mTextSettingDescription;
private CheckBox mCheckbox; public CheckBoxSettingViewHolder(ListItemSettingCheckboxBinding binding, SettingsAdapter adapter)
public CheckBoxSettingViewHolder(View itemView, SettingsAdapter adapter)
{ {
super(itemView, adapter); super(binding.getRoot(), adapter);
} mBinding = binding;
@Override
protected void findViews(View root)
{
mTextSettingName = root.findViewById(R.id.text_setting_name);
mTextSettingDescription = root.findViewById(R.id.text_setting_description);
mCheckbox = root.findViewById(R.id.checkbox);
} }
@Override @Override
@ -40,12 +28,12 @@ public final class CheckBoxSettingViewHolder extends SettingViewHolder
{ {
mItem = (CheckBoxSetting) item; mItem = (CheckBoxSetting) item;
mTextSettingName.setText(item.getName()); mBinding.textSettingName.setText(item.getName());
mTextSettingDescription.setText(item.getDescription()); mBinding.textSettingDescription.setText(item.getDescription());
mCheckbox.setChecked(mItem.isChecked(getAdapter().getSettings())); mBinding.checkbox.setChecked(mItem.isChecked(getAdapter().getSettings()));
setStyle(mTextSettingName, mItem); setStyle(mBinding.textSettingName, mItem);
} }
@Override @Override
@ -57,11 +45,11 @@ public final class CheckBoxSettingViewHolder extends SettingViewHolder
return; return;
} }
mCheckbox.toggle(); mBinding.checkbox.toggle();
getAdapter().onBooleanClick(mItem, getBindingAdapterPosition(), mCheckbox.isChecked()); getAdapter().onBooleanClick(mItem, getBindingAdapterPosition(), mBinding.checkbox.isChecked());
setStyle(mTextSettingName, mItem); setStyle(mBinding.textSettingName, mItem);
} }
@Nullable @Override @Nullable @Override

View File

@ -2,14 +2,13 @@
package org.dolphinemu.dolphinemu.features.settings.ui.viewholder; package org.dolphinemu.dolphinemu.features.settings.ui.viewholder;
import android.graphics.drawable.Drawable;
import android.text.TextUtils; import android.text.TextUtils;
import android.view.View; import android.view.View;
import android.widget.TextView;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.databinding.ListItemSettingBinding;
import org.dolphinemu.dolphinemu.features.settings.model.view.FilePicker; import org.dolphinemu.dolphinemu.features.settings.model.view.FilePicker;
import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem; import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter; import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
@ -22,23 +21,12 @@ public final class FilePickerViewHolder extends SettingViewHolder
private FilePicker mFilePicker; private FilePicker mFilePicker;
private SettingsItem mItem; private SettingsItem mItem;
private TextView mTextSettingName; private final ListItemSettingBinding mBinding;
private TextView mTextSettingDescription;
private Drawable mDefaultBackground; public FilePickerViewHolder(ListItemSettingBinding binding, SettingsAdapter adapter)
public FilePickerViewHolder(View itemView, SettingsAdapter adapter)
{ {
super(itemView, adapter); super(binding.getRoot(), adapter);
} mBinding = binding;
@Override
protected void findViews(View root)
{
mTextSettingName = root.findViewById(R.id.text_setting_name);
mTextSettingDescription = root.findViewById(R.id.text_setting_description);
mDefaultBackground = root.getBackground();
} }
@Override @Override
@ -51,18 +39,18 @@ public final class FilePickerViewHolder extends SettingViewHolder
if (FileBrowserHelper.isPathEmptyOrValid(path)) if (FileBrowserHelper.isPathEmptyOrValid(path))
{ {
itemView.setBackground(mDefaultBackground); itemView.setBackground(mBinding.getRoot().getBackground());
} }
else else
{ {
itemView.setBackgroundResource(R.drawable.invalid_setting_background); itemView.setBackgroundResource(R.drawable.invalid_setting_background);
} }
mTextSettingName.setText(item.getName()); mBinding.textSettingName.setText(item.getName());
if (!TextUtils.isEmpty(item.getDescription())) if (!TextUtils.isEmpty(item.getDescription()))
{ {
mTextSettingDescription.setText(item.getDescription()); mBinding.textSettingDescription.setText(item.getDescription());
} }
else else
{ {
@ -75,10 +63,10 @@ public final class FilePickerViewHolder extends SettingViewHolder
} }
} }
mTextSettingDescription.setText(path); mBinding.textSettingDescription.setText(path);
} }
setStyle(mTextSettingName, mItem); setStyle(mBinding.textSettingName, mItem);
} }
@Override @Override
@ -100,7 +88,7 @@ public final class FilePickerViewHolder extends SettingViewHolder
getAdapter().onFilePickerFileClick(mItem, position); getAdapter().onFilePickerFileClick(mItem, position);
} }
setStyle(mTextSettingName, mItem); setStyle(mBinding.textSettingName, mItem);
} }
@Nullable @Override @Nullable @Override

View File

@ -2,33 +2,35 @@
package org.dolphinemu.dolphinemu.features.settings.ui.viewholder; package org.dolphinemu.dolphinemu.features.settings.ui.viewholder;
import android.content.Context;
import android.text.method.LinkMovementMethod; import android.text.method.LinkMovementMethod;
import android.view.View;
import androidx.annotation.NonNull;
import com.google.android.material.color.MaterialColors; import com.google.android.material.color.MaterialColors;
import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.databinding.ListItemHeaderBinding;
import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem; import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter; import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
public final class HeaderHyperLinkViewHolder extends HeaderViewHolder public final class HeaderHyperLinkViewHolder extends HeaderViewHolder
{ {
private Context mContext; private final ListItemHeaderBinding mBinding;
public HeaderHyperLinkViewHolder(View itemView, SettingsAdapter adapter, Context context) public HeaderHyperLinkViewHolder(@NonNull ListItemHeaderBinding binding, SettingsAdapter adapter)
{ {
super(itemView, adapter); super(binding, adapter);
mContext = context; mBinding = binding;
itemView.setOnClickListener(null); itemView.setOnClickListener(null);
} }
@Override @Override
public void bind(SettingsItem item) public void bind(@NonNull SettingsItem item)
{ {
super.bind(item); super.bind(item);
mHeaderName.setMovementMethod(LinkMovementMethod.getInstance()); mBinding.textHeaderName.setMovementMethod(LinkMovementMethod.getInstance());
mHeaderName.setLinkTextColor(MaterialColors.getColor(itemView, R.attr.colorTertiary)); mBinding.textHeaderName.setLinkTextColor(
MaterialColors.getColor(itemView, R.attr.colorTertiary));
} }
} }

View File

@ -3,34 +3,29 @@
package org.dolphinemu.dolphinemu.features.settings.ui.viewholder; package org.dolphinemu.dolphinemu.features.settings.ui.viewholder;
import android.view.View; import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem; import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter; import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
import org.dolphinemu.dolphinemu.databinding.ListItemHeaderBinding;
public class HeaderViewHolder extends SettingViewHolder public class HeaderViewHolder extends SettingViewHolder
{ {
protected TextView mHeaderName; private final ListItemHeaderBinding mBinding;
public HeaderViewHolder(View itemView, SettingsAdapter adapter) public HeaderViewHolder(@NonNull ListItemHeaderBinding binding, SettingsAdapter adapter)
{ {
super(itemView, adapter); super(binding.getRoot(), adapter);
itemView.setOnClickListener(null); itemView.setOnClickListener(null);
mBinding = binding;
} }
@Override @Override
protected void findViews(View root) public void bind(@NonNull SettingsItem item)
{ {
mHeaderName = root.findViewById(R.id.text_header_name); mBinding.textHeaderName.setText(item.getName());
}
@Override
public void bind(SettingsItem item)
{
mHeaderName.setText(item.getName());
} }
@Override @Override

View File

@ -6,11 +6,11 @@ import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.view.View; import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.databinding.ListItemSettingBinding;
import org.dolphinemu.dolphinemu.features.settings.model.view.InputBindingSetting; import org.dolphinemu.dolphinemu.features.settings.model.view.InputBindingSetting;
import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem; import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter; import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
@ -19,25 +19,18 @@ public final class InputBindingSettingViewHolder extends SettingViewHolder
{ {
private InputBindingSetting mItem; private InputBindingSetting mItem;
private TextView mTextSettingName; private final Context mContext;
private TextView mTextSettingDescription;
private Context mContext; private final ListItemSettingBinding mBinding;
public InputBindingSettingViewHolder(View itemView, SettingsAdapter adapter, Context context) public InputBindingSettingViewHolder(@NonNull ListItemSettingBinding binding,
SettingsAdapter adapter, Context context)
{ {
super(itemView, adapter); super(binding.getRoot(), adapter);
mBinding = binding;
mContext = context; mContext = context;
} }
@Override
protected void findViews(View root)
{
mTextSettingName = root.findViewById(R.id.text_setting_name);
mTextSettingDescription = root.findViewById(R.id.text_setting_description);
}
@Override @Override
public void bind(SettingsItem item) public void bind(SettingsItem item)
{ {
@ -45,11 +38,11 @@ public final class InputBindingSettingViewHolder extends SettingViewHolder
mItem = (InputBindingSetting) item; mItem = (InputBindingSetting) item;
mTextSettingName.setText(mItem.getName()); mBinding.textSettingName.setText(mItem.getName());
mTextSettingDescription mBinding.textSettingDescription
.setText(sharedPreferences.getString(mItem.getKey() + mItem.getGameId(), "")); .setText(sharedPreferences.getString(mItem.getKey() + mItem.getGameId(), ""));
setStyle(mTextSettingName, mItem); setStyle(mBinding.textSettingName, mItem);
} }
@Override @Override
@ -63,7 +56,7 @@ public final class InputBindingSettingViewHolder extends SettingViewHolder
getAdapter().onInputBindingClick(mItem, getBindingAdapterPosition()); getAdapter().onInputBindingClick(mItem, getBindingAdapterPosition());
setStyle(mTextSettingName, mItem); setStyle(mBinding.textSettingName, mItem);
} }
@Nullable @Override @Nullable @Override

View File

@ -4,11 +4,11 @@ package org.dolphinemu.dolphinemu.features.settings.ui.viewholder;
import android.text.TextUtils; import android.text.TextUtils;
import android.view.View; import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.databinding.ListItemSettingBinding;
import org.dolphinemu.dolphinemu.features.settings.model.view.InputStringSetting; import org.dolphinemu.dolphinemu.features.settings.model.view.InputStringSetting;
import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem; import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter; import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
@ -17,19 +17,13 @@ public final class InputStringSettingViewHolder extends SettingViewHolder
{ {
private InputStringSetting mInputString; private InputStringSetting mInputString;
private TextView mTextSettingName; private final ListItemSettingBinding mBinding;
private TextView mTextSettingDescription;
public InputStringSettingViewHolder(View itemView, SettingsAdapter adapter) public InputStringSettingViewHolder(@NonNull ListItemSettingBinding binding,
SettingsAdapter adapter)
{ {
super(itemView, adapter); super(binding.getRoot(), adapter);
} mBinding = binding;
@Override
protected void findViews(View root)
{
mTextSettingName = root.findViewById(R.id.text_setting_name);
mTextSettingDescription = root.findViewById(R.id.text_setting_description);
} }
@Override @Override
@ -39,18 +33,18 @@ public final class InputStringSettingViewHolder extends SettingViewHolder
String inputString = mInputString.getSelectedValue(getAdapter().getSettings()); String inputString = mInputString.getSelectedValue(getAdapter().getSettings());
mTextSettingName.setText(item.getName()); mBinding.textSettingName.setText(item.getName());
if (!TextUtils.isEmpty(inputString)) if (!TextUtils.isEmpty(inputString))
{ {
mTextSettingDescription.setText(inputString); mBinding.textSettingDescription.setText(inputString);
} }
else else
{ {
mTextSettingDescription.setText(item.getDescription()); mBinding.textSettingDescription.setText(item.getDescription());
} }
setStyle(mTextSettingName, mInputString); setStyle(mBinding.textSettingName, mInputString);
} }
@Override @Override
@ -62,11 +56,11 @@ public final class InputStringSettingViewHolder extends SettingViewHolder
return; return;
} }
int position = getAdapterPosition(); int position = getBindingAdapterPosition();
getAdapter().onInputStringClick(mInputString, position); getAdapter().onInputStringClick(mInputString, position);
setStyle(mTextSettingName, mInputString); setStyle(mBinding.textSettingName, mInputString);
} }
@Nullable @Override @Nullable @Override

View File

@ -6,11 +6,11 @@ import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.view.View; import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.databinding.ListItemSettingBinding;
import org.dolphinemu.dolphinemu.features.settings.model.view.RumbleBindingSetting; import org.dolphinemu.dolphinemu.features.settings.model.view.RumbleBindingSetting;
import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem; import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter; import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
@ -19,25 +19,18 @@ public class RumbleBindingViewHolder extends SettingViewHolder
{ {
private RumbleBindingSetting mItem; private RumbleBindingSetting mItem;
private TextView mTextSettingName; private final Context mContext;
private TextView mTextSettingDescription;
private Context mContext; private final ListItemSettingBinding mBinding;
public RumbleBindingViewHolder(View itemView, SettingsAdapter adapter, Context context) public RumbleBindingViewHolder(@NonNull ListItemSettingBinding binding, SettingsAdapter adapter,
Context context)
{ {
super(itemView, adapter); super(binding.getRoot(), adapter);
mBinding = binding;
mContext = context; mContext = context;
} }
@Override
protected void findViews(View root)
{
mTextSettingName = root.findViewById(R.id.text_setting_name);
mTextSettingDescription = root.findViewById(R.id.text_setting_description);
}
@Override @Override
public void bind(SettingsItem item) public void bind(SettingsItem item)
{ {
@ -45,11 +38,11 @@ public class RumbleBindingViewHolder extends SettingViewHolder
mItem = (RumbleBindingSetting) item; mItem = (RumbleBindingSetting) item;
mTextSettingName.setText(item.getName()); mBinding.textSettingName.setText(item.getName());
mTextSettingDescription mBinding.textSettingDescription
.setText(sharedPreferences.getString(mItem.getKey() + mItem.getGameId(), "")); .setText(sharedPreferences.getString(mItem.getKey() + mItem.getGameId(), ""));
setStyle(mTextSettingName, mItem); setStyle(mBinding.textSettingName, mItem);
} }
@Override @Override
@ -63,7 +56,7 @@ public class RumbleBindingViewHolder extends SettingViewHolder
getAdapter().onInputBindingClick(mItem, getBindingAdapterPosition()); getAdapter().onInputBindingClick(mItem, getBindingAdapterPosition());
setStyle(mTextSettingName, mItem); setStyle(mBinding.textSettingName, mItem);
} }
@Nullable @Override @Nullable @Override

View File

@ -4,14 +4,15 @@ package org.dolphinemu.dolphinemu.features.settings.ui.viewholder;
import android.content.Context; import android.content.Context;
import android.view.View; import android.view.View;
import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.databinding.ListItemSettingBinding;
import org.dolphinemu.dolphinemu.features.settings.model.view.RunRunnable; import org.dolphinemu.dolphinemu.features.settings.model.view.RunRunnable;
import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem; import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter; import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
@ -22,30 +23,23 @@ public final class RunRunnableViewHolder extends SettingViewHolder
private final Context mContext; private final Context mContext;
private TextView mTextSettingName; private final ListItemSettingBinding mBinding;
private TextView mTextSettingDescription;
public RunRunnableViewHolder(View itemView, SettingsAdapter adapter, Context context) public RunRunnableViewHolder(@NonNull ListItemSettingBinding binding, SettingsAdapter adapter,
Context context)
{ {
super(itemView, adapter); super(binding.getRoot(), adapter);
mBinding = binding;
mContext = context; mContext = context;
} }
@Override
protected void findViews(View root)
{
mTextSettingName = root.findViewById(R.id.text_setting_name);
mTextSettingDescription = root.findViewById(R.id.text_setting_description);
}
@Override @Override
public void bind(SettingsItem item) public void bind(SettingsItem item)
{ {
mItem = (RunRunnable) item; mItem = (RunRunnable) item;
mTextSettingName.setText(item.getName()); mBinding.textSettingName.setText(item.getName());
mTextSettingDescription.setText(item.getDescription()); mBinding.textSettingDescription.setText(item.getDescription());
} }
@Override @Override

View File

@ -32,8 +32,6 @@ public abstract class SettingViewHolder extends RecyclerView.ViewHolder
itemView.setOnClickListener(this); itemView.setOnClickListener(this);
itemView.setOnLongClickListener(this); itemView.setOnLongClickListener(this);
findViews(itemView);
} }
protected SettingsAdapter getAdapter() protected SettingsAdapter getAdapter()
@ -56,13 +54,6 @@ public abstract class SettingViewHolder extends RecyclerView.ViewHolder
Toast.LENGTH_SHORT).show(); Toast.LENGTH_SHORT).show();
} }
/**
* Gets handles to all this ViewHolder's child views using their XML-defined identifiers.
*
* @param root The newly inflated top-level view.
*/
protected abstract void findViews(View root);
/** /**
* 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

@ -5,11 +5,11 @@ package org.dolphinemu.dolphinemu.features.settings.ui.viewholder;
import android.content.res.Resources; import android.content.res.Resources;
import android.text.TextUtils; import android.text.TextUtils;
import android.view.View; import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.databinding.ListItemSettingBinding;
import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem; import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem;
import org.dolphinemu.dolphinemu.features.settings.model.view.SingleChoiceSetting; import org.dolphinemu.dolphinemu.features.settings.model.view.SingleChoiceSetting;
import org.dolphinemu.dolphinemu.features.settings.model.view.SingleChoiceSettingDynamicDescriptions; import org.dolphinemu.dolphinemu.features.settings.model.view.SingleChoiceSettingDynamicDescriptions;
@ -20,19 +20,12 @@ public final class SingleChoiceViewHolder extends SettingViewHolder
{ {
private SettingsItem mItem; private SettingsItem mItem;
private TextView mTextSettingName; private final ListItemSettingBinding mBinding;
private TextView mTextSettingDescription;
public SingleChoiceViewHolder(View itemView, SettingsAdapter adapter) public SingleChoiceViewHolder(@NonNull ListItemSettingBinding binding, SettingsAdapter adapter)
{ {
super(itemView, adapter); super(binding.getRoot(), adapter);
} mBinding = binding;
@Override
protected void findViews(View root)
{
mTextSettingName = root.findViewById(R.id.text_setting_name);
mTextSettingDescription = root.findViewById(R.id.text_setting_description);
} }
@Override @Override
@ -40,24 +33,24 @@ public final class SingleChoiceViewHolder extends SettingViewHolder
{ {
mItem = item; mItem = item;
mTextSettingName.setText(item.getName()); mBinding.textSettingName.setText(item.getName());
if (!TextUtils.isEmpty(item.getDescription())) if (!TextUtils.isEmpty(item.getDescription()))
{ {
mTextSettingDescription.setText(item.getDescription()); mBinding.textSettingDescription.setText(item.getDescription());
} }
else if (item instanceof SingleChoiceSetting) else if (item instanceof SingleChoiceSetting)
{ {
SingleChoiceSetting setting = (SingleChoiceSetting) item; SingleChoiceSetting setting = (SingleChoiceSetting) item;
int selected = setting.getSelectedValue(getAdapter().getSettings()); int selected = setting.getSelectedValue(getAdapter().getSettings());
Resources resMgr = mTextSettingDescription.getContext().getResources(); Resources resMgr = mBinding.textSettingDescription.getContext().getResources();
String[] choices = resMgr.getStringArray(setting.getChoicesId()); String[] choices = resMgr.getStringArray(setting.getChoicesId());
int[] values = resMgr.getIntArray(setting.getValuesId()); int[] values = resMgr.getIntArray(setting.getValuesId());
for (int i = 0; i < values.length; ++i) for (int i = 0; i < values.length; ++i)
{ {
if (values[i] == selected) if (values[i] == selected)
{ {
mTextSettingDescription.setText(choices[i]); mBinding.textSettingDescription.setText(choices[i]);
} }
} }
} }
@ -67,26 +60,26 @@ public final class SingleChoiceViewHolder extends SettingViewHolder
String[] choices = setting.getChoices(); String[] choices = setting.getChoices();
int valueIndex = setting.getSelectedValueIndex(getAdapter().getSettings()); int valueIndex = setting.getSelectedValueIndex(getAdapter().getSettings());
if (valueIndex != -1) if (valueIndex != -1)
mTextSettingDescription.setText(choices[valueIndex]); mBinding.textSettingDescription.setText(choices[valueIndex]);
} }
else if (item instanceof SingleChoiceSettingDynamicDescriptions) else if (item instanceof SingleChoiceSettingDynamicDescriptions)
{ {
SingleChoiceSettingDynamicDescriptions setting = SingleChoiceSettingDynamicDescriptions setting =
(SingleChoiceSettingDynamicDescriptions) item; (SingleChoiceSettingDynamicDescriptions) item;
int selected = setting.getSelectedValue(getAdapter().getSettings()); int selected = setting.getSelectedValue(getAdapter().getSettings());
Resources resMgr = mTextSettingDescription.getContext().getResources(); Resources resMgr = mBinding.textSettingDescription.getContext().getResources();
String[] choices = resMgr.getStringArray(setting.getDescriptionChoicesId()); String[] choices = resMgr.getStringArray(setting.getDescriptionChoicesId());
int[] values = resMgr.getIntArray(setting.getDescriptionValuesId()); int[] values = resMgr.getIntArray(setting.getDescriptionValuesId());
for (int i = 0; i < values.length; ++i) for (int i = 0; i < values.length; ++i)
{ {
if (values[i] == selected) if (values[i] == selected)
{ {
mTextSettingDescription.setText(choices[i]); mBinding.textSettingDescription.setText(choices[i]);
} }
} }
} }
setStyle(mTextSettingName, mItem); setStyle(mBinding.textSettingName, mItem);
} }
@Override @Override
@ -113,7 +106,7 @@ public final class SingleChoiceViewHolder extends SettingViewHolder
(SingleChoiceSettingDynamicDescriptions) mItem, position); (SingleChoiceSettingDynamicDescriptions) mItem, position);
} }
setStyle(mTextSettingName, mItem); setStyle(mBinding.textSettingName, mItem);
} }
@Nullable @Override @Nullable @Override

View File

@ -5,57 +5,51 @@ package org.dolphinemu.dolphinemu.features.settings.ui.viewholder;
import android.content.Context; import android.content.Context;
import android.text.TextUtils; import android.text.TextUtils;
import android.view.View; import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.databinding.ListItemSettingBinding;
import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem; import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem;
import org.dolphinemu.dolphinemu.features.settings.model.view.SliderSetting; import org.dolphinemu.dolphinemu.features.settings.model.view.SliderSetting;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter; import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
public final class SliderViewHolder extends SettingViewHolder public final class SliderViewHolder extends SettingViewHolder
{ {
private Context mContext; private final Context mContext;
private SliderSetting mItem; private SliderSetting mItem;
private TextView mTextSettingName; private final ListItemSettingBinding mBinding;
private TextView mTextSettingDescription;
public SliderViewHolder(View itemView, SettingsAdapter adapter, Context context) public SliderViewHolder(@NonNull ListItemSettingBinding binding, SettingsAdapter adapter,
Context context)
{ {
super(itemView, adapter); super(binding.getRoot(), adapter);
mBinding = binding;
mContext = context; mContext = context;
} }
@Override
protected void findViews(View root)
{
mTextSettingName = root.findViewById(R.id.text_setting_name);
mTextSettingDescription = root.findViewById(R.id.text_setting_description);
}
@Override @Override
public void bind(SettingsItem item) public void bind(SettingsItem item)
{ {
mItem = (SliderSetting) item; mItem = (SliderSetting) item;
mTextSettingName.setText(item.getName()); mBinding.textSettingName.setText(item.getName());
if (!TextUtils.isEmpty(item.getDescription())) if (!TextUtils.isEmpty(item.getDescription()))
{ {
mTextSettingDescription.setText(item.getDescription()); mBinding.textSettingDescription.setText(item.getDescription());
} }
else else
{ {
mTextSettingDescription.setText(mContext mBinding.textSettingDescription.setText(mContext
.getString(R.string.slider_setting_value, .getString(R.string.slider_setting_value,
mItem.getSelectedValue(getAdapter().getSettings()), mItem.getUnits())); mItem.getSelectedValue(getAdapter().getSettings()), mItem.getUnits()));
} }
setStyle(mTextSettingName, mItem); setStyle(mBinding.textSettingName, mItem);
} }
@Override @Override
@ -69,7 +63,7 @@ public final class SliderViewHolder extends SettingViewHolder
getAdapter().onSliderClick(mItem, getBindingAdapterPosition()); getAdapter().onSliderClick(mItem, getBindingAdapterPosition());
setStyle(mTextSettingName, mItem); setStyle(mBinding.textSettingName, mItem);
} }
@Nullable @Override @Nullable @Override

View File

@ -3,11 +3,11 @@
package org.dolphinemu.dolphinemu.features.settings.ui.viewholder; package org.dolphinemu.dolphinemu.features.settings.ui.viewholder;
import android.view.View; import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.databinding.ListItemSubmenuBinding;
import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem; import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem;
import org.dolphinemu.dolphinemu.features.settings.model.view.SubmenuSetting; import org.dolphinemu.dolphinemu.features.settings.model.view.SubmenuSetting;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter; import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
@ -16,17 +16,12 @@ public final class SubmenuViewHolder extends SettingViewHolder
{ {
private SubmenuSetting mItem; private SubmenuSetting mItem;
private TextView mTextSettingName; private final ListItemSubmenuBinding mBinding;
public SubmenuViewHolder(View itemView, SettingsAdapter adapter) public SubmenuViewHolder(@NonNull ListItemSubmenuBinding binding, SettingsAdapter adapter)
{ {
super(itemView, adapter); super(binding.getRoot(), adapter);
} mBinding = binding;
@Override
protected void findViews(View root)
{
mTextSettingName = root.findViewById(R.id.text_setting_name);
} }
@Override @Override
@ -34,7 +29,7 @@ public final class SubmenuViewHolder extends SettingViewHolder
{ {
mItem = (SubmenuSetting) item; mItem = (SubmenuSetting) item;
mTextSettingName.setText(item.getName()); mBinding.textSettingName.setText(item.getName());
} }
@Override @Override

View File

@ -5,7 +5,6 @@ package org.dolphinemu.dolphinemu.features.sysupdate.ui;
import android.app.Dialog; import android.app.Dialog;
import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo;
import android.os.Bundle; import android.os.Bundle;
import android.view.View;
import android.widget.Button; import android.widget.Button;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@ -15,9 +14,9 @@ import androidx.fragment.app.DialogFragment;
import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelProvider;
import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.progressindicator.LinearProgressIndicator;
import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.databinding.DialogProgressBinding;
public class SystemUpdateProgressBarDialogFragment extends DialogFragment public class SystemUpdateProgressBarDialogFragment extends DialogFragment
{ {
@ -33,20 +32,22 @@ public class SystemUpdateProgressBarDialogFragment extends DialogFragment
SystemUpdateViewModel viewModel = SystemUpdateViewModel viewModel =
new ViewModelProvider(requireActivity()).get(SystemUpdateViewModel.class); new ViewModelProvider(requireActivity()).get(SystemUpdateViewModel.class);
View dialogView = getLayoutInflater().inflate(R.layout.dialog_progress, null, false); DialogProgressBinding dialogProgressBinding =
LinearProgressIndicator progressBar = dialogView.findViewById(R.id.update_progress); DialogProgressBinding.inflate(getLayoutInflater());
// We need to set the message to something here, otherwise the text will not appear when we set it later. // We need to set the message to something here, otherwise the text will not appear when we set it later.
AlertDialog progressDialog = new MaterialAlertDialogBuilder(requireContext()) AlertDialog progressDialog = new MaterialAlertDialogBuilder(requireContext())
.setTitle(getString(R.string.updating)) .setTitle(getString(R.string.updating))
.setMessage("") .setMessage("")
.setNegativeButton(getString(R.string.cancel), null) .setNegativeButton(getString(R.string.cancel), null)
.setView(dialogView) .setView(dialogProgressBinding.getRoot())
.setCancelable(false) .setCancelable(false)
.create(); .create();
viewModel.getProgressData() viewModel.getProgressData()
.observe(this, (@Nullable Integer progress) -> progressBar.setProgress(progress)); .observe(this, (@Nullable
Integer progress) -> dialogProgressBinding.updateProgress.setProgress(
progress));
viewModel.getTotalData().observe(this, (@Nullable Integer total) -> viewModel.getTotalData().observe(this, (@Nullable Integer total) ->
{ {
@ -55,7 +56,7 @@ public class SystemUpdateProgressBarDialogFragment extends DialogFragment
return; return;
} }
progressBar.setMax(total); dialogProgressBinding.updateProgress.setMax(total);
}); });
viewModel.getTitleIdData().observe(this, (@Nullable Long titleId) -> progressDialog.setMessage( viewModel.getTitleIdData().observe(this, (@Nullable Long titleId) -> progressDialog.setMessage(

View File

@ -13,7 +13,6 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.AdapterView; import android.widget.AdapterView;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.StringRes; import androidx.annotation.StringRes;
@ -27,6 +26,8 @@ import com.google.android.material.textfield.TextInputLayout;
import org.dolphinemu.dolphinemu.NativeLibrary; import org.dolphinemu.dolphinemu.NativeLibrary;
import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.databinding.DialogProgressBinding;
import org.dolphinemu.dolphinemu.databinding.FragmentConvertBinding;
import org.dolphinemu.dolphinemu.model.GameFile; import org.dolphinemu.dolphinemu.model.GameFile;
import org.dolphinemu.dolphinemu.services.GameFileCacheManager; import org.dolphinemu.dolphinemu.services.GameFileCacheManager;
import org.dolphinemu.dolphinemu.ui.platform.Platform; import org.dolphinemu.dolphinemu.ui.platform.Platform;
@ -114,21 +115,13 @@ public class ConvertFragment extends Fragment implements View.OnClickListener
private DropdownValue mCompression = new DropdownValue(); private DropdownValue mCompression = new DropdownValue();
private DropdownValue mCompressionLevel = new DropdownValue(); private DropdownValue mCompressionLevel = new DropdownValue();
private TextInputLayout mFormatLayout;
private MaterialAutoCompleteTextView mFormatDropdown;
private TextInputLayout mBlockSizeLayout;
private MaterialAutoCompleteTextView mBlockSizeDropdown;
private TextInputLayout mCompressionLayout;
private MaterialAutoCompleteTextView mCompressionDropdown;
private TextInputLayout mCompressionLevelLayout;
private MaterialAutoCompleteTextView mCompressionLevelDropdown;
private CheckBox mRemoveJunkDataCheckbox;
private GameFile gameFile; private GameFile gameFile;
private volatile boolean mCanceled; private volatile boolean mCanceled;
private volatile Thread mThread = null; private volatile Thread mThread = null;
private FragmentConvertBinding mBinding;
public static ConvertFragment newInstance(String gamePath) public static ConvertFragment newInstance(String gamePath)
{ {
Bundle args = new Bundle(); Bundle args = new Bundle();
@ -150,20 +143,19 @@ public class ConvertFragment extends Fragment implements View.OnClickListener
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) Bundle savedInstanceState)
{ {
return inflater.inflate(R.layout.fragment_convert, container, false); mBinding = FragmentConvertBinding.inflate(inflater, container, false);
return mBinding.getRoot();
} }
@Override @Override
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) public void onViewCreated(@NonNull View view, Bundle savedInstanceState)
{ {
findViews();
// TODO: Remove workaround for text filtering issue in material components when fixed // TODO: Remove workaround for text filtering issue in material components when fixed
// https://github.com/material-components/material-components-android/issues/1464 // https://github.com/material-components/material-components-android/issues/1464
mFormatDropdown.setSaveEnabled(false); mBinding.dropdownFormat.setSaveEnabled(false);
mBlockSizeDropdown.setSaveEnabled(false); mBinding.dropdownBlockSize.setSaveEnabled(false);
mCompressionDropdown.setSaveEnabled(false); mBinding.dropdownCompression.setSaveEnabled(false);
mCompressionLevelDropdown.setSaveEnabled(false); mBinding.dropdownCompressionLevel.setSaveEnabled(false);
populateFormats(); populateFormats();
populateBlockSize(); populateBlockSize();
@ -177,35 +169,23 @@ public class ConvertFragment extends Fragment implements View.OnClickListener
mCompression.addCallback(this::populateCompressionLevel); mCompression.addCallback(this::populateCompressionLevel);
mFormat.addCallback(this::populateRemoveJunkData); mFormat.addCallback(this::populateRemoveJunkData);
view.findViewById(R.id.button_convert).setOnClickListener(this); mBinding.buttonConvert.setOnClickListener(this);
if (savedInstanceState != null) if (savedInstanceState != null)
{ {
setDropdownSelection(mFormatDropdown, mFormat, savedInstanceState.getInt(KEY_FORMAT)); setDropdownSelection(mBinding.dropdownFormat, mFormat, savedInstanceState.getInt(KEY_FORMAT));
setDropdownSelection(mBlockSizeDropdown, mBlockSize, setDropdownSelection(mBinding.dropdownBlockSize, mBlockSize,
savedInstanceState.getInt(KEY_BLOCK_SIZE)); savedInstanceState.getInt(KEY_BLOCK_SIZE));
setDropdownSelection(mCompressionDropdown, mCompression, setDropdownSelection(mBinding.dropdownCompression, mCompression,
savedInstanceState.getInt(KEY_COMPRESSION)); savedInstanceState.getInt(KEY_COMPRESSION));
setDropdownSelection(mCompressionLevelDropdown, mCompressionLevel, setDropdownSelection(mBinding.dropdownCompressionLevel, mCompressionLevel,
savedInstanceState.getInt(KEY_COMPRESSION_LEVEL)); savedInstanceState.getInt(KEY_COMPRESSION_LEVEL));
mRemoveJunkDataCheckbox.setChecked(savedInstanceState.getBoolean(KEY_REMOVE_JUNK_DATA)); mBinding.checkboxRemoveJunkData.setChecked(
savedInstanceState.getBoolean(KEY_REMOVE_JUNK_DATA));
} }
} }
private void findViews()
{
mFormatLayout = requireView().findViewById(R.id.format);
mFormatDropdown = requireView().findViewById(R.id.dropdown_format);
mBlockSizeLayout = requireView().findViewById(R.id.block_size);
mBlockSizeDropdown = requireView().findViewById(R.id.dropdown_block_size);
mCompressionLayout = requireView().findViewById(R.id.compression);
mCompressionDropdown = requireView().findViewById(R.id.dropdown_compression);
mCompressionLevelLayout = requireView().findViewById(R.id.compression_level);
mCompressionLevelDropdown = requireView().findViewById(R.id.dropdown_compression_level);
mRemoveJunkDataCheckbox = requireView().findViewById(R.id.checkbox_remove_junk_data);
}
@Override @Override
public void onSaveInstanceState(@NonNull Bundle outState) public void onSaveInstanceState(@NonNull Bundle outState)
{ {
@ -214,7 +194,7 @@ public class ConvertFragment extends Fragment implements View.OnClickListener
outState.putInt(KEY_COMPRESSION, mCompression.getPosition()); outState.putInt(KEY_COMPRESSION, mCompression.getPosition());
outState.putInt(KEY_COMPRESSION_LEVEL, mCompressionLevel.getPosition()); outState.putInt(KEY_COMPRESSION_LEVEL, mCompressionLevel.getPosition());
outState.putBoolean(KEY_REMOVE_JUNK_DATA, mRemoveJunkDataCheckbox.isChecked()); outState.putBoolean(KEY_REMOVE_JUNK_DATA, mBinding.checkboxRemoveJunkData.isChecked());
} }
private void setDropdownSelection(MaterialAutoCompleteTextView dropdown, private void setDropdownSelection(MaterialAutoCompleteTextView dropdown,
@ -236,6 +216,13 @@ public class ConvertFragment extends Fragment implements View.OnClickListener
joinThread(); joinThread();
} }
@Override
public void onDestroyView()
{
super.onDestroyView();
mBinding = null;
}
private void populateDropdown(TextInputLayout layout, MaterialAutoCompleteTextView dropdown, private void populateDropdown(TextInputLayout layout, MaterialAutoCompleteTextView dropdown,
int entriesId, int valuesId, DropdownValue valueWrapper) int entriesId, int valuesId, DropdownValue valueWrapper)
{ {
@ -263,13 +250,15 @@ public class ConvertFragment extends Fragment implements View.OnClickListener
private void populateFormats() private void populateFormats()
{ {
populateDropdown(mFormatLayout, mFormatDropdown, R.array.convertFormatEntries, populateDropdown(mBinding.format, mBinding.dropdownFormat, R.array.convertFormatEntries,
R.array.convertFormatValues, mFormat); R.array.convertFormatValues, mFormat);
if (gameFile.getBlobType() == BLOB_TYPE_ISO) if (gameFile.getBlobType() == BLOB_TYPE_ISO)
{ {
setDropdownSelection(mFormatDropdown, mFormat, mFormatDropdown.getAdapter().getCount() - 1); setDropdownSelection(mBinding.dropdownFormat, mFormat,
mBinding.dropdownFormat.getAdapter().getCount() - 1);
} }
mFormatDropdown.setText(mFormatDropdown.getAdapter().getItem(mFormat.getPosition()).toString(), mBinding.dropdownFormat.setText(
mBinding.dropdownFormat.getAdapter().getItem(mFormat.getPosition()).toString(),
false); false);
} }
@ -281,25 +270,31 @@ public class ConvertFragment extends Fragment implements View.OnClickListener
// In the equivalent DolphinQt code, we have some logic for avoiding block sizes that can // In the equivalent DolphinQt code, we have some logic for avoiding block sizes that can
// trigger bugs in Dolphin versions older than 5.0-11893, but it was too annoying to port. // trigger bugs in Dolphin versions older than 5.0-11893, but it was too annoying to port.
// TODO: Port it? // TODO: Port it?
populateDropdown(mBlockSizeLayout, mBlockSizeDropdown, R.array.convertBlockSizeGczEntries, populateDropdown(mBinding.blockSize, mBinding.dropdownBlockSize,
R.array.convertBlockSizeGczEntries,
R.array.convertBlockSizeGczValues, mBlockSize); R.array.convertBlockSizeGczValues, mBlockSize);
mBlockSize.setPosition(0); mBlockSize.setPosition(0);
mBlockSizeDropdown.setText(mBlockSizeDropdown.getAdapter().getItem(0).toString(), false); mBinding.dropdownBlockSize.setText(
mBinding.dropdownBlockSize.getAdapter().getItem(0).toString(), false);
break; break;
case BLOB_TYPE_WIA: case BLOB_TYPE_WIA:
populateDropdown(mBlockSizeLayout, mBlockSizeDropdown, R.array.convertBlockSizeWiaEntries, populateDropdown(mBinding.blockSize, mBinding.dropdownBlockSize,
R.array.convertBlockSizeWiaEntries,
R.array.convertBlockSizeWiaValues, mBlockSize); R.array.convertBlockSizeWiaValues, mBlockSize);
mBlockSize.setPosition(0); mBlockSize.setPosition(0);
mBlockSizeDropdown.setText(mBlockSizeDropdown.getAdapter().getItem(0).toString(), false); mBinding.dropdownBlockSize.setText(
mBinding.dropdownBlockSize.getAdapter().getItem(0).toString(), false);
break; break;
case BLOB_TYPE_RVZ: case BLOB_TYPE_RVZ:
populateDropdown(mBlockSizeLayout, mBlockSizeDropdown, R.array.convertBlockSizeRvzEntries, populateDropdown(mBinding.blockSize, mBinding.dropdownBlockSize,
R.array.convertBlockSizeRvzEntries,
R.array.convertBlockSizeRvzValues, mBlockSize); R.array.convertBlockSizeRvzValues, mBlockSize);
mBlockSize.setPosition(2); mBlockSize.setPosition(2);
mBlockSizeDropdown.setText(mBlockSizeDropdown.getAdapter().getItem(2).toString(), false); mBinding.dropdownBlockSize.setText(
mBinding.dropdownBlockSize.getAdapter().getItem(2).toString(), false);
break; break;
default: default:
clearDropdown(mBlockSizeLayout, mBlockSizeDropdown, mBlockSize); clearDropdown(mBinding.blockSize, mBinding.dropdownBlockSize, mBlockSize);
} }
} }
@ -308,31 +303,31 @@ public class ConvertFragment extends Fragment implements View.OnClickListener
switch (mFormat.getValue(requireContext())) switch (mFormat.getValue(requireContext()))
{ {
case BLOB_TYPE_GCZ: case BLOB_TYPE_GCZ:
populateDropdown(mCompressionLayout, mCompressionDropdown, populateDropdown(mBinding.compression, mBinding.dropdownCompression,
R.array.convertCompressionGczEntries, R.array.convertCompressionGczValues, R.array.convertCompressionGczEntries, R.array.convertCompressionGczValues,
mCompression); mCompression);
mCompression.setPosition(0); mCompression.setPosition(0);
mCompressionDropdown.setText(mCompressionDropdown.getAdapter().getItem(0).toString(), mBinding.dropdownCompression.setText(
false); mBinding.dropdownCompression.getAdapter().getItem(0).toString(), false);
break; break;
case BLOB_TYPE_WIA: case BLOB_TYPE_WIA:
populateDropdown(mCompressionLayout, mCompressionDropdown, populateDropdown(mBinding.compression, mBinding.dropdownCompression,
R.array.convertCompressionWiaEntries, R.array.convertCompressionWiaValues, R.array.convertCompressionWiaEntries, R.array.convertCompressionWiaValues,
mCompression); mCompression);
mCompression.setPosition(0); mCompression.setPosition(0);
mCompressionDropdown.setText(mCompressionDropdown.getAdapter().getItem(0).toString(), mBinding.dropdownCompression.setText(
false); mBinding.dropdownCompression.getAdapter().getItem(0).toString(), false);
break; break;
case BLOB_TYPE_RVZ: case BLOB_TYPE_RVZ:
populateDropdown(mCompressionLayout, mCompressionDropdown, populateDropdown(mBinding.compression, mBinding.dropdownCompression,
R.array.convertCompressionRvzEntries, R.array.convertCompressionRvzValues, R.array.convertCompressionRvzEntries, R.array.convertCompressionRvzValues,
mCompression); mCompression);
mCompression.setPosition(4); mCompression.setPosition(4);
mCompressionDropdown.setText(mCompressionDropdown.getAdapter().getItem(4).toString(), mBinding.dropdownCompression.setText(
false); mBinding.dropdownCompression.getAdapter().getItem(4).toString(), false);
break; break;
default: default:
clearDropdown(mCompressionLayout, mCompressionDropdown, mCompression); clearDropdown(mBinding.compression, mBinding.dropdownCompression, mCompression);
} }
} }
@ -343,24 +338,25 @@ public class ConvertFragment extends Fragment implements View.OnClickListener
case COMPRESSION_BZIP2: case COMPRESSION_BZIP2:
case COMPRESSION_LZMA: case COMPRESSION_LZMA:
case COMPRESSION_LZMA2: case COMPRESSION_LZMA2:
populateDropdown(mCompressionLevelLayout, mCompressionLevelDropdown, populateDropdown(mBinding.compressionLevel, mBinding.dropdownCompressionLevel,
R.array.convertCompressionLevelEntries, R.array.convertCompressionLevelValues, R.array.convertCompressionLevelEntries, R.array.convertCompressionLevelValues,
mCompressionLevel); mCompressionLevel);
mCompressionLevel.setPosition(4); mCompressionLevel.setPosition(4);
mCompressionLevelDropdown.setText( mBinding.dropdownCompressionLevel.setText(
mCompressionLevelDropdown.getAdapter().getItem(4).toString(), false); mBinding.dropdownCompressionLevel.getAdapter().getItem(4).toString(), false);
break; break;
case COMPRESSION_ZSTD: case COMPRESSION_ZSTD:
// TODO: Query DiscIO for the supported compression levels, like we do in DolphinQt? // TODO: Query DiscIO for the supported compression levels, like we do in DolphinQt?
populateDropdown(mCompressionLevelLayout, mCompressionLevelDropdown, populateDropdown(mBinding.compressionLevel, mBinding.dropdownCompressionLevel,
R.array.convertCompressionLevelZstdEntries, R.array.convertCompressionLevelZstdEntries,
R.array.convertCompressionLevelZstdValues, mCompressionLevel); R.array.convertCompressionLevelZstdValues, mCompressionLevel);
mCompressionLevel.setPosition(4); mCompressionLevel.setPosition(4);
mCompressionLevelDropdown.setText( mBinding.dropdownCompressionLevel.setText(
mCompressionLevelDropdown.getAdapter().getItem(4).toString(), false); mBinding.dropdownCompressionLevel.getAdapter().getItem(4).toString(), false);
break; break;
default: default:
clearDropdown(mCompressionLevelLayout, mCompressionLevelDropdown, mCompressionLevel); clearDropdown(mBinding.compressionLevel, mBinding.dropdownCompressionLevel,
mCompressionLevel);
} }
} }
@ -369,15 +365,15 @@ public class ConvertFragment extends Fragment implements View.OnClickListener
boolean scrubbingAllowed = mFormat.getValue(requireContext()) != BLOB_TYPE_RVZ && boolean scrubbingAllowed = mFormat.getValue(requireContext()) != BLOB_TYPE_RVZ &&
!gameFile.isDatelDisc(); !gameFile.isDatelDisc();
mRemoveJunkDataCheckbox.setEnabled(scrubbingAllowed); mBinding.checkboxRemoveJunkData.setEnabled(scrubbingAllowed);
if (!scrubbingAllowed) if (!scrubbingAllowed)
mRemoveJunkDataCheckbox.setChecked(false); mBinding.checkboxRemoveJunkData.setChecked(false);
} }
@Override @Override
public void onClick(View view) public void onClick(View view)
{ {
boolean scrub = mRemoveJunkDataCheckbox.isChecked(); boolean scrub = mBinding.checkboxRemoveJunkData.isChecked();
int format = mFormat.getValue(requireContext()); int format = mFormat.getValue(requireContext());
Runnable action = this::showSavePrompt; Runnable action = this::showSavePrompt;
@ -466,15 +462,15 @@ public class ConvertFragment extends Fragment implements View.OnClickListener
mCanceled = false; mCanceled = false;
View dialogView = getLayoutInflater().inflate(R.layout.dialog_progress, null, false); DialogProgressBinding dialogProgressBinding =
LinearProgressIndicator progressBar = dialogView.findViewById(R.id.update_progress); DialogProgressBinding.inflate(getLayoutInflater(), null, false);
progressBar.setMax(PROGRESS_RESOLUTION); dialogProgressBinding.updateProgress.setMax(PROGRESS_RESOLUTION);
AlertDialog progressDialog = new MaterialAlertDialogBuilder(context) AlertDialog progressDialog = new MaterialAlertDialogBuilder(context)
.setTitle(R.string.convert_converting) .setTitle(R.string.convert_converting)
.setOnCancelListener((dialog) -> mCanceled = true) .setOnCancelListener((dialog) -> mCanceled = true)
.setNegativeButton(getString(R.string.cancel), (dialog, i) -> dialog.dismiss()) .setNegativeButton(getString(R.string.cancel), (dialog, i) -> dialog.dismiss())
.setView(dialogView) .setView(dialogProgressBinding.getRoot())
.show(); .show();
mThread = new Thread(() -> mThread = new Thread(() ->
@ -482,12 +478,13 @@ public class ConvertFragment extends Fragment implements View.OnClickListener
boolean success = NativeLibrary.ConvertDiscImage(gameFile.getPath(), outPath, boolean success = NativeLibrary.ConvertDiscImage(gameFile.getPath(), outPath,
gameFile.getPlatform(), mFormat.getValue(context), mBlockSize.getValueOr(context, 0), gameFile.getPlatform(), mFormat.getValue(context), mBlockSize.getValueOr(context, 0),
mCompression.getValueOr(context, 0), mCompressionLevel.getValueOr(context, 0), mCompression.getValueOr(context, 0), mCompressionLevel.getValueOr(context, 0),
mRemoveJunkDataCheckbox.isChecked(), (text, completion) -> mBinding.checkboxRemoveJunkData.isChecked(), (text, completion) ->
{ {
requireActivity().runOnUiThread(() -> requireActivity().runOnUiThread(() ->
{ {
progressDialog.setMessage(text); progressDialog.setMessage(text);
progressBar.setProgress((int) (completion * PROGRESS_RESOLUTION)); dialogProgressBinding.updateProgress.setProgress(
(int) (completion * PROGRESS_RESOLUTION));
}); });
return !mCanceled; return !mCanceled;
}); });

View File

@ -13,11 +13,12 @@ import android.view.ViewGroup;
import android.widget.Button; import android.widget.Button;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import org.dolphinemu.dolphinemu.NativeLibrary; import org.dolphinemu.dolphinemu.NativeLibrary;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.activities.EmulationActivity; import org.dolphinemu.dolphinemu.activities.EmulationActivity;
import org.dolphinemu.dolphinemu.databinding.FragmentEmulationBinding;
import org.dolphinemu.dolphinemu.features.settings.model.BooleanSetting; import org.dolphinemu.dolphinemu.features.settings.model.BooleanSetting;
import org.dolphinemu.dolphinemu.features.settings.model.Settings; import org.dolphinemu.dolphinemu.features.settings.model.Settings;
import org.dolphinemu.dolphinemu.overlay.InputOverlay; import org.dolphinemu.dolphinemu.overlay.InputOverlay;
@ -41,6 +42,8 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
private EmulationActivity activity; private EmulationActivity activity;
private FragmentEmulationBinding mBinding;
public static EmulationFragment newInstance(String[] gamePaths, boolean riivolution, public static EmulationFragment newInstance(String[] gamePaths, boolean riivolution,
boolean systemMenu) boolean systemMenu)
{ {
@ -83,20 +86,24 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
mLaunchSystemMenu = getArguments().getBoolean(KEY_SYSTEM_MENU); mLaunchSystemMenu = getArguments().getBoolean(KEY_SYSTEM_MENU);
} }
/**
* Initialize the UI and start emulation in here.
*/
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{ {
View contents = inflater.inflate(R.layout.fragment_emulation, container, false); mBinding = FragmentEmulationBinding.inflate(inflater, container, false);
return mBinding.getRoot();
}
SurfaceView surfaceView = contents.findViewById(R.id.surface_emulation); @Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState)
{
// The new Surface created here will get passed to the native code via onSurfaceChanged.
SurfaceView surfaceView = mBinding.surfaceEmulation;
surfaceView.getHolder().addCallback(this); surfaceView.getHolder().addCallback(this);
mInputOverlay = contents.findViewById(R.id.surface_input_overlay); mInputOverlay = mBinding.surfaceInputOverlay;
Button doneButton = contents.findViewById(R.id.done_control_config); Button doneButton = mBinding.doneControlConfig;
if (doneButton != null) if (doneButton != null)
{ {
doneButton.setOnClickListener(v -> stopConfiguringControls()); doneButton.setOnClickListener(v -> stopConfiguringControls());
@ -104,7 +111,7 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
if (mInputOverlay != null) if (mInputOverlay != null)
{ {
contents.post(() -> view.post(() ->
{ {
int overlayX = mInputOverlay.getLeft(); int overlayX = mInputOverlay.getLeft();
int overlayY = mInputOverlay.getTop(); int overlayY = mInputOverlay.getTop();
@ -113,10 +120,13 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
surfaceView.getRight() - overlayX, surfaceView.getBottom() - overlayY)); surfaceView.getRight() - overlayX, surfaceView.getBottom() - overlayY));
}); });
} }
}
// The new Surface created here will get passed to the native code via onSurfaceChanged. @Override
public void onDestroyView()
return contents; {
super.onDestroyView();
mBinding = null;
} }
@Override @Override
@ -223,7 +233,7 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
{ {
if (mInputOverlay != null) if (mInputOverlay != null)
{ {
requireView().findViewById(R.id.done_control_config).setVisibility(View.VISIBLE); mBinding.doneControlConfig.setVisibility(View.VISIBLE);
mInputOverlay.setIsInEditMode(true); mInputOverlay.setIsInEditMode(true);
} }
} }
@ -232,7 +242,7 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
{ {
if (mInputOverlay != null) if (mInputOverlay != null)
{ {
requireView().findViewById(R.id.done_control_config).setVisibility(View.GONE); mBinding.doneControlConfig.setVisibility(View.GONE);
mInputOverlay.setIsInEditMode(false); mInputOverlay.setIsInEditMode(false);
} }
} }

View File

@ -11,21 +11,19 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.Button; import android.widget.Button;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import org.dolphinemu.dolphinemu.NativeLibrary; import org.dolphinemu.dolphinemu.NativeLibrary;
import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.activities.EmulationActivity; import org.dolphinemu.dolphinemu.activities.EmulationActivity;
import org.dolphinemu.dolphinemu.databinding.FragmentIngameMenuBinding;
import org.dolphinemu.dolphinemu.features.settings.model.BooleanSetting; import org.dolphinemu.dolphinemu.features.settings.model.BooleanSetting;
public final class MenuFragment extends Fragment implements View.OnClickListener public final class MenuFragment extends Fragment implements View.OnClickListener
{ {
private TextView mTitleText;
private View mPauseEmulation;
private View mUnpauseEmulation;
private static final String KEY_TITLE = "title"; private static final String KEY_TITLE = "title";
private static final String KEY_WII = "wii"; private static final String KEY_WII = "wii";
private static SparseIntArray buttonsActionsMap = new SparseIntArray(); private static SparseIntArray buttonsActionsMap = new SparseIntArray();
@ -53,6 +51,8 @@ public final class MenuFragment extends Fragment implements View.OnClickListener
buttonsActionsMap.append(R.id.menu_settings, EmulationActivity.MENU_ACTION_SETTINGS); buttonsActionsMap.append(R.id.menu_settings, EmulationActivity.MENU_ACTION_SETTINGS);
} }
private FragmentIngameMenuBinding mBinding;
public static MenuFragment newInstance() public static MenuFragment newInstance()
{ {
MenuFragment fragment = new MenuFragment(); MenuFragment fragment = new MenuFragment();
@ -76,26 +76,28 @@ public final class MenuFragment extends Fragment implements View.OnClickListener
return visibleFrame.bottom - visibleFrame.top - getResources().getDisplayMetrics().heightPixels; return visibleFrame.bottom - visibleFrame.top - getResources().getDisplayMetrics().heightPixels;
} }
@NonNull
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{ {
View rootView = inflater.inflate(R.layout.fragment_ingame_menu, container, false); mBinding = FragmentIngameMenuBinding.inflate(inflater, container, false);
return mBinding.getRoot();
LinearLayout options = rootView.findViewById(R.id.layout_options); }
mPauseEmulation = options.findViewById(R.id.menu_pause_emulation);
mUnpauseEmulation = options.findViewById(R.id.menu_unpause_emulation);
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState)
{
updatePauseUnpauseVisibility(); updatePauseUnpauseVisibility();
if (!requireActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN)) if (!requireActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN))
{ {
options.findViewById(R.id.menu_overlay_controls).setVisibility(View.GONE); mBinding.menuOverlayControls.setVisibility(View.GONE);
} }
if (!getArguments().getBoolean(KEY_WII, true)) if (!getArguments().getBoolean(KEY_WII, true))
{ {
options.findViewById(R.id.menu_refresh_wiimotes).setVisibility(View.GONE); mBinding.menuRefreshWiimotes.setVisibility(View.GONE);
} }
int bottomPaddingRequired = getBottomPaddingRequired(); int bottomPaddingRequired = getBottomPaddingRequired();
@ -107,12 +109,13 @@ public final class MenuFragment extends Fragment implements View.OnClickListener
bottomPaddingRequired += 32 * density; bottomPaddingRequired += 32 * density;
} }
if (bottomPaddingRequired > rootView.getPaddingBottom()) if (bottomPaddingRequired > view.getPaddingBottom())
{ {
rootView.setPadding(rootView.getPaddingLeft(), rootView.getPaddingTop(), view.setPadding(view.getPaddingLeft(), view.getPaddingTop(),
rootView.getPaddingRight(), bottomPaddingRequired); view.getPaddingRight(), bottomPaddingRequired);
} }
LinearLayout options = mBinding.layoutOptions;
for (int childIndex = 0; childIndex < options.getChildCount(); childIndex++) for (int childIndex = 0; childIndex < options.getChildCount(); childIndex++)
{ {
Button button = (Button) options.getChildAt(childIndex); Button button = (Button) options.getChildAt(childIndex);
@ -120,21 +123,18 @@ public final class MenuFragment extends Fragment implements View.OnClickListener
button.setOnClickListener(this); button.setOnClickListener(this);
} }
rootView.findViewById(R.id.menu_exit).setOnClickListener(this); mBinding.menuExit.setOnClickListener(this);
mTitleText = rootView.findViewById(R.id.text_game_title);
String title = getArguments().getString(KEY_TITLE, null); String title = getArguments().getString(KEY_TITLE, null);
if (title != null) if (title != null)
{ {
mTitleText.setText(title); mBinding.textGameTitle.setText(title);
} }
if (getResources().getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_LTR) if (getResources().getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_LTR)
{ {
rootView.post(() -> NativeLibrary.SetObscuredPixelsLeft(rootView.getWidth())); view.post(() -> NativeLibrary.SetObscuredPixelsLeft(view.getWidth()));
} }
return rootView;
} }
@Override @Override
@ -142,14 +142,12 @@ public final class MenuFragment extends Fragment implements View.OnClickListener
{ {
super.onResume(); super.onResume();
LinearLayout options = requireView().findViewById(R.id.layout_options);
boolean savestatesEnabled = BooleanSetting.MAIN_ENABLE_SAVESTATES.getBooleanGlobal(); boolean savestatesEnabled = BooleanSetting.MAIN_ENABLE_SAVESTATES.getBooleanGlobal();
int savestateVisibility = savestatesEnabled ? View.VISIBLE : View.GONE; int savestateVisibility = savestatesEnabled ? View.VISIBLE : View.GONE;
options.findViewById(R.id.menu_quicksave).setVisibility(savestateVisibility); mBinding.menuQuicksave.setVisibility(savestateVisibility);
options.findViewById(R.id.menu_quickload).setVisibility(savestateVisibility); mBinding.menuQuickload.setVisibility(savestateVisibility);
options.findViewById(R.id.menu_emulation_save_root).setVisibility(savestateVisibility); mBinding.menuEmulationSaveRoot.setVisibility(savestateVisibility);
options.findViewById(R.id.menu_emulation_load_root).setVisibility(savestateVisibility); mBinding.menuEmulationLoadRoot.setVisibility(savestateVisibility);
} }
@Override @Override
@ -158,14 +156,15 @@ public final class MenuFragment extends Fragment implements View.OnClickListener
super.onDestroyView(); super.onDestroyView();
NativeLibrary.SetObscuredPixelsLeft(0); NativeLibrary.SetObscuredPixelsLeft(0);
mBinding = null;
} }
private void updatePauseUnpauseVisibility() private void updatePauseUnpauseVisibility()
{ {
boolean paused = EmulationActivity.getHasUserPausedEmulation(); boolean paused = EmulationActivity.getHasUserPausedEmulation();
mUnpauseEmulation.setVisibility(paused ? View.VISIBLE : View.GONE); mBinding.menuUnpauseEmulation.setVisibility(paused ? View.VISIBLE : View.GONE);
mPauseEmulation.setVisibility(paused ? View.GONE : View.VISIBLE); mBinding.menuPauseEmulation.setVisibility(paused ? View.GONE : View.VISIBLE);
} }
@Override @Override
@ -178,7 +177,7 @@ public final class MenuFragment extends Fragment implements View.OnClickListener
{ {
// We could use the button parameter as the anchor here, but this often results in a tiny menu // We could use the button parameter as the anchor here, but this often results in a tiny menu
// (because the button often is in the middle of the screen), so let's use mTitleText instead // (because the button often is in the middle of the screen), so let's use mTitleText instead
activity.showOverlayControlsMenu(mTitleText); activity.showOverlayControlsMenu(mBinding.textGameTitle);
} }
else if (action >= 0) else if (action >= 0)
{ {

View File

@ -11,12 +11,14 @@ import android.view.ViewGroup;
import android.widget.Button; import android.widget.Button;
import android.widget.GridLayout; import android.widget.GridLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import org.dolphinemu.dolphinemu.NativeLibrary; import org.dolphinemu.dolphinemu.NativeLibrary;
import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.activities.EmulationActivity; import org.dolphinemu.dolphinemu.activities.EmulationActivity;
import org.dolphinemu.dolphinemu.databinding.FragmentSaveloadStateBinding;
public final class SaveLoadStateFragment extends Fragment implements View.OnClickListener public final class SaveLoadStateFragment extends Fragment implements View.OnClickListener
{ {
@ -59,6 +61,8 @@ public final class SaveLoadStateFragment extends Fragment implements View.OnClic
private SaveOrLoad mSaveOrLoad; private SaveOrLoad mSaveOrLoad;
private FragmentSaveloadStateBinding mBinding;
public static SaveLoadStateFragment newInstance(SaveOrLoad saveOrLoad) public static SaveLoadStateFragment newInstance(SaveOrLoad saveOrLoad)
{ {
SaveLoadStateFragment fragment = new SaveLoadStateFragment(); SaveLoadStateFragment fragment = new SaveLoadStateFragment();
@ -78,12 +82,19 @@ public final class SaveLoadStateFragment extends Fragment implements View.OnClic
mSaveOrLoad = (SaveOrLoad) getArguments().getSerializable(KEY_SAVEORLOAD); mSaveOrLoad = (SaveOrLoad) getArguments().getSerializable(KEY_SAVEORLOAD);
} }
@NonNull
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{ {
View rootView = inflater.inflate(R.layout.fragment_saveload_state, container, false); mBinding = FragmentSaveloadStateBinding.inflate(inflater, container, false);
return mBinding.getRoot();
}
GridLayout grid = rootView.findViewById(R.id.grid_state_slots); @Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState)
{
GridLayout grid = mBinding.gridStateSlots;
for (int childIndex = 0; childIndex < grid.getChildCount(); childIndex++) for (int childIndex = 0; childIndex < grid.getChildCount(); childIndex++)
{ {
Button button = (Button) grid.getChildAt(childIndex); Button button = (Button) grid.getChildAt(childIndex);
@ -93,8 +104,13 @@ public final class SaveLoadStateFragment extends Fragment implements View.OnClic
// So that item clicked to start this Fragment is no longer the focused item. // So that item clicked to start this Fragment is no longer the focused item.
grid.requestFocus(); grid.requestFocus();
}
return rootView; @Override
public void onDestroyView()
{
super.onDestroyView();
mBinding = null;
} }
@Override @Override

View File

@ -9,24 +9,20 @@ import android.os.Bundle;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.splashscreen.SplashScreen; import androidx.core.splashscreen.SplashScreen;
import androidx.core.view.WindowCompat; import androidx.core.view.WindowCompat;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import androidx.viewpager.widget.ViewPager;
import com.google.android.material.appbar.AppBarLayout;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.tabs.TabLayout; import com.google.android.material.tabs.TabLayout;
import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.activities.EmulationActivity; import org.dolphinemu.dolphinemu.activities.EmulationActivity;
import org.dolphinemu.dolphinemu.adapters.PlatformPagerAdapter; import org.dolphinemu.dolphinemu.adapters.PlatformPagerAdapter;
import org.dolphinemu.dolphinemu.databinding.ActivityMainBinding;
import org.dolphinemu.dolphinemu.features.settings.model.IntSetting; import org.dolphinemu.dolphinemu.features.settings.model.IntSetting;
import org.dolphinemu.dolphinemu.features.settings.model.NativeConfig; import org.dolphinemu.dolphinemu.features.settings.model.NativeConfig;
import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag; import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag;
@ -51,16 +47,12 @@ import org.dolphinemu.dolphinemu.utils.WiiUtils;
public final class MainActivity extends AppCompatActivity public final class MainActivity extends AppCompatActivity
implements MainView, SwipeRefreshLayout.OnRefreshListener, ThemeProvider implements MainView, SwipeRefreshLayout.OnRefreshListener, ThemeProvider
{ {
private ViewPager mViewPager;
private Toolbar mToolbar;
private TabLayout mTabLayout;
private AppBarLayout mAppBarLayout;
private FloatingActionButton mFab;
private int mThemeId; private int mThemeId;
private final MainPresenter mPresenter = new MainPresenter(this, this); private final MainPresenter mPresenter = new MainPresenter(this, this);
private ActivityMainBinding mBinding;
@Override @Override
protected void onCreate(Bundle savedInstanceState) protected void onCreate(Bundle savedInstanceState)
{ {
@ -71,19 +63,19 @@ public final class MainActivity extends AppCompatActivity
ThemeHelper.setTheme(this); ThemeHelper.setTheme(this);
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViews(); mBinding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(mBinding.getRoot());
View workaroundView = findViewById(R.id.workaround_view);
WindowCompat.setDecorFitsSystemWindows(getWindow(), false); WindowCompat.setDecorFitsSystemWindows(getWindow(), false);
InsetsHelper.setUpMainLayout(this, mAppBarLayout, mFab, mViewPager, workaroundView); InsetsHelper.setUpMainLayout(this, mBinding.appbarMain, mBinding.buttonAddDirectory,
ThemeHelper.enableStatusBarScrollTint(this, mAppBarLayout); mBinding.pagerPlatforms, mBinding.workaroundView);
ThemeHelper.enableStatusBarScrollTint(this, mBinding.appbarMain);
setSupportActionBar(mToolbar); setSupportActionBar(mBinding.toolbarMain);
// Set up the FAB. // Set up the FAB.
mFab.setOnClickListener(view -> mPresenter.onFabClick()); mBinding.buttonAddDirectory.setOnClickListener(view -> mPresenter.onFabClick());
mPresenter.onCreate(); mPresenter.onCreate();
@ -154,16 +146,6 @@ public final class MainActivity extends AppCompatActivity
StartupHandler.setSessionTime(this); StartupHandler.setSessionTime(this);
} }
// TODO: Replace with a ButterKnife injection.
private void findViews()
{
mAppBarLayout = findViewById(R.id.appbar_main);
mToolbar = findViewById(R.id.toolbar_main);
mViewPager = findViewById(R.id.pager_platforms);
mTabLayout = findViewById(R.id.tabs_platforms);
mFab = findViewById(R.id.button_add_directory);
}
@Override @Override
public boolean onCreateOptionsMenu(Menu menu) public boolean onCreateOptionsMenu(Menu menu)
{ {
@ -190,7 +172,7 @@ public final class MainActivity extends AppCompatActivity
@Override @Override
public void setVersionString(String version) public void setVersionString(String version)
{ {
mToolbar.setSubtitle(version); mBinding.toolbarMain.setSubtitle(version);
} }
@Override @Override
@ -351,7 +333,8 @@ public final class MainActivity extends AppCompatActivity
@Nullable @Nullable
private PlatformGamesView getPlatformGamesView(Platform platform) private PlatformGamesView getPlatformGamesView(Platform platform)
{ {
String fragmentTag = "android:switcher:" + mViewPager.getId() + ":" + platform.toInt(); String fragmentTag =
"android:switcher:" + mBinding.pagerPlatforms.getId() + ":" + platform.toInt();
return (PlatformGamesView) getSupportFragmentManager().findFragmentByTag(fragmentTag); return (PlatformGamesView) getSupportFragmentManager().findFragmentByTag(fragmentTag);
} }
@ -361,25 +344,27 @@ public final class MainActivity extends AppCompatActivity
{ {
PlatformPagerAdapter platformPagerAdapter = new PlatformPagerAdapter( PlatformPagerAdapter platformPagerAdapter = new PlatformPagerAdapter(
getSupportFragmentManager(), this); getSupportFragmentManager(), this);
mViewPager.setAdapter(platformPagerAdapter); mBinding.pagerPlatforms.setAdapter(platformPagerAdapter);
mViewPager.setOffscreenPageLimit(platformPagerAdapter.getCount()); mBinding.pagerPlatforms.setOffscreenPageLimit(platformPagerAdapter.getCount());
mTabLayout.setupWithViewPager(mViewPager); mBinding.tabsPlatforms.setupWithViewPager(mBinding.pagerPlatforms);
mTabLayout.addOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(mViewPager) mBinding.tabsPlatforms.addOnTabSelectedListener(
{ new TabLayout.ViewPagerOnTabSelectedListener(mBinding.pagerPlatforms)
@Override {
public void onTabSelected(@NonNull TabLayout.Tab tab) @Override
{ public void onTabSelected(@NonNull TabLayout.Tab tab)
super.onTabSelected(tab); {
IntSetting.MAIN_LAST_PLATFORM_TAB.setIntGlobal(NativeConfig.LAYER_BASE, tab.getPosition()); super.onTabSelected(tab);
} IntSetting.MAIN_LAST_PLATFORM_TAB.setIntGlobal(NativeConfig.LAYER_BASE,
}); tab.getPosition());
}
});
for (int i = 0; i < PlatformPagerAdapter.TAB_ICONS.length; i++) for (int i = 0; i < PlatformPagerAdapter.TAB_ICONS.length; i++)
{ {
mTabLayout.getTabAt(i).setIcon(PlatformPagerAdapter.TAB_ICONS[i]); mBinding.tabsPlatforms.getTabAt(i).setIcon(PlatformPagerAdapter.TAB_ICONS[i]);
} }
mViewPager.setCurrentItem(IntSetting.MAIN_LAST_PLATFORM_TAB.getIntGlobal()); mBinding.pagerPlatforms.setCurrentItem(IntSetting.MAIN_LAST_PLATFORM_TAB.getIntGlobal());
showGames(); showGames();
GameFileCacheManager.startLoad(); GameFileCacheManager.startLoad();

View File

@ -23,6 +23,7 @@ import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.activities.EmulationActivity; import org.dolphinemu.dolphinemu.activities.EmulationActivity;
import org.dolphinemu.dolphinemu.adapters.GameRowPresenter; import org.dolphinemu.dolphinemu.adapters.GameRowPresenter;
import org.dolphinemu.dolphinemu.adapters.SettingsRowPresenter; import org.dolphinemu.dolphinemu.adapters.SettingsRowPresenter;
import org.dolphinemu.dolphinemu.databinding.ActivityTvMainBinding;
import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag; import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsActivity; import org.dolphinemu.dolphinemu.features.settings.ui.SettingsActivity;
import org.dolphinemu.dolphinemu.model.GameFile; import org.dolphinemu.dolphinemu.model.GameFile;
@ -50,6 +51,8 @@ public final class TvMainActivity extends FragmentActivity
private final ArrayList<ArrayObjectAdapter> mGameRows = new ArrayList<>(); private final ArrayList<ArrayObjectAdapter> mGameRows = new ArrayList<>();
private ActivityTvMainBinding mBinding;
@Override @Override
protected void onCreate(Bundle savedInstanceState) protected void onCreate(Bundle savedInstanceState)
{ {
@ -58,7 +61,8 @@ public final class TvMainActivity extends FragmentActivity
() -> !DirectoryInitialization.areDolphinDirectoriesReady()); () -> !DirectoryInitialization.areDolphinDirectoriesReady());
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tv_main); mBinding = ActivityTvMainBinding.inflate(getLayoutInflater());
setContentView(mBinding.getRoot());
setupUI(); setupUI();
@ -118,7 +122,7 @@ public final class TvMainActivity extends FragmentActivity
void setupUI() void setupUI()
{ {
mSwipeRefresh = findViewById(R.id.swipe_refresh); mSwipeRefresh = mBinding.swipeRefresh;
mSwipeRefresh.setOnRefreshListener(this); mSwipeRefresh.setOnRefreshListener(this);

View File

@ -18,6 +18,7 @@ import com.google.android.material.color.MaterialColors;
import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.adapters.GameAdapter; import org.dolphinemu.dolphinemu.adapters.GameAdapter;
import org.dolphinemu.dolphinemu.databinding.FragmentGridBinding;
import org.dolphinemu.dolphinemu.services.GameFileCacheManager; import org.dolphinemu.dolphinemu.services.GameFileCacheManager;
import org.dolphinemu.dolphinemu.utils.InsetsHelper; import org.dolphinemu.dolphinemu.utils.InsetsHelper;
@ -26,10 +27,11 @@ public final class PlatformGamesFragment extends Fragment implements PlatformGam
private static final String ARG_PLATFORM = "platform"; private static final String ARG_PLATFORM = "platform";
private GameAdapter mAdapter; private GameAdapter mAdapter;
private RecyclerView mRecyclerView;
private SwipeRefreshLayout mSwipeRefresh; private SwipeRefreshLayout mSwipeRefresh;
private SwipeRefreshLayout.OnRefreshListener mOnRefreshListener; private SwipeRefreshLayout.OnRefreshListener mOnRefreshListener;
private FragmentGridBinding mBinding;
public static PlatformGamesFragment newInstance(Platform platform) public static PlatformGamesFragment newInstance(Platform platform)
{ {
PlatformGamesFragment fragment = new PlatformGamesFragment(); PlatformGamesFragment fragment = new PlatformGamesFragment();
@ -47,19 +49,20 @@ public final class PlatformGamesFragment extends Fragment implements PlatformGam
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
} }
@NonNull
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{ {
View rootView = inflater.inflate(R.layout.fragment_grid, container, false); mBinding = FragmentGridBinding.inflate(inflater, container, false);
return mBinding.getRoot();
findViews(rootView);
return rootView;
} }
@Override @Override
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) public void onViewCreated(@NonNull View view, Bundle savedInstanceState)
{ {
mSwipeRefresh = mBinding.swipeRefresh;
int columns = getResources().getInteger(R.integer.game_grid_columns); int columns = getResources().getInteger(R.integer.game_grid_columns);
RecyclerView.LayoutManager layoutManager = new GridLayoutManager(getActivity(), columns); RecyclerView.LayoutManager layoutManager = new GridLayoutManager(getActivity(), columns);
mAdapter = new GameAdapter(); mAdapter = new GameAdapter();
@ -72,16 +75,23 @@ public final class PlatformGamesFragment extends Fragment implements PlatformGam
mSwipeRefresh.setOnRefreshListener(mOnRefreshListener); mSwipeRefresh.setOnRefreshListener(mOnRefreshListener);
mRecyclerView.setLayoutManager(layoutManager); mBinding.gridGames.setLayoutManager(layoutManager);
mRecyclerView.setAdapter(mAdapter); mBinding.gridGames.setAdapter(mAdapter);
InsetsHelper.setUpList(getContext(), mRecyclerView); InsetsHelper.setUpList(getContext(), mBinding.gridGames);
setRefreshing(GameFileCacheManager.isLoadingOrRescanning()); setRefreshing(GameFileCacheManager.isLoadingOrRescanning());
showGames(); showGames();
} }
@Override
public void onDestroyView()
{
super.onDestroyView();
mBinding = null;
}
@Override @Override
public void refreshScreenshotAtPosition(int position) public void refreshScreenshotAtPosition(int position)
{ {
@ -115,17 +125,13 @@ public final class PlatformGamesFragment extends Fragment implements PlatformGam
mOnRefreshListener = listener; mOnRefreshListener = listener;
if (mSwipeRefresh != null) if (mSwipeRefresh != null)
{
mSwipeRefresh.setOnRefreshListener(listener); mSwipeRefresh.setOnRefreshListener(listener);
}
} }
public void setRefreshing(boolean refreshing) public void setRefreshing(boolean refreshing)
{ {
mSwipeRefresh.setRefreshing(refreshing); mBinding.swipeRefresh.setRefreshing(refreshing);
}
private void findViews(View root)
{
mSwipeRefresh = root.findViewById(R.id.swipe_refresh);
mRecyclerView = root.findViewById(R.id.grid_games);
} }
} }

View File

@ -23,9 +23,9 @@ import com.bumptech.glide.request.target.Target;
import com.bumptech.glide.request.transition.Transition; import com.bumptech.glide.request.transition.Transition;
import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.adapters.GameAdapter;
import org.dolphinemu.dolphinemu.features.settings.model.BooleanSetting; import org.dolphinemu.dolphinemu.features.settings.model.BooleanSetting;
import org.dolphinemu.dolphinemu.model.GameFile; import org.dolphinemu.dolphinemu.model.GameFile;
import org.dolphinemu.dolphinemu.viewholders.GameViewHolder;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
@ -60,21 +60,21 @@ public class GlideUtils
} }
} }
public static void loadGameCover(GameViewHolder gameViewHolder, ImageView imageView, public static void loadGameCover(GameAdapter.GameViewHolder gameViewHolder, ImageView imageView,
GameFile gameFile) GameFile gameFile)
{ {
if (BooleanSetting.MAIN_SHOW_GAME_TITLES.getBooleanGlobal() && gameViewHolder != null) if (BooleanSetting.MAIN_SHOW_GAME_TITLES.getBooleanGlobal() && gameViewHolder != null)
{ {
gameViewHolder.textGameTitle.setText(gameFile.getTitle()); gameViewHolder.binding.textGameTitle.setText(gameFile.getTitle());
gameViewHolder.textGameTitle.setVisibility(View.VISIBLE); gameViewHolder.binding.textGameTitle.setVisibility(View.VISIBLE);
gameViewHolder.textGameTitleInner.setVisibility(View.GONE); gameViewHolder.binding.textGameTitleInner.setVisibility(View.GONE);
gameViewHolder.textGameCaption.setVisibility(View.VISIBLE); gameViewHolder.binding.textGameCaption.setVisibility(View.VISIBLE);
} }
else if (gameViewHolder != null) else if (gameViewHolder != null)
{ {
gameViewHolder.textGameTitleInner.setText(gameFile.getTitle()); gameViewHolder.binding.textGameTitleInner.setText(gameFile.getTitle());
gameViewHolder.textGameTitle.setVisibility(View.GONE); gameViewHolder.binding.textGameTitle.setVisibility(View.GONE);
gameViewHolder.textGameCaption.setVisibility(View.GONE); gameViewHolder.binding.textGameCaption.setVisibility(View.GONE);
} }
String customCoverPath = gameFile.getCustomCoverPath(); String customCoverPath = gameFile.getCustomCoverPath();
@ -198,7 +198,8 @@ public class GlideUtils
} }
} }
private static void enableInnerTitle(GameViewHolder gameViewHolder, ImageView imageView) private static void enableInnerTitle(GameAdapter.GameViewHolder gameViewHolder,
ImageView imageView)
{ {
Glide.with(imageView.getContext()) Glide.with(imageView.getContext())
.load(R.drawable.no_banner) .load(R.drawable.no_banner)
@ -206,15 +207,15 @@ public class GlideUtils
if (gameViewHolder != null && !BooleanSetting.MAIN_SHOW_GAME_TITLES.getBooleanGlobal()) if (gameViewHolder != null && !BooleanSetting.MAIN_SHOW_GAME_TITLES.getBooleanGlobal())
{ {
gameViewHolder.textGameTitleInner.setVisibility(View.VISIBLE); gameViewHolder.binding.textGameTitleInner.setVisibility(View.VISIBLE);
} }
} }
private static void disableInnerTitle(GameViewHolder gameViewHolder) private static void disableInnerTitle(GameAdapter.GameViewHolder gameViewHolder)
{ {
if (gameViewHolder != null && !BooleanSetting.MAIN_SHOW_GAME_TITLES.getBooleanGlobal()) if (gameViewHolder != null && !BooleanSetting.MAIN_SHOW_GAME_TITLES.getBooleanGlobal())
{ {
gameViewHolder.textGameTitleInner.setVisibility(View.GONE); gameViewHolder.binding.textGameTitleInner.setVisibility(View.GONE);
} }
} }
} }

View File

@ -1,38 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.viewholders;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.model.GameFile;
/**
* A simple class that stores references to views so that the GameAdapter doesn't need to
* keep calling findViewById(), which is expensive.
*/
public class GameViewHolder extends RecyclerView.ViewHolder
{
public ImageView imageScreenshot;
public TextView textGameTitle;
public TextView textGameTitleInner;
public TextView textGameCaption;
public GameFile gameFile;
public GameViewHolder(View itemView)
{
super(itemView);
itemView.setTag(this);
imageScreenshot = itemView.findViewById(R.id.image_game_screen);
textGameTitle = itemView.findViewById(R.id.text_game_title);
textGameTitleInner = itemView.findViewById(R.id.text_game_title_inner);
textGameCaption = itemView.findViewById(R.id.text_game_caption);
}
}

View File

@ -1,37 +1,36 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout <!-- Set nextFocusLeft so checkbox functionality is maintained in rtl layouts -->
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/root" android:id="@+id/root"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:focusable="true" android:focusable="true"
android:clickable="true"
android:background="?android:attr/selectableItemBackground"
android:nextFocusLeft="@id/checkbox"> android:nextFocusLeft="@id/checkbox">
<TextView <TextView
android:id="@+id/text_name" android:id="@+id/text_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
style="@style/TextAppearance.MaterialComponents.Headline5" style="@style/TextAppearance.MaterialComponents.Headline5"
android:layout_width="wrap_content"
android:layout_height="64dp"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:gravity="center_vertical"
android:layout_marginStart="@dimen/spacing_large"
android:textSize="16sp" android:textSize="16sp"
tools:text="Hyrule Field Speed Hack" tools:text="Hyrule Field Speed Hack" />
android:layout_margin="@dimen/spacing_large"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/checkbox"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
<CheckBox <CheckBox
android:id="@+id/checkbox" android:id="@+id/checkbox"
android:layout_width="48dp" android:layout_width="wrap_content"
android:layout_height="64dp" android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_marginEnd="@dimen/spacing_small"
android:focusable="true" android:focusable="true"
android:gravity="center" android:nextFocusRight="@id/root" />
android:nextFocusRight="@id/root"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/text_name"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout> </RelativeLayout>

View File

@ -1,7 +1,14 @@
<SurfaceView xmlns:android="http://schemas.android.com/apk/res/android" <View
android:id="@+id/surface_emulation" xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent" android:id="@+id/layout_emulation"
android:layout_width="match_parent" android:layout_height="match_parent"
android:focusable="false" android:layout_width="match_parent">
android:focusableInTouchMode="false"
/> <SurfaceView
android:id="@+id/surface_emulation"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:focusable="false"
android:focusableInTouchMode="false" />
</View>

View File

@ -1,7 +1,14 @@
<SurfaceView xmlns:android="http://schemas.android.com/apk/res/android" <View
android:id="@+id/surface_emulation" xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent" android:id="@+id/layout_emulation"
android:layout_width="match_parent" android:layout_height="match_parent"
android:focusable="false" android:layout_width="match_parent">
android:focusableInTouchMode="false"
/> <SurfaceView
android:id="@+id/surface_emulation"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:focusable="false"
android:focusableInTouchMode="false" />
</View>

View File

@ -1,9 +1,11 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" <FrameLayout
xmlns:tools="http://schemas.android.com/tools" xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" xmlns:tools="http://schemas.android.com/tools"
android:layout_height="match_parent" android:id="@+id/layout_emulation"
android:keepScreenOn="true" android:layout_width="match_parent"
tools:context="org.dolphinemu.dolphinemu.fragments.EmulationFragment"> android:layout_height="match_parent"
android:keepScreenOn="true"
tools:context="org.dolphinemu.dolphinemu.fragments.EmulationFragment">
<!-- Places the emulation surface to the top half of the screen --> <!-- Places the emulation surface to the top half of the screen -->
<LinearLayout <LinearLayout
@ -11,6 +13,7 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical" android:orientation="vertical"
android:baselineAligned="false"> android:baselineAligned="false">
<!-- This is what everything is rendered to during emulation --> <!-- This is what everything is rendered to during emulation -->
<SurfaceView <SurfaceView
android:id="@+id/surface_emulation" android:id="@+id/surface_emulation"
@ -18,19 +21,22 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_weight="1" android:layout_weight="1"
android:focusable="false" android:focusable="false"
android:focusableInTouchMode="false"/> android:focusableInTouchMode="false" />
<RelativeLayout <RelativeLayout
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_weight="1"/> android:layout_weight="1" />
</LinearLayout> </LinearLayout>
<!-- This is the onscreen input overlay --> <!-- This is the onscreen input overlay -->
<org.dolphinemu.dolphinemu.overlay.InputOverlay <org.dolphinemu.dolphinemu.overlay.InputOverlay
android:id="@+id/surface_input_overlay" android:id="@+id/surface_input_overlay"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_width="match_parent" android:layout_width="match_parent"
android:focusable="true" android:focusable="true"
android:focusableInTouchMode="true"/> android:focusableInTouchMode="true" />
<Button <Button
android:id="@+id/done_control_config" android:id="@+id/done_control_config"
@ -39,6 +45,6 @@
android:layout_gravity="center" android:layout_gravity="center"
android:padding="@dimen/spacing_small" android:padding="@dimen/spacing_small"
android:text="@string/emulation_done" android:text="@string/emulation_done"
android:visibility="gone"/> android:visibility="gone" />
</FrameLayout> </FrameLayout>

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android" <androidx.appcompat.widget.LinearLayoutCompat
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical" android:orientation="vertical"

View File

@ -12,7 +12,7 @@
android:layout_weight="1"> android:layout_weight="1">
<com.google.android.material.slider.Slider <com.google.android.material.slider.Slider
android:id="@+id/slider_width" android:id="@+id/slider_yaw"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:layout_constraintEnd_toStartOf="@id/text_ir_yaw" app:layout_constraintEnd_toStartOf="@id/text_ir_yaw"
@ -26,10 +26,10 @@
android:layout_marginEnd="24dp" android:layout_marginEnd="24dp"
android:layout_marginStart="@dimen/spacing_medlarge" android:layout_marginStart="@dimen/spacing_medlarge"
android:gravity="end" android:gravity="end"
app:layout_constraintBottom_toBottomOf="@+id/slider_width" app:layout_constraintBottom_toBottomOf="@+id/slider_yaw"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/slider_width" app:layout_constraintStart_toEndOf="@id/slider_yaw"
app:layout_constraintTop_toTopOf="@+id/slider_width" app:layout_constraintTop_toTopOf="@+id/slider_yaw"
tools:text="100" /> tools:text="100" />
<TextView <TextView
@ -39,10 +39,10 @@
android:gravity="start" android:gravity="start"
android:layout_marginStart="24dp" android:layout_marginStart="24dp"
android:layout_marginEnd="@dimen/spacing_medlarge" android:layout_marginEnd="@dimen/spacing_medlarge"
app:layout_constraintBottom_toBottomOf="@+id/slider_width" app:layout_constraintBottom_toBottomOf="@+id/slider_yaw"
app:layout_constraintEnd_toStartOf="@id/slider_width" app:layout_constraintEnd_toStartOf="@id/slider_yaw"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/slider_width" app:layout_constraintTop_toTopOf="@+id/slider_yaw"
tools:text="Total Yaw" /> tools:text="Total Yaw" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,9 +1,11 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" <FrameLayout
xmlns:tools="http://schemas.android.com/tools" xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" xmlns:tools="http://schemas.android.com/tools"
android:layout_height="match_parent" android:id="@+id/layout_emulation"
android:keepScreenOn="true" android:layout_width="match_parent"
tools:context="org.dolphinemu.dolphinemu.fragments.EmulationFragment"> android:layout_height="match_parent"
android:keepScreenOn="true"
tools:context="org.dolphinemu.dolphinemu.fragments.EmulationFragment">
<!-- This is what everything is rendered to during emulation --> <!-- This is what everything is rendered to during emulation -->
<SurfaceView <SurfaceView
@ -11,7 +13,7 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_width="match_parent" android:layout_width="match_parent"
android:focusable="false" android:focusable="false"
android:focusableInTouchMode="false"/> android:focusableInTouchMode="false" />
<!-- This is the onscreen input overlay --> <!-- This is the onscreen input overlay -->
<org.dolphinemu.dolphinemu.overlay.InputOverlay <org.dolphinemu.dolphinemu.overlay.InputOverlay
@ -19,7 +21,7 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_width="match_parent" android:layout_width="match_parent"
android:focusable="true" android:focusable="true"
android:focusableInTouchMode="true"/> android:focusableInTouchMode="true" />
<Button <Button
android:id="@+id/done_control_config" android:id="@+id/done_control_config"
@ -28,6 +30,6 @@
android:layout_gravity="center" android:layout_gravity="center"
android:padding="@dimen/spacing_small" android:padding="@dimen/spacing_small"
android:text="@string/emulation_done" android:text="@string/emulation_done"
android:visibility="gone"/> android:visibility="gone" />
</FrameLayout> </FrameLayout>

View File

@ -1,37 +1,35 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout <RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/root" android:id="@+id/root"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:focusable="true" android:focusable="true"
android:clickable="true"
android:background="?android:attr/selectableItemBackground"
android:nextFocusRight="@id/checkbox"> android:nextFocusRight="@id/checkbox">
<TextView <TextView
android:id="@+id/text_name" android:id="@+id/text_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
style="@style/TextAppearance.MaterialComponents.Headline5" style="@style/TextAppearance.MaterialComponents.Headline5"
android:layout_width="wrap_content"
android:layout_height="64dp"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:gravity="center_vertical"
android:layout_marginStart="@dimen/spacing_large"
android:textSize="16sp" android:textSize="16sp"
tools:text="Hyrule Field Speed Hack" tools:text="Hyrule Field Speed Hack" />
android:layout_margin="@dimen/spacing_large"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/checkbox"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
<CheckBox <CheckBox
android:id="@+id/checkbox" android:id="@+id/checkbox"
android:layout_width="48dp" android:layout_width="wrap_content"
android:layout_height="64dp" android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_marginEnd="@dimen/spacing_small"
android:focusable="true" android:focusable="true"
android:gravity="center" android:nextFocusRight="@id/root" />
android:nextFocusRight="@id/root"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/text_name"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout> </RelativeLayout>

View File

@ -1,19 +1,21 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout
xmlns:tools="http://schemas.android.com/tools" xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" xmlns:tools="http://schemas.android.com/tools"
android:focusable="true" android:layout_width="match_parent"
android:layout_height="48dp"> android:focusable="true"
android:layout_height="wrap_content">
<TextView <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/text_header_name" android:id="@+id/text_header_name"
tools:text="CPU Settings" android:layout_width="wrap_content"
android:layout_height="46dp"
android:gravity="bottom"
android:layout_alignParentTop="true"
android:layout_marginStart="@dimen/spacing_large" android:layout_marginStart="@dimen/spacing_large"
android:layout_marginBottom="@dimen/spacing_small" android:layout_marginBottom="2dp"
android:textColor="?attr/colorPrimary" android:textColor="?attr/colorPrimary"
android:textStyle="bold" android:textStyle="bold"
android:layout_gravity="start|bottom"/> tools:text="CPU Settings" />
</FrameLayout> </RelativeLayout>

View File

@ -1,12 +1,13 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout
xmlns:tools="http://schemas.android.com/tools" xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" xmlns:tools="http://schemas.android.com/tools"
android:layout_height="wrap_content" android:layout_width="match_parent"
android:minHeight="72dp" android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground" android:minHeight="72dp"
android:focusable="true" android:background="?android:attr/selectableItemBackground"
android:clickable="true"> android:focusable="true"
android:clickable="true">
<TextView <TextView
android:layout_width="0dp" android:layout_width="0dp"

View File

@ -1,12 +1,13 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout
xmlns:tools="http://schemas.android.com/tools" xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" xmlns:tools="http://schemas.android.com/tools"
android:layout_height="wrap_content" android:layout_width="match_parent"
android:minHeight="72dp" android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground" android:minHeight="72dp"
android:focusable="true" android:background="?android:attr/selectableItemBackground"
android:clickable="true"> android:focusable="true"
android:clickable="true">
<TextView <TextView
android:id="@+id/text_setting_name" android:id="@+id/text_setting_name"

View File

@ -1,12 +1,13 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout
xmlns:tools="http://schemas.android.com/tools" xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" xmlns:tools="http://schemas.android.com/tools"
android:layout_height="wrap_content" android:layout_width="match_parent"
android:minHeight="54dp" android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground" android:minHeight="54dp"
android:focusable="true" android:background="?android:attr/selectableItemBackground"
android:clickable="true"> android:focusable="true"
android:clickable="true">
<TextView <TextView
android:layout_width="0dp" android:layout_width="0dp"
@ -20,6 +21,6 @@
android:layout_marginEnd="@dimen/spacing_large" android:layout_marginEnd="@dimen/spacing_large"
android:layout_marginTop="@dimen/spacing_large" android:layout_marginTop="@dimen/spacing_large"
android:id="@+id/text_setting_name" android:id="@+id/text_setting_name"
android:textSize="16sp"/> android:textSize="16sp" />
</RelativeLayout> </RelativeLayout>