mirror of
https://github.com/Lime3DS/Lime3DS.git
synced 2024-12-27 04:04:21 +01:00
android: Add game shortcuts to about game dialog (#313)
Adapted from https://github.com/mandarine3ds/mandarine/pull/47 Co-authored-by: Charles Lombardo <clombardo169@gmail.com> Co-authored-by: Ishan09811 <156402647+Ishan09811@users.noreply.github.com> Co-authored-by: OpenSauce04 <opensauce04@gmail.com>
This commit is contained in:
parent
973faeb9d7
commit
3d1936cf5c
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2023 Citra Emulator Project
|
// Copyright Citra Emulator Project / Lime3DS Emulator Project
|
||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
@ -95,7 +95,13 @@ class EmulationActivity : AppCompatActivity() {
|
|||||||
windowManager.defaultDisplay.rotation
|
windowManager.defaultDisplay.rotation
|
||||||
)
|
)
|
||||||
|
|
||||||
EmulationLifecycleUtil.addShutdownHook(hook = { this.finish() })
|
EmulationLifecycleUtil.addShutdownHook(hook = {
|
||||||
|
if (intent.getBooleanExtra("launched_from_shortcut", false)) {
|
||||||
|
finishAffinity()
|
||||||
|
} else {
|
||||||
|
this.finish()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
isEmulationRunning = true
|
isEmulationRunning = true
|
||||||
instance = this
|
instance = this
|
||||||
|
@ -14,6 +14,10 @@ import android.content.Context
|
|||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
import android.graphics.drawable.BitmapDrawable
|
||||||
|
import android.graphics.Bitmap
|
||||||
|
import android.content.pm.ShortcutInfo
|
||||||
|
import android.content.pm.ShortcutManager
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.documentfile.provider.DocumentFile
|
import androidx.documentfile.provider.DocumentFile
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
@ -23,6 +27,10 @@ import androidx.recyclerview.widget.AsyncDifferConfig
|
|||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.ListAdapter
|
import androidx.recyclerview.widget.ListAdapter
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import android.graphics.drawable.Icon
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import com.google.android.material.color.MaterialColors
|
import com.google.android.material.color.MaterialColors
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||||
@ -214,6 +222,24 @@ class GameAdapter(private val activity: AppCompatActivity, private val inflater:
|
|||||||
view.findNavController().navigate(action)
|
view.findNavController().navigate(action)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bottomSheetView.findViewById<MaterialButton>(R.id.game_shortcut).setOnClickListener {
|
||||||
|
val shortcutManager = activity.getSystemService(ShortcutManager::class.java)
|
||||||
|
|
||||||
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
val bitmap = (bottomSheetView.findViewById<ImageView>(R.id.game_icon).drawable as BitmapDrawable).bitmap
|
||||||
|
val icon = Icon.createWithBitmap(bitmap)
|
||||||
|
|
||||||
|
val shortcut = ShortcutInfo.Builder(context, game.title)
|
||||||
|
.setShortLabel(game.title)
|
||||||
|
.setIcon(icon)
|
||||||
|
.setIntent(game.launchIntent.apply {
|
||||||
|
putExtra("launched_from_shortcut", true)
|
||||||
|
})
|
||||||
|
.build()
|
||||||
|
shortcutManager.requestPinShortcut(shortcut, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bottomSheetView.findViewById<MaterialButton>(R.id.cheats).setOnClickListener {
|
bottomSheetView.findViewById<MaterialButton>(R.id.cheats).setOnClickListener {
|
||||||
val action = CheatsFragmentDirections.actionGlobalCheatsFragment(holder.game.titleId)
|
val action = CheatsFragmentDirections.actionGlobalCheatsFragment(holder.game.titleId)
|
||||||
view.findNavController().navigate(action)
|
view.findNavController().navigate(action)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2023 Citra Emulator Project
|
// Copyright Citra Emulator Project / Lime3DS Emulator Project
|
||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
@ -60,6 +60,7 @@ class GamesFragment : Fragment() {
|
|||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
homeViewModel.setNavigationVisibility(visible = true, animated = true)
|
homeViewModel.setNavigationVisibility(visible = true, animated = true)
|
||||||
homeViewModel.setStatusBarShadeVisibility(visible = true)
|
homeViewModel.setStatusBarShadeVisibility(visible = true)
|
||||||
|
|
||||||
val inflater = LayoutInflater.from(requireContext())
|
val inflater = LayoutInflater.from(requireContext())
|
||||||
|
|
||||||
binding.gridGames.apply {
|
binding.gridGames.apply {
|
||||||
|
@ -1,13 +1,17 @@
|
|||||||
// Copyright 2023 Citra Emulator Project
|
// Copyright Citra Emulator Project / Lime3DS Emulator Project
|
||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
package io.github.lime3ds.android.model
|
package io.github.lime3ds.android.model
|
||||||
|
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
|
import android.content.Intent
|
||||||
|
import android.net.Uri
|
||||||
import java.util.HashSet
|
import java.util.HashSet
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
import io.github.lime3ds.android.LimeApplication
|
||||||
|
import io.github.lime3ds.android.activities.EmulationActivity
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
@Serializable
|
@Serializable
|
||||||
@ -27,6 +31,16 @@ class Game(
|
|||||||
val keyAddedToLibraryTime get() = "${filename}_AddedToLibraryTime"
|
val keyAddedToLibraryTime get() = "${filename}_AddedToLibraryTime"
|
||||||
val keyLastPlayedTime get() = "${filename}_LastPlayed"
|
val keyLastPlayedTime get() = "${filename}_LastPlayed"
|
||||||
|
|
||||||
|
val launchIntent: Intent
|
||||||
|
get() = Intent(LimeApplication.appContext, EmulationActivity::class.java).apply {
|
||||||
|
action = Intent.ACTION_VIEW
|
||||||
|
data = if (isInstalled) {
|
||||||
|
LimeApplication.documentsTree.getUri(path)
|
||||||
|
} else {
|
||||||
|
Uri.parse(path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (other !is Game) {
|
if (other !is Game) {
|
||||||
return false
|
return false
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2023 Citra Emulator Project
|
// Copyright Citra Emulator Project / Lime3DS Emulator Project
|
||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
@ -100,6 +100,12 @@ class DocumentsTree {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
fun getUri(filepath: String): Uri {
|
||||||
|
val node = resolvePath(filepath) ?: return Uri.EMPTY
|
||||||
|
return node.uri ?: return Uri.EMPTY
|
||||||
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
fun isDirectory(filepath: String): Boolean {
|
fun isDirectory(filepath: String): Boolean {
|
||||||
val node = resolvePath(filepath) ?: return false
|
val node = resolvePath(filepath) ?: return false
|
||||||
|
10
src/android/app/src/main/res/drawable/ic_shortcut.xml
Normal file
10
src/android/app/src/main/res/drawable/ic_shortcut.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="960"
|
||||||
|
android:viewportHeight="960"
|
||||||
|
android:tint="?attr/colorControlNormal">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M280,920Q247,920 223.5,896.5Q200,873 200,840L200,120Q200,87 223.5,63.5Q247,40 280,40L680,40Q713,40 736.5,63.5Q760,87 760,120L760,280L680,280L680,240L280,240L280,720L680,720L680,680L760,680L760,840Q760,873 736.5,896.5Q713,920 680,920L280,920ZM686,520L480,520Q480,520 480,520Q480,520 480,520L480,640L400,640L400,520Q400,487 423.5,463.5Q447,440 480,440L686,440L624,376L680,320L840,480L680,640L624,584L686,520Z"/>
|
||||||
|
</vector>
|
@ -109,6 +109,17 @@
|
|||||||
android:focusedByDefault="true"
|
android:focusedByDefault="true"
|
||||||
android:text="@string/play"
|
android:text="@string/play"
|
||||||
app:icon="@drawable/ic_play" />
|
app:icon="@drawable/ic_play" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/game_shortcut"
|
||||||
|
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
|
||||||
|
android:layout_width="48dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:contentDescription="@string/shortcut"
|
||||||
|
app:icon="@drawable/ic_shortcut"
|
||||||
|
app:iconGravity="textStart" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
@ -141,4 +152,4 @@
|
|||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
@ -456,6 +456,7 @@
|
|||||||
|
|
||||||
<!-- About Game Dialog -->
|
<!-- About Game Dialog -->
|
||||||
<string name="play">Play</string>
|
<string name="play">Play</string>
|
||||||
|
<string name="shortcut">Shortcut</string>
|
||||||
|
|
||||||
<!-- Cheats -->
|
<!-- Cheats -->
|
||||||
<string name="cheats">Cheats</string>
|
<string name="cheats">Cheats</string>
|
||||||
|
Loading…
Reference in New Issue
Block a user