Display fine permission explanation in empty views

This commit is contained in:
Nicolas Pomepuy 2024-10-15 08:48:28 +02:00 committed by Duncan McNamara
parent 61eeb101c2
commit 7d9760aab6
7 changed files with 89 additions and 27 deletions

View File

@ -839,6 +839,8 @@
<string name="welcome_title">Welcome to VLC!</string>
<string name="welcome_subtitle">The free and open source multimedia player</string>
<string name="permission_media">VLC needs your permission to access media on your device</string>
<string name="permission_video">VLC needs your permission to access video media on your device</string>
<string name="permission_audio">VLC needs your permission to access audio media on your device</string>
<string name="medialibrary_scan_explanation">VLC can automatically scan your device to organize your media collection.</string>
<string name="onboarding_theme_title">Make yourself at home</string>
<string name="done">Done</string>

View File

@ -61,31 +61,28 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/changelog" />
<TextView
android:id="@+id/remote_access_hash_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:text="@string/remote_access_hash_title"
android:textColor="?attr/font_light"
android:maxWidth="150dp"
app:layout_constraintBottom_toBottomOf="@+id/remote_access_revision"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/remote_access_version" />
<TextView
android:id="@+id/remote_access"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:text="@string/remote_access_version_title"
android:textColor="?attr/font_light"
app:layout_constraintBottom_toBottomOf="@+id/remote_access_version"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/divider2" />
<TextView
android:id="@+id/remote_access_hash_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="16dp"
android:text="@string/remote_access_hash_title"
android:textColor="?attr/font_light"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/compilation_barrier"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/remote_access" />
app:layout_constraintTop_toTopOf="@+id/remote_access_version" />
<TextView
android:id="@+id/textView28"
@ -281,7 +278,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="end"
app:constraint_referenced_ids="remote_access,textView28,textView30,textView29" />
app:constraint_referenced_ids="remote_access_hash_title,remote_access,textView28,textView30,textView29" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -25,6 +25,7 @@ import android.annotation.TargetApi
import android.app.Activity
import android.app.AlertDialog
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import android.view.KeyEvent
@ -162,6 +163,19 @@ class MainActivity : ContentActivity(),
configurationChanged(getScreenWidth())
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String?>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == 1000) {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
forceRefresh()
}
}
}
private fun prepareActionBar() {
toolbarIcon = findViewById(R.id.toolbar_icon)

View File

@ -46,6 +46,7 @@ import kotlinx.coroutines.launch
import org.videolan.medialibrary.interfaces.Medialibrary
import org.videolan.medialibrary.interfaces.media.MediaWrapper
import org.videolan.medialibrary.media.MediaLibraryItem
import org.videolan.resources.AppContextProvider
import org.videolan.resources.KEY_AUDIO_CURRENT_TAB
import org.videolan.resources.KEY_AUDIO_LAST_PLAYLIST
import org.videolan.resources.util.waitForML
@ -359,6 +360,7 @@ class AudioBrowserFragment : BaseAudioBrowser<AudioBrowserViewModel>() {
binding.audioEmptyLoading.emptyText = viewModel.filterQuery?.let { getString(R.string.empty_search, it) } ?: if (viewModel.providers[currentTab].onlyFavorites) getString(R.string.nofav) else getString(R.string.nomedia)
binding.audioEmptyLoading.state = when {
!Permissions.canReadStorage(requireActivity()) && empty -> EmptyLoadingState.MISSING_PERMISSION
!Permissions.canReadAudios(AppContextProvider.appContext) && empty -> EmptyLoadingState.MISSING_AUDIO_PERMISSION
viewModel.providers[currentTab].loading.value == true && empty -> EmptyLoadingState.LOADING
emptyAt(currentTab) && viewModel.filterQuery?.isNotEmpty() == true -> EmptyLoadingState.EMPTY_SEARCH
emptyAt(currentTab) && viewModel.providers[currentTab].onlyFavorites -> EmptyLoadingState.EMPTY_FAVORITES

View File

@ -349,6 +349,7 @@ class VideoGridFragment : MediaBrowserFragment<VideosViewModel>(), SwipeRefreshL
binding.emptyLoading.emptyText = viewModel.filterQuery?.let { getString(R.string.empty_search, it) } ?: if (viewModel.provider.onlyFavorites) getString(R.string.nofav) else getString(R.string.nomedia)
binding.emptyLoading.state = when {
!Permissions.canReadStorage(AppContextProvider.appContext) && empty -> EmptyLoadingState.MISSING_PERMISSION
!Permissions.canReadVideos(AppContextProvider.appContext) && empty -> EmptyLoadingState.MISSING_VIDEO_PERMISSION
empty && working -> EmptyLoadingState.LOADING
empty && !working && viewModel.provider.onlyFavorites -> EmptyLoadingState.EMPTY_FAVORITES
empty && !working && viewModel.filterQuery == null -> EmptyLoadingState.EMPTY

View File

@ -24,6 +24,7 @@
package org.videolan.vlc.gui.view
import android.Manifest
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
@ -38,14 +39,18 @@ import android.view.View
import android.widget.*
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
import androidx.core.app.ActivityCompat
import androidx.fragment.app.FragmentActivity
import androidx.transition.TransitionManager
import kotlinx.coroutines.launch
import org.videolan.resources.ACTIVITY_RESULT_PREFERENCES
import org.videolan.tools.AppScope
import org.videolan.vlc.R
import org.videolan.vlc.gui.BaseActivity
import org.videolan.vlc.gui.SecondaryActivity
import org.videolan.vlc.gui.helpers.getBitmapFromDrawable
import org.videolan.vlc.gui.helpers.hf.StoragePermissionsDelegate.Companion.askStoragePermission
import org.videolan.vlc.gui.helpers.hf.StoragePermissionsDelegate.Companion.getStoragePermission
class EmptyLoadingStateView : FrameLayout {
@ -74,13 +79,23 @@ class EmptyLoadingStateView : FrameLayout {
loadingFlipper.visibility = if (value == EmptyLoadingState.LOADING) View.VISIBLE else View.GONE
loadingTitle.visibility = if (value == EmptyLoadingState.LOADING) View.VISIBLE else View.GONE
emptyTextView.visibility = if (value in arrayOf(EmptyLoadingState.EMPTY, EmptyLoadingState.EMPTY_SEARCH, EmptyLoadingState.EMPTY_FAVORITES)) View.VISIBLE else View.GONE
emptyImageView.visibility = if (value in arrayOf(EmptyLoadingState.EMPTY,EmptyLoadingState.MISSING_PERMISSION, EmptyLoadingState.EMPTY_SEARCH, EmptyLoadingState.EMPTY_FAVORITES)) View.VISIBLE else View.GONE
emptyImageView.visibility = if (value in arrayOf(EmptyLoadingState.EMPTY,EmptyLoadingState.MISSING_PERMISSION,EmptyLoadingState.MISSING_VIDEO_PERMISSION, EmptyLoadingState.MISSING_AUDIO_PERMISSION, EmptyLoadingState.EMPTY_SEARCH, EmptyLoadingState.EMPTY_FAVORITES)) View.VISIBLE else View.GONE
emptyImageView.setImageBitmap(context.getBitmapFromDrawable(if (value == EmptyLoadingState.EMPTY_FAVORITES) R.drawable.ic_fav_empty else if (value in arrayOf(EmptyLoadingState.EMPTY, EmptyLoadingState.EMPTY_SEARCH, EmptyLoadingState.EMPTY_FAVORITES)) R.drawable.ic_empty else R.drawable.ic_empty_warning))
permissionTitle.visibility = if (value == EmptyLoadingState.MISSING_PERMISSION) View.VISIBLE else View.GONE
permissionTextView.visibility = if (value == EmptyLoadingState.MISSING_PERMISSION) View.VISIBLE else View.GONE
grantPermissionButton.visibility = if (value == EmptyLoadingState.MISSING_PERMISSION) View.VISIBLE else View.GONE
pickFileButton.visibility = if (value == EmptyLoadingState.MISSING_PERMISSION && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) View.VISIBLE else View.GONE
permissionTitle.visibility = if (value in arrayOf(EmptyLoadingState.MISSING_PERMISSION, EmptyLoadingState.MISSING_VIDEO_PERMISSION, EmptyLoadingState.MISSING_AUDIO_PERMISSION)) View.VISIBLE else View.GONE
permissionTextView.visibility = if (value in arrayOf(EmptyLoadingState.MISSING_PERMISSION, EmptyLoadingState.MISSING_VIDEO_PERMISSION, EmptyLoadingState.MISSING_AUDIO_PERMISSION)) View.VISIBLE else View.GONE
grantPermissionButton.visibility = if (value in arrayOf(EmptyLoadingState.MISSING_PERMISSION, EmptyLoadingState.MISSING_VIDEO_PERMISSION, EmptyLoadingState.MISSING_AUDIO_PERMISSION)) View.VISIBLE else View.GONE
pickFileButton.visibility = if (value in arrayOf(EmptyLoadingState.MISSING_PERMISSION, EmptyLoadingState.MISSING_VIDEO_PERMISSION, EmptyLoadingState.MISSING_AUDIO_PERMISSION) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) View.VISIBLE else View.GONE
noMediaButton.visibility = if (showNoMedia && value == EmptyLoadingState.EMPTY) View.VISIBLE else if (value == EmptyLoadingState.EMPTY_FAVORITES) View.INVISIBLE else View.GONE
permissionTextView.text = when (state) {
EmptyLoadingState.MISSING_VIDEO_PERMISSION -> context.getString(R.string.permission_video)
EmptyLoadingState.MISSING_AUDIO_PERMISSION -> context.getString(R.string.permission_audio)
else ->
buildString {
append(context.getString(R.string.permission_expanation_no_allow))
append("\n\n")
append(context.getString(R.string.permission_expanation_allow))
}
}
field = value
}
@ -139,15 +154,29 @@ class EmptyLoadingStateView : FrameLayout {
noMediaClickListener?.invoke()
}
grantPermissionButton.setOnClickListener {
(context as? FragmentActivity)?.askStoragePermission(false, null)
when (state) {
EmptyLoadingState.MISSING_AUDIO_PERMISSION -> ActivityCompat.requestPermissions(
context as Activity, arrayOf(
Manifest.permission.READ_MEDIA_AUDIO
), 1000
)
EmptyLoadingState.MISSING_VIDEO_PERMISSION -> ActivityCompat.requestPermissions(
context as Activity, arrayOf(
Manifest.permission.READ_MEDIA_VIDEO,
Manifest.permission.READ_MEDIA_IMAGES
), 1000
)
else -> (context as? FragmentActivity)?.askStoragePermission(false, null)
}
}
pickFileButton.setOnClickListener {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
(context as BaseActivity).openFile(Uri.parse(""))
}
}
permissionTextView.text = "${context.getString(R.string.permission_expanation_no_allow)}\n\n${context.getString(R.string.permission_expanation_allow)}"
}
private fun applyCompactMode() {
@ -172,5 +201,5 @@ class EmptyLoadingStateView : FrameLayout {
}
enum class EmptyLoadingState {
LOADING, EMPTY, EMPTY_SEARCH, NONE, MISSING_PERMISSION, EMPTY_FAVORITES
LOADING, EMPTY, EMPTY_SEARCH, NONE, MISSING_PERMISSION, MISSING_VIDEO_PERMISSION, MISSING_AUDIO_PERMISSION, EMPTY_FAVORITES
}

View File

@ -108,6 +108,23 @@ object Permissions {
) == PackageManager.PERMISSION_GRANTED || isExternalStorageManager()
}
fun canReadVideos(context: Context): Boolean {
return Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU || isExternalStorageManager() ||
ContextCompat.checkSelfPermission(
context,
Manifest.permission.READ_MEDIA_VIDEO
) == PackageManager.PERMISSION_GRANTED
}
fun canReadAudios(context: Context): Boolean {
return Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU || isExternalStorageManager() ||
ContextCompat.checkSelfPermission(
context,
Manifest.permission.READ_MEDIA_AUDIO
) == PackageManager.PERMISSION_GRANTED
}
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
private fun isAnyFileFinePermissionGranted(context: Context) = (
ContextCompat.checkSelfPermission(