24 changed files with 703 additions and 9 deletions
-
32src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt
-
90src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AppletAdapter.kt
-
72src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/CabinetLauncherDialogAdapter.kt
-
113src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AppletLauncherFragment.kt
-
41src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/CabinetLauncherDialogFragment.kt
-
15src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt
-
5src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/MessageDialogFragment.kt
-
55src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Applet.kt
-
10src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt
-
3src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt
-
2src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/DirectoryInitialization.kt
-
45src/android/app/src/main/jni/native.cpp
-
9src/android/app/src/main/res/drawable/ic_album.xml
-
9src/android/app/src/main/res/drawable/ic_applet.xml
-
9src/android/app/src/main/res/drawable/ic_edit.xml
-
18src/android/app/src/main/res/drawable/ic_mii.xml
-
9src/android/app/src/main/res/drawable/ic_refresh.xml
-
9src/android/app/src/main/res/drawable/ic_restore.xml
-
57src/android/app/src/main/res/layout/card_applet_option.xml
-
15src/android/app/src/main/res/layout/dialog_list.xml
-
30src/android/app/src/main/res/layout/dialog_list_item.xml
-
31src/android/app/src/main/res/layout/fragment_applet_launcher.xml
-
15src/android/app/src/main/res/navigation/home_navigation.xml
-
18src/android/app/src/main/res/values/strings.xml
@ -0,0 +1,90 @@ |
|||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
package org.yuzu.yuzu_emu.adapters |
|||
|
|||
import android.view.LayoutInflater |
|||
import android.view.View |
|||
import android.view.ViewGroup |
|||
import android.widget.Toast |
|||
import androidx.core.content.res.ResourcesCompat |
|||
import androidx.fragment.app.FragmentActivity |
|||
import androidx.navigation.findNavController |
|||
import androidx.recyclerview.widget.RecyclerView |
|||
import org.yuzu.yuzu_emu.HomeNavigationDirections |
|||
import org.yuzu.yuzu_emu.NativeLibrary |
|||
import org.yuzu.yuzu_emu.R |
|||
import org.yuzu.yuzu_emu.YuzuApplication |
|||
import org.yuzu.yuzu_emu.databinding.CardAppletOptionBinding |
|||
import org.yuzu.yuzu_emu.model.Applet |
|||
import org.yuzu.yuzu_emu.model.AppletInfo |
|||
import org.yuzu.yuzu_emu.model.Game |
|||
|
|||
class AppletAdapter(val activity: FragmentActivity, var applets: List<Applet>) : |
|||
RecyclerView.Adapter<AppletAdapter.AppletViewHolder>(), |
|||
View.OnClickListener { |
|||
|
|||
override fun onCreateViewHolder( |
|||
parent: ViewGroup, |
|||
viewType: Int |
|||
): AppletAdapter.AppletViewHolder { |
|||
CardAppletOptionBinding.inflate(LayoutInflater.from(parent.context), parent, false) |
|||
.apply { root.setOnClickListener(this@AppletAdapter) } |
|||
.also { return AppletViewHolder(it) } |
|||
} |
|||
|
|||
override fun onBindViewHolder(holder: AppletViewHolder, position: Int) = |
|||
holder.bind(applets[position]) |
|||
|
|||
override fun getItemCount(): Int = applets.size |
|||
|
|||
override fun onClick(view: View) { |
|||
val applet = (view.tag as AppletViewHolder).applet |
|||
val appletPath = NativeLibrary.getAppletLaunchPath(applet.appletInfo.entryId) |
|||
if (appletPath.isEmpty()) { |
|||
Toast.makeText( |
|||
YuzuApplication.appContext, |
|||
R.string.applets_error_applet, |
|||
Toast.LENGTH_SHORT |
|||
).show() |
|||
return |
|||
} |
|||
|
|||
if (applet.appletInfo == AppletInfo.Cabinet) { |
|||
view.findNavController() |
|||
.navigate(R.id.action_appletLauncherFragment_to_cabinetLauncherDialogFragment) |
|||
return |
|||
} |
|||
|
|||
NativeLibrary.setCurrentAppletId(applet.appletInfo.appletId) |
|||
val appletGame = Game( |
|||
title = YuzuApplication.appContext.getString(applet.titleId), |
|||
path = appletPath |
|||
) |
|||
val action = HomeNavigationDirections.actionGlobalEmulationActivity(appletGame) |
|||
view.findNavController().navigate(action) |
|||
} |
|||
|
|||
inner class AppletViewHolder(val binding: CardAppletOptionBinding) : |
|||
RecyclerView.ViewHolder(binding.root) { |
|||
lateinit var applet: Applet |
|||
|
|||
init { |
|||
itemView.tag = this |
|||
} |
|||
|
|||
fun bind(applet: Applet) { |
|||
this.applet = applet |
|||
|
|||
binding.title.setText(applet.titleId) |
|||
binding.description.setText(applet.descriptionId) |
|||
binding.icon.setImageDrawable( |
|||
ResourcesCompat.getDrawable( |
|||
binding.icon.context.resources, |
|||
applet.iconId, |
|||
binding.icon.context.theme |
|||
) |
|||
) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,72 @@ |
|||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
package org.yuzu.yuzu_emu.adapters |
|||
|
|||
import android.view.LayoutInflater |
|||
import android.view.View |
|||
import android.view.ViewGroup |
|||
import androidx.core.content.res.ResourcesCompat |
|||
import androidx.fragment.app.Fragment |
|||
import androidx.navigation.fragment.findNavController |
|||
import androidx.recyclerview.widget.RecyclerView |
|||
import org.yuzu.yuzu_emu.HomeNavigationDirections |
|||
import org.yuzu.yuzu_emu.NativeLibrary |
|||
import org.yuzu.yuzu_emu.R |
|||
import org.yuzu.yuzu_emu.YuzuApplication |
|||
import org.yuzu.yuzu_emu.databinding.DialogListItemBinding |
|||
import org.yuzu.yuzu_emu.model.CabinetMode |
|||
import org.yuzu.yuzu_emu.adapters.CabinetLauncherDialogAdapter.CabinetModeViewHolder |
|||
import org.yuzu.yuzu_emu.model.AppletInfo |
|||
import org.yuzu.yuzu_emu.model.Game |
|||
|
|||
class CabinetLauncherDialogAdapter(val fragment: Fragment) : |
|||
RecyclerView.Adapter<CabinetModeViewHolder>(), |
|||
View.OnClickListener { |
|||
private val cabinetModes = CabinetMode.values().copyOfRange(1, CabinetMode.values().size) |
|||
|
|||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CabinetModeViewHolder { |
|||
DialogListItemBinding.inflate(LayoutInflater.from(parent.context), parent, false) |
|||
.apply { root.setOnClickListener(this@CabinetLauncherDialogAdapter) } |
|||
.also { return CabinetModeViewHolder(it) } |
|||
} |
|||
|
|||
override fun getItemCount(): Int = cabinetModes.size |
|||
|
|||
override fun onBindViewHolder(holder: CabinetModeViewHolder, position: Int) = |
|||
holder.bind(cabinetModes[position]) |
|||
|
|||
override fun onClick(view: View) { |
|||
val mode = (view.tag as CabinetModeViewHolder).cabinetMode |
|||
val appletPath = NativeLibrary.getAppletLaunchPath(AppletInfo.Cabinet.entryId) |
|||
NativeLibrary.setCurrentAppletId(AppletInfo.Cabinet.appletId) |
|||
NativeLibrary.setCabinetMode(mode.id) |
|||
val appletGame = Game( |
|||
title = YuzuApplication.appContext.getString(R.string.cabinet_applet), |
|||
path = appletPath |
|||
) |
|||
val action = HomeNavigationDirections.actionGlobalEmulationActivity(appletGame) |
|||
fragment.findNavController().navigate(action) |
|||
} |
|||
|
|||
inner class CabinetModeViewHolder(val binding: DialogListItemBinding) : |
|||
RecyclerView.ViewHolder(binding.root) { |
|||
lateinit var cabinetMode: CabinetMode |
|||
|
|||
init { |
|||
itemView.tag = this |
|||
} |
|||
|
|||
fun bind(cabinetMode: CabinetMode) { |
|||
this.cabinetMode = cabinetMode |
|||
binding.icon.setImageDrawable( |
|||
ResourcesCompat.getDrawable( |
|||
binding.icon.context.resources, |
|||
cabinetMode.iconId, |
|||
binding.icon.context.theme |
|||
) |
|||
) |
|||
binding.title.setText(cabinetMode.titleId) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,113 @@ |
|||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
package org.yuzu.yuzu_emu.fragments |
|||
|
|||
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.navigation.findNavController |
|||
import androidx.recyclerview.widget.GridLayoutManager |
|||
import com.google.android.material.transition.MaterialSharedAxis |
|||
import org.yuzu.yuzu_emu.R |
|||
import org.yuzu.yuzu_emu.adapters.AppletAdapter |
|||
import org.yuzu.yuzu_emu.databinding.FragmentAppletLauncherBinding |
|||
import org.yuzu.yuzu_emu.model.Applet |
|||
import org.yuzu.yuzu_emu.model.AppletInfo |
|||
import org.yuzu.yuzu_emu.model.HomeViewModel |
|||
|
|||
class AppletLauncherFragment : Fragment() { |
|||
private var _binding: FragmentAppletLauncherBinding? = null |
|||
private val binding get() = _binding!! |
|||
|
|||
private val homeViewModel: HomeViewModel 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) |
|||
} |
|||
|
|||
override fun onCreateView( |
|||
inflater: LayoutInflater, |
|||
container: ViewGroup?, |
|||
savedInstanceState: Bundle? |
|||
): View { |
|||
_binding = FragmentAppletLauncherBinding.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.toolbarApplets.setNavigationOnClickListener { |
|||
binding.root.findNavController().popBackStack() |
|||
} |
|||
|
|||
val applets = listOf( |
|||
Applet( |
|||
R.string.album_applet, |
|||
R.string.album_applet_description, |
|||
R.drawable.ic_album, |
|||
AppletInfo.PhotoViewer |
|||
), |
|||
Applet( |
|||
R.string.cabinet_applet, |
|||
R.string.cabinet_applet_description, |
|||
R.drawable.ic_nfc, |
|||
AppletInfo.Cabinet |
|||
), |
|||
Applet( |
|||
R.string.mii_edit_applet, |
|||
R.string.mii_edit_applet_description, |
|||
R.drawable.ic_mii, |
|||
AppletInfo.MiiEdit |
|||
) |
|||
) |
|||
|
|||
binding.listApplets.apply { |
|||
layoutManager = GridLayoutManager( |
|||
requireContext(), |
|||
resources.getInteger(R.integer.grid_columns) |
|||
) |
|||
adapter = AppletAdapter(requireActivity(), applets) |
|||
} |
|||
|
|||
setInsets() |
|||
} |
|||
|
|||
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 mlpAppBar = binding.toolbarApplets.layoutParams as ViewGroup.MarginLayoutParams |
|||
mlpAppBar.leftMargin = leftInsets |
|||
mlpAppBar.rightMargin = rightInsets |
|||
binding.toolbarApplets.layoutParams = mlpAppBar |
|||
|
|||
val mlpListApplets = |
|||
binding.listApplets.layoutParams as ViewGroup.MarginLayoutParams |
|||
mlpListApplets.leftMargin = leftInsets |
|||
mlpListApplets.rightMargin = rightInsets |
|||
binding.listApplets.layoutParams = mlpListApplets |
|||
|
|||
binding.listApplets.updatePadding(bottom = barInsets.bottom) |
|||
|
|||
windowInsets |
|||
} |
|||
} |
|||
@ -0,0 +1,41 @@ |
|||
// 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.os.Bundle |
|||
import android.view.LayoutInflater |
|||
import android.view.View |
|||
import android.view.ViewGroup |
|||
import androidx.fragment.app.DialogFragment |
|||
import androidx.recyclerview.widget.LinearLayoutManager |
|||
import com.google.android.material.dialog.MaterialAlertDialogBuilder |
|||
import org.yuzu.yuzu_emu.R |
|||
import org.yuzu.yuzu_emu.adapters.CabinetLauncherDialogAdapter |
|||
import org.yuzu.yuzu_emu.databinding.DialogListBinding |
|||
|
|||
class CabinetLauncherDialogFragment : DialogFragment() { |
|||
private lateinit var binding: DialogListBinding |
|||
|
|||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { |
|||
binding = DialogListBinding.inflate(layoutInflater) |
|||
binding.dialogList.apply { |
|||
layoutManager = LinearLayoutManager(requireContext()) |
|||
adapter = CabinetLauncherDialogAdapter(this@CabinetLauncherDialogFragment) |
|||
} |
|||
|
|||
return MaterialAlertDialogBuilder(requireContext()) |
|||
.setTitle(R.string.cabinet_launcher) |
|||
.setView(binding.root) |
|||
.create() |
|||
} |
|||
|
|||
override fun onCreateView( |
|||
inflater: LayoutInflater, |
|||
container: ViewGroup?, |
|||
savedInstanceState: Bundle? |
|||
): View { |
|||
return binding.root |
|||
} |
|||
} |
|||
@ -0,0 +1,55 @@ |
|||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
package org.yuzu.yuzu_emu.model |
|||
|
|||
import androidx.annotation.DrawableRes |
|||
import androidx.annotation.StringRes |
|||
import org.yuzu.yuzu_emu.R |
|||
|
|||
data class Applet( |
|||
@StringRes val titleId: Int, |
|||
@StringRes val descriptionId: Int, |
|||
@DrawableRes val iconId: Int, |
|||
val appletInfo: AppletInfo, |
|||
val cabinetMode: CabinetMode = CabinetMode.None |
|||
) |
|||
|
|||
// Combination of Common::AM::Applets::AppletId enum and the entry id |
|||
enum class AppletInfo(val appletId: Int, val entryId: Long = 0) { |
|||
None(0x00), |
|||
Application(0x01), |
|||
OverlayDisplay(0x02), |
|||
QLaunch(0x03), |
|||
Starter(0x04), |
|||
Auth(0x0A), |
|||
Cabinet(0x0B, 0x0100000000001002), |
|||
Controller(0x0C), |
|||
DataErase(0x0D), |
|||
Error(0x0E), |
|||
NetConnect(0x0F), |
|||
ProfileSelect(0x10), |
|||
SoftwareKeyboard(0x11), |
|||
MiiEdit(0x12, 0x0100000000001009), |
|||
Web(0x13), |
|||
Shop(0x14), |
|||
PhotoViewer(0x015, 0x010000000000100D), |
|||
Settings(0x16), |
|||
OfflineWeb(0x17), |
|||
LoginShare(0x18), |
|||
WebAuth(0x19), |
|||
MyPage(0x1A) |
|||
} |
|||
|
|||
// Matches enum in Service::NFP::CabinetMode with extra metadata |
|||
enum class CabinetMode( |
|||
val id: Int, |
|||
@StringRes val titleId: Int = 0, |
|||
@DrawableRes val iconId: Int = 0 |
|||
) { |
|||
None(-1), |
|||
StartNicknameAndOwnerSettings(0, R.string.cabinet_nickname_and_owner, R.drawable.ic_edit), |
|||
StartGameDataEraser(1, R.string.cabinet_game_data_eraser, R.drawable.ic_refresh), |
|||
StartRestorer(2, R.string.cabinet_restorer, R.drawable.ic_restore), |
|||
StartFormatter(3, R.string.cabinet_formatter, R.drawable.ic_clear) |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
|||
android:width="24dp" |
|||
android:height="24dp" |
|||
android:viewportWidth="24" |
|||
android:viewportHeight="24"> |
|||
<path |
|||
android:fillColor="?attr/colorControlNormal" |
|||
android:pathData="M21,19V5c0,-1.1 -0.9,-2 -2,-2H5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2zM8.5,13.5l2.5,3.01L14.5,12l4.5,6H5l3.5,-4.5z" /> |
|||
</vector> |
|||
@ -0,0 +1,9 @@ |
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
|||
android:width="24dp" |
|||
android:height="24dp" |
|||
android:viewportWidth="24" |
|||
android:viewportHeight="24"> |
|||
<path |
|||
android:fillColor="?attr/colorControlNormal" |
|||
android:pathData="M17,16l-4,-4V8.82C14.16,8.4 15,7.3 15,6c0,-1.66 -1.34,-3 -3,-3S9,4.34 9,6c0,1.3 0.84,2.4 2,2.82V12l-4,4H3v5h5v-3.05l4,-4.2 4,4.2V21h5v-5h-4z" /> |
|||
</vector> |
|||
@ -0,0 +1,9 @@ |
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
|||
android:width="24dp" |
|||
android:height="24dp" |
|||
android:viewportWidth="24" |
|||
android:viewportHeight="24"> |
|||
<path |
|||
android:fillColor="?attr/colorControlNormal" |
|||
android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z" /> |
|||
</vector> |
|||
@ -0,0 +1,18 @@ |
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
|||
android:width="24dp" |
|||
android:height="24dp" |
|||
android:viewportWidth="24" |
|||
android:viewportHeight="24"> |
|||
<path |
|||
android:fillColor="?attr/colorControlNormal" |
|||
android:pathData="M9,13m-1.25,0a1.25,1.25 0,1 1,2.5 0a1.25,1.25 0,1 1,-2.5 0" /> |
|||
<path |
|||
android:fillColor="?attr/colorControlNormal" |
|||
android:pathData="M20.77,8.58l-0.92,2.01c0.09,0.46 0.15,0.93 0.15,1.41 0,4.41 -3.59,8 -8,8s-8,-3.59 -8,-8c0,-0.05 0.01,-0.1 0,-0.14 2.6,-0.98 4.69,-2.99 5.74,-5.55C11.58,8.56 14.37,10 17.5,10c0.45,0 0.89,-0.04 1.33,-0.1l-0.6,-1.32 -0.88,-1.93 -1.93,-0.88 -2.79,-1.27 2.79,-1.27 0.71,-0.32C14.87,2.33 13.47,2 12,2 6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10c0,-1.47 -0.33,-2.87 -0.9,-4.13l-0.33,0.71z" /> |
|||
<path |
|||
android:fillColor="?attr/colorControlNormal" |
|||
android:pathData="M15,13m-1.25,0a1.25,1.25 0,1 1,2.5 0a1.25,1.25 0,1 1,-2.5 0" /> |
|||
<path |
|||
android:fillColor="?attr/colorControlNormal" |
|||
android:pathData="M20.6,5.6L19.5,8l-1.1,-2.4L16,4.5l2.4,-1.1L19.5,1l1.1,2.4L23,4.5z" /> |
|||
</vector> |
|||
@ -0,0 +1,9 @@ |
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
|||
android:width="24dp" |
|||
android:height="24dp" |
|||
android:viewportWidth="24" |
|||
android:viewportHeight="24"> |
|||
<path |
|||
android:fillColor="?attr/colorControlNormal" |
|||
android:pathData="M17.65,6.35C16.2,4.9 14.21,4 12,4c-4.42,0 -7.99,3.58 -7.99,8s3.57,8 7.99,8c3.73,0 6.84,-2.55 7.73,-6h-2.08c-0.82,2.33 -3.04,4 -5.65,4 -3.31,0 -6,-2.69 -6,-6s2.69,-6 6,-6c1.66,0 3.14,0.69 4.22,1.78L13,11h7V4l-2.35,2.35z" /> |
|||
</vector> |
|||
@ -0,0 +1,9 @@ |
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
|||
android:width="24dp" |
|||
android:height="24dp" |
|||
android:viewportWidth="24" |
|||
android:viewportHeight="24"> |
|||
<path |
|||
android:fillColor="?attr/colorControlNormal" |
|||
android:pathData="M13,3c-4.97,0 -9,4.03 -9,9L1,12l3.89,3.89 0.07,0.14L9,12L6,12c0,-3.87 3.13,-7 7,-7s7,3.13 7,7 -3.13,7 -7,7c-1.93,0 -3.68,-0.79 -4.94,-2.06l-1.42,1.42C8.27,19.99 10.51,21 13,21c4.97,0 9,-4.03 9,-9s-4.03,-9 -9,-9zM12,8v5l4.28,2.54 0.72,-1.21 -3.5,-2.08L13.5,8L12,8z" /> |
|||
</vector> |
|||
@ -0,0 +1,57 @@ |
|||
<?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:background="?attr/selectableItemBackground" |
|||
android:clickable="true" |
|||
android:focusable="true"> |
|||
|
|||
<LinearLayout |
|||
android:layout_width="match_parent" |
|||
android:layout_height="wrap_content" |
|||
android:orientation="horizontal" |
|||
android:layout_gravity="center" |
|||
android:padding="24dp"> |
|||
|
|||
<ImageView |
|||
android:id="@+id/icon" |
|||
android:layout_width="24dp" |
|||
android:layout_height="24dp" |
|||
android:layout_marginEnd="20dp" |
|||
android:layout_gravity="center_vertical" |
|||
app:tint="?attr/colorOnSurface" /> |
|||
|
|||
<LinearLayout |
|||
android:layout_width="0dp" |
|||
android:layout_height="wrap_content" |
|||
android:layout_weight="1" |
|||
android:orientation="vertical" |
|||
android:layout_gravity="center_vertical"> |
|||
|
|||
<com.google.android.material.textview.MaterialTextView |
|||
android:id="@+id/title" |
|||
style="@style/TextAppearance.Material3.TitleMedium" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="wrap_content" |
|||
android:textAlignment="viewStart" |
|||
tools:text="@string/applets" /> |
|||
|
|||
<com.google.android.material.textview.MaterialTextView |
|||
android:id="@+id/description" |
|||
style="@style/TextAppearance.Material3.BodyMedium" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="wrap_content" |
|||
android:layout_marginTop="6dp" |
|||
android:textAlignment="viewStart" |
|||
tools:text="@string/applets_description" /> |
|||
|
|||
</LinearLayout> |
|||
|
|||
</LinearLayout> |
|||
|
|||
</com.google.android.material.card.MaterialCardView> |
|||
@ -0,0 +1,15 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="wrap_content"> |
|||
|
|||
<androidx.recyclerview.widget.RecyclerView |
|||
android:id="@+id/dialog_list" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="wrap_content" |
|||
android:clipToPadding="false" |
|||
android:fadeScrollbars="false" |
|||
android:paddingVertical="12dp" |
|||
android:scrollbars="vertical" /> |
|||
|
|||
</androidx.appcompat.widget.LinearLayoutCompat> |
|||
@ -0,0 +1,30 @@ |
|||
<?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:background="?attr/selectableItemBackground" |
|||
android:clickable="true" |
|||
android:focusable="true" |
|||
android:orientation="horizontal" |
|||
android:paddingHorizontal="24dp" |
|||
android:paddingVertical="16dp"> |
|||
|
|||
<ImageView |
|||
android:id="@+id/icon" |
|||
android:layout_width="20dp" |
|||
android:layout_height="20dp" |
|||
android:layout_gravity="center" |
|||
tools:src="@drawable/ic_nfc" /> |
|||
|
|||
<com.google.android.material.textview.MaterialTextView |
|||
android:id="@+id/title" |
|||
style="@style/TextAppearance.Material3.BodyMedium" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="wrap_content" |
|||
android:layout_marginStart="16dp" |
|||
android:layout_gravity="center_vertical|start" |
|||
android:textAlignment="viewStart" |
|||
tools:text="List option" /> |
|||
|
|||
</LinearLayout> |
|||
@ -0,0 +1,31 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" |
|||
xmlns:app="http://schemas.android.com/apk/res-auto" |
|||
android:id="@+id/coordinator_applets" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="match_parent" |
|||
android:background="?attr/colorSurface"> |
|||
|
|||
<com.google.android.material.appbar.AppBarLayout |
|||
android:id="@+id/appbar_applets" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="wrap_content" |
|||
android:fitsSystemWindows="true"> |
|||
|
|||
<com.google.android.material.appbar.MaterialToolbar |
|||
android:id="@+id/toolbar_applets" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="?attr/actionBarSize" |
|||
app:navigationIcon="@drawable/ic_back" |
|||
app:title="@string/applets" /> |
|||
|
|||
</com.google.android.material.appbar.AppBarLayout> |
|||
|
|||
<androidx.recyclerview.widget.RecyclerView |
|||
android:id="@+id/list_applets" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="match_parent" |
|||
android:clipToPadding="false" |
|||
app:layout_behavior="@string/appbar_scrolling_view_behavior" /> |
|||
|
|||
</androidx.coordinatorlayout.widget.CoordinatorLayout> |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue