mirror of
https://github.com/YTVanced/VancedManager
synced 2024-11-24 20:25:13 +00:00
Revert "Added an option to switch between internal and external storage"
This reverts commit 98c4b88961
.
This commit is contained in:
parent
f82dc4eecf
commit
a570aae1a1
18 changed files with 44 additions and 210 deletions
|
@ -24,6 +24,6 @@ object MicrogDownloader {
|
|||
fun startMicrogInstall(context: Context) {
|
||||
installing.postValue(true)
|
||||
postReset()
|
||||
install(context.getFilePathInStorage("$folderName/$fileName"), context)
|
||||
install("$folderName/$fileName".managerFilepath, context)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -68,6 +68,6 @@ object MusicDownloader {
|
|||
if (variant == "root")
|
||||
installMusicRoot(context)
|
||||
else
|
||||
install(context.getFilePathInStorage("music/nonroot/nonroot.apk"), context)
|
||||
install("music/nonroot/nonroot.apk".managerFilepath, context)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ object VancedDownloader {
|
|||
prefs = context.installPrefs
|
||||
variant = defPrefs.managerVariant
|
||||
folderName = "vanced/$variant"
|
||||
downloadPath = context.getFilePathInStorage(folderName!!)
|
||||
downloadPath = context.getExternalFilesDir(folderName)?.path
|
||||
File(downloadPath.toString()).deleteRecursively()
|
||||
prefs.lang?.let {
|
||||
lang = it.split(", ").toMutableList()
|
||||
|
|
|
@ -102,7 +102,7 @@ class MainActivity : AppCompatActivity() {
|
|||
setFinalTheme()
|
||||
super.onResume()
|
||||
Crowdin.registerDataLoadingObserver(loadingObserver)
|
||||
if (defPrefs.managerStorage == externalPath && !canAccessStorage(this)) {
|
||||
if (!canAccessStorage(this)) {
|
||||
DialogContainer.storageDialog(this)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ object DialogContainer {
|
|||
setMessage(R.string.storage_access_required_summary)
|
||||
setPositiveButton(R.string.auth_dialog_ok) { dialog, _ ->
|
||||
dialog.cancel()
|
||||
requestStoragePerms(activity, null)
|
||||
requestStoragePerms(activity)
|
||||
}
|
||||
setCancelable(false)
|
||||
create()
|
||||
|
|
|
@ -1,67 +0,0 @@
|
|||
package com.vanced.manager.ui.dialogs
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.preference.PreferenceManager.getDefaultSharedPreferences
|
||||
import com.google.android.material.radiobutton.MaterialRadioButton
|
||||
import com.vanced.manager.core.ui.base.BindingBottomSheetDialogFragment
|
||||
import com.vanced.manager.databinding.DialogManagerStorageBinding
|
||||
import com.vanced.manager.utils.*
|
||||
|
||||
class ManagerStorageDialog : BindingBottomSheetDialogFragment<DialogManagerStorageBinding>() {
|
||||
|
||||
private val permissionLauncher = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { results ->
|
||||
if (results.all { it.value == true }) {
|
||||
prefs.managerStorage = externalPath
|
||||
} else {
|
||||
prefs.managerStorage = internalPath
|
||||
}
|
||||
dismiss()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun newInstance(): ManagerStorageDialog = ManagerStorageDialog().apply {
|
||||
arguments = Bundle()
|
||||
}
|
||||
}
|
||||
|
||||
private val prefs by lazy { getDefaultSharedPreferences(requireActivity()) }
|
||||
|
||||
override fun binding(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
) = DialogManagerStorageBinding.inflate(inflater, container, false)
|
||||
|
||||
override fun otherSetups() {
|
||||
bindData()
|
||||
}
|
||||
|
||||
private fun bindData() {
|
||||
with(binding) {
|
||||
val storage = prefs.managerStorage
|
||||
root.findViewWithTag<MaterialRadioButton>(storage).isChecked = true
|
||||
storageSave.setOnClickListener {
|
||||
val newPref = storageRadiogroup.checkedButtonTag
|
||||
if (storage != newPref) {
|
||||
if (newPref == externalPath) {
|
||||
if (!canAccessStorage(requireActivity())) {
|
||||
return@setOnClickListener requestStoragePerms(requireActivity(), permissionLauncher)
|
||||
}
|
||||
|
||||
prefs.managerStorage = externalPath
|
||||
} else {
|
||||
prefs.managerStorage = internalPath
|
||||
}
|
||||
dismiss()
|
||||
requireActivity().recreate()
|
||||
} else {
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,7 +10,7 @@ import com.vanced.manager.core.ui.base.BindingFragment
|
|||
import com.vanced.manager.databinding.FragmentLogBinding
|
||||
import com.vanced.manager.utils.AppUtils
|
||||
import com.vanced.manager.utils.AppUtils.logs
|
||||
import com.vanced.manager.utils.getFilePathInStorage
|
||||
import com.vanced.manager.utils.managerFilepath
|
||||
import com.vanced.manager.utils.performStorageAction
|
||||
import java.io.File
|
||||
import java.io.FileWriter
|
||||
|
@ -42,7 +42,7 @@ class LogFragment : BindingFragment<FragmentLogBinding>() {
|
|||
val second = calendar.get(Calendar.SECOND)
|
||||
try {
|
||||
performStorageAction(requireActivity()) {
|
||||
val logPath = File(requireActivity().getFilePathInStorage("logs")).apply {
|
||||
val logPath = File("logs".managerFilepath).apply {
|
||||
if (!exists()) {
|
||||
mkdirs()
|
||||
}
|
||||
|
|
|
@ -19,7 +19,10 @@ import com.vanced.manager.core.ui.base.BindingFragment
|
|||
import com.vanced.manager.core.ui.ext.showDialog
|
||||
import com.vanced.manager.databinding.FragmentSettingsBinding
|
||||
import com.vanced.manager.ui.dialogs.*
|
||||
import com.vanced.manager.utils.*
|
||||
import com.vanced.manager.utils.accentColor
|
||||
import com.vanced.manager.utils.defAccentColor
|
||||
import com.vanced.manager.utils.getLanguageFormat
|
||||
import com.vanced.manager.utils.toHex
|
||||
import java.io.File
|
||||
|
||||
class SettingsFragment : BindingFragment<FragmentSettingsBinding>() {
|
||||
|
@ -57,7 +60,6 @@ class SettingsFragment : BindingFragment<FragmentSettingsBinding>() {
|
|||
bindManagerTheme()
|
||||
bindManagerAccentColor()
|
||||
bindManagerLanguage()
|
||||
bindManagerStorage()
|
||||
selectApps.setOnClickListener { showDialog(SelectAppsDialog()) }
|
||||
}
|
||||
}
|
||||
|
@ -84,21 +86,6 @@ class SettingsFragment : BindingFragment<FragmentSettingsBinding>() {
|
|||
}
|
||||
}
|
||||
|
||||
private fun FragmentSettingsBinding.bindManagerStorage() {
|
||||
managerStorage.apply {
|
||||
setSummary(
|
||||
getString(
|
||||
if (prefs.managerStorage == externalPath) {
|
||||
R.string.storage_external
|
||||
} else {
|
||||
R.string.storage_internal
|
||||
}
|
||||
)
|
||||
)
|
||||
setOnClickListener { showDialog(ManagerStorageDialog()) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun FragmentSettingsBinding.bindServiceDTimer() {
|
||||
servicedTimer.apply {
|
||||
if (variant == "root") this.isVisible = true
|
||||
|
@ -109,13 +96,10 @@ class SettingsFragment : BindingFragment<FragmentSettingsBinding>() {
|
|||
private fun FragmentSettingsBinding.bindClearFiles() {
|
||||
clearFiles.setOnClickListener {
|
||||
with(requireActivity()) {
|
||||
performStorageAction(this) { managerPath ->
|
||||
if (File(managerPath).deleteRecursively()) {
|
||||
Toast.makeText(this, getString(R.string.cleared_files), Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
Toast.makeText(this, getString(R.string.clear_files_failed), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
listOf("vanced/nonroot", "vanced/root", "music/nonroot", "music/root", "microg").forEach { dir ->
|
||||
File(getExternalFilesDir(dir)?.path.toString()).deleteRecursively()
|
||||
}
|
||||
Toast.makeText(this, getString(R.string.cleared_files), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -110,7 +110,7 @@ class HomeViewModel(private val activity: FragmentActivity): ViewModel() {
|
|||
activity.getString(R.string.vanced) -> {
|
||||
when (variant) {
|
||||
"nonroot" -> {
|
||||
if (vancedInstallFilesExist(activity)) {
|
||||
if (vancedInstallFilesExist()) {
|
||||
InstallationFilesDetectedDialog.newInstance(app).show(activity)
|
||||
} else {
|
||||
VancedPreferencesDialog().show(activity)
|
||||
|
@ -124,7 +124,7 @@ class HomeViewModel(private val activity: FragmentActivity): ViewModel() {
|
|||
activity.getString(R.string.music) -> {
|
||||
when (variant) {
|
||||
"nonroot" -> {
|
||||
if (musicApkExists(activity)) {
|
||||
if (musicApkExists()) {
|
||||
InstallationFilesDetectedDialog.newInstance(app).show(activity)
|
||||
} else {
|
||||
MusicPreferencesDialog().show(activity)
|
||||
|
@ -136,7 +136,7 @@ class HomeViewModel(private val activity: FragmentActivity): ViewModel() {
|
|||
}
|
||||
}
|
||||
activity.getString(R.string.microg) -> {
|
||||
if (apkExist("microg.apk", activity)) {
|
||||
if (apkExist("microg.apk")) {
|
||||
InstallationFilesDetectedDialog.newInstance(app).show(activity)
|
||||
} else {
|
||||
AppDownloadDialog.newInstance(app).show(activity)
|
||||
|
|
|
@ -49,7 +49,7 @@ object DownloadHelper : CoroutineScope by CoroutineScope(Dispatchers.IO) {
|
|||
override fun onResponse(call: Call<ResponseBody>, response: Response<ResponseBody>) {
|
||||
if (response.isSuccessful) {
|
||||
launch {
|
||||
if (response.body()?.let { writeFile(it, fileFolder, fileName, context) } == true) {
|
||||
if (response.body()?.let { writeFile(it, fileFolder, fileName) } == true) {
|
||||
onDownloadComplete()
|
||||
} else {
|
||||
onError(response.errorBody().toString())
|
||||
|
@ -78,12 +78,12 @@ object DownloadHelper : CoroutineScope by CoroutineScope(Dispatchers.IO) {
|
|||
})
|
||||
}
|
||||
|
||||
fun writeFile(body: ResponseBody, folderName: String, fileName: String, context: Context): Boolean =
|
||||
fun writeFile(body: ResponseBody, folderName: String, fileName: String): Boolean =
|
||||
try {
|
||||
val totalBytes = body.contentLength()
|
||||
val fileReader = ByteArray(8096)
|
||||
var downloadedBytes: Long = 0
|
||||
val dir = File(context.getFilePathInStorage(folderName)).apply {
|
||||
val dir = File(managerPath, folderName).apply {
|
||||
if (!exists()) {
|
||||
mkdirs()
|
||||
}
|
||||
|
@ -114,7 +114,7 @@ object DownloadHelper : CoroutineScope by CoroutineScope(Dispatchers.IO) {
|
|||
"manager.apk",
|
||||
context,
|
||||
onDownloadComplete = {
|
||||
val apk = File(context.getFilePathInStorage("manager/manager.apk"))
|
||||
val apk = File("manager/manager.apk".managerFilepath)
|
||||
val uri =
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
|
||||
FileProvider.getUriForFile(context, "${context.packageName}.provider", apk)
|
||||
|
|
|
@ -19,6 +19,8 @@ import java.util.*
|
|||
|
||||
val RadioGroup.checkedButtonTag: String? get() = findViewById<MaterialRadioButton>(checkedRadioButtonId)?.tag?.toString()
|
||||
|
||||
val String.managerFilepath get() = "$managerPath/$this"
|
||||
|
||||
fun DialogFragment.show(activity: FragmentActivity) {
|
||||
try {
|
||||
show(activity.supportFragmentManager, "")
|
||||
|
|
|
@ -100,16 +100,16 @@ object PackageHelper {
|
|||
}
|
||||
}
|
||||
|
||||
fun apkExist(apk: String, context: Context): Boolean {
|
||||
val apkPath = File(context.getFilePathInStorage("${apk.removeSuffix(".apk")}/$apk"))
|
||||
fun apkExist(apk: String): Boolean {
|
||||
val apkPath = File("${apk.removeSuffix(".apk")}/$apk".managerFilepath)
|
||||
if (apkPath.exists())
|
||||
return true
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
fun musicApkExists(context: Context): Boolean {
|
||||
val apkPath = File(context.getFilePathInStorage("music/nonroot/nonroot.apk"))
|
||||
fun musicApkExists(): Boolean {
|
||||
val apkPath = File("music/nonroot/nonroot.apk".managerFilepath)
|
||||
if (apkPath.exists()) {
|
||||
return true
|
||||
}
|
||||
|
@ -117,8 +117,8 @@ object PackageHelper {
|
|||
return false
|
||||
}
|
||||
|
||||
fun vancedInstallFilesExist(context: Context): Boolean {
|
||||
val apksPath = File(context.getFilePathInStorage("vanced/nonroot"))
|
||||
fun vancedInstallFilesExist(): Boolean {
|
||||
val apksPath = File("vanced/nonroot".managerFilepath)
|
||||
val splitFiles = mutableListOf<String>()
|
||||
if (apksPath.exists()) {
|
||||
val files = apksPath.listFiles()
|
||||
|
@ -212,7 +212,7 @@ object PackageHelper {
|
|||
|
||||
private fun installRootApp(context: Context, app: String, appVerCode: Int?, pkg: String, modApkBool: (fileName: String) -> Boolean) = CoroutineScope(Dispatchers.IO).launch {
|
||||
Shell.getShell {
|
||||
val apkFilesPath = context.getFilePathInStorage("$app/root")
|
||||
val apkFilesPath = "$app/root".managerFilepath
|
||||
val files = File(apkFilesPath).listFiles()?.toList()
|
||||
if (files != null) {
|
||||
val modApk: File? = files.lastOrNull { modApkBool(it.name) }
|
||||
|
@ -268,7 +268,7 @@ object PackageHelper {
|
|||
appName: String
|
||||
) {
|
||||
val packageInstaller = context.packageManager.packageInstaller
|
||||
val folder = File(context.getFilePathInStorage("$appName/nonroot"))
|
||||
val folder = File("$appName/nonroot".managerFilepath)
|
||||
var session: PackageInstaller.Session? = null
|
||||
val sessionId: Int
|
||||
val sessionParams = PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL)
|
||||
|
|
|
@ -19,10 +19,6 @@ var SharedPreferences.managerVariant
|
|||
get() = getString("vanced_variant", "nonroot")
|
||||
set(value) = edit { putString("vanced_variant", value) }
|
||||
|
||||
var SharedPreferences.managerStorage
|
||||
get() = getString("manager_storage", internalPath)
|
||||
set(value) = edit { putString("manager_storage", value) }
|
||||
|
||||
var SharedPreferences.managerLang
|
||||
get() = getString("manager_lang", "System Default")
|
||||
set(value) = edit { putString("manager_lang", value) }
|
||||
|
|
|
@ -1,63 +1,40 @@
|
|||
package com.vanced.manager.utils
|
||||
|
||||
import android.Manifest
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import android.os.Environment
|
||||
import android.provider.Settings
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import com.vanced.manager.ui.MainActivity
|
||||
import com.vanced.manager.ui.dialogs.DialogContainer.storageDialog
|
||||
|
||||
const val storage = "/storage/emulated/0"
|
||||
|
||||
const val internalPath = "$storage/Android/data/com.vanced.manager/files"
|
||||
const val externalPath = "$storage/Vanced Manager"
|
||||
|
||||
val Context.managerPath: String
|
||||
get() {
|
||||
var path = defPrefs.managerStorage ?: internalPath
|
||||
|
||||
if (path == externalPath && !canAccessStorage(this)) {
|
||||
path = internalPath
|
||||
}
|
||||
|
||||
return path
|
||||
}
|
||||
|
||||
fun Context.getFilePathInStorage(child: String): String = "$managerPath/$child"
|
||||
|
||||
|
||||
inline fun performStorageAction(activity: FragmentActivity, action: (managerPath: String) -> Unit) {
|
||||
val managerPath = activity.managerPath
|
||||
|
||||
if (managerPath == internalPath) {
|
||||
return action(managerPath)
|
||||
}
|
||||
@Suppress("DEPRECATION")
|
||||
val managerPath get() = "${Environment.getExternalStorageDirectory().path}/Vanced Manager"
|
||||
|
||||
inline fun performStorageAction(activity: FragmentActivity, action: () -> Unit) {
|
||||
if (canAccessStorage(activity)) {
|
||||
action(managerPath)
|
||||
action()
|
||||
} else {
|
||||
storageDialog(activity)
|
||||
}
|
||||
}
|
||||
|
||||
fun canAccessStorage(context: Context): Boolean = when {
|
||||
fun canAccessStorage(activity: FragmentActivity): Boolean = when {
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.R -> Environment.isExternalStorageManager()
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M -> {
|
||||
listOf(
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE
|
||||
).all {
|
||||
context.checkSelfPermission(it) == PackageManager.PERMISSION_GRANTED
|
||||
activity.checkSelfPermission(it) == PackageManager.PERMISSION_GRANTED
|
||||
}
|
||||
}
|
||||
else -> true
|
||||
}
|
||||
|
||||
fun requestStoragePerms(activity: FragmentActivity, permissionLauncher: ActivityResultLauncher<Array<String>>?) {
|
||||
fun requestStoragePerms(activity: FragmentActivity) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
activity.startActivity(
|
||||
Intent(
|
||||
|
@ -65,11 +42,12 @@ fun requestStoragePerms(activity: FragmentActivity, permissionLauncher: Activity
|
|||
)
|
||||
)
|
||||
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
permissionLauncher?.launch(
|
||||
activity.requestPermissions(
|
||||
arrayOf(
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE,
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE
|
||||
)
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE
|
||||
),
|
||||
MainActivity.REQUEST_CODE
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
style="@style/BottomDialogCard">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:text="@string/storage"
|
||||
style="@style/BottomDialogCardTitle" />
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<RadioGroup
|
||||
android:id="@+id/storage_radiogroup"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
tools:ignore="HardcodedText">
|
||||
|
||||
<com.vanced.manager.ui.core.ThemedMaterialRadioButton
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:tag="@string/internal_storage_path"
|
||||
android:text="@string/storage_internal"
|
||||
android:textSize="18sp" />
|
||||
|
||||
<com.vanced.manager.ui.core.ThemedMaterialRadioButton
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:tag="@string/external_storage_path"
|
||||
android:text="@string/storage_external"
|
||||
android:textSize="18sp" />
|
||||
</RadioGroup>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
<com.vanced.manager.ui.core.ThemedMaterialButton
|
||||
android:id="@+id/storage_save"
|
||||
android:text="@string/save"
|
||||
style="@style/BottomDialogButtonStyle" />
|
||||
</LinearLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
|
@ -49,12 +49,6 @@
|
|||
android:layout_height="wrap_content"
|
||||
app:preference_title="@string/variant" />
|
||||
|
||||
<com.vanced.manager.ui.core.EmptyPreference
|
||||
android:id="@+id/manager_storage"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:preference_title="@string/storage" />
|
||||
|
||||
<com.vanced.manager.ui.core.EmptyPreference
|
||||
android:id="@+id/serviced_timer"
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
@ -16,7 +16,4 @@
|
|||
<!-- prefs -->
|
||||
<string name="use_custom_tabs" translatable="false">use_custom_tabs</string>
|
||||
|
||||
<string name="internal_storage_path" translatable="false">/storage/emulated/0/Android/data/com.vanced.manager/files</string>
|
||||
<string name="external_storage_path" translatable="false">/storage/emulated/0/Vanced Manager</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -50,7 +50,6 @@
|
|||
<string name="category_appearance">Appearance</string>
|
||||
<string name="category_behaviour">Behavior</string>
|
||||
<string name="clear_files">Clear downloaded files</string>
|
||||
<string name="clear_files_failed">Failed to clear files</string>
|
||||
<string name="cleared_files">Successfully cleared files</string>
|
||||
<string name="firebase_summary">This lets us collect information about app performance and crash logs</string>
|
||||
<string name="firebase_title">Firebase Analytics</string>
|
||||
|
@ -96,11 +95,8 @@
|
|||
<string name="please_be_patient">Please do NOT exit the app during this process!</string>
|
||||
<string name="redownload">Redownload</string>
|
||||
<string name="security_context">Make sure that you downloaded the app from vancedapp.com, the Vanced Discord server, or the Vanced GitHub</string>
|
||||
<string name="storage">Storage</string>
|
||||
<string name="storage_access_required">Storage access required</string>
|
||||
<string name="storage_access_required_summary">In order for Vanced Manager to work, you must grant the storage permission</string>
|
||||
<string name="storage_external">Internal Storage</string>
|
||||
<string name="storage_internal">App-Specific Storage</string>
|
||||
<string name="version">Version</string>
|
||||
<string name="welcome">Welcome</string>
|
||||
|
||||
|
|
Loading…
Reference in a new issue