Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: add notification permissions and bump min sdk to 24 #809

Merged
merged 1 commit into from
Dec 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package co.anitrend.core.android.helpers.notification

import android.Manifest
import android.content.Context
import android.os.Build
import androidx.core.app.ActivityCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
import androidx.core.content.PermissionChecker.PERMISSION_GRANTED
import androidx.fragment.app.FragmentActivity
import co.anitrend.core.android.helpers.notification.NotificationHelper.Companion.POST_NOTIFICATION_PERMISSION_REQUEST_CODE
import co.anitrend.core.android.helpers.notification.config.NotificationConfig


fun Context.hasNotificationPermissionFor(config: NotificationConfig): Boolean {
val hasPermission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) == PERMISSION_GRANTED
} else {
NotificationManagerCompat.from(this).areNotificationsEnabled()
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && hasPermission) {
val channel = NotificationManagerCompat.from(this).getNotificationChannel(config.name)
if (channel != null && channel.importance == config.importance) {
return false
}
}
return hasPermission
}

fun FragmentActivity.requestPostNotificationPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && ContextCompat.checkSelfPermission(
/* context = */ this,
/* permission = */ Manifest.permission.POST_NOTIFICATIONS,
) != PERMISSION_GRANTED
) {
ActivityCompat.requestPermissions(
/* activity = */ this,
/* permissions = */ arrayOf(Manifest.permission.POST_NOTIFICATIONS),
/* requestCode = */ POST_NOTIFICATION_PERMISSION_REQUEST_CODE,
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package co.anitrend.core.android.helpers.notification

import android.app.NotificationChannel
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import co.anitrend.core.android.helpers.notification.config.NotificationConfig

class NotificationHelper(
private val notificationManager: NotificationManagerCompat
) {

@RequiresApi(Build.VERSION_CODES.O)
fun createNotificationChannels() {
val channels = NotificationConfig.entries.map { config ->
return with (NotificationChannel(config.name, config.title, config.importance)) {
description = config.description
group = config.group
setShowBadge(true)
enableLights(false)
}
}
notificationManager.createNotificationChannels(channels)
}

companion object {
const val POST_NOTIFICATION_PERMISSION_REQUEST_CODE = 0x12

fun notificationVisibilityFor(isAdult: Boolean) =
if (isAdult) NotificationCompat.VISIBILITY_SECRET else NotificationCompat.VISIBILITY_PUBLIC
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package co.anitrend.core.android.helpers.notification.config

import android.app.NotificationManager

enum class NotificationConfig(
val title: String,
val description: String,
val importance: Int,
val group: String,
) {
GENERAL(
title = "General",
description = "AniTrend specific notifications",
importance = NotificationManager.IMPORTANCE_DEFAULT,
group = "co.anitrend.notification.group.GENERAL",
),
ANILIST(
title = "AniList",
description = "AniList related notifications",
importance = NotificationManager.IMPORTANCE_DEFAULT,
group = "co.anitrend.notification.group.ANILIST",
),
ANNOUNCEMENT(
title = "Announcements",
description = "Announcements and other important information",
importance = NotificationManager.IMPORTANCE_HIGH,
group = "co.anitrend.notification.group.ANNOUNCEMENT",
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@ package co.anitrend.core.android.koin
import android.content.pm.ShortcutManager
import android.net.ConnectivityManager
import android.os.PowerManager
import androidx.core.app.NotificationManagerCompat
import co.anitrend.arch.extension.dispatchers.SupportDispatcher
import co.anitrend.arch.extension.dispatchers.contract.ISupportDispatcher
import co.anitrend.arch.extension.ext.systemServiceOf
import co.anitrend.arch.extension.util.date.contract.AbstractSupportDateHelper
import co.anitrend.core.android.controller.power.AndroidPowerController
import co.anitrend.core.android.controller.power.contract.IPowerController
import co.anitrend.core.android.helpers.date.AniTrendDateHelper
import co.anitrend.core.android.helpers.notification.NotificationHelper
import co.anitrend.core.android.settings.Settings
import co.anitrend.core.android.settings.helper.config.ConfigurationHelper
import co.anitrend.core.android.settings.helper.config.contract.IConfigurationHelper
Expand Down Expand Up @@ -68,6 +70,13 @@ private val coreModule = module {
val localeHelper = get<ILocaleHelper>()
PrettyTime(localeHelper.locale)
}

factory {
NotificationHelper(
notificationManager = NotificationManagerCompat
.from(androidContext())
)
}
}

private val configurationModule = module {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ abstract class AniTrendScreen : SupportActivity(), AndroidScopeComponent, KoinSc

override val scope by activityRetainedScope()


private val connectivity by inject<ISupportConnectivity>()

/**
Expand Down
1 change: 1 addition & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

<uses-permission
android:name="android.permission.CLEAR_APP_CACHE"
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/kotlin/co/anitrend/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,4 @@ class App : AniTrendApplication() {
override fun restartDependencyInjection() {
stopKoin()
}
}
}
11 changes: 11 additions & 0 deletions app/src/main/kotlin/co/anitrend/component/screen/MainScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ import co.anitrend.component.action.ChangeSettingsMenuStateAction
import co.anitrend.component.action.ShowHideFabStateAction
import co.anitrend.component.presenter.MainPresenter
import co.anitrend.component.viewmodel.MainScreenViewModel
import co.anitrend.core.android.helpers.notification.config.NotificationConfig
import co.anitrend.core.android.helpers.notification.hasNotificationPermissionFor
import co.anitrend.core.android.helpers.notification.requestPostNotificationPermission
import co.anitrend.core.component.screen.AniTrendBoundScreen
import co.anitrend.core.extensions.invoke
import co.anitrend.core.koin.scope.AppScope
Expand Down Expand Up @@ -191,6 +194,14 @@ class MainScreen : AniTrendBoundScreen<MainScreenBinding>() {
observeNavigationDrawer()
}
}
lifecycleScope.launch {
val needsNotificationPermission = NotificationConfig.entries.any {
!hasNotificationPermissionFor(it)
}
if (needsNotificationPermission) {
requestPostNotificationPermission()
}
}
onUpdateUserInterface()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ private fun Project.configureLint() = baseAppExtension().run {
internal fun Project.configureAndroid(): Unit = baseExtension().run {
compileSdkVersion(35)
defaultConfig {
minSdk = 23
minSdk = 24
targetSdk = 35
versionCode = props[PropertyTypes.CODE].toInt()
versionName = props[PropertyTypes.VERSION]
Expand Down
Loading