Skip to content

Commit

Permalink
Don't show the notification permission request as the first screen (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
mebarbosa authored Dec 13, 2024
1 parent ccfa7c4 commit 3fb03a0
Show file tree
Hide file tree
Showing 4 changed files with 198 additions and 66 deletions.
72 changes: 28 additions & 44 deletions app/src/main/java/au/com/shiftyjelly/pocketcasts/ui/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
package au.com.shiftyjelly.pocketcasts.ui

import android.Manifest
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Intent
import android.content.pm.PackageManager
import android.content.res.Configuration
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
Expand All @@ -21,7 +17,6 @@ import androidx.appcompat.widget.Toolbar
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.platform.ComposeView
import androidx.core.content.ContextCompat
import androidx.core.view.doOnLayout
import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
Expand Down Expand Up @@ -142,6 +137,7 @@ import au.com.shiftyjelly.pocketcasts.ui.helper.StatusBarColor
import au.com.shiftyjelly.pocketcasts.ui.theme.Theme
import au.com.shiftyjelly.pocketcasts.ui.theme.ThemeColor
import au.com.shiftyjelly.pocketcasts.utils.Network
import au.com.shiftyjelly.pocketcasts.utils.NotificationPermissionHelper
import au.com.shiftyjelly.pocketcasts.utils.featureflag.Feature
import au.com.shiftyjelly.pocketcasts.utils.featureflag.FeatureFlag
import au.com.shiftyjelly.pocketcasts.utils.log.LogBuffer
Expand Down Expand Up @@ -311,43 +307,6 @@ class MainActivity :

private val deepLinkFactory = DeepLinkFactory()

@SuppressLint("WrongConstant") // for custom snackbar duration constant
private fun checkForNotificationPermission(onPermissionGranted: () -> Unit = {}) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
when {
ContextCompat.checkSelfPermission(
this, Manifest.permission.POST_NOTIFICATIONS,
) == PackageManager.PERMISSION_GRANTED -> {
onPermissionGranted()
}
shouldShowRequestPermissionRationale(Manifest.permission.POST_NOTIFICATIONS) -> {
if (settings.isNotificationsDisabledMessageShown()) return
Snackbar.make(
findViewById(R.id.root),
getString(LR.string.notifications_blocked_warning),
EXTRA_LONG_SNACKBAR_DURATION_MS,
).setAction(
getString(LR.string.notifications_blocked_warning_snackbar_action)
.uppercase(Locale.getDefault()),
) {
// Responds to click on the action
val intent = Intent(AndroidProviderSettings.ACTION_APPLICATION_DETAILS_SETTINGS)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
val uri: Uri = Uri.fromParts("package", packageName, null)
intent.data = uri
startActivity(intent)
}.show()
settings.setNotificationsDisabledMessageShown(true)
}
else -> {
notificationPermissionLauncher.launch(
Manifest.permission.POST_NOTIFICATIONS,
)
}
}
}
}

override fun onCreate(savedInstanceState: Bundle?) {
Timber.d("Main Activity onCreate")
super.onCreate(savedInstanceState)
Expand All @@ -364,7 +323,6 @@ class MainActivity :
binding = ActivityMainBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
checkForNotificationPermission()

binding.bottomNavigation.doOnLayout {
val miniPlayerHeight = miniPlayerHeight
Expand Down Expand Up @@ -1597,7 +1555,33 @@ class MainActivity :
}

override fun checkNotificationPermission(onPermissionGranted: () -> Unit) {
checkForNotificationPermission(onPermissionGranted)
NotificationPermissionHelper.checkForNotificationPermission(
this,
notificationPermissionLauncher,
onShowRequestPermissionRationale = {
if (settings.isNotificationsDisabledMessageShown()) return@checkForNotificationPermission

Snackbar.make(
findViewById(R.id.root),
getString(LR.string.notifications_blocked_warning),
EXTRA_LONG_SNACKBAR_DURATION_MS,
).setAction(
getString(LR.string.notifications_blocked_warning_snackbar_action)
.uppercase(Locale.getDefault()),
) {
// Responds to click on the action
val intent = Intent(AndroidProviderSettings.ACTION_APPLICATION_DETAILS_SETTINGS)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
val uri: Uri = Uri.fromParts("package", packageName, null)
intent.data = uri
startActivity(intent)
}.show()

settings.setNotificationsDisabledMessageShown(true)
},
onPermissionGranted = onPermissionGranted,
onPermissionHandlingNotRequired = {},
)
}

private fun showPlayerBookmarks() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package au.com.shiftyjelly.pocketcasts.podcasts.view.podcast

import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.os.Parcelable
import android.view.LayoutInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import androidx.core.os.BundleCompat
Expand Down Expand Up @@ -67,6 +70,7 @@ import au.com.shiftyjelly.pocketcasts.ui.helper.FragmentHostListener
import au.com.shiftyjelly.pocketcasts.ui.helper.StatusBarColor
import au.com.shiftyjelly.pocketcasts.ui.images.CoilManager
import au.com.shiftyjelly.pocketcasts.ui.theme.ThemeColor
import au.com.shiftyjelly.pocketcasts.utils.NotificationPermissionHelper
import au.com.shiftyjelly.pocketcasts.utils.extensions.dpToPx
import au.com.shiftyjelly.pocketcasts.utils.featureflag.Feature
import au.com.shiftyjelly.pocketcasts.utils.featureflag.FeatureFlag
Expand All @@ -84,7 +88,9 @@ import au.com.shiftyjelly.pocketcasts.views.helper.UiUtil
import au.com.shiftyjelly.pocketcasts.views.multiselect.MultiSelectBookmarksHelper.NavigationState
import au.com.shiftyjelly.pocketcasts.views.multiselect.MultiSelectHelper
import au.com.shiftyjelly.pocketcasts.views.multiselect.MultiSelectToolbar
import com.google.android.material.snackbar.Snackbar
import dagger.hilt.android.AndroidEntryPoint
import java.util.Locale
import javax.inject.Inject
import kotlin.time.Duration.Companion.seconds
import kotlinx.coroutines.Dispatchers
Expand Down Expand Up @@ -166,6 +172,14 @@ class PodcastFragment : BaseFragment(), Toolbar.OnMenuItemClickListener {

private var listState: Parcelable? = null

private val notificationPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission(),
) { isGranted ->
if (isGranted) {
viewModel.toggleNotifications(requireContext())
}
}

private val onScrollListener = object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {}

Expand Down Expand Up @@ -484,8 +498,29 @@ class PodcastFragment : BaseFragment(), Toolbar.OnMenuItemClickListener {
}

private val onNotificationsClicked: () -> Unit = {
context?.let {
viewModel.toggleNotifications(it)
context?.let { context ->
NotificationPermissionHelper.checkForNotificationPermission(
requireActivity(),
launcher = notificationPermissionLauncher,
onShowRequestPermissionRationale = {
(activity as? FragmentHostListener)?.snackBarView()?.let { snackBarView ->
Snackbar.make(snackBarView, getString(LR.string.notifications_blocked_warning), Snackbar.LENGTH_LONG)
.setAction(
getString(LR.string.notifications_blocked_warning_snackbar_action)
.uppercase(Locale.getDefault()),
) {
// Open app settings for the user to enable permissions
val intent = Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
val uri: Uri = Uri.fromParts("package", requireContext().packageName, null)
intent.data = uri
startActivity(intent)
}.show()
}
},
onPermissionGranted = { viewModel.toggleNotifications(context) },
onPermissionHandlingNotRequired = { viewModel.toggleNotifications(context) },
)
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package au.com.shiftyjelly.pocketcasts.settings

import android.content.Intent
import android.media.RingtoneManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.view.View
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.widget.Toolbar
import androidx.core.content.IntentCompat.getParcelableExtra
import androidx.core.view.updatePadding
Expand All @@ -26,7 +28,10 @@ import au.com.shiftyjelly.pocketcasts.preferences.model.NotificationVibrateSetti
import au.com.shiftyjelly.pocketcasts.preferences.model.PlayOverNotificationSetting
import au.com.shiftyjelly.pocketcasts.repositories.notification.NotificationHelper
import au.com.shiftyjelly.pocketcasts.repositories.podcast.PodcastManager
import au.com.shiftyjelly.pocketcasts.ui.helper.FragmentHostListener
import au.com.shiftyjelly.pocketcasts.ui.theme.Theme
import au.com.shiftyjelly.pocketcasts.utils.NotificationPermissionHelper
import au.com.shiftyjelly.pocketcasts.utils.NotificationPermissionHelper.hasNotificationPermissionGranted
import au.com.shiftyjelly.pocketcasts.views.extensions.findToolbar
import au.com.shiftyjelly.pocketcasts.views.extensions.setup
import au.com.shiftyjelly.pocketcasts.views.fragments.PodcastSelectFragment
Expand All @@ -37,7 +42,9 @@ import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.list.MultiChoiceListener
import com.afollestad.materialdialogs.list.listItemsMultiChoice
import com.afollestad.materialdialogs.list.updateListItemsMultiChoice
import com.google.android.material.snackbar.Snackbar
import dagger.hilt.android.AndroidEntryPoint
import java.util.Locale
import javax.inject.Inject
import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.CoroutineScope
Expand Down Expand Up @@ -83,6 +90,16 @@ class NotificationsSettingsFragment :
private val toolbar
get() = view?.findViewById<Toolbar>(R.id.toolbar)

private var pendingNotificationValue: Boolean = false

private val notificationPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission(),
) { granted ->
if (granted) {
updateNotificationToggle(pendingNotificationValue)
}
}

override val coroutineContext: CoroutineContext
get() = Dispatchers.Default

Expand Down Expand Up @@ -425,31 +442,36 @@ class NotificationsSettingsFragment :
private fun setupEnabledNotifications() {
launch(Dispatchers.Default) {
val enabled = settings.notifyRefreshPodcast.flow.value
val hasPermissionGranted = hasNotificationPermissionGranted(requireContext())

launch(Dispatchers.Main) {
enabledPreference?.isChecked = enabled
enabledPreferences(enabled)
updateNotificationToggle(enabled && hasPermissionGranted)
enabledPreferences(enabled && hasPermissionGranted)

enabledPreference?.setOnPreferenceChangeListener { _, newValue ->
val checked = newValue as Boolean
settings.notifyRefreshPodcast.set(checked, updateModifiedAt = true)

analyticsTracker.track(
AnalyticsEvent.SETTINGS_NOTIFICATIONS_NEW_EPISODES_TOGGLED,
mapOf("enabled" to checked),
)

lifecycleScope.launch {
podcastManager.updateAllShowNotifications(checked)
// Don't change the podcasts summary until after the podcasts have been updated
changePodcastsSummary()
}
if (checked) {
settings.setNotificationLastSeenToNow()
pendingNotificationValue = newValue as Boolean

if (!pendingNotificationValue || hasNotificationPermissionGranted(requireContext())) {
onNotifyNotificationsChange(pendingNotificationValue)
true
} else {
context?.let {
NotificationPermissionHelper.checkForNotificationPermission(
requireActivity(),
launcher = notificationPermissionLauncher,
onShowRequestPermissionRationale = {
showSnackbarPermissionBlocked()
},
onPermissionGranted = {
updateNotificationToggle(pendingNotificationValue)
},
onPermissionHandlingNotRequired = {
updateNotificationToggle(pendingNotificationValue)
},
)
}
false
}
enabledPreferences(checked)

true
}

notificationPodcasts?.setOnPreferenceClickListener {
Expand All @@ -465,6 +487,46 @@ class NotificationsSettingsFragment :
}
}

private fun showSnackbarPermissionBlocked() {
(activity as? FragmentHostListener)?.snackBarView()?.let { snackBarView ->
Snackbar.make(snackBarView, getString(LR.string.notifications_blocked_warning), Snackbar.LENGTH_LONG)
.setAction(
getString(LR.string.notifications_blocked_warning_snackbar_action)
.uppercase(Locale.getDefault()),
) {
val intent = Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
val uri: Uri = Uri.fromParts("package", requireContext().packageName, null)
intent.data = uri
startActivity(intent)
}.show()
}
}

private fun onNotifyNotificationsChange(newValue: Boolean) {
settings.notifyRefreshPodcast.set(newValue, updateModifiedAt = true)

analyticsTracker.track(
AnalyticsEvent.SETTINGS_NOTIFICATIONS_NEW_EPISODES_TOGGLED,
mapOf("enabled" to newValue),
)

lifecycleScope.launch {
podcastManager.updateAllShowNotifications(newValue)
// Don't change the podcasts summary until after the podcasts have been updated
changePodcastsSummary()
}
if (newValue) {
settings.setNotificationLastSeenToNow()
}
enabledPreferences(newValue)
}

private fun updateNotificationToggle(newValue: Boolean) {
enabledPreference?.isChecked = newValue
onNotifyNotificationsChange(newValue)
}

private fun setupNotificationVibrate() {
vibratePreference?.let {
val options = arrayOf(
Expand Down
Loading

0 comments on commit 3fb03a0

Please sign in to comment.