Browse Source
Merge pull request #12204 from t895/config-migration
Merge pull request #12204 from t895/config-migration
android: Multi directory UInce_cpp
committed by
GitHub
32 changed files with 848 additions and 122 deletions
-
76src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/FolderAdapter.kt
-
24src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt
-
30src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivity.kt
-
2src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt
-
53src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AddGameFolderDialogFragment.kt
-
72src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GameFolderPropertiesDialogFragment.kt
-
128src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GameFoldersFragment.kt
-
13src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt
-
8src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SettingsDialogFragment.kt
-
8src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SetupFragment.kt
-
13src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GameDir.kt
-
61src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt
-
19src/android/app/src/main/java/org/yuzu/yuzu_emu/model/HomeViewModel.kt
-
3src/android/app/src/main/java/org/yuzu/yuzu_emu/model/SettingsViewModel.kt
-
33src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt
-
21src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt
-
39src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt
-
20src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/NativeConfig.kt
-
50src/android/app/src/main/jni/android_config.cpp
-
8src/android/app/src/main/jni/android_config.h
-
8src/android/app/src/main/jni/android_settings.h
-
16src/android/app/src/main/jni/id_cache.cpp
-
2src/android/app/src/main/jni/id_cache.h
-
52src/android/app/src/main/jni/native_config.cpp
-
70src/android/app/src/main/res/layout/card_folder.xml
-
45src/android/app/src/main/res/layout/dialog_add_folder.xml
-
30src/android/app/src/main/res/layout/dialog_folder_properties.xml
-
48src/android/app/src/main/res/layout/fragment_folders.xml
-
7src/android/app/src/main/res/navigation/home_navigation.xml
-
2src/android/app/src/main/res/values/dimens.xml
-
7src/android/app/src/main/res/values/strings.xml
-
2src/frontend_common/config.cpp
@ -0,0 +1,76 @@ |
|||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
package org.yuzu.yuzu_emu.adapters |
|||
|
|||
import android.net.Uri |
|||
import android.text.TextUtils |
|||
import android.view.LayoutInflater |
|||
import android.view.ViewGroup |
|||
import androidx.fragment.app.FragmentActivity |
|||
import androidx.recyclerview.widget.AsyncDifferConfig |
|||
import androidx.recyclerview.widget.DiffUtil |
|||
import androidx.recyclerview.widget.ListAdapter |
|||
import androidx.recyclerview.widget.RecyclerView |
|||
import org.yuzu.yuzu_emu.databinding.CardFolderBinding |
|||
import org.yuzu.yuzu_emu.fragments.GameFolderPropertiesDialogFragment |
|||
import org.yuzu.yuzu_emu.model.GameDir |
|||
import org.yuzu.yuzu_emu.model.GamesViewModel |
|||
|
|||
class FolderAdapter(val activity: FragmentActivity, val gamesViewModel: GamesViewModel) : |
|||
ListAdapter<GameDir, FolderAdapter.FolderViewHolder>( |
|||
AsyncDifferConfig.Builder(DiffCallback()).build() |
|||
) { |
|||
override fun onCreateViewHolder( |
|||
parent: ViewGroup, |
|||
viewType: Int |
|||
): FolderAdapter.FolderViewHolder { |
|||
CardFolderBinding.inflate(LayoutInflater.from(parent.context), parent, false) |
|||
.also { return FolderViewHolder(it) } |
|||
} |
|||
|
|||
override fun onBindViewHolder(holder: FolderAdapter.FolderViewHolder, position: Int) = |
|||
holder.bind(currentList[position]) |
|||
|
|||
inner class FolderViewHolder(val binding: CardFolderBinding) : |
|||
RecyclerView.ViewHolder(binding.root) { |
|||
private lateinit var gameDir: GameDir |
|||
|
|||
fun bind(gameDir: GameDir) { |
|||
this.gameDir = gameDir |
|||
|
|||
binding.apply { |
|||
path.text = Uri.parse(gameDir.uriString).path |
|||
path.postDelayed( |
|||
{ |
|||
path.isSelected = true |
|||
path.ellipsize = TextUtils.TruncateAt.MARQUEE |
|||
}, |
|||
3000 |
|||
) |
|||
|
|||
buttonEdit.setOnClickListener { |
|||
GameFolderPropertiesDialogFragment.newInstance(this@FolderViewHolder.gameDir) |
|||
.show( |
|||
activity.supportFragmentManager, |
|||
GameFolderPropertiesDialogFragment.TAG |
|||
) |
|||
} |
|||
|
|||
buttonDelete.setOnClickListener { |
|||
gamesViewModel.removeFolder(this@FolderViewHolder.gameDir) |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
private class DiffCallback : DiffUtil.ItemCallback<GameDir>() { |
|||
override fun areItemsTheSame(oldItem: GameDir, newItem: GameDir): Boolean { |
|||
return oldItem == newItem |
|||
} |
|||
|
|||
override fun areContentsTheSame(oldItem: GameDir, newItem: GameDir): Boolean { |
|||
return oldItem == newItem |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,53 @@ |
|||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
package org.yuzu.yuzu_emu.fragments |
|||
|
|||
import android.app.Dialog |
|||
import android.content.DialogInterface |
|||
import android.net.Uri |
|||
import android.os.Bundle |
|||
import androidx.fragment.app.DialogFragment |
|||
import androidx.fragment.app.activityViewModels |
|||
import com.google.android.material.dialog.MaterialAlertDialogBuilder |
|||
import org.yuzu.yuzu_emu.R |
|||
import org.yuzu.yuzu_emu.databinding.DialogAddFolderBinding |
|||
import org.yuzu.yuzu_emu.model.GameDir |
|||
import org.yuzu.yuzu_emu.model.GamesViewModel |
|||
|
|||
class AddGameFolderDialogFragment : DialogFragment() { |
|||
private val gamesViewModel: GamesViewModel by activityViewModels() |
|||
|
|||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { |
|||
val binding = DialogAddFolderBinding.inflate(layoutInflater) |
|||
val folderUriString = requireArguments().getString(FOLDER_URI_STRING) |
|||
if (folderUriString == null) { |
|||
dismiss() |
|||
} |
|||
binding.path.text = Uri.parse(folderUriString).path |
|||
|
|||
return MaterialAlertDialogBuilder(requireContext()) |
|||
.setTitle(R.string.add_game_folder) |
|||
.setPositiveButton(android.R.string.ok) { _: DialogInterface, _: Int -> |
|||
val newGameDir = GameDir(folderUriString!!, binding.deepScanSwitch.isChecked) |
|||
gamesViewModel.addFolder(newGameDir) |
|||
} |
|||
.setNegativeButton(android.R.string.cancel, null) |
|||
.setView(binding.root) |
|||
.show() |
|||
} |
|||
|
|||
companion object { |
|||
const val TAG = "AddGameFolderDialogFragment" |
|||
|
|||
private const val FOLDER_URI_STRING = "FolderUriString" |
|||
|
|||
fun newInstance(folderUriString: String): AddGameFolderDialogFragment { |
|||
val args = Bundle() |
|||
args.putString(FOLDER_URI_STRING, folderUriString) |
|||
val fragment = AddGameFolderDialogFragment() |
|||
fragment.arguments = args |
|||
return fragment |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,72 @@ |
|||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
package org.yuzu.yuzu_emu.fragments |
|||
|
|||
import android.app.Dialog |
|||
import android.content.DialogInterface |
|||
import android.os.Bundle |
|||
import androidx.fragment.app.DialogFragment |
|||
import androidx.fragment.app.activityViewModels |
|||
import com.google.android.material.dialog.MaterialAlertDialogBuilder |
|||
import org.yuzu.yuzu_emu.R |
|||
import org.yuzu.yuzu_emu.databinding.DialogFolderPropertiesBinding |
|||
import org.yuzu.yuzu_emu.model.GameDir |
|||
import org.yuzu.yuzu_emu.model.GamesViewModel |
|||
import org.yuzu.yuzu_emu.utils.SerializableHelper.parcelable |
|||
|
|||
class GameFolderPropertiesDialogFragment : DialogFragment() { |
|||
private val gamesViewModel: GamesViewModel by activityViewModels() |
|||
|
|||
private var deepScan = false |
|||
|
|||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { |
|||
val binding = DialogFolderPropertiesBinding.inflate(layoutInflater) |
|||
val gameDir = requireArguments().parcelable<GameDir>(GAME_DIR)!! |
|||
|
|||
// Restore checkbox state |
|||
binding.deepScanSwitch.isChecked = |
|||
savedInstanceState?.getBoolean(DEEP_SCAN) ?: gameDir.deepScan |
|||
|
|||
// Ensure that we can get the checkbox state even if the view is destroyed |
|||
deepScan = binding.deepScanSwitch.isChecked |
|||
binding.deepScanSwitch.setOnClickListener { |
|||
deepScan = binding.deepScanSwitch.isChecked |
|||
} |
|||
|
|||
return MaterialAlertDialogBuilder(requireContext()) |
|||
.setView(binding.root) |
|||
.setTitle(R.string.game_folder_properties) |
|||
.setPositiveButton(android.R.string.ok) { _: DialogInterface, _: Int -> |
|||
val folderIndex = gamesViewModel.folders.value.indexOf(gameDir) |
|||
if (folderIndex != -1) { |
|||
gamesViewModel.folders.value[folderIndex].deepScan = |
|||
binding.deepScanSwitch.isChecked |
|||
gamesViewModel.updateGameDirs() |
|||
} |
|||
} |
|||
.setNegativeButton(android.R.string.cancel, null) |
|||
.show() |
|||
} |
|||
|
|||
override fun onSaveInstanceState(outState: Bundle) { |
|||
super.onSaveInstanceState(outState) |
|||
outState.putBoolean(DEEP_SCAN, deepScan) |
|||
} |
|||
|
|||
companion object { |
|||
const val TAG = "GameFolderPropertiesDialogFragment" |
|||
|
|||
private const val GAME_DIR = "GameDir" |
|||
|
|||
private const val DEEP_SCAN = "DeepScan" |
|||
|
|||
fun newInstance(gameDir: GameDir): GameFolderPropertiesDialogFragment { |
|||
val args = Bundle() |
|||
args.putParcelable(GAME_DIR, gameDir) |
|||
val fragment = GameFolderPropertiesDialogFragment() |
|||
fragment.arguments = args |
|||
return fragment |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,128 @@ |
|||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
package org.yuzu.yuzu_emu.fragments |
|||
|
|||
import android.content.Intent |
|||
import android.os.Bundle |
|||
import android.view.LayoutInflater |
|||
import android.view.View |
|||
import android.view.ViewGroup |
|||
import androidx.core.view.ViewCompat |
|||
import androidx.core.view.WindowInsetsCompat |
|||
import androidx.core.view.updatePadding |
|||
import androidx.fragment.app.Fragment |
|||
import androidx.fragment.app.activityViewModels |
|||
import androidx.lifecycle.Lifecycle |
|||
import androidx.lifecycle.lifecycleScope |
|||
import androidx.lifecycle.repeatOnLifecycle |
|||
import androidx.navigation.findNavController |
|||
import androidx.recyclerview.widget.GridLayoutManager |
|||
import com.google.android.material.transition.MaterialSharedAxis |
|||
import kotlinx.coroutines.launch |
|||
import org.yuzu.yuzu_emu.R |
|||
import org.yuzu.yuzu_emu.adapters.FolderAdapter |
|||
import org.yuzu.yuzu_emu.databinding.FragmentFoldersBinding |
|||
import org.yuzu.yuzu_emu.model.GamesViewModel |
|||
import org.yuzu.yuzu_emu.model.HomeViewModel |
|||
import org.yuzu.yuzu_emu.ui.main.MainActivity |
|||
|
|||
class GameFoldersFragment : Fragment() { |
|||
private var _binding: FragmentFoldersBinding? = null |
|||
private val binding get() = _binding!! |
|||
|
|||
private val homeViewModel: HomeViewModel by activityViewModels() |
|||
private val gamesViewModel: GamesViewModel by activityViewModels() |
|||
|
|||
override fun onCreate(savedInstanceState: Bundle?) { |
|||
super.onCreate(savedInstanceState) |
|||
enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true) |
|||
returnTransition = MaterialSharedAxis(MaterialSharedAxis.X, false) |
|||
reenterTransition = MaterialSharedAxis(MaterialSharedAxis.X, false) |
|||
|
|||
gamesViewModel.onOpenGameFoldersFragment() |
|||
} |
|||
|
|||
override fun onCreateView( |
|||
inflater: LayoutInflater, |
|||
container: ViewGroup?, |
|||
savedInstanceState: Bundle? |
|||
): View { |
|||
_binding = FragmentFoldersBinding.inflate(inflater) |
|||
return binding.root |
|||
} |
|||
|
|||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { |
|||
super.onViewCreated(view, savedInstanceState) |
|||
homeViewModel.setNavigationVisibility(visible = false, animated = true) |
|||
homeViewModel.setStatusBarShadeVisibility(visible = false) |
|||
|
|||
binding.toolbarFolders.setNavigationOnClickListener { |
|||
binding.root.findNavController().popBackStack() |
|||
} |
|||
|
|||
binding.listFolders.apply { |
|||
layoutManager = GridLayoutManager( |
|||
requireContext(), |
|||
resources.getInteger(R.integer.grid_columns) |
|||
) |
|||
adapter = FolderAdapter(requireActivity(), gamesViewModel) |
|||
} |
|||
|
|||
viewLifecycleOwner.lifecycleScope.launch { |
|||
repeatOnLifecycle(Lifecycle.State.CREATED) { |
|||
gamesViewModel.folders.collect { |
|||
(binding.listFolders.adapter as FolderAdapter).submitList(it) |
|||
} |
|||
} |
|||
} |
|||
|
|||
val mainActivity = requireActivity() as MainActivity |
|||
binding.buttonAdd.setOnClickListener { |
|||
mainActivity.getGamesDirectory.launch(Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).data) |
|||
} |
|||
|
|||
setInsets() |
|||
} |
|||
|
|||
override fun onStop() { |
|||
super.onStop() |
|||
gamesViewModel.onCloseGameFoldersFragment() |
|||
} |
|||
|
|||
private fun setInsets() = |
|||
ViewCompat.setOnApplyWindowInsetsListener( |
|||
binding.root |
|||
) { _: View, windowInsets: WindowInsetsCompat -> |
|||
val barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()) |
|||
val cutoutInsets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout()) |
|||
|
|||
val leftInsets = barInsets.left + cutoutInsets.left |
|||
val rightInsets = barInsets.right + cutoutInsets.right |
|||
|
|||
val mlpToolbar = binding.toolbarFolders.layoutParams as ViewGroup.MarginLayoutParams |
|||
mlpToolbar.leftMargin = leftInsets |
|||
mlpToolbar.rightMargin = rightInsets |
|||
binding.toolbarFolders.layoutParams = mlpToolbar |
|||
|
|||
val fabSpacing = resources.getDimensionPixelSize(R.dimen.spacing_fab) |
|||
val mlpFab = |
|||
binding.buttonAdd.layoutParams as ViewGroup.MarginLayoutParams |
|||
mlpFab.leftMargin = leftInsets + fabSpacing |
|||
mlpFab.rightMargin = rightInsets + fabSpacing |
|||
mlpFab.bottomMargin = barInsets.bottom + fabSpacing |
|||
binding.buttonAdd.layoutParams = mlpFab |
|||
|
|||
val mlpListFolders = binding.listFolders.layoutParams as ViewGroup.MarginLayoutParams |
|||
mlpListFolders.leftMargin = leftInsets |
|||
mlpListFolders.rightMargin = rightInsets |
|||
binding.listFolders.layoutParams = mlpListFolders |
|||
|
|||
binding.listFolders.updatePadding( |
|||
bottom = barInsets.bottom + |
|||
resources.getDimensionPixelSize(R.dimen.spacing_bottom_list_fab) |
|||
) |
|||
|
|||
windowInsets |
|||
} |
|||
} |
|||
@ -0,0 +1,13 @@ |
|||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
package org.yuzu.yuzu_emu.model |
|||
|
|||
import android.os.Parcelable |
|||
import kotlinx.parcelize.Parcelize |
|||
|
|||
@Parcelize |
|||
data class GameDir( |
|||
val uriString: String, |
|||
var deepScan: Boolean |
|||
) : Parcelable |
|||
@ -0,0 +1,70 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android" |
|||
xmlns:app="http://schemas.android.com/apk/res-auto" |
|||
xmlns:tools="http://schemas.android.com/tools" |
|||
style="?attr/materialCardViewOutlinedStyle" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="wrap_content" |
|||
android:layout_marginHorizontal="16dp" |
|||
android:layout_marginVertical="12dp" |
|||
android:focusable="true"> |
|||
|
|||
<androidx.constraintlayout.widget.ConstraintLayout |
|||
android:layout_width="match_parent" |
|||
android:layout_height="wrap_content" |
|||
android:orientation="horizontal" |
|||
android:padding="16dp" |
|||
android:layout_gravity="center_vertical" |
|||
android:animateLayoutChanges="true"> |
|||
|
|||
<com.google.android.material.textview.MaterialTextView |
|||
android:id="@+id/path" |
|||
style="@style/TextAppearance.Material3.BodyLarge" |
|||
android:layout_width="0dp" |
|||
android:layout_height="wrap_content" |
|||
android:layout_gravity="center_vertical|start" |
|||
android:ellipsize="none" |
|||
android:marqueeRepeatLimit="marquee_forever" |
|||
android:requiresFadingEdge="horizontal" |
|||
android:singleLine="true" |
|||
android:textAlignment="viewStart" |
|||
app:layout_constraintBottom_toBottomOf="parent" |
|||
app:layout_constraintEnd_toStartOf="@+id/button_layout" |
|||
app:layout_constraintStart_toStartOf="parent" |
|||
app:layout_constraintTop_toTopOf="parent" |
|||
tools:text="@string/select_gpu_driver_default" /> |
|||
|
|||
<LinearLayout |
|||
android:id="@+id/button_layout" |
|||
android:layout_width="wrap_content" |
|||
android:layout_height="wrap_content" |
|||
android:orientation="horizontal" |
|||
app:layout_constraintBottom_toBottomOf="parent" |
|||
app:layout_constraintEnd_toEndOf="parent" |
|||
app:layout_constraintTop_toTopOf="parent"> |
|||
|
|||
<Button |
|||
android:id="@+id/button_edit" |
|||
style="@style/Widget.Material3.Button.IconButton" |
|||
android:layout_width="wrap_content" |
|||
android:layout_height="wrap_content" |
|||
android:contentDescription="@string/delete" |
|||
android:tooltipText="@string/edit" |
|||
app:icon="@drawable/ic_edit" |
|||
app:iconTint="?attr/colorControlNormal" /> |
|||
|
|||
<Button |
|||
android:id="@+id/button_delete" |
|||
style="@style/Widget.Material3.Button.IconButton" |
|||
android:layout_width="wrap_content" |
|||
android:layout_height="wrap_content" |
|||
android:contentDescription="@string/delete" |
|||
android:tooltipText="@string/delete" |
|||
app:icon="@drawable/ic_delete" |
|||
app:iconTint="?attr/colorControlNormal" /> |
|||
|
|||
</LinearLayout> |
|||
|
|||
</androidx.constraintlayout.widget.ConstraintLayout> |
|||
|
|||
</com.google.android.material.card.MaterialCardView> |
|||
@ -0,0 +1,45 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
|||
xmlns:tools="http://schemas.android.com/tools" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="wrap_content" |
|||
android:padding="24dp" |
|||
android:orientation="vertical"> |
|||
|
|||
<com.google.android.material.textview.MaterialTextView |
|||
android:id="@+id/path" |
|||
style="@style/TextAppearance.Material3.BodyLarge" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="0dp" |
|||
android:layout_gravity="center_vertical|start" |
|||
android:layout_weight="1" |
|||
android:ellipsize="marquee" |
|||
android:marqueeRepeatLimit="marquee_forever" |
|||
android:requiresFadingEdge="horizontal" |
|||
android:singleLine="true" |
|||
android:textAlignment="viewStart" |
|||
tools:text="folder/folder/folder/folder" /> |
|||
|
|||
<LinearLayout |
|||
android:layout_width="match_parent" |
|||
android:layout_height="wrap_content" |
|||
android:orientation="horizontal" |
|||
android:paddingTop="8dp"> |
|||
|
|||
<com.google.android.material.textview.MaterialTextView |
|||
style="@style/TextAppearance.Material3.BodyMedium" |
|||
android:layout_width="0dp" |
|||
android:layout_height="wrap_content" |
|||
android:layout_gravity="center_vertical|start" |
|||
android:layout_weight="1" |
|||
android:text="@string/deep_scan" |
|||
android:textAlignment="viewStart" /> |
|||
|
|||
<com.google.android.material.checkbox.MaterialCheckBox |
|||
android:id="@+id/deep_scan_switch" |
|||
android:layout_width="wrap_content" |
|||
android:layout_height="wrap_content" /> |
|||
|
|||
</LinearLayout> |
|||
|
|||
</LinearLayout> |
|||
@ -0,0 +1,30 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="wrap_content" |
|||
android:padding="24dp" |
|||
android:orientation="vertical"> |
|||
|
|||
<LinearLayout |
|||
android:id="@+id/deep_scan_layout" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="wrap_content" |
|||
android:orientation="horizontal"> |
|||
|
|||
<com.google.android.material.textview.MaterialTextView |
|||
style="@style/TextAppearance.Material3.BodyMedium" |
|||
android:layout_width="0dp" |
|||
android:layout_height="wrap_content" |
|||
android:layout_gravity="center_vertical|start" |
|||
android:layout_weight="1" |
|||
android:text="@string/deep_scan" |
|||
android:textAlignment="viewStart" /> |
|||
|
|||
<com.google.android.material.checkbox.MaterialCheckBox |
|||
android:id="@+id/deep_scan_switch" |
|||
android:layout_width="wrap_content" |
|||
android:layout_height="wrap_content" /> |
|||
|
|||
</LinearLayout> |
|||
|
|||
</LinearLayout> |
|||
@ -0,0 +1,48 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" |
|||
xmlns:app="http://schemas.android.com/apk/res-auto" |
|||
android:id="@+id/coordinator_folders" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="match_parent" |
|||
android:background="?attr/colorSurface"> |
|||
|
|||
<androidx.coordinatorlayout.widget.CoordinatorLayout |
|||
android:layout_width="match_parent" |
|||
android:layout_height="match_parent"> |
|||
|
|||
<com.google.android.material.appbar.AppBarLayout |
|||
android:id="@+id/appbar_folders" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="wrap_content" |
|||
android:fitsSystemWindows="true" |
|||
app:liftOnScrollTargetViewId="@id/list_folders"> |
|||
|
|||
<com.google.android.material.appbar.MaterialToolbar |
|||
android:id="@+id/toolbar_folders" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="?attr/actionBarSize" |
|||
app:navigationIcon="@drawable/ic_back" |
|||
app:title="@string/game_folders" /> |
|||
|
|||
</com.google.android.material.appbar.AppBarLayout> |
|||
|
|||
<androidx.recyclerview.widget.RecyclerView |
|||
android:id="@+id/list_folders" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="wrap_content" |
|||
android:clipToPadding="false" |
|||
app:layout_behavior="@string/appbar_scrolling_view_behavior" /> |
|||
|
|||
</androidx.coordinatorlayout.widget.CoordinatorLayout> |
|||
|
|||
<com.google.android.material.floatingactionbutton.FloatingActionButton |
|||
android:id="@+id/button_add" |
|||
android:layout_width="wrap_content" |
|||
android:layout_height="wrap_content" |
|||
android:layout_gravity="bottom|end" |
|||
android:contentDescription="@string/add_games" |
|||
app:srcCompat="@drawable/ic_add" |
|||
app:layout_constraintBottom_toBottomOf="parent" |
|||
app:layout_constraintEnd_toEndOf="parent" /> |
|||
|
|||
</androidx.constraintlayout.widget.ConstraintLayout> |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue