diff --git a/Source/Android/app/build.gradle b/Source/Android/app/build.gradle index db568618a5..6ee7dfa9ab 100644 --- a/Source/Android/app/build.gradle +++ b/Source/Android/app/build.gradle @@ -4,6 +4,8 @@ android { compileSdkVersion 33 ndkVersion "25.0.8775105" + viewBinding.enabled = true + compileOptions { // Flag to enable support for the new language APIs coreLibraryDesugaringEnabled true diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/ConvertActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/ConvertActivity.java index 2ba35c4d26..49e0687c61 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/ConvertActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/ConvertActivity.java @@ -5,17 +5,12 @@ package org.dolphinemu.dolphinemu.activities; import android.content.Context; import android.content.Intent; import android.os.Bundle; -import android.view.View; import androidx.appcompat.app.AppCompatActivity; 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.databinding.ActivityConvertBinding; import org.dolphinemu.dolphinemu.fragments.ConvertFragment; import org.dolphinemu.dolphinemu.utils.InsetsHelper; import org.dolphinemu.dolphinemu.utils.ThemeHelper; @@ -38,7 +33,8 @@ public class ConvertActivity extends AppCompatActivity super.onCreate(savedInstanceState); - setContentView(R.layout.activity_convert); + ActivityConvertBinding binding = ActivityConvertBinding.inflate(getLayoutInflater()); + setContentView(binding.getRoot()); WindowCompat.setDecorFitsSystemWindows(getWindow(), false); @@ -52,17 +48,13 @@ public class ConvertActivity extends AppCompatActivity getSupportFragmentManager().beginTransaction().add(R.id.fragment_convert, fragment).commit(); } - MaterialToolbar tb = findViewById(R.id.toolbar_convert); - CollapsingToolbarLayout ctb = findViewById(R.id.toolbar_convert_layout); - ctb.setTitle(getString(R.string.convert_convert)); - setSupportActionBar(tb); + binding.toolbarConvertLayout.setTitle(getString(R.string.convert_convert)); + setSupportActionBar(binding.toolbarConvert); getSupportActionBar().setDisplayHomeAsUpEnabled(true); - AppBarLayout appBarLayout = findViewById(R.id.appbar_convert); - NestedScrollView scrollView = findViewById(R.id.scroll_view_convert); - View workaroundView = findViewById(R.id.workaround_view); - InsetsHelper.setUpAppBarWithScrollView(this, appBarLayout, scrollView, workaroundView); - ThemeHelper.enableScrollTint(this, tb, appBarLayout); + InsetsHelper.setUpAppBarWithScrollView(this, binding.appbarConvert, binding.scrollViewConvert, + binding.workaroundView); + ThemeHelper.enableScrollTint(this, binding.toolbarConvert, binding.appbarConvert); } @Override diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java index 9106d8d81c..53b72df4b8 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java @@ -13,7 +13,6 @@ import android.preference.PreferenceManager; import android.util.SparseIntArray; import android.view.InputDevice; import android.view.KeyEvent; -import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; @@ -33,6 +32,9 @@ import androidx.fragment.app.FragmentManager; import org.dolphinemu.dolphinemu.NativeLibrary; 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.IntSetting; import org.dolphinemu.dolphinemu.features.settings.model.Settings; @@ -62,7 +64,6 @@ import java.util.List; import static java.lang.annotation.RetentionPolicy.SOURCE; import com.google.android.material.dialog.MaterialAlertDialogBuilder; -import com.google.android.material.slider.LabelFormatter; import com.google.android.material.slider.Slider; public final class EmulationActivity extends AppCompatActivity implements ThemeProvider @@ -338,7 +339,8 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP Rumble.initRumble(this); - setContentView(R.layout.activity_emulation); + ActivityEmulationBinding binding = ActivityEmulationBinding.inflate(getLayoutInflater()); + setContentView(binding.getRoot()); // Find or create the EmulationFragment mEmulationFragment = (EmulationFragment) getSupportFragmentManager() @@ -905,11 +907,10 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP private void adjustScale() { - LayoutInflater inflater = LayoutInflater.from(this); - View view = inflater.inflate(R.layout.dialog_input_adjust, null); + DialogInputAdjustBinding dialogBinding = DialogInputAdjustBinding.inflate(getLayoutInflater()); - final Slider scaleSlider = view.findViewById(R.id.input_scale_slider); - final TextView scaleValue = view.findViewById(R.id.input_scale_value); + final Slider scaleSlider = dialogBinding.inputScaleSlider; + final TextView scaleValue = dialogBinding.inputScaleValue; scaleSlider.setValueTo(150); scaleSlider.setValue(IntSetting.MAIN_CONTROL_SCALE.getInt(mSettings)); scaleSlider.setStepSize(1); @@ -918,8 +919,8 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP scaleValue.setText(((int) scaleSlider.getValue() + 50) + "%"); // alpha - final Slider sliderOpacity = view.findViewById(R.id.input_opacity_slider); - final TextView valueOpacity = view.findViewById(R.id.input_opacity_value); + final Slider sliderOpacity = dialogBinding.inputOpacitySlider; + final TextView valueOpacity = dialogBinding.inputOpacityValue; sliderOpacity.setValueTo(100); sliderOpacity.setValue(IntSetting.MAIN_CONTROL_OPACITY.getInt(mSettings)); sliderOpacity.setStepSize(1); @@ -927,10 +928,9 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP (slider, progress, fromUser) -> valueOpacity.setText(((int) progress) + "%")); valueOpacity.setText(((int) sliderOpacity.getValue()) + "%"); - new MaterialAlertDialogBuilder(this) .setTitle(R.string.emulation_control_adjustments) - .setView(view) + .setView(dialogBinding.getRoot()) .setPositiveButton(R.string.ok, (dialog, which) -> { 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); - LayoutInflater inflater = LayoutInflater.from(this); - View view = inflater.inflate(R.layout.dialog_ir_sensitivity, null); + DialogIrSensitivityBinding dialogBinding = + DialogIrSensitivityBinding.inflate(getLayoutInflater()); - TextView text_slider_value_pitch = view.findViewById(R.id.text_ir_pitch); - TextView units = view.findViewById(R.id.text_ir_pitch_units); - Slider slider_pitch = view.findViewById(R.id.slider_pitch); + TextView text_slider_value_pitch = dialogBinding.textIrPitch; + TextView units = dialogBinding.textIrPitchUnits; + Slider slider_pitch = dialogBinding.sliderPitch; text_slider_value_pitch.setText(String.valueOf(ir_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); - TextView text_slider_value_yaw = view.findViewById(R.id.text_ir_yaw); - TextView units_yaw = view.findViewById(R.id.text_ir_yaw_units); - Slider seekbar_yaw = view.findViewById(R.id.slider_width); + TextView text_slider_value_yaw = dialogBinding.textIrYaw; + TextView units_yaw = dialogBinding.textIrYawUnits; + Slider seekbar_yaw = dialogBinding.sliderYaw; text_slider_value_yaw.setText(String.valueOf(ir_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( String.valueOf((int) progress))); - int ir_vertical_offset = 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 units_vertical_offset = view.findViewById(R.id.text_ir_vertical_offset_units); - Slider seekbar_vertical_offset = view.findViewById(R.id.slider_vertical_offset); + TextView text_slider_value_vertical_offset = dialogBinding.textIrVerticalOffset; + TextView units_vertical_offset = dialogBinding.textIrVerticalOffsetUnits; + Slider seekbar_vertical_offset = dialogBinding.sliderVerticalOffset; text_slider_value_vertical_offset.setText(String.valueOf(ir_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) .setTitle(getString(R.string.emulation_ir_sensitivity)) - .setView(view) + .setView(dialogBinding.getRoot()) .setPositiveButton(R.string.ok, (dialogInterface, i) -> { ini.setString(Settings.SECTION_CONTROLS, SettingsFile.KEY_WIIBIND_IR_PITCH, diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/UserDataActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/UserDataActivity.java index 9f6a211cd9..c40d4e2e57 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/UserDataActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/UserDataActivity.java @@ -10,19 +10,15 @@ import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.view.View; -import android.widget.Button; -import android.widget.TextView; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; 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 org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.databinding.ActivityUserDataBinding; import org.dolphinemu.dolphinemu.utils.DirectoryInitialization; import org.dolphinemu.dolphinemu.utils.InsetsHelper; import org.dolphinemu.dolphinemu.utils.Log; @@ -61,45 +57,36 @@ public class UserDataActivity extends AppCompatActivity super.onCreate(savedInstanceState); - setContentView(R.layout.activity_user_data); + ActivityUserDataBinding binding = ActivityUserDataBinding.inflate(getLayoutInflater()); + setContentView(binding.getRoot()); 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_11 = Build.VERSION.SDK_INT >= Build.VERSION_CODES.R; boolean legacy = DirectoryInitialization.isUsingLegacyUserDirectory(); int user_data_new_location = android_10 ? 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); - buttonOpenSystemFileManager.setOnClickListener(view -> openFileManager()); + binding.buttonOpenSystemFileManager.setVisibility(android_11 ? View.VISIBLE : View.GONE); + 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(tb); + setSupportActionBar(binding.toolbarUserData); getSupportActionBar().setDisplayHomeAsUpEnabled(true); - AppBarLayout appBarLayout = findViewById(R.id.appbar_user_data); - NestedScrollView scrollView = findViewById(R.id.scroll_view_user_data); - View workaroundView = findViewById(R.id.workaround_view); - InsetsHelper.setUpAppBarWithScrollView(this, appBarLayout, scrollView, workaroundView); - ThemeHelper.enableScrollTint(this, tb, appBarLayout); + InsetsHelper.setUpAppBarWithScrollView(this, binding.appbarUserData, + binding.scrollViewUserData, binding.workaroundView); + ThemeHelper.enableScrollTint(this, binding.toolbarUserData, binding.appbarUserData); } @Override diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/GameAdapter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/GameAdapter.java index 25d683cbac..21470269a9 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/GameAdapter.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/GameAdapter.java @@ -3,7 +3,6 @@ package org.dolphinemu.dolphinemu.adapters; import android.content.Context; -import android.graphics.Rect; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -14,16 +13,16 @@ import androidx.recyclerview.widget.RecyclerView; import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.activities.EmulationActivity; +import org.dolphinemu.dolphinemu.databinding.CardGameBinding; import org.dolphinemu.dolphinemu.dialogs.GamePropertiesDialog; import org.dolphinemu.dolphinemu.model.GameFile; import org.dolphinemu.dolphinemu.services.GameFileCacheManager; import org.dolphinemu.dolphinemu.utils.GlideUtils; -import org.dolphinemu.dolphinemu.viewholders.GameViewHolder; import java.util.ArrayList; import java.util.List; -public final class GameAdapter extends RecyclerView.Adapter implements +public final class GameAdapter extends RecyclerView.Adapter implements View.OnClickListener, View.OnLongClickListener { @@ -45,18 +44,17 @@ public final class GameAdapter extends RecyclerView.Adapter impl * @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. */ + @NonNull @Override public GameViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - // Create a new view. - View gameCard = LayoutInflater.from(parent.getContext()) - .inflate(R.layout.card_game, parent, false); + CardGameBinding binding = CardGameBinding.inflate(LayoutInflater.from(parent.getContext())); - gameCard.setOnClickListener(this); - gameCard.setOnLongClickListener(this); + binding.getRoot().setOnClickListener(this); + binding.getRoot().setOnLongClickListener(this); // 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 impl { Context context = holder.itemView.getContext(); GameFile gameFile = mGameFiles.get(position); - GlideUtils.loadGameCover(holder, holder.imageScreenshot, gameFile); + GlideUtils.loadGameCover(holder, holder.binding.imageGameScreen, gameFile); if (GameFileCacheManager.findSecondDisc(gameFile) != null) { - holder.textGameCaption + holder.binding.textGameCaption .setText(context.getString(R.string.disc_number, gameFile.getDiscNumber() + 1)); } else { - holder.textGameCaption.setText(gameFile.getCompany()); + holder.binding.textGameCaption.setText(gameFile.getCompany()); } 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. * diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/GameDetailsDialog.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/GameDetailsDialog.java index f049fd97a8..dec25dbf2a 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/GameDetailsDialog.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/GameDetailsDialog.java @@ -5,16 +5,15 @@ package org.dolphinemu.dolphinemu.dialogs; 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; @@ -34,90 +33,72 @@ public final class GameDetailsDialog extends DialogFragment 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(); } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/ActionViewHolder.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/ActionViewHolder.java index 3e99384fdd..fd6617cd21 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/ActionViewHolder.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/ActionViewHolder.java @@ -9,6 +9,7 @@ import androidx.annotation.NonNull; 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; @@ -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) diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/CheatDetailsFragment.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/CheatDetailsFragment.java index f08b04abec..9e118e3932 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/CheatDetailsFragment.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/CheatDetailsFragment.java @@ -6,8 +6,6 @@ import android.os.Bundle; 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; @@ -15,78 +13,57 @@ 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) @@ -101,22 +78,24 @@ public class CheatDetailsFragment extends Fragment 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) { @@ -131,23 +110,23 @@ public class CheatDetailsFragment extends Fragment 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; } } @@ -156,18 +135,18 @@ public class CheatDetailsFragment extends Fragment { 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 @@ -175,10 +154,10 @@ public class CheatDetailsFragment extends Fragment 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; @@ -186,14 +165,14 @@ public class CheatDetailsFragment extends Fragment private void onIsEditingUpdated(boolean isEditing) { - mEditName.setEnabled(isEditing); - mEditCreator.setEnabled(isEditing); - mEditNotes.setEnabled(isEditing); - mEditCode.setEnabled(isEditing); + mBinding.editNameInput.setEnabled(isEditing); + mBinding.editCreatorInput.setEnabled(isEditing); + mBinding.editNotesInput.setEnabled(isEditing); + mBinding.editCodeInput.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.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); } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/CheatListFragment.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/CheatListFragment.java index 60c20590d9..6f1d295dde 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/CheatListFragment.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/CheatListFragment.java @@ -12,40 +12,47 @@ import androidx.annotation.Nullable; 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(), recyclerView); + InsetsHelper.setUpList(getContext(), mBinding.cheatList); + } + + @Override + public void onDestroyView() + { + super.onDestroyView(); + mBinding = null; } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/CheatViewHolder.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/CheatViewHolder.java index a37abd145a..806b960b58 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/CheatViewHolder.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/CheatViewHolder.java @@ -10,43 +10,38 @@ import android.widget.TextView; 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) diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/CheatsActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/CheatsActivity.java index 189db827be..0827c3197e 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/CheatsActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/CheatsActivity.java @@ -19,12 +19,11 @@ import androidx.core.view.WindowCompat; 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; @@ -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) { @@ -86,38 +83,34 @@ public class CheatsActivity extends AppCompatActivity 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 = mBinding.cheatList; + mCheatDetailsLastFocus = mBinding.cheatDetails; - mCheatListLastFocus = mCheatList; - mCheatDetailsLastFocus = mCheatDetails; - - 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); } @@ -161,10 +154,10 @@ public class CheatsActivity extends AppCompatActivity { 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); } @@ -172,11 +165,11 @@ public class CheatsActivity extends AppCompatActivity { if (hasFocus) { - mCheatListLastFocus = mCheatList.findFocus(); + mCheatListLastFocus = mBinding.cheatList.findFocus(); if (mCheatListLastFocus == null) throw new NullPointerException(); - mSlidingPaneLayout.close(); + mBinding.slidingPaneLayout.close(); } } @@ -184,11 +177,11 @@ public class CheatsActivity extends AppCompatActivity { if (hasFocus) { - mCheatDetailsLastFocus = mCheatDetails.findFocus(); + mCheatDetailsLastFocus = mBinding.cheatDetails.findFocus(); if (mCheatDetailsLastFocus == null) throw new NullPointerException(); - mSlidingPaneLayout.open(); + mBinding.slidingPaneLayout.open(); } } @@ -202,7 +195,7 @@ public class CheatsActivity extends AppCompatActivity private void openDetailsView(boolean open) { if (open) - mSlidingPaneLayout.open(); + mBinding.slidingPaneLayout.open(); } public Settings loadGameSpecificSettings() diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/CheatsAdapter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/CheatsAdapter.java index e5be47a3f1..3335795c75 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/CheatsAdapter.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/CheatsAdapter.java @@ -10,6 +10,9 @@ import androidx.annotation.NonNull; 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; @@ -66,17 +69,17 @@ public class CheatsAdapter extends RecyclerView.Adapter 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(); } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/HeaderViewHolder.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/HeaderViewHolder.java index c48ec500ff..8f347d363e 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/HeaderViewHolder.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/HeaderViewHolder.java @@ -8,16 +8,17 @@ import android.widget.TextView; 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) diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/SettingDisabledWarningFragment.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/SettingDisabledWarningFragment.java index c239c5c9af..7e703f3fd1 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/SettingDisabledWarningFragment.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/SettingDisabledWarningFragment.java @@ -6,14 +6,12 @@ import android.os.Bundle; 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; @@ -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) { @@ -38,10 +38,11 @@ public abstract class SettingDisabledWarningFragment extends Fragment @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 @@ -49,11 +50,8 @@ public abstract class SettingDisabledWarningFragment extends Fragment { 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, @@ -73,6 +71,13 @@ public abstract class SettingDisabledWarningFragment extends Fragment } } + @Override + public void onDestroyView() + { + super.onDestroyView(); + mBinding = null; + } + public void onClick(View view) { SettingsActivity.launch(requireContext(), mSettingShortcut); diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/riivolution/ui/RiivolutionAdapter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/riivolution/ui/RiivolutionAdapter.java index 92d933b3d6..68c209cc0c 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/riivolution/ui/RiivolutionAdapter.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/riivolution/ui/RiivolutionAdapter.java @@ -9,7 +9,7 @@ import android.view.ViewGroup; 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; @@ -48,8 +48,8 @@ public class RiivolutionAdapter extends RecyclerView.Adapter + mBinding.buttonStart.setOnClickListener((v) -> { if (mPatches != null) mPatches.saveConfig(); @@ -88,17 +81,13 @@ public class RiivolutionBootActivity extends AppCompatActivity 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 @@ -121,9 +110,7 @@ public class RiivolutionBootActivity extends AppCompatActivity { 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)); } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/riivolution/ui/RiivolutionViewHolder.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/riivolution/ui/RiivolutionViewHolder.java index 8cd8a21c59..4a8c4f383f 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/riivolution/ui/RiivolutionViewHolder.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/riivolution/ui/RiivolutionViewHolder.java @@ -6,60 +6,53 @@ import android.content.Context; 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) { @@ -78,11 +71,11 @@ public class RiivolutionViewHolder extends RecyclerView.ViewHolder 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); } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsActivity.java index 45a48a1cfa..fa42a7a78c 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsActivity.java @@ -28,6 +28,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder; 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; @@ -81,7 +82,8 @@ public final class SettingsActivity extends AppCompatActivity implements Setting MainPresenter.skipRescanningLibrary(); } - setContentView(R.layout.activity_settings); + ActivitySettingsBinding binding = ActivitySettingsBinding.inflate(getLayoutInflater()); + setContentView(binding.getRoot()); WindowCompat.setDecorFitsSystemWindows(getWindow(), false); @@ -96,21 +98,17 @@ public final class SettingsActivity extends AppCompatActivity implements Setting 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 diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsAdapter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsAdapter.java index d8ceb5ba29..42f7d5cb04 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsAdapter.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsAdapter.java @@ -8,7 +8,6 @@ import android.content.Intent; import android.os.Build; import android.provider.DocumentsContract; import android.view.LayoutInflater; -import android.view.View; import android.view.ViewGroup; import android.widget.TextView; @@ -21,6 +20,12 @@ import com.google.android.material.slider.Slider; 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; @@ -79,59 +84,50 @@ public final class SettingsAdapter extends RecyclerView.Adapter { @@ -275,26 +271,25 @@ public final class SettingsAdapter extends RecyclerView.Adapter progressBar.setProgress(progress)); + .observe(this, (@Nullable + Integer progress) -> dialogProgressBinding.updateProgress.setProgress( + progress)); viewModel.getTotalData().observe(this, (@Nullable Integer total) -> { @@ -55,7 +56,7 @@ public class SystemUpdateProgressBarDialogFragment extends DialogFragment return; } - progressBar.setMax(total); + dialogProgressBinding.updateProgress.setMax(total); }); viewModel.getTitleIdData().observe(this, (@Nullable Long titleId) -> progressDialog.setMessage( diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/ConvertFragment.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/ConvertFragment.java index 555401bfa3..ec67b32061 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/ConvertFragment.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/ConvertFragment.java @@ -13,7 +13,6 @@ import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ArrayAdapter; -import android.widget.CheckBox; import androidx.annotation.NonNull; import androidx.annotation.StringRes; @@ -27,6 +26,8 @@ import com.google.android.material.textfield.TextInputLayout; 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; @@ -114,21 +115,13 @@ public class ConvertFragment extends Fragment implements View.OnClickListener 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(); @@ -150,20 +143,19 @@ public class ConvertFragment extends Fragment implements View.OnClickListener 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(); @@ -177,35 +169,23 @@ public class ConvertFragment extends Fragment implements View.OnClickListener 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) { @@ -214,7 +194,7 @@ public class ConvertFragment extends Fragment implements View.OnClickListener 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, @@ -236,6 +216,13 @@ public class ConvertFragment extends Fragment implements View.OnClickListener joinThread(); } + @Override + public void onDestroyView() + { + super.onDestroyView(); + mBinding = null; + } + private void populateDropdown(TextInputLayout layout, MaterialAutoCompleteTextView dropdown, int entriesId, int valuesId, DropdownValue valueWrapper) { @@ -263,13 +250,15 @@ public class ConvertFragment extends Fragment implements View.OnClickListener 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); } @@ -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 // 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); } } @@ -308,31 +303,31 @@ public class ConvertFragment extends Fragment implements View.OnClickListener 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); } } @@ -343,24 +338,25 @@ public class ConvertFragment extends Fragment implements View.OnClickListener 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); } } @@ -369,15 +365,15 @@ public class ConvertFragment extends Fragment implements View.OnClickListener 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; @@ -466,15 +462,15 @@ public class ConvertFragment extends Fragment implements View.OnClickListener 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(() -> @@ -482,12 +478,13 @@ public class ConvertFragment extends Fragment implements View.OnClickListener 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; }); diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.java index 7af1c09dfa..142aca0641 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.java @@ -13,11 +13,12 @@ import android.view.ViewGroup; 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; @@ -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) { @@ -83,20 +86,24 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C 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()); @@ -104,7 +111,7 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C if (mInputOverlay != null) { - contents.post(() -> + view.post(() -> { int overlayX = mInputOverlay.getLeft(); int overlayY = mInputOverlay.getTop(); @@ -113,10 +120,13 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C 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 @@ -223,7 +233,7 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C { if (mInputOverlay != null) { - requireView().findViewById(R.id.done_control_config).setVisibility(View.VISIBLE); + mBinding.doneControlConfig.setVisibility(View.VISIBLE); mInputOverlay.setIsInEditMode(true); } } @@ -232,7 +242,7 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C { if (mInputOverlay != null) { - requireView().findViewById(R.id.done_control_config).setVisibility(View.GONE); + mBinding.doneControlConfig.setVisibility(View.GONE); mInputOverlay.setIsInEditMode(false); } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/MenuFragment.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/MenuFragment.java index 253892aafe..dfed5871c0 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/MenuFragment.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/MenuFragment.java @@ -11,21 +11,19 @@ import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.LinearLayout; -import android.widget.TextView; +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.FragmentIngameMenuBinding; import org.dolphinemu.dolphinemu.features.settings.model.BooleanSetting; 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_WII = "wii"; 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); } + private FragmentIngameMenuBinding mBinding; + public static MenuFragment newInstance() { 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; } + @NonNull @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); - - LinearLayout options = rootView.findViewById(R.id.layout_options); - - mPauseEmulation = options.findViewById(R.id.menu_pause_emulation); - mUnpauseEmulation = options.findViewById(R.id.menu_unpause_emulation); + mBinding = FragmentIngameMenuBinding.inflate(inflater, container, false); + return mBinding.getRoot(); + } + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) + { updatePauseUnpauseVisibility(); 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)) { - options.findViewById(R.id.menu_refresh_wiimotes).setVisibility(View.GONE); + mBinding.menuRefreshWiimotes.setVisibility(View.GONE); } int bottomPaddingRequired = getBottomPaddingRequired(); @@ -107,12 +109,13 @@ public final class MenuFragment extends Fragment implements View.OnClickListener bottomPaddingRequired += 32 * density; } - if (bottomPaddingRequired > rootView.getPaddingBottom()) + if (bottomPaddingRequired > view.getPaddingBottom()) { - rootView.setPadding(rootView.getPaddingLeft(), rootView.getPaddingTop(), - rootView.getPaddingRight(), bottomPaddingRequired); + view.setPadding(view.getPaddingLeft(), view.getPaddingTop(), + view.getPaddingRight(), bottomPaddingRequired); } + LinearLayout options = mBinding.layoutOptions; for (int childIndex = 0; childIndex < options.getChildCount(); childIndex++) { Button button = (Button) options.getChildAt(childIndex); @@ -120,21 +123,18 @@ public final class MenuFragment extends Fragment implements View.OnClickListener 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); if (title != null) { - mTitleText.setText(title); + mBinding.textGameTitle.setText(title); } if (getResources().getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_LTR) { - rootView.post(() -> NativeLibrary.SetObscuredPixelsLeft(rootView.getWidth())); + view.post(() -> NativeLibrary.SetObscuredPixelsLeft(view.getWidth())); } - - return rootView; } @Override @@ -142,14 +142,12 @@ public final class MenuFragment extends Fragment implements View.OnClickListener { super.onResume(); - LinearLayout options = requireView().findViewById(R.id.layout_options); - boolean savestatesEnabled = BooleanSetting.MAIN_ENABLE_SAVESTATES.getBooleanGlobal(); int savestateVisibility = savestatesEnabled ? View.VISIBLE : View.GONE; - options.findViewById(R.id.menu_quicksave).setVisibility(savestateVisibility); - options.findViewById(R.id.menu_quickload).setVisibility(savestateVisibility); - options.findViewById(R.id.menu_emulation_save_root).setVisibility(savestateVisibility); - options.findViewById(R.id.menu_emulation_load_root).setVisibility(savestateVisibility); + mBinding.menuQuicksave.setVisibility(savestateVisibility); + mBinding.menuQuickload.setVisibility(savestateVisibility); + mBinding.menuEmulationSaveRoot.setVisibility(savestateVisibility); + mBinding.menuEmulationLoadRoot.setVisibility(savestateVisibility); } @Override @@ -158,14 +156,15 @@ public final class MenuFragment extends Fragment implements View.OnClickListener super.onDestroyView(); NativeLibrary.SetObscuredPixelsLeft(0); + mBinding = null; } private void updatePauseUnpauseVisibility() { boolean paused = EmulationActivity.getHasUserPausedEmulation(); - mUnpauseEmulation.setVisibility(paused ? View.VISIBLE : View.GONE); - mPauseEmulation.setVisibility(paused ? View.GONE : View.VISIBLE); + mBinding.menuUnpauseEmulation.setVisibility(paused ? View.VISIBLE : View.GONE); + mBinding.menuPauseEmulation.setVisibility(paused ? View.GONE : View.VISIBLE); } @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 // (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) { diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/SaveLoadStateFragment.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/SaveLoadStateFragment.java index d07d2d4c7b..2afce4d1cf 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/SaveLoadStateFragment.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/SaveLoadStateFragment.java @@ -11,12 +11,14 @@ import android.view.ViewGroup; import android.widget.Button; import android.widget.GridLayout; +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.FragmentSaveloadStateBinding; 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 FragmentSaveloadStateBinding mBinding; + public static SaveLoadStateFragment newInstance(SaveOrLoad saveOrLoad) { SaveLoadStateFragment fragment = new SaveLoadStateFragment(); @@ -78,12 +82,19 @@ public final class SaveLoadStateFragment extends Fragment implements View.OnClic mSaveOrLoad = (SaveOrLoad) getArguments().getSerializable(KEY_SAVEORLOAD); } + @NonNull @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++) { 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. grid.requestFocus(); + } - return rootView; + @Override + public void onDestroyView() + { + super.onDestroyView(); + mBinding = null; } @Override diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.java index 96dc44d83b..2a0512e3ac 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.java @@ -9,24 +9,20 @@ import android.os.Bundle; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; -import android.view.View; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; -import androidx.appcompat.widget.Toolbar; import androidx.core.splashscreen.SplashScreen; import androidx.core.view.WindowCompat; 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 org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.activities.EmulationActivity; 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.NativeConfig; import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag; @@ -51,16 +47,12 @@ import org.dolphinemu.dolphinemu.utils.WiiUtils; public final class MainActivity extends AppCompatActivity implements MainView, SwipeRefreshLayout.OnRefreshListener, ThemeProvider { - private ViewPager mViewPager; - private Toolbar mToolbar; - private TabLayout mTabLayout; - private AppBarLayout mAppBarLayout; - private FloatingActionButton mFab; - private int mThemeId; private final MainPresenter mPresenter = new MainPresenter(this, this); + private ActivityMainBinding mBinding; + @Override protected void onCreate(Bundle savedInstanceState) { @@ -71,19 +63,19 @@ public final class MainActivity extends AppCompatActivity ThemeHelper.setTheme(this); 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); - InsetsHelper.setUpMainLayout(this, mAppBarLayout, mFab, mViewPager, workaroundView); - ThemeHelper.enableStatusBarScrollTint(this, mAppBarLayout); + InsetsHelper.setUpMainLayout(this, mBinding.appbarMain, mBinding.buttonAddDirectory, + mBinding.pagerPlatforms, mBinding.workaroundView); + ThemeHelper.enableStatusBarScrollTint(this, mBinding.appbarMain); - setSupportActionBar(mToolbar); + setSupportActionBar(mBinding.toolbarMain); // Set up the FAB. - mFab.setOnClickListener(view -> mPresenter.onFabClick()); + mBinding.buttonAddDirectory.setOnClickListener(view -> mPresenter.onFabClick()); mPresenter.onCreate(); @@ -154,16 +146,6 @@ public final class MainActivity extends AppCompatActivity 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 public boolean onCreateOptionsMenu(Menu menu) { @@ -190,7 +172,7 @@ public final class MainActivity extends AppCompatActivity @Override public void setVersionString(String version) { - mToolbar.setSubtitle(version); + mBinding.toolbarMain.setSubtitle(version); } @Override @@ -351,7 +333,8 @@ public final class MainActivity extends AppCompatActivity @Nullable 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); } @@ -361,25 +344,27 @@ public final class MainActivity extends AppCompatActivity { PlatformPagerAdapter platformPagerAdapter = new PlatformPagerAdapter( getSupportFragmentManager(), this); - mViewPager.setAdapter(platformPagerAdapter); - mViewPager.setOffscreenPageLimit(platformPagerAdapter.getCount()); - mTabLayout.setupWithViewPager(mViewPager); - mTabLayout.addOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(mViewPager) - { - @Override - public void onTabSelected(@NonNull TabLayout.Tab tab) - { - super.onTabSelected(tab); - IntSetting.MAIN_LAST_PLATFORM_TAB.setIntGlobal(NativeConfig.LAYER_BASE, tab.getPosition()); - } - }); + mBinding.pagerPlatforms.setAdapter(platformPagerAdapter); + mBinding.pagerPlatforms.setOffscreenPageLimit(platformPagerAdapter.getCount()); + mBinding.tabsPlatforms.setupWithViewPager(mBinding.pagerPlatforms); + mBinding.tabsPlatforms.addOnTabSelectedListener( + new TabLayout.ViewPagerOnTabSelectedListener(mBinding.pagerPlatforms) + { + @Override + public void onTabSelected(@NonNull TabLayout.Tab tab) + { + super.onTabSelected(tab); + IntSetting.MAIN_LAST_PLATFORM_TAB.setIntGlobal(NativeConfig.LAYER_BASE, + tab.getPosition()); + } + }); 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(); GameFileCacheManager.startLoad(); diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/TvMainActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/TvMainActivity.java index 32db29e802..925c755880 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/TvMainActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/TvMainActivity.java @@ -23,6 +23,7 @@ import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.activities.EmulationActivity; import org.dolphinemu.dolphinemu.adapters.GameRowPresenter; 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.SettingsActivity; import org.dolphinemu.dolphinemu.model.GameFile; @@ -50,6 +51,8 @@ public final class TvMainActivity extends FragmentActivity private final ArrayList mGameRows = new ArrayList<>(); + private ActivityTvMainBinding mBinding; + @Override protected void onCreate(Bundle savedInstanceState) { @@ -58,7 +61,8 @@ public final class TvMainActivity extends FragmentActivity () -> !DirectoryInitialization.areDolphinDirectoriesReady()); super.onCreate(savedInstanceState); - setContentView(R.layout.activity_tv_main); + mBinding = ActivityTvMainBinding.inflate(getLayoutInflater()); + setContentView(mBinding.getRoot()); setupUI(); @@ -118,7 +122,7 @@ public final class TvMainActivity extends FragmentActivity void setupUI() { - mSwipeRefresh = findViewById(R.id.swipe_refresh); + mSwipeRefresh = mBinding.swipeRefresh; mSwipeRefresh.setOnRefreshListener(this); diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/platform/PlatformGamesFragment.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/platform/PlatformGamesFragment.java index 62063caaeb..80a7a35fac 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/platform/PlatformGamesFragment.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/platform/PlatformGamesFragment.java @@ -18,6 +18,7 @@ import com.google.android.material.color.MaterialColors; import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.adapters.GameAdapter; +import org.dolphinemu.dolphinemu.databinding.FragmentGridBinding; import org.dolphinemu.dolphinemu.services.GameFileCacheManager; 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 GameAdapter mAdapter; - private RecyclerView mRecyclerView; private SwipeRefreshLayout mSwipeRefresh; private SwipeRefreshLayout.OnRefreshListener mOnRefreshListener; + private FragmentGridBinding mBinding; + public static PlatformGamesFragment newInstance(Platform platform) { PlatformGamesFragment fragment = new PlatformGamesFragment(); @@ -47,19 +49,20 @@ public final class PlatformGamesFragment extends Fragment implements PlatformGam super.onCreate(savedInstanceState); } + @NonNull @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); - - findViews(rootView); - - return rootView; + mBinding = FragmentGridBinding.inflate(inflater, container, false); + return mBinding.getRoot(); } @Override public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { + mSwipeRefresh = mBinding.swipeRefresh; + int columns = getResources().getInteger(R.integer.game_grid_columns); RecyclerView.LayoutManager layoutManager = new GridLayoutManager(getActivity(), columns); mAdapter = new GameAdapter(); @@ -72,16 +75,23 @@ public final class PlatformGamesFragment extends Fragment implements PlatformGam mSwipeRefresh.setOnRefreshListener(mOnRefreshListener); - mRecyclerView.setLayoutManager(layoutManager); - mRecyclerView.setAdapter(mAdapter); + mBinding.gridGames.setLayoutManager(layoutManager); + mBinding.gridGames.setAdapter(mAdapter); - InsetsHelper.setUpList(getContext(), mRecyclerView); + InsetsHelper.setUpList(getContext(), mBinding.gridGames); setRefreshing(GameFileCacheManager.isLoadingOrRescanning()); showGames(); } + @Override + public void onDestroyView() + { + super.onDestroyView(); + mBinding = null; + } + @Override public void refreshScreenshotAtPosition(int position) { @@ -115,17 +125,13 @@ public final class PlatformGamesFragment extends Fragment implements PlatformGam mOnRefreshListener = listener; if (mSwipeRefresh != null) + { mSwipeRefresh.setOnRefreshListener(listener); + } } public void setRefreshing(boolean refreshing) { - mSwipeRefresh.setRefreshing(refreshing); - } - - private void findViews(View root) - { - mSwipeRefresh = root.findViewById(R.id.swipe_refresh); - mRecyclerView = root.findViewById(R.id.grid_games); + mBinding.swipeRefresh.setRefreshing(refreshing); } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/GlideUtils.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/GlideUtils.java index f3a626bebd..0ddf4d44f8 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/GlideUtils.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/GlideUtils.java @@ -23,9 +23,9 @@ import com.bumptech.glide.request.target.Target; import com.bumptech.glide.request.transition.Transition; import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.adapters.GameAdapter; import org.dolphinemu.dolphinemu.features.settings.model.BooleanSetting; import org.dolphinemu.dolphinemu.model.GameFile; -import org.dolphinemu.dolphinemu.viewholders.GameViewHolder; import java.io.File; 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) { if (BooleanSetting.MAIN_SHOW_GAME_TITLES.getBooleanGlobal() && gameViewHolder != null) { - gameViewHolder.textGameTitle.setText(gameFile.getTitle()); - gameViewHolder.textGameTitle.setVisibility(View.VISIBLE); - gameViewHolder.textGameTitleInner.setVisibility(View.GONE); - gameViewHolder.textGameCaption.setVisibility(View.VISIBLE); + gameViewHolder.binding.textGameTitle.setText(gameFile.getTitle()); + gameViewHolder.binding.textGameTitle.setVisibility(View.VISIBLE); + gameViewHolder.binding.textGameTitleInner.setVisibility(View.GONE); + gameViewHolder.binding.textGameCaption.setVisibility(View.VISIBLE); } else if (gameViewHolder != null) { - gameViewHolder.textGameTitleInner.setText(gameFile.getTitle()); - gameViewHolder.textGameTitle.setVisibility(View.GONE); - gameViewHolder.textGameCaption.setVisibility(View.GONE); + gameViewHolder.binding.textGameTitleInner.setText(gameFile.getTitle()); + gameViewHolder.binding.textGameTitle.setVisibility(View.GONE); + gameViewHolder.binding.textGameCaption.setVisibility(View.GONE); } 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()) .load(R.drawable.no_banner) @@ -206,15 +207,15 @@ public class GlideUtils 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()) { - gameViewHolder.textGameTitleInner.setVisibility(View.GONE); + gameViewHolder.binding.textGameTitleInner.setVisibility(View.GONE); } } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/viewholders/GameViewHolder.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/viewholders/GameViewHolder.java deleted file mode 100644 index b829847488..0000000000 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/viewholders/GameViewHolder.java +++ /dev/null @@ -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); - } -} diff --git a/Source/Android/app/src/main/res/layout-ldrtl/list_item_cheat.xml b/Source/Android/app/src/main/res/layout-ldrtl/list_item_cheat.xml index 2a151e8a2d..2ef0c4da01 100644 --- a/Source/Android/app/src/main/res/layout-ldrtl/list_item_cheat.xml +++ b/Source/Android/app/src/main/res/layout-ldrtl/list_item_cheat.xml @@ -1,37 +1,36 @@ - + + tools:text="Hyrule Field Speed Hack" /> + android:nextFocusRight="@id/root" /> - + diff --git a/Source/Android/app/src/main/res/layout-notouch/fragment_emulation.xml b/Source/Android/app/src/main/res/layout-notouch/fragment_emulation.xml index 1766a2c8e6..28746017a5 100644 --- a/Source/Android/app/src/main/res/layout-notouch/fragment_emulation.xml +++ b/Source/Android/app/src/main/res/layout-notouch/fragment_emulation.xml @@ -1,7 +1,14 @@ - \ No newline at end of file + + + + + diff --git a/Source/Android/app/src/main/res/layout-port-notouch/fragment_emulation.xml b/Source/Android/app/src/main/res/layout-port-notouch/fragment_emulation.xml index 1766a2c8e6..28746017a5 100644 --- a/Source/Android/app/src/main/res/layout-port-notouch/fragment_emulation.xml +++ b/Source/Android/app/src/main/res/layout-port-notouch/fragment_emulation.xml @@ -1,7 +1,14 @@ - \ No newline at end of file + + + + + diff --git a/Source/Android/app/src/main/res/layout-port/fragment_emulation.xml b/Source/Android/app/src/main/res/layout-port/fragment_emulation.xml index f90c67a5ec..eca2849ef4 100644 --- a/Source/Android/app/src/main/res/layout-port/fragment_emulation.xml +++ b/Source/Android/app/src/main/res/layout-port/fragment_emulation.xml @@ -1,9 +1,11 @@ - + + + android:focusableInTouchMode="false" /> + + android:layout_weight="1" /> + + + android:focusableInTouchMode="true" />