Expand Up @@ -5,16 +5,15 @@
import android.app.Dialog;
import android.os.Bundle;
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 com.google.android.material.dialog.MaterialAlertDialogBuilder;

import org.dolphinemu.dolphinemu.NativeLibrary;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.databinding.DialogGameDetailsBinding;
import org.dolphinemu.dolphinemu.model.GameFile;
import org.dolphinemu.dolphinemu.services.GameFileCacheManager;
import org.dolphinemu.dolphinemu.utils.GlideUtils;
Expand All @@ -34,90 +33,72 @@ public static GameDetailsDialog newInstance(String gamePath)
return fragment;
}

@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState)
{
GameFile gameFile = GameFileCacheManager.addOrGet(getArguments().getString(ARG_GAME_PATH));

ViewGroup contents = (ViewGroup) getActivity().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);
DialogGameDetailsBinding binding = DialogGameDetailsBinding.inflate(getLayoutInflater());

String country = getResources().getStringArray(R.array.countryNames)[gameFile.getCountry()];
String description = gameFile.getDescription();
String fileSize = NativeLibrary.FormatSize(gameFile.getFileSize(), 2);

textTitle.setText(gameFile.getTitle());
textDescription.setText(gameFile.getDescription());
binding.textGameTitle.setText(gameFile.getTitle());
binding.textDescription.setText(gameFile.getDescription());
if (description.isEmpty())
{
textDescription.setVisibility(View.GONE);
binding.textDescription.setVisibility(View.GONE);
}

textCountry.setText(country);
textCompany.setText(gameFile.getCompany());
textGameId.setText(gameFile.getGameId());
textRevision.setText(String.valueOf(gameFile.getRevision()));
binding.textCountry.setText(country);
binding.textCompany.setText(gameFile.getCompany());
binding.textGameId.setText(gameFile.getGameId());
binding.textRevision.setText(String.valueOf(gameFile.getRevision()));

if (!gameFile.shouldShowFileFormatDetails())
{
labelFileFormat.setText(R.string.game_details_file_size);
textFileFormat.setText(fileSize);
binding.labelFileFormat.setText(R.string.game_details_file_size);
binding.textFileFormat.setText(fileSize);

labelCompression.setVisibility(View.GONE);
textCompression.setVisibility(View.GONE);
labelBlockSize.setVisibility(View.GONE);
textBlockSize.setVisibility(View.GONE);
binding.labelCompression.setVisibility(View.GONE);
binding.textCompression.setVisibility(View.GONE);
binding.labelBlockSize.setVisibility(View.GONE);
binding.textBlockSize.setVisibility(View.GONE);
}
else
{
long blockSize = gameFile.getBlockSize();
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));

if (compression.isEmpty())
{
textCompression.setText(R.string.game_details_no_compression);
binding.textCompression.setText(R.string.game_details_no_compression);
}
else
{
textCompression.setText(gameFile.getCompressionMethod());
binding.textCompression.setText(gameFile.getCompressionMethod());
}

if (blockSize > 0)
{
textBlockSize.setText(NativeLibrary.FormatSize(blockSize, 0));
binding.textBlockSize.setText(NativeLibrary.FormatSize(blockSize, 0));
}
else
{
labelBlockSize.setVisibility(View.GONE);
textBlockSize.setVisibility(View.GONE);
binding.labelBlockSize.setVisibility(View.GONE);
binding.textBlockSize.setVisibility(View.GONE);
}
}

GlideUtils.loadGameBanner(banner, gameFile);
GlideUtils.loadGameBanner(binding.banner, gameFile);

return new MaterialAlertDialogBuilder(requireActivity())
.setView(contents)
.setView(binding.getRoot())
.create();
}
}
Expand Up @@ -9,6 +9,7 @@
import androidx.lifecycle.ViewModelProvider;

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.CheatsViewModel;
import org.dolphinemu.dolphinemu.features.cheats.model.GeckoCheat;
Expand All @@ -23,13 +24,13 @@ public class ActionViewHolder extends CheatItemViewHolder implements View.OnClic
private int mString;
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)
Expand Down
Expand Up @@ -6,87 +6,64 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ScrollView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;

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.databinding.FragmentCheatDetailsBinding;
import org.dolphinemu.dolphinemu.features.cheats.model.Cheat;
import org.dolphinemu.dolphinemu.features.cheats.model.CheatsViewModel;

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 Cheat mCheat;

private FragmentCheatDetailsBinding mBinding;

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState)
{
return inflater.inflate(R.layout.fragment_cheat_details, container, false);
mBinding = FragmentCheatDetailsBinding.inflate(inflater, container, false);
return mBinding.getRoot();
}

@Override
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();
mViewModel = new ViewModelProvider(activity).get(CheatsViewModel.class);

mViewModel.getSelectedCheat().observe(getViewLifecycleOwner(), this::onSelectedCheatUpdated);
mViewModel.getIsEditing().observe(getViewLifecycleOwner(), this::onIsEditingUpdated);

mButtonDelete.setOnClickListener(this::onDeleteClicked);
mButtonEdit.setOnClickListener(this::onEditClicked);
mButtonCancel.setOnClickListener(this::onCancelClicked);
mButtonOk.setOnClickListener(this::onOkClicked);
mBinding.buttonDelete.setOnClickListener(this::onDeleteClicked);
mBinding.buttonEdit.setOnClickListener(this::onEditClicked);
mBinding.buttonCancel.setOnClickListener(this::onCancelClicked);
mBinding.buttonOk.setOnClickListener(this::onOkClicked);

CheatsActivity.setOnFocusChangeListenerRecursively(view,
(v, hasFocus) -> activity.onDetailsViewFocusChange(hasFocus));
}

@Override
public void onDestroyView()
{
super.onDestroyView();
mBinding = null;
}

private void clearEditErrors()
{
mEditNameLayout.setError(null);
mEditCodeLayout.setError(null);
mBinding.editName.setError(null);
mBinding.editCode.setError(null);
}

private void onDeleteClicked(View view)
Expand All @@ -101,22 +78,24 @@ private void onDeleteClicked(View view)
private void onEditClicked(View view)
{
mViewModel.setIsEditing(true);
mButtonOk.requestFocus();
mBinding.buttonOk.requestFocus();
}

private void onCancelClicked(View view)
{
mViewModel.setIsEditing(false);
onSelectedCheatUpdated(mCheat);
mButtonDelete.requestFocus();
mBinding.buttonDelete.requestFocus();
}

private void onOkClicked(View view)
{
clearEditErrors();

int result = mCheat.trySet(mEditName.getText().toString(), mEditCreator.getText().toString(),
mEditNotes.getText().toString(), mEditCode.getText().toString());
int result = mCheat.trySet(mBinding.editNameInput.getText().toString(),
mBinding.editCreatorInput.getText().toString(),
mBinding.editNotesInput.getText().toString(),
mBinding.editCodeInput.getText().toString());

switch (result)
{
Expand All @@ -131,23 +110,23 @@ private void onOkClicked(View view)
mViewModel.notifySelectedCheatChanged();
mViewModel.setIsEditing(false);
}
mButtonEdit.requestFocus();
mBinding.buttonEdit.requestFocus();
break;
case Cheat.TRY_SET_FAIL_NO_NAME:
mEditNameLayout.setError(getString(R.string.cheats_error_no_name));
mScrollView.smoothScrollTo(0, mEditName.getTop());
mBinding.editName.setError(getString(R.string.cheats_error_no_name));
mBinding.scrollView.smoothScrollTo(0, mBinding.editNameInput.getTop());
break;
case Cheat.TRY_SET_FAIL_NO_CODE_LINES:
mEditCodeLayout.setError(getString(R.string.cheats_error_no_code_lines));
mScrollView.smoothScrollTo(0, mEditCode.getBottom());
mBinding.editCode.setError(getString(R.string.cheats_error_no_code_lines));
mBinding.scrollView.smoothScrollTo(0, mBinding.editCodeInput.getBottom());
break;
case Cheat.TRY_SET_FAIL_CODE_MIXED_ENCRYPTION:
mEditCodeLayout.setError(getString(R.string.cheats_error_mixed_encryption));
mScrollView.smoothScrollTo(0, mEditCode.getBottom());
mBinding.editCode.setError(getString(R.string.cheats_error_mixed_encryption));
mBinding.scrollView.smoothScrollTo(0, mBinding.editCodeInput.getBottom());
break;
default:
mEditCodeLayout.setError(getString(R.string.cheats_error_on_line, result));
mScrollView.smoothScrollTo(0, mEditCode.getBottom());
mBinding.editCode.setError(getString(R.string.cheats_error_on_line, result));
mBinding.scrollView.smoothScrollTo(0, mBinding.editCodeInput.getBottom());
break;
}
}
Expand All @@ -156,44 +135,44 @@ private void onSelectedCheatUpdated(@Nullable Cheat cheat)
{
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 notesVisibility = cheat != null && cheat.supportsNotes() ? View.VISIBLE : View.GONE;
int codeVisibility = cheat != null && cheat.supportsCode() ? View.VISIBLE : View.GONE;
mEditCreatorLayout.setVisibility(creatorVisibility);
mEditNotesLayout.setVisibility(notesVisibility);
mEditCodeLayout.setVisibility(codeVisibility);
mBinding.editCreator.setVisibility(creatorVisibility);
mBinding.editNotes.setVisibility(notesVisibility);
mBinding.editCode.setVisibility(codeVisibility);

boolean userDefined = cheat != null && cheat.getUserDefined();
mButtonDelete.setEnabled(userDefined);
mButtonEdit.setEnabled(userDefined);
mBinding.buttonDelete.setEnabled(userDefined);
mBinding.buttonEdit.setEnabled(userDefined);

// 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
boolean isEditing = mViewModel.getIsEditing().getValue();

if (!isEditing && cheat != null)
{
mEditName.setText(cheat.getName());
mEditCreator.setText(cheat.getCreator());
mEditNotes.setText(cheat.getNotes());
mEditCode.setText(cheat.getCode());
mBinding.editNameInput.setText(cheat.getName());
mBinding.editCreatorInput.setText(cheat.getCreator());
mBinding.editNotesInput.setText(cheat.getNotes());
mBinding.editCodeInput.setText(cheat.getCode());
}

mCheat = cheat;
}

private void onIsEditingUpdated(boolean isEditing)
{
mEditName.setEnabled(isEditing);
mEditCreator.setEnabled(isEditing);
mEditNotes.setEnabled(isEditing);
mEditCode.setEnabled(isEditing);

mButtonDelete.setVisibility(isEditing ? View.GONE : View.VISIBLE);
mButtonEdit.setVisibility(isEditing ? View.GONE : View.VISIBLE);
mButtonCancel.setVisibility(isEditing ? View.VISIBLE : View.GONE);
mButtonOk.setVisibility(isEditing ? View.VISIBLE : View.GONE);
mBinding.editNameInput.setEnabled(isEditing);
mBinding.editCreatorInput.setEnabled(isEditing);
mBinding.editNotesInput.setEnabled(isEditing);
mBinding.editCodeInput.setEnabled(isEditing);

mBinding.buttonDelete.setVisibility(isEditing ? View.GONE : View.VISIBLE);
mBinding.buttonEdit.setVisibility(isEditing ? View.GONE : View.VISIBLE);
mBinding.buttonCancel.setVisibility(isEditing ? View.VISIBLE : View.GONE);
mBinding.buttonOk.setVisibility(isEditing ? View.VISIBLE : View.GONE);
}
}
Expand Up @@ -12,40 +12,47 @@
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

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.utils.InsetsHelper;

public class CheatListFragment extends Fragment
{
private FragmentCheatListBinding mBinding;

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState)
{
return inflater.inflate(R.layout.fragment_cheat_list, container, false);
mBinding = FragmentCheatListBinding.inflate(inflater, container, false);
return mBinding.getRoot();
}

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState)
{
RecyclerView recyclerView = view.findViewById(R.id.cheat_list);

CheatsActivity activity = (CheatsActivity) requireActivity();
CheatsViewModel viewModel = new ViewModelProvider(activity).get(CheatsViewModel.class);

recyclerView.setAdapter(new CheatsAdapter(activity, viewModel));
recyclerView.setLayoutManager(new LinearLayoutManager(activity));
mBinding.cheatList.setAdapter(new CheatsAdapter(activity, viewModel));
mBinding.cheatList.setLayoutManager(new LinearLayoutManager(activity));

MaterialDividerItemDecoration divider =
new MaterialDividerItemDecoration(requireActivity(), LinearLayoutManager.VERTICAL);
divider.setLastItemDecorated(false);
recyclerView.addItemDecoration(divider);
mBinding.cheatList.addItemDecoration(divider);

InsetsHelper.setUpList(getContext(), mBinding.cheatList);
}

InsetsHelper.setUpList(getContext(), recyclerView);
@Override
public void onDestroyView()
{
super.onDestroyView();
mBinding = null;
}
}
Expand Up @@ -10,43 +10,38 @@
import androidx.annotation.NonNull;
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.CheatsViewModel;

public class CheatViewHolder extends CheatItemViewHolder
implements View.OnClickListener, CompoundButton.OnCheckedChangeListener
{
private final View mRoot;
private final TextView mName;
private final CheckBox mCheckbox;
private final ListItemCheatBinding mBinding;

private CheatsViewModel mViewModel;
private Cheat mCheat;
private int mPosition;

public CheatViewHolder(@NonNull View itemView)
public CheatViewHolder(@NonNull ListItemCheatBinding binding)
{
super(itemView);

mRoot = itemView.findViewById(R.id.root);
mName = itemView.findViewById(R.id.text_name);
mCheckbox = itemView.findViewById(R.id.checkbox);
super(binding.getRoot());
mBinding = binding;
}

public void bind(CheatsActivity activity, CheatItem item, int position)
{
mCheckbox.setOnCheckedChangeListener(null);
mBinding.checkbox.setOnCheckedChangeListener(null);

mViewModel = new ViewModelProvider(activity).get(CheatsViewModel.class);
mCheat = item.getCheat();
mPosition = position;

mName.setText(mCheat.getName());
mCheckbox.setChecked(mCheat.getEnabled());
mBinding.textName.setText(mCheat.getName());
mBinding.checkbox.setChecked(mCheat.getEnabled());

mRoot.setOnClickListener(this);
mCheckbox.setOnCheckedChangeListener(this);
mBinding.root.setOnClickListener(this);
mBinding.checkbox.setOnCheckedChangeListener(this);
}

public void onClick(View root)
Expand Down
Expand Up @@ -19,12 +19,11 @@
import androidx.lifecycle.ViewModelProvider;
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.dialog.MaterialAlertDialogBuilder;

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.CheatsViewModel;
import org.dolphinemu.dolphinemu.features.cheats.model.GeckoCheat;
Expand All @@ -48,13 +47,11 @@ public class CheatsActivity extends AppCompatActivity
private boolean mIsWii;
private CheatsViewModel mViewModel;

private SlidingPaneLayout mSlidingPaneLayout;
private View mCheatList;
private View mCheatDetails;

private View mCheatListLastFocus;
private View mCheatDetailsLastFocus;

private ActivityCheatsBinding mBinding;

public static void launch(Context context, String gameId, String gameTdbId, int revision,
boolean isWii)
{
Expand Down Expand Up @@ -86,38 +83,34 @@ protected void onCreate(Bundle savedInstanceState)
mViewModel = new ViewModelProvider(this).get(CheatsViewModel.class);
mViewModel.load(mGameId, mRevision);

setContentView(R.layout.activity_cheats);
mBinding = ActivityCheatsBinding.inflate(getLayoutInflater());
setContentView(mBinding.getRoot());

WindowCompat.setDecorFitsSystemWindows(getWindow(), false);

mSlidingPaneLayout = findViewById(R.id.sliding_pane_layout);
mCheatList = findViewById(R.id.cheat_list);
mCheatDetails = findViewById(R.id.cheat_details);

mCheatListLastFocus = mCheatList;
mCheatDetailsLastFocus = mCheatDetails;
mCheatListLastFocus = mBinding.cheatList;
mCheatDetailsLastFocus = mBinding.cheatDetails;

mSlidingPaneLayout.addPanelSlideListener(this);
mBinding.slidingPaneLayout.addPanelSlideListener(this);

getOnBackPressedDispatcher().addCallback(this,
new TwoPaneOnBackPressedCallback(mSlidingPaneLayout));
new TwoPaneOnBackPressedCallback(mBinding.slidingPaneLayout));

mViewModel.getSelectedCheat().observe(this, this::onSelectedCheatChanged);
onSelectedCheatChanged(mViewModel.getSelectedCheat().getValue());

mViewModel.getOpenDetailsViewEvent().observe(this, this::openDetailsView);

MaterialToolbar tb = findViewById(R.id.toolbar_cheats);
setSupportActionBar(tb);
setSupportActionBar(mBinding.toolbarCheats);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);

View workaroundView = findViewById(R.id.workaround_view);
AppBarLayout appBarLayout = findViewById(R.id.appbar_cheats);
InsetsHelper.setUpCheatsLayout(this, appBarLayout, mSlidingPaneLayout, mCheatDetails,
workaroundView);
InsetsHelper.setUpCheatsLayout(this, mBinding.appbarCheats, mBinding.slidingPaneLayout,
mBinding.cheatDetails,
mBinding.workaroundView);

@ColorInt int color = MaterialColors.getColor(tb, R.attr.colorSurfaceVariant);
tb.setBackgroundColor(color);
@ColorInt int color =
MaterialColors.getColor(mBinding.toolbarCheats, R.attr.colorSurfaceVariant);
mBinding.toolbarCheats.setBackgroundColor(color);
ThemeHelper.setStatusBarColor(this, color);
}

Expand Down Expand Up @@ -161,34 +154,34 @@ private void onSelectedCheatChanged(Cheat selectedCheat)
{
boolean cheatSelected = selectedCheat != null;

if (!cheatSelected && mSlidingPaneLayout.isOpen())
mSlidingPaneLayout.close();
if (!cheatSelected && mBinding.slidingPaneLayout.isOpen())
mBinding.slidingPaneLayout.close();

mSlidingPaneLayout.setLockMode(cheatSelected ?
mBinding.slidingPaneLayout.setLockMode(cheatSelected ?
SlidingPaneLayout.LOCK_MODE_UNLOCKED : SlidingPaneLayout.LOCK_MODE_LOCKED_CLOSED);
}

public void onListViewFocusChange(boolean hasFocus)
{
if (hasFocus)
{
mCheatListLastFocus = mCheatList.findFocus();
mCheatListLastFocus = mBinding.cheatList.findFocus();
if (mCheatListLastFocus == null)
throw new NullPointerException();

mSlidingPaneLayout.close();
mBinding.slidingPaneLayout.close();
}
}

public void onDetailsViewFocusChange(boolean hasFocus)
{
if (hasFocus)
{
mCheatDetailsLastFocus = mCheatDetails.findFocus();
mCheatDetailsLastFocus = mBinding.cheatDetails.findFocus();
if (mCheatDetailsLastFocus == null)
throw new NullPointerException();

mSlidingPaneLayout.open();
mBinding.slidingPaneLayout.open();
}
}

Expand All @@ -202,7 +195,7 @@ public boolean onSupportNavigateUp()
private void openDetailsView(boolean open)
{
if (open)
mSlidingPaneLayout.open();
mBinding.slidingPaneLayout.open();
}

public Settings loadGameSpecificSettings()
Expand Down
Expand Up @@ -10,6 +10,9 @@
import androidx.recyclerview.widget.RecyclerView;

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.CheatsViewModel;
import org.dolphinemu.dolphinemu.features.cheats.model.GeckoCheat;
Expand Down Expand Up @@ -66,17 +69,17 @@ public CheatItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int vie
switch (viewType)
{
case CheatItem.TYPE_CHEAT:
View cheatView = inflater.inflate(R.layout.list_item_cheat, parent, false);
addViewListeners(cheatView);
return new CheatViewHolder(cheatView);
ListItemCheatBinding listItemCheatBinding = ListItemCheatBinding.inflate(inflater);
addViewListeners(listItemCheatBinding.getRoot());
return new CheatViewHolder(listItemCheatBinding);
case CheatItem.TYPE_HEADER:
View headerView = inflater.inflate(R.layout.list_item_header, parent, false);
addViewListeners(headerView);
return new HeaderViewHolder(headerView);
ListItemHeaderBinding listItemHeaderBinding = ListItemHeaderBinding.inflate(inflater);
addViewListeners(listItemHeaderBinding.getRoot());
return new HeaderViewHolder(listItemHeaderBinding);
case CheatItem.TYPE_ACTION:
View actionView = inflater.inflate(R.layout.list_item_submenu, parent, false);
addViewListeners(actionView);
return new ActionViewHolder(actionView);
ListItemSubmenuBinding listItemSubmenuBinding = ListItemSubmenuBinding.inflate(inflater);
addViewListeners(listItemSubmenuBinding.getRoot());
return new ActionViewHolder(listItemSubmenuBinding);
default:
throw new UnsupportedOperationException();
}
Expand Down
Expand Up @@ -8,16 +8,17 @@
import androidx.annotation.NonNull;

import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.databinding.ListItemHeaderBinding;

public class HeaderViewHolder extends CheatItemViewHolder
{
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)
Expand Down
Expand Up @@ -6,14 +6,12 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
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.Settings;
import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag;
Expand All @@ -28,6 +26,8 @@ public abstract class SettingDisabledWarningFragment extends Fragment
private final MenuTag mSettingShortcut;
private final int mText;

private FragmentCheatWarningBinding mBinding;

public SettingDisabledWarningFragment(AbstractBooleanSetting setting, MenuTag settingShortcut,
int text)
{
Expand All @@ -38,22 +38,20 @@ public SettingDisabledWarningFragment(AbstractBooleanSetting setting, MenuTag se

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState)
{
return inflater.inflate(R.layout.fragment_cheat_warning, container, false);
mBinding = FragmentCheatWarningBinding.inflate(inflater, container, false);
return mBinding.getRoot();
}

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState)
{
mView = view;

TextView textView = view.findViewById(R.id.text_warning);
textView.setText(mText);

Button settingsButton = view.findViewById(R.id.button_settings);
settingsButton.setOnClickListener(this);
mBinding.textWarning.setText(mText);
mBinding.buttonSettings.setOnClickListener(this);

CheatsActivity activity = (CheatsActivity) requireActivity();
CheatsActivity.setOnFocusChangeListenerRecursively(view,
Expand All @@ -73,6 +71,13 @@ public void onResume()
}
}

@Override
public void onDestroyView()
{
super.onDestroyView();
mBinding = null;
}

public void onClick(View view)
{
SettingsActivity.launch(requireContext(), mSettingShortcut);
Expand Down
Expand Up @@ -9,7 +9,7 @@
import androidx.annotation.NonNull;
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 java.util.ArrayList;
Expand Down Expand Up @@ -48,8 +48,8 @@ public RiivolutionAdapter(Context context, RiivolutionPatches patches)
public RiivolutionViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType)
{
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
return new RiivolutionViewHolder(
inflater.inflate(R.layout.list_item_riivolution, parent, false));
ListItemRiivolutionBinding binding = ListItemRiivolutionBinding.inflate(inflater);
return new RiivolutionViewHolder(binding.getRoot(), binding);
}

@Override
Expand Down
Expand Up @@ -5,22 +5,14 @@
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.view.WindowCompat;
import androidx.core.widget.NestedScrollView;
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.activities.EmulationActivity;
import org.dolphinemu.dolphinemu.databinding.ActivityRiivolutionBootBinding;
import org.dolphinemu.dolphinemu.features.riivolution.model.RiivolutionPatches;
import org.dolphinemu.dolphinemu.features.settings.model.StringSetting;
import org.dolphinemu.dolphinemu.utils.DirectoryInitialization;
Expand All @@ -36,6 +28,8 @@ public class RiivolutionBootActivity extends AppCompatActivity

private RiivolutionPatches mPatches;

private ActivityRiivolutionBootBinding mBinding;

public static void launch(Context context, String gamePath, String gameId, int revision,
int discNumber)
{
Expand All @@ -54,7 +48,8 @@ protected void onCreate(Bundle savedInstanceState)

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_riivolution_boot);
mBinding = ActivityRiivolutionBootBinding.inflate(getLayoutInflater());
setContentView(mBinding.getRoot());

WindowCompat.setDecorFitsSystemWindows(getWindow(), false);

Expand All @@ -69,11 +64,9 @@ protected void onCreate(Bundle savedInstanceState)
if (loadPath.isEmpty())
loadPath = DirectoryInitialization.getUserDirectory() + "/Load";

TextView textSdRoot = findViewById(R.id.text_sd_root);
textSdRoot.setText(getString(R.string.riivolution_sd_root, loadPath + "/Riivolution"));
mBinding.textSdRoot.setText(getString(R.string.riivolution_sd_root, loadPath + "/Riivolution"));

Button buttonStart = findViewById(R.id.button_start);
buttonStart.setOnClickListener((v) ->
mBinding.buttonStart.setOnClickListener((v) ->
{
if (mPatches != null)
mPatches.saveConfig();
Expand All @@ -88,17 +81,13 @@ protected void onCreate(Bundle savedInstanceState)
runOnUiThread(() -> populateList(patches));
}).start();

MaterialToolbar tb = findViewById(R.id.toolbar_riivolution);
CollapsingToolbarLayout ctb = findViewById(R.id.toolbar_riivolution_layout);
ctb.setTitle(getString(R.string.riivolution_riivolution));
setSupportActionBar(tb);
mBinding.toolbarRiivolutionLayout.setTitle(getString(R.string.riivolution_riivolution));
setSupportActionBar(mBinding.toolbarRiivolution);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);

AppBarLayout appBarLayout = findViewById(R.id.appbar_riivolution);
NestedScrollView scrollView = findViewById(R.id.scroll_view_riivolution);
View workaroundView = findViewById(R.id.workaround_view);
InsetsHelper.setUpAppBarWithScrollView(this, appBarLayout, scrollView, workaroundView);
ThemeHelper.enableScrollTint(this, tb, appBarLayout);
InsetsHelper.setUpAppBarWithScrollView(this, mBinding.appbarRiivolution,
mBinding.scrollViewRiivolution, mBinding.workaroundView);
ThemeHelper.enableScrollTint(this, mBinding.toolbarRiivolution, mBinding.appbarRiivolution);
}

@Override
Expand All @@ -121,9 +110,7 @@ private void populateList(RiivolutionPatches patches)
{
mPatches = patches;

RecyclerView recyclerView = findViewById(R.id.recycler_view);

recyclerView.setAdapter(new RiivolutionAdapter(this, patches));
recyclerView.setLayoutManager(new LinearLayoutManager(this));
mBinding.recyclerView.setAdapter(new RiivolutionAdapter(this, patches));
mBinding.recyclerView.setLayoutManager(new LinearLayoutManager(this));
}
}
Expand Up @@ -6,60 +6,53 @@
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.TextView;

import androidx.annotation.NonNull;
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.databinding.ListItemRiivolutionBinding;
import org.dolphinemu.dolphinemu.features.riivolution.model.RiivolutionPatches;

public class RiivolutionViewHolder extends RecyclerView.ViewHolder
implements AdapterView.OnItemClickListener
{
private final TextView mTextView;
private final TextInputLayout mChoiceLayout;
private final MaterialAutoCompleteTextView mChoiceDropdown;
private final ListItemRiivolutionBinding mBinding;

private RiivolutionPatches mPatches;
private RiivolutionItem mItem;

public RiivolutionViewHolder(@NonNull View itemView)
public RiivolutionViewHolder(@NonNull View itemView, ListItemRiivolutionBinding binding)
{
super(itemView);

mTextView = itemView.findViewById(R.id.text_name);
mChoiceLayout = itemView.findViewById(R.id.layout_choice);
mChoiceDropdown = itemView.findViewById(R.id.dropdown_choice);
mBinding = binding;
}

public void bind(Context context, RiivolutionPatches patches, RiivolutionItem item)
{
// TODO: Remove workaround for text filtering issue in material components when fixed
// https://github.com/material-components/material-components-android/issues/1464
mChoiceDropdown.setSaveEnabled(false);
mBinding.dropdownChoice.setSaveEnabled(false);

String text;
if (item.mOptionIndex != -1)
{
mTextView.setVisibility(View.GONE);
mBinding.textName.setVisibility(View.GONE);
text = patches.getOptionName(item.mDiscIndex, item.mSectionIndex, item.mOptionIndex);
mChoiceLayout.setHint(text);
mBinding.layoutChoice.setHint(text);
}
else if (item.mSectionIndex != -1)
{
mTextView.setTextAppearance(context, R.style.TextAppearance_AppCompat_Medium);
mChoiceLayout.setVisibility(View.GONE);
mBinding.textName.setTextAppearance(context, R.style.TextAppearance_AppCompat_Medium);
mBinding.layoutChoice.setVisibility(View.GONE);
text = patches.getSectionName(item.mDiscIndex, item.mSectionIndex);
}
else
{
mChoiceLayout.setVisibility(View.GONE);
mBinding.layoutChoice.setVisibility(View.GONE);
text = patches.getDiscName(item.mDiscIndex);
}
mTextView.setText(text);
mBinding.textName.setText(text);

if (item.mOptionIndex != -1)
{
Expand All @@ -78,11 +71,11 @@ else if (item.mSectionIndex != -1)
i));
}

mChoiceDropdown.setAdapter(adapter);
mChoiceDropdown.setText(adapter.getItem(
mBinding.dropdownChoice.setAdapter(adapter);
mBinding.dropdownChoice.setText(adapter.getItem(
patches.getSelectedChoice(mItem.mDiscIndex, mItem.mSectionIndex, mItem.mOptionIndex)),
false);
mChoiceDropdown.setOnItemClickListener(this);
mBinding.dropdownChoice.setOnItemClickListener(this);
}
}

Expand Down
Expand Up @@ -28,6 +28,7 @@

import org.dolphinemu.dolphinemu.NativeLibrary;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.databinding.ActivitySettingsBinding;
import org.dolphinemu.dolphinemu.ui.main.MainPresenter;
import org.dolphinemu.dolphinemu.utils.FileBrowserHelper;
import org.dolphinemu.dolphinemu.utils.InsetsHelper;
Expand Down Expand Up @@ -81,7 +82,8 @@ protected void onCreate(Bundle savedInstanceState)
MainPresenter.skipRescanningLibrary();
}

setContentView(R.layout.activity_settings);
ActivitySettingsBinding binding = ActivitySettingsBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());

WindowCompat.setDecorFitsSystemWindows(getWindow(), false);

Expand All @@ -96,21 +98,17 @@ protected void onCreate(Bundle savedInstanceState)
mPresenter = new SettingsActivityPresenter(this, getSettings());
mPresenter.onCreate(savedInstanceState, menuTag, gameID, revision, isWii, this);

MaterialToolbar tb = findViewById(R.id.toolbar_settings);
mToolbarLayout = findViewById(R.id.toolbar_settings_layout);
setSupportActionBar(tb);
mToolbarLayout = binding.toolbarSettingsLayout;
setSupportActionBar(binding.toolbarSettings);
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
// https://github.com/material-components/material-components-android/issues/1310
ViewCompat.setOnApplyWindowInsetsListener(mToolbarLayout, null);

View workaroundView = findViewById(R.id.workaround_view);
InsetsHelper.setUpSettingsLayout(this, appBarLayout, frameLayout, workaroundView);
ThemeHelper.enableScrollTint(this, tb, appBarLayout);
InsetsHelper.setUpSettingsLayout(this, binding.appbarSettings, binding.frameContentSettings,
binding.workaroundView);
ThemeHelper.enableScrollTint(this, binding.toolbarSettings, binding.appbarSettings);
}

@Override
Expand Down
Expand Up @@ -8,7 +8,6 @@
import android.os.Build;
import android.provider.DocumentsContract;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

Expand All @@ -21,6 +20,12 @@
import com.google.android.material.textfield.TextInputEditText;

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.features.settings.model.Settings;
import org.dolphinemu.dolphinemu.features.settings.model.view.CheckBoxSetting;
Expand Down Expand Up @@ -79,67 +84,58 @@ public SettingsAdapter(SettingsFragmentView view, Context context)
mClickedPosition = -1;
}

@NonNull
@Override
public SettingViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
public SettingViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType)
{
View view;
LayoutInflater inflater = LayoutInflater.from(parent.getContext());

switch (viewType)
{
case SettingsItem.TYPE_HEADER:
view = inflater.inflate(R.layout.list_item_header, parent, false);
return new HeaderViewHolder(view, this);
return new HeaderViewHolder(ListItemHeaderBinding.inflate(inflater), this);

case SettingsItem.TYPE_CHECKBOX:
view = inflater.inflate(R.layout.list_item_setting_checkbox, parent, false);
return new CheckBoxSettingViewHolder(view, this);
return new CheckBoxSettingViewHolder(ListItemSettingCheckboxBinding.inflate(inflater),
this);

case SettingsItem.TYPE_STRING_SINGLE_CHOICE:
case SettingsItem.TYPE_SINGLE_CHOICE_DYNAMIC_DESCRIPTIONS:
case SettingsItem.TYPE_SINGLE_CHOICE:
view = inflater.inflate(R.layout.list_item_setting, parent, false);
return new SingleChoiceViewHolder(view, this);
return new SingleChoiceViewHolder(ListItemSettingBinding.inflate(inflater), this);

case SettingsItem.TYPE_SLIDER:
view = inflater.inflate(R.layout.list_item_setting, parent, false);
return new SliderViewHolder(view, this, mContext);
return new SliderViewHolder(ListItemSettingBinding.inflate(inflater), this, mContext);

case SettingsItem.TYPE_SUBMENU:
view = inflater.inflate(R.layout.list_item_submenu, parent, false);
return new SubmenuViewHolder(view, this);
return new SubmenuViewHolder(ListItemSubmenuBinding.inflate(inflater), this);

case SettingsItem.TYPE_INPUT_BINDING:
view = inflater.inflate(R.layout.list_item_setting, parent, false);
return new InputBindingSettingViewHolder(view, this, mContext);
return new InputBindingSettingViewHolder(ListItemSettingBinding.inflate(inflater), this,
mContext);

case SettingsItem.TYPE_RUMBLE_BINDING:
view = inflater.inflate(R.layout.list_item_setting, parent, false);
return new RumbleBindingViewHolder(view, this, mContext);
return new RumbleBindingViewHolder(ListItemSettingBinding.inflate(inflater), this,
mContext);

case SettingsItem.TYPE_FILE_PICKER:
view = inflater.inflate(R.layout.list_item_setting, parent, false);
return new FilePickerViewHolder(view, this);
return new FilePickerViewHolder(ListItemSettingBinding.inflate(inflater), this);

case SettingsItem.TYPE_RUN_RUNNABLE:
view = inflater.inflate(R.layout.list_item_setting, parent, false);
return new RunRunnableViewHolder(view, this, mContext);
return new RunRunnableViewHolder(ListItemSettingBinding.inflate(inflater), this, mContext);

case SettingsItem.TYPE_STRING:
view = inflater.inflate(R.layout.list_item_setting, parent, false);
return new InputStringSettingViewHolder(view, this);
return new InputStringSettingViewHolder(ListItemSettingBinding.inflate(inflater), this);

case SettingsItem.TYPE_HYPERLINK_HEADER:
view = inflater.inflate(R.layout.list_item_header, parent, false);
return new HeaderHyperLinkViewHolder(view, this, mContext);
return new HeaderHyperLinkViewHolder(ListItemHeaderBinding.inflate(inflater), this);

default:
throw new IllegalArgumentException("Invalid view type: " + viewType);
}
}

@Override
public void onBindViewHolder(SettingViewHolder holder, int position)
public void onBindViewHolder(@NonNull SettingViewHolder holder, int position)
{
holder.bind(getItem(position));
}
Expand Down Expand Up @@ -206,12 +202,12 @@ public void onInputStringClick(InputStringSetting item, int position)
{
LayoutInflater inflater = LayoutInflater.from(mContext);

View dialogView = inflater.inflate(R.layout.dialog_input_string, null);
TextInputEditText input = dialogView.findViewById(R.id.input);
DialogInputStringBinding binding = DialogInputStringBinding.inflate(inflater);
TextInputEditText input = binding.input;
input.setText(item.getSelectedValue(getSettings()));

mDialog = new MaterialAlertDialogBuilder(mView.getActivity())
.setView(dialogView)
.setView(binding.getRoot())
.setMessage(item.getDescription())
.setPositiveButton(R.string.ok, (dialogInterface, i) ->
{
Expand Down Expand Up @@ -275,26 +271,25 @@ public void onSliderClick(SliderSetting item, int position)
mSeekbarProgress = item.getSelectedValue(getSettings());

LayoutInflater inflater = LayoutInflater.from(mView.getActivity());
View view = inflater.inflate(R.layout.dialog_slider, null);

mDialog = new MaterialAlertDialogBuilder(mView.getActivity())
.setTitle(item.getName())
.setView(view)
.setPositiveButton(R.string.ok, this)
.show();
DialogSliderBinding binding = DialogSliderBinding.inflate(inflater);

mTextSliderValue = view.findViewById(R.id.text_value);
mTextSliderValue = binding.textValue;
mTextSliderValue.setText(String.valueOf(mSeekbarProgress));

TextView units = view.findViewById(R.id.text_units);
units.setText(item.getUnits());
binding.textUnits.setText(item.getUnits());

Slider slider = view.findViewById(R.id.slider);
Slider slider = binding.slider;
slider.setValueFrom(item.getMin());
slider.setValueTo(item.getMax());
slider.setValue(mSeekbarProgress);
slider.setStepSize(1);
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)
Expand Down
Expand Up @@ -17,6 +17,7 @@
import com.google.android.material.divider.MaterialDividerItemDecoration;

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.view.SettingsItem;
import org.dolphinemu.dolphinemu.utils.InsetsHelper;
Expand Down Expand Up @@ -74,6 +75,8 @@ public final class SettingsFragment extends Fragment implements SettingsFragment
titles.put(MenuTag.WIIMOTE_EXTENSION_4, R.string.wiimote_extension_7);
}

private FragmentSettingsBinding mBinding;

public static Fragment newInstance(MenuTag menuTag, String gameId, Bundle extras)
{
SettingsFragment fragment = new SettingsFragment();
Expand Down Expand Up @@ -114,12 +117,13 @@ public void onCreate(Bundle savedInstanceState)
mPresenter.onCreate(menuTag, gameId, args);
}

@Nullable
@NonNull
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState)
{
return inflater.inflate(R.layout.fragment_settings, container, false);
mBinding = FragmentSettingsBinding.inflate(inflater, container, false);
return mBinding.getRoot();
}

@Override
Expand All @@ -135,7 +139,7 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat

LinearLayoutManager manager = new LinearLayoutManager(getActivity());

RecyclerView recyclerView = view.findViewById(R.id.list_settings);
RecyclerView recyclerView = mBinding.listSettings;

recyclerView.setAdapter(mAdapter);
recyclerView.setLayoutManager(manager);
Expand All @@ -151,6 +155,13 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat
mPresenter.onViewCreated(menuTag, activity.getSettings());
}

@Override
public void onDestroyView()
{
super.onDestroyView();
mBinding = null;
}

@Override
public void onDetach()
{
Expand Down
Expand Up @@ -3,12 +3,10 @@
package org.dolphinemu.dolphinemu.features.settings.ui.viewholder;

import android.view.View;
import android.widget.CheckBox;
import android.widget.TextView;

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.SettingsItem;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
Expand All @@ -17,35 +15,25 @@ public final class CheckBoxSettingViewHolder extends SettingViewHolder
{
private CheckBoxSetting mItem;

private TextView mTextSettingName;
private TextView mTextSettingDescription;
private final ListItemSettingCheckboxBinding mBinding;

private CheckBox mCheckbox;

public CheckBoxSettingViewHolder(View itemView, SettingsAdapter adapter)
{
super(itemView, adapter);
}

@Override
protected void findViews(View root)
public CheckBoxSettingViewHolder(ListItemSettingCheckboxBinding binding, SettingsAdapter adapter)
{
mTextSettingName = root.findViewById(R.id.text_setting_name);
mTextSettingDescription = root.findViewById(R.id.text_setting_description);
mCheckbox = root.findViewById(R.id.checkbox);
super(binding.getRoot(), adapter);
mBinding = binding;
}

@Override
public void bind(SettingsItem item)
{
mItem = (CheckBoxSetting) item;

mTextSettingName.setText(item.getName());
mTextSettingDescription.setText(item.getDescription());
mBinding.textSettingName.setText(item.getName());
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
Expand All @@ -57,11 +45,11 @@ public void onClick(View clicked)
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
Expand Down
Expand Up @@ -2,14 +2,13 @@

package org.dolphinemu.dolphinemu.features.settings.ui.viewholder;

import android.graphics.drawable.Drawable;
import android.text.TextUtils;
import android.view.View;
import android.widget.TextView;

import androidx.annotation.Nullable;

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.SettingsItem;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
Expand All @@ -22,23 +21,12 @@ public final class FilePickerViewHolder extends SettingViewHolder
private FilePicker mFilePicker;
private SettingsItem mItem;

private TextView mTextSettingName;
private TextView mTextSettingDescription;
private final ListItemSettingBinding mBinding;

private Drawable mDefaultBackground;

public FilePickerViewHolder(View itemView, SettingsAdapter adapter)
{
super(itemView, adapter);
}

@Override
protected void findViews(View root)
public FilePickerViewHolder(ListItemSettingBinding binding, SettingsAdapter adapter)
{
mTextSettingName = root.findViewById(R.id.text_setting_name);
mTextSettingDescription = root.findViewById(R.id.text_setting_description);

mDefaultBackground = root.getBackground();
super(binding.getRoot(), adapter);
mBinding = binding;
}

@Override
Expand All @@ -51,18 +39,18 @@ public void bind(SettingsItem item)

if (FileBrowserHelper.isPathEmptyOrValid(path))
{
itemView.setBackground(mDefaultBackground);
itemView.setBackground(mBinding.getRoot().getBackground());
}
else
{
itemView.setBackgroundResource(R.drawable.invalid_setting_background);
}

mTextSettingName.setText(item.getName());
mBinding.textSettingName.setText(item.getName());

if (!TextUtils.isEmpty(item.getDescription()))
{
mTextSettingDescription.setText(item.getDescription());
mBinding.textSettingDescription.setText(item.getDescription());
}
else
{
Expand All @@ -75,10 +63,10 @@ public void bind(SettingsItem item)
}
}

mTextSettingDescription.setText(path);
mBinding.textSettingDescription.setText(path);
}

setStyle(mTextSettingName, mItem);
setStyle(mBinding.textSettingName, mItem);
}

@Override
Expand All @@ -100,7 +88,7 @@ public void onClick(View clicked)
getAdapter().onFilePickerFileClick(mItem, position);
}

setStyle(mTextSettingName, mItem);
setStyle(mBinding.textSettingName, mItem);
}

@Nullable @Override
Expand Down
Expand Up @@ -2,33 +2,35 @@

package org.dolphinemu.dolphinemu.features.settings.ui.viewholder;

import android.content.Context;
import android.text.method.LinkMovementMethod;
import android.view.View;

import androidx.annotation.NonNull;

import com.google.android.material.color.MaterialColors;

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.ui.SettingsAdapter;

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);
mContext = context;
super(binding, adapter);
mBinding = binding;
itemView.setOnClickListener(null);
}

@Override
public void bind(SettingsItem item)
public void bind(@NonNull SettingsItem item)
{
super.bind(item);

mHeaderName.setMovementMethod(LinkMovementMethod.getInstance());
mHeaderName.setLinkTextColor(MaterialColors.getColor(itemView, R.attr.colorTertiary));
mBinding.textHeaderName.setMovementMethod(LinkMovementMethod.getInstance());
mBinding.textHeaderName.setLinkTextColor(
MaterialColors.getColor(itemView, R.attr.colorTertiary));
}
}
Expand Up @@ -3,34 +3,29 @@
package org.dolphinemu.dolphinemu.features.settings.ui.viewholder;

import android.view.View;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
import org.dolphinemu.dolphinemu.databinding.ListItemHeaderBinding;

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);
mBinding = binding;
}

@Override
protected void findViews(View root)
public void bind(@NonNull SettingsItem item)
{
mHeaderName = root.findViewById(R.id.text_header_name);
}

@Override
public void bind(SettingsItem item)
{
mHeaderName.setText(item.getName());
mBinding.textHeaderName.setText(item.getName());
}

@Override
Expand Down
Expand Up @@ -5,12 +5,12 @@
import android.content.Context;
import android.content.SharedPreferences;
import android.view.View;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.preference.PreferenceManager;

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.SettingsItem;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
Expand All @@ -19,37 +19,30 @@ public final class InputBindingSettingViewHolder extends SettingViewHolder
{
private InputBindingSetting mItem;

private TextView mTextSettingName;
private TextView mTextSettingDescription;
private final Context mContext;

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;
}

@Override
protected void findViews(View root)
{
mTextSettingName = root.findViewById(R.id.text_setting_name);
mTextSettingDescription = root.findViewById(R.id.text_setting_description);
}

@Override
public void bind(SettingsItem item)
{
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(mContext);

mItem = (InputBindingSetting) item;

mTextSettingName.setText(mItem.getName());
mTextSettingDescription
mBinding.textSettingName.setText(mItem.getName());
mBinding.textSettingDescription
.setText(sharedPreferences.getString(mItem.getKey() + mItem.getGameId(), ""));

setStyle(mTextSettingName, mItem);
setStyle(mBinding.textSettingName, mItem);
}

@Override
Expand All @@ -63,7 +56,7 @@ public void onClick(View clicked)

getAdapter().onInputBindingClick(mItem, getBindingAdapterPosition());

setStyle(mTextSettingName, mItem);
setStyle(mBinding.textSettingName, mItem);
}

@Nullable @Override
Expand Down
Expand Up @@ -4,11 +4,11 @@

import android.text.TextUtils;
import android.view.View;
import android.widget.TextView;

import androidx.annotation.NonNull;
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.SettingsItem;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
Expand All @@ -17,19 +17,13 @@ public final class InputStringSettingViewHolder extends SettingViewHolder
{
private InputStringSetting mInputString;

private TextView mTextSettingName;
private TextView mTextSettingDescription;
private final ListItemSettingBinding mBinding;

public InputStringSettingViewHolder(View itemView, SettingsAdapter adapter)
public InputStringSettingViewHolder(@NonNull ListItemSettingBinding binding,
SettingsAdapter adapter)
{
super(itemView, adapter);
}

@Override
protected void findViews(View root)
{
mTextSettingName = root.findViewById(R.id.text_setting_name);
mTextSettingDescription = root.findViewById(R.id.text_setting_description);
super(binding.getRoot(), adapter);
mBinding = binding;
}

@Override
Expand All @@ -39,18 +33,18 @@ public void bind(SettingsItem item)

String inputString = mInputString.getSelectedValue(getAdapter().getSettings());

mTextSettingName.setText(item.getName());
mBinding.textSettingName.setText(item.getName());

if (!TextUtils.isEmpty(inputString))
{
mTextSettingDescription.setText(inputString);
mBinding.textSettingDescription.setText(inputString);
}
else
{
mTextSettingDescription.setText(item.getDescription());
mBinding.textSettingDescription.setText(item.getDescription());
}

setStyle(mTextSettingName, mInputString);
setStyle(mBinding.textSettingName, mInputString);
}

@Override
Expand All @@ -62,11 +56,11 @@ public void onClick(View clicked)
return;
}

int position = getAdapterPosition();
int position = getBindingAdapterPosition();

getAdapter().onInputStringClick(mInputString, position);

setStyle(mTextSettingName, mInputString);
setStyle(mBinding.textSettingName, mInputString);
}

@Nullable @Override
Expand Down
Expand Up @@ -5,12 +5,12 @@
import android.content.Context;
import android.content.SharedPreferences;
import android.view.View;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.preference.PreferenceManager;

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.SettingsItem;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
Expand All @@ -19,37 +19,30 @@ public class RumbleBindingViewHolder extends SettingViewHolder
{
private RumbleBindingSetting mItem;

private TextView mTextSettingName;
private TextView mTextSettingDescription;
private final Context mContext;

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;
}

@Override
protected void findViews(View root)
{
mTextSettingName = root.findViewById(R.id.text_setting_name);
mTextSettingDescription = root.findViewById(R.id.text_setting_description);
}

@Override
public void bind(SettingsItem item)
{
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(mContext);

mItem = (RumbleBindingSetting) item;

mTextSettingName.setText(item.getName());
mTextSettingDescription
mBinding.textSettingName.setText(item.getName());
mBinding.textSettingDescription
.setText(sharedPreferences.getString(mItem.getKey() + mItem.getGameId(), ""));

setStyle(mTextSettingName, mItem);
setStyle(mBinding.textSettingName, mItem);
}

@Override
Expand All @@ -63,7 +56,7 @@ public void onClick(View clicked)

getAdapter().onInputBindingClick(mItem, getBindingAdapterPosition());

setStyle(mTextSettingName, mItem);
setStyle(mBinding.textSettingName, mItem);
}

@Nullable @Override
Expand Down
Expand Up @@ -4,14 +4,15 @@

import android.content.Context;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.google.android.material.dialog.MaterialAlertDialogBuilder;

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.SettingsItem;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
Expand All @@ -22,30 +23,23 @@ public final class RunRunnableViewHolder extends SettingViewHolder

private final Context mContext;

private TextView mTextSettingName;
private TextView mTextSettingDescription;
private final ListItemSettingBinding mBinding;

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;
}

@Override
protected void findViews(View root)
{
mTextSettingName = root.findViewById(R.id.text_setting_name);
mTextSettingDescription = root.findViewById(R.id.text_setting_description);
}

@Override
public void bind(SettingsItem item)
{
mItem = (RunRunnable) item;

mTextSettingName.setText(item.getName());
mTextSettingDescription.setText(item.getDescription());
mBinding.textSettingName.setText(item.getName());
mBinding.textSettingDescription.setText(item.getDescription());
}

@Override
Expand Down
Expand Up @@ -32,8 +32,6 @@ public SettingViewHolder(View itemView, SettingsAdapter adapter)

itemView.setOnClickListener(this);
itemView.setOnLongClickListener(this);

findViews(itemView);
}

protected SettingsAdapter getAdapter()
Expand All @@ -56,13 +54,6 @@ protected static void showNotRuntimeEditableError()
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
* it must now represent.
Expand Down
Expand Up @@ -5,11 +5,11 @@
import android.content.res.Resources;
import android.text.TextUtils;
import android.view.View;
import android.widget.TextView;

import androidx.annotation.NonNull;
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.SingleChoiceSetting;
import org.dolphinemu.dolphinemu.features.settings.model.view.SingleChoiceSettingDynamicDescriptions;
Expand All @@ -20,44 +20,37 @@ public final class SingleChoiceViewHolder extends SettingViewHolder
{
private SettingsItem mItem;

private TextView mTextSettingName;
private TextView mTextSettingDescription;
private final ListItemSettingBinding mBinding;

public SingleChoiceViewHolder(View itemView, SettingsAdapter adapter)
public SingleChoiceViewHolder(@NonNull ListItemSettingBinding binding, SettingsAdapter adapter)
{
super(itemView, adapter);
}

@Override
protected void findViews(View root)
{
mTextSettingName = root.findViewById(R.id.text_setting_name);
mTextSettingDescription = root.findViewById(R.id.text_setting_description);
super(binding.getRoot(), adapter);
mBinding = binding;
}

@Override
public void bind(SettingsItem item)
{
mItem = item;

mTextSettingName.setText(item.getName());
mBinding.textSettingName.setText(item.getName());

if (!TextUtils.isEmpty(item.getDescription()))
{
mTextSettingDescription.setText(item.getDescription());
mBinding.textSettingDescription.setText(item.getDescription());
}
else if (item instanceof SingleChoiceSetting)
{
SingleChoiceSetting setting = (SingleChoiceSetting) item;
int selected = setting.getSelectedValue(getAdapter().getSettings());
Resources resMgr = mTextSettingDescription.getContext().getResources();
Resources resMgr = mBinding.textSettingDescription.getContext().getResources();
String[] choices = resMgr.getStringArray(setting.getChoicesId());
int[] values = resMgr.getIntArray(setting.getValuesId());
for (int i = 0; i < values.length; ++i)
{
if (values[i] == selected)
{
mTextSettingDescription.setText(choices[i]);
mBinding.textSettingDescription.setText(choices[i]);
}
}
}
Expand All @@ -67,26 +60,26 @@ else if (item instanceof StringSingleChoiceSetting)
String[] choices = setting.getChoices();
int valueIndex = setting.getSelectedValueIndex(getAdapter().getSettings());
if (valueIndex != -1)
mTextSettingDescription.setText(choices[valueIndex]);
mBinding.textSettingDescription.setText(choices[valueIndex]);
}
else if (item instanceof SingleChoiceSettingDynamicDescriptions)
{
SingleChoiceSettingDynamicDescriptions setting =
(SingleChoiceSettingDynamicDescriptions) item;
int selected = setting.getSelectedValue(getAdapter().getSettings());
Resources resMgr = mTextSettingDescription.getContext().getResources();
Resources resMgr = mBinding.textSettingDescription.getContext().getResources();
String[] choices = resMgr.getStringArray(setting.getDescriptionChoicesId());
int[] values = resMgr.getIntArray(setting.getDescriptionValuesId());
for (int i = 0; i < values.length; ++i)
{
if (values[i] == selected)
{
mTextSettingDescription.setText(choices[i]);
mBinding.textSettingDescription.setText(choices[i]);
}
}
}

setStyle(mTextSettingName, mItem);
setStyle(mBinding.textSettingName, mItem);
}

@Override
Expand All @@ -113,7 +106,7 @@ else if (mItem instanceof SingleChoiceSettingDynamicDescriptions)
(SingleChoiceSettingDynamicDescriptions) mItem, position);
}

setStyle(mTextSettingName, mItem);
setStyle(mBinding.textSettingName, mItem);
}

@Nullable @Override
Expand Down
Expand Up @@ -5,57 +5,51 @@
import android.content.Context;
import android.text.TextUtils;
import android.view.View;
import android.widget.TextView;

import androidx.annotation.NonNull;
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.SliderSetting;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;

public final class SliderViewHolder extends SettingViewHolder
{
private Context mContext;
private final Context mContext;

private SliderSetting mItem;

private TextView mTextSettingName;
private TextView mTextSettingDescription;
private final ListItemSettingBinding mBinding;

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;
}

@Override
protected void findViews(View root)
{
mTextSettingName = root.findViewById(R.id.text_setting_name);
mTextSettingDescription = root.findViewById(R.id.text_setting_description);
}

@Override
public void bind(SettingsItem item)
{
mItem = (SliderSetting) item;

mTextSettingName.setText(item.getName());
mBinding.textSettingName.setText(item.getName());

if (!TextUtils.isEmpty(item.getDescription()))
{
mTextSettingDescription.setText(item.getDescription());
mBinding.textSettingDescription.setText(item.getDescription());
}
else
{
mTextSettingDescription.setText(mContext
mBinding.textSettingDescription.setText(mContext
.getString(R.string.slider_setting_value,
mItem.getSelectedValue(getAdapter().getSettings()), mItem.getUnits()));
}

setStyle(mTextSettingName, mItem);
setStyle(mBinding.textSettingName, mItem);
}

@Override
Expand All @@ -69,7 +63,7 @@ public void onClick(View clicked)

getAdapter().onSliderClick(mItem, getBindingAdapterPosition());

setStyle(mTextSettingName, mItem);
setStyle(mBinding.textSettingName, mItem);
}

@Nullable @Override
Expand Down
Expand Up @@ -3,11 +3,11 @@
package org.dolphinemu.dolphinemu.features.settings.ui.viewholder;

import android.view.View;
import android.widget.TextView;

import androidx.annotation.NonNull;
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.SubmenuSetting;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
Expand All @@ -16,25 +16,20 @@ public final class SubmenuViewHolder extends SettingViewHolder
{
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);
}

@Override
protected void findViews(View root)
{
mTextSettingName = root.findViewById(R.id.text_setting_name);
super(binding.getRoot(), adapter);
mBinding = binding;
}

@Override
public void bind(SettingsItem item)
{
mItem = (SubmenuSetting) item;

mTextSettingName.setText(item.getName());
mBinding.textSettingName.setText(item.getName());
}

@Override
Expand Down
Expand Up @@ -5,7 +5,6 @@
import android.app.Dialog;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

import androidx.annotation.NonNull;
Expand All @@ -15,9 +14,9 @@
import androidx.lifecycle.ViewModelProvider;

import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.progressindicator.LinearProgressIndicator;

import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.databinding.DialogProgressBinding;

public class SystemUpdateProgressBarDialogFragment extends DialogFragment
{
Expand All @@ -33,20 +32,22 @@ public Dialog onCreateDialog(@Nullable Bundle savedInstanceState)
SystemUpdateViewModel viewModel =
new ViewModelProvider(requireActivity()).get(SystemUpdateViewModel.class);

View dialogView = getLayoutInflater().inflate(R.layout.dialog_progress, null, false);
LinearProgressIndicator progressBar = dialogView.findViewById(R.id.update_progress);
DialogProgressBinding dialogProgressBinding =
DialogProgressBinding.inflate(getLayoutInflater());

// 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())
.setTitle(getString(R.string.updating))
.setMessage("")
.setNegativeButton(getString(R.string.cancel), null)
.setView(dialogView)
.setView(dialogProgressBinding.getRoot())
.setCancelable(false)
.create();

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) ->
{
Expand All @@ -55,7 +56,7 @@ public Dialog onCreateDialog(@Nullable Bundle savedInstanceState)
return;
}

progressBar.setMax(total);
dialogProgressBinding.updateProgress.setMax(total);
});

viewModel.getTitleIdData().observe(this, (@Nullable Long titleId) -> progressDialog.setMessage(
Expand Down
Expand Up @@ -13,7 +13,6 @@
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;

import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
Expand All @@ -27,6 +26,8 @@

import org.dolphinemu.dolphinemu.NativeLibrary;
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.services.GameFileCacheManager;
import org.dolphinemu.dolphinemu.ui.platform.Platform;
Expand Down Expand Up @@ -114,21 +115,13 @@ void addCallback(Runnable callback)
private DropdownValue mCompression = 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 volatile boolean mCanceled;
private volatile Thread mThread = null;

private FragmentConvertBinding mBinding;

public static ConvertFragment newInstance(String gamePath)
{
Bundle args = new Bundle();
Expand All @@ -150,20 +143,19 @@ public void onCreate(Bundle savedInstanceState)
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
return inflater.inflate(R.layout.fragment_convert, container, false);
mBinding = FragmentConvertBinding.inflate(inflater, container, false);
return mBinding.getRoot();
}

@Override
public void onViewCreated(@NonNull View view, Bundle savedInstanceState)
{
findViews();

// TODO: Remove workaround for text filtering issue in material components when fixed
// https://github.com/material-components/material-components-android/issues/1464
mFormatDropdown.setSaveEnabled(false);
mBlockSizeDropdown.setSaveEnabled(false);
mCompressionDropdown.setSaveEnabled(false);
mCompressionLevelDropdown.setSaveEnabled(false);
mBinding.dropdownFormat.setSaveEnabled(false);
mBinding.dropdownBlockSize.setSaveEnabled(false);
mBinding.dropdownCompression.setSaveEnabled(false);
mBinding.dropdownCompressionLevel.setSaveEnabled(false);

populateFormats();
populateBlockSize();
Expand All @@ -177,35 +169,23 @@ public void onViewCreated(@NonNull View view, Bundle savedInstanceState)
mCompression.addCallback(this::populateCompressionLevel);
mFormat.addCallback(this::populateRemoveJunkData);

view.findViewById(R.id.button_convert).setOnClickListener(this);
mBinding.buttonConvert.setOnClickListener(this);

if (savedInstanceState != null)
{
setDropdownSelection(mFormatDropdown, mFormat, savedInstanceState.getInt(KEY_FORMAT));
setDropdownSelection(mBlockSizeDropdown, mBlockSize,
setDropdownSelection(mBinding.dropdownFormat, mFormat, savedInstanceState.getInt(KEY_FORMAT));
setDropdownSelection(mBinding.dropdownBlockSize, mBlockSize,
savedInstanceState.getInt(KEY_BLOCK_SIZE));
setDropdownSelection(mCompressionDropdown, mCompression,
setDropdownSelection(mBinding.dropdownCompression, mCompression,
savedInstanceState.getInt(KEY_COMPRESSION));
setDropdownSelection(mCompressionLevelDropdown, mCompressionLevel,
setDropdownSelection(mBinding.dropdownCompressionLevel, mCompressionLevel,
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
public void onSaveInstanceState(@NonNull Bundle outState)
{
Expand All @@ -214,7 +194,7 @@ public void onSaveInstanceState(@NonNull Bundle outState)
outState.putInt(KEY_COMPRESSION, mCompression.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,
Expand All @@ -236,6 +216,13 @@ public void onStop()
joinThread();
}

@Override
public void onDestroyView()
{
super.onDestroyView();
mBinding = null;
}

private void populateDropdown(TextInputLayout layout, MaterialAutoCompleteTextView dropdown,
int entriesId, int valuesId, DropdownValue valueWrapper)
{
Expand Down Expand Up @@ -263,13 +250,15 @@ private void clearDropdown(TextInputLayout layout, MaterialAutoCompleteTextView

private void populateFormats()
{
populateDropdown(mFormatLayout, mFormatDropdown, R.array.convertFormatEntries,
populateDropdown(mBinding.format, mBinding.dropdownFormat, R.array.convertFormatEntries,
R.array.convertFormatValues, mFormat);
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);
}

Expand All @@ -281,25 +270,31 @@ private void populateBlockSize()
// 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.
// TODO: Port it?
populateDropdown(mBlockSizeLayout, mBlockSizeDropdown, R.array.convertBlockSizeGczEntries,
populateDropdown(mBinding.blockSize, mBinding.dropdownBlockSize,
R.array.convertBlockSizeGczEntries,
R.array.convertBlockSizeGczValues, mBlockSize);
mBlockSize.setPosition(0);
mBlockSizeDropdown.setText(mBlockSizeDropdown.getAdapter().getItem(0).toString(), false);
mBinding.dropdownBlockSize.setText(
mBinding.dropdownBlockSize.getAdapter().getItem(0).toString(), false);
break;
case BLOB_TYPE_WIA:
populateDropdown(mBlockSizeLayout, mBlockSizeDropdown, R.array.convertBlockSizeWiaEntries,
populateDropdown(mBinding.blockSize, mBinding.dropdownBlockSize,
R.array.convertBlockSizeWiaEntries,
R.array.convertBlockSizeWiaValues, mBlockSize);
mBlockSize.setPosition(0);
mBlockSizeDropdown.setText(mBlockSizeDropdown.getAdapter().getItem(0).toString(), false);
mBinding.dropdownBlockSize.setText(
mBinding.dropdownBlockSize.getAdapter().getItem(0).toString(), false);
break;
case BLOB_TYPE_RVZ:
populateDropdown(mBlockSizeLayout, mBlockSizeDropdown, R.array.convertBlockSizeRvzEntries,
populateDropdown(mBinding.blockSize, mBinding.dropdownBlockSize,
R.array.convertBlockSizeRvzEntries,
R.array.convertBlockSizeRvzValues, mBlockSize);
mBlockSize.setPosition(2);
mBlockSizeDropdown.setText(mBlockSizeDropdown.getAdapter().getItem(2).toString(), false);
mBinding.dropdownBlockSize.setText(
mBinding.dropdownBlockSize.getAdapter().getItem(2).toString(), false);
break;
default:
clearDropdown(mBlockSizeLayout, mBlockSizeDropdown, mBlockSize);
clearDropdown(mBinding.blockSize, mBinding.dropdownBlockSize, mBlockSize);
}
}

Expand All @@ -308,31 +303,31 @@ private void populateCompression()
switch (mFormat.getValue(requireContext()))
{
case BLOB_TYPE_GCZ:
populateDropdown(mCompressionLayout, mCompressionDropdown,
populateDropdown(mBinding.compression, mBinding.dropdownCompression,
R.array.convertCompressionGczEntries, R.array.convertCompressionGczValues,
mCompression);
mCompression.setPosition(0);
mCompressionDropdown.setText(mCompressionDropdown.getAdapter().getItem(0).toString(),
false);
mBinding.dropdownCompression.setText(
mBinding.dropdownCompression.getAdapter().getItem(0).toString(), false);
break;
case BLOB_TYPE_WIA:
populateDropdown(mCompressionLayout, mCompressionDropdown,
populateDropdown(mBinding.compression, mBinding.dropdownCompression,
R.array.convertCompressionWiaEntries, R.array.convertCompressionWiaValues,
mCompression);
mCompression.setPosition(0);
mCompressionDropdown.setText(mCompressionDropdown.getAdapter().getItem(0).toString(),
false);
mBinding.dropdownCompression.setText(
mBinding.dropdownCompression.getAdapter().getItem(0).toString(), false);
break;
case BLOB_TYPE_RVZ:
populateDropdown(mCompressionLayout, mCompressionDropdown,
populateDropdown(mBinding.compression, mBinding.dropdownCompression,
R.array.convertCompressionRvzEntries, R.array.convertCompressionRvzValues,
mCompression);
mCompression.setPosition(4);
mCompressionDropdown.setText(mCompressionDropdown.getAdapter().getItem(4).toString(),
false);
mBinding.dropdownCompression.setText(
mBinding.dropdownCompression.getAdapter().getItem(4).toString(), false);
break;
default:
clearDropdown(mCompressionLayout, mCompressionDropdown, mCompression);
clearDropdown(mBinding.compression, mBinding.dropdownCompression, mCompression);
}
}

Expand All @@ -343,24 +338,25 @@ private void populateCompressionLevel()
case COMPRESSION_BZIP2:
case COMPRESSION_LZMA:
case COMPRESSION_LZMA2:
populateDropdown(mCompressionLevelLayout, mCompressionLevelDropdown,
populateDropdown(mBinding.compressionLevel, mBinding.dropdownCompressionLevel,
R.array.convertCompressionLevelEntries, R.array.convertCompressionLevelValues,
mCompressionLevel);
mCompressionLevel.setPosition(4);
mCompressionLevelDropdown.setText(
mCompressionLevelDropdown.getAdapter().getItem(4).toString(), false);
mBinding.dropdownCompressionLevel.setText(
mBinding.dropdownCompressionLevel.getAdapter().getItem(4).toString(), false);
break;
case COMPRESSION_ZSTD:
// 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.convertCompressionLevelZstdValues, mCompressionLevel);
mCompressionLevel.setPosition(4);
mCompressionLevelDropdown.setText(
mCompressionLevelDropdown.getAdapter().getItem(4).toString(), false);
mBinding.dropdownCompressionLevel.setText(
mBinding.dropdownCompressionLevel.getAdapter().getItem(4).toString(), false);
break;
default:
clearDropdown(mCompressionLevelLayout, mCompressionLevelDropdown, mCompressionLevel);
clearDropdown(mBinding.compressionLevel, mBinding.dropdownCompressionLevel,
mCompressionLevel);
}
}

Expand All @@ -369,15 +365,15 @@ private void populateRemoveJunkData()
boolean scrubbingAllowed = mFormat.getValue(requireContext()) != BLOB_TYPE_RVZ &&
!gameFile.isDatelDisc();

mRemoveJunkDataCheckbox.setEnabled(scrubbingAllowed);
mBinding.checkboxRemoveJunkData.setEnabled(scrubbingAllowed);
if (!scrubbingAllowed)
mRemoveJunkDataCheckbox.setChecked(false);
mBinding.checkboxRemoveJunkData.setChecked(false);
}

@Override
public void onClick(View view)
{
boolean scrub = mRemoveJunkDataCheckbox.isChecked();
boolean scrub = mBinding.checkboxRemoveJunkData.isChecked();
int format = mFormat.getValue(requireContext());

Runnable action = this::showSavePrompt;
Expand Down Expand Up @@ -466,28 +462,29 @@ private void convert(String outPath)

mCanceled = false;

View dialogView = getLayoutInflater().inflate(R.layout.dialog_progress, null, false);
LinearProgressIndicator progressBar = dialogView.findViewById(R.id.update_progress);
progressBar.setMax(PROGRESS_RESOLUTION);
DialogProgressBinding dialogProgressBinding =
DialogProgressBinding.inflate(getLayoutInflater(), null, false);
dialogProgressBinding.updateProgress.setMax(PROGRESS_RESOLUTION);

AlertDialog progressDialog = new MaterialAlertDialogBuilder(context)
.setTitle(R.string.convert_converting)
.setOnCancelListener((dialog) -> mCanceled = true)
.setNegativeButton(getString(R.string.cancel), (dialog, i) -> dialog.dismiss())
.setView(dialogView)
.setView(dialogProgressBinding.getRoot())
.show();

mThread = new Thread(() ->
{
boolean success = NativeLibrary.ConvertDiscImage(gameFile.getPath(), outPath,
gameFile.getPlatform(), mFormat.getValue(context), mBlockSize.getValueOr(context, 0),
mCompression.getValueOr(context, 0), mCompressionLevel.getValueOr(context, 0),
mRemoveJunkDataCheckbox.isChecked(), (text, completion) ->
mBinding.checkboxRemoveJunkData.isChecked(), (text, completion) ->
{
requireActivity().runOnUiThread(() ->
{
progressDialog.setMessage(text);
progressBar.setProgress((int) (completion * PROGRESS_RESOLUTION));
dialogProgressBinding.updateProgress.setProgress(
(int) (completion * PROGRESS_RESOLUTION));
});
return !mCanceled;
});
Expand Down
Expand Up @@ -13,11 +13,12 @@
import android.widget.Button;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;

import org.dolphinemu.dolphinemu.NativeLibrary;
import org.dolphinemu.dolphinemu.R;
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.Settings;
import org.dolphinemu.dolphinemu.overlay.InputOverlay;
Expand All @@ -41,6 +42,8 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C

private EmulationActivity activity;

private FragmentEmulationBinding mBinding;

public static EmulationFragment newInstance(String[] gamePaths, boolean riivolution,
boolean systemMenu)
{
Expand Down Expand Up @@ -83,28 +86,32 @@ public void onCreate(Bundle savedInstanceState)
mLaunchSystemMenu = getArguments().getBoolean(KEY_SYSTEM_MENU);
}

/**
* Initialize the UI and start emulation in here.
*/
@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);

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)
{
doneButton.setOnClickListener(v -> stopConfiguringControls());
}

if (mInputOverlay != null)
{
contents.post(() ->
view.post(() ->
{
int overlayX = mInputOverlay.getLeft();
int overlayY = mInputOverlay.getTop();
Expand All @@ -113,10 +120,13 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa
surfaceView.getRight() - overlayX, surfaceView.getBottom() - overlayY));
});
}
}

// The new Surface created here will get passed to the native code via onSurfaceChanged.

return contents;
@Override
public void onDestroyView()
{
super.onDestroyView();
mBinding = null;
}

@Override
Expand Down Expand Up @@ -223,7 +233,7 @@ public void startConfiguringControls()
{
if (mInputOverlay != null)
{
requireView().findViewById(R.id.done_control_config).setVisibility(View.VISIBLE);
mBinding.doneControlConfig.setVisibility(View.VISIBLE);
mInputOverlay.setIsInEditMode(true);
}
}
Expand All @@ -232,7 +242,7 @@ public void stopConfiguringControls()
{
if (mInputOverlay != null)
{
requireView().findViewById(R.id.done_control_config).setVisibility(View.GONE);
mBinding.doneControlConfig.setVisibility(View.GONE);
mInputOverlay.setIsInEditMode(false);
}
}
Expand Down