Skip to content

Commit

Permalink
wip permissions
Browse files Browse the repository at this point in the history
  • Loading branch information
zsmb13 committed Feb 11, 2025
1 parent 0895106 commit eeda6bb
Show file tree
Hide file tree
Showing 30 changed files with 239 additions and 246 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,19 @@ import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.systemBars
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.ui.Modifier
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import com.jetbrains.kotlinconf.R
import org.jetbrains.kotlinconf.App
import org.jetbrains.kotlinconf.ApplicationContext
import org.jetbrains.kotlinconf.platformModule

class MainActivity : ComponentActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
installSplashScreen()

val context = ApplicationContext(
application,
R.mipmap.ic_launcher,
)

enableEdgeToEdge()

val platformModule = platformModule(activity = this, application = application)
setContent {
App(context)
App(platformModule)
}
}
}
7 changes: 7 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ postgresql = "42.7.3"
androidx-navigation = "2.8.0-alpha12"
doistx-normalize = "1.0.5"
multiplatform-settings = "1.3.0"
moko-permissions = "0.19.0"
alarmee = "1.6.1"

[libraries]

Expand Down Expand Up @@ -95,6 +97,7 @@ kotlinx-coroutines-swing = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-
kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "kotlinx-datetime" }
logback-classic = { module = "ch.qos.logback:logback-classic", version.ref = "logbackClassic" }
doistx-normalize = { module = "com.doist.x:normalize", version.ref = "doistx-normalize" }
alarmee = { module = "io.github.tweener:alarmee", version.ref = "alarmee" }

# images
android-svg = { module = "com.caverock:androidsvg-aar", version.ref = "android-svg" }
Expand All @@ -110,6 +113,10 @@ settings-coroutines = { module = "com.russhwolf:multiplatform-settings-coroutine
settings-serialization = { module = "com.russhwolf:multiplatform-settings-serialization", version.ref = "multiplatform-settings" }
settings-observable = { module = "com.russhwolf:multiplatform-settings-make-observable", version.ref = "multiplatform-settings" }

# moko-permissions
moko-permissions = { module = "dev.icerock.moko:permissions", version.ref = "moko-permissions" }
moko-permissions-notifications = { module = "dev.icerock.moko:permissions-notifications", version.ref = "moko-permissions" }

[plugins]
aboutLibraries = { id= "com.mikepenz.aboutlibraries.plugin", version.ref="aboutlibraries"}
androidApplication = { id = "com.android.application", version.ref = "agp" }
Expand Down
11 changes: 11 additions & 0 deletions shared/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,22 @@ kotlin {
}
}

val mobileMain by creating {
dependsOn(commonMain.get())
dependencies {
implementation(libs.moko.permissions)
implementation(libs.moko.permissions.notifications)
implementation(libs.alarmee)
}
}

val nonAndroidMain by creating {
dependsOn(commonMain.get())
}

androidMain {
dependsOn(nonWebMain)
dependsOn(mobileMain)
dependencies {
implementation(libs.android.svg)
implementation(libs.androidx.core.ktx)
Expand All @@ -119,6 +129,7 @@ kotlin {
iosMain {
dependsOn(nonWebMain)
dependsOn(nonAndroidMain)
dependsOn(mobileMain)
dependencies {
implementation(libs.ktor.client.darwin)
}
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package org.jetbrains.kotlinconf

import android.app.Application
import androidx.activity.ComponentActivity
import androidx.compose.ui.graphics.Color
import com.russhwolf.settings.ObservableSettings
import com.tweener.alarmee.AlarmeeScheduler
import com.tweener.alarmee.AlarmeeSchedulerAndroid
import com.tweener.alarmee.configuration.AlarmeeAndroidPlatformConfiguration
import dev.icerock.moko.permissions.PermissionsController
import dev.icerock.moko.permissions.PermissionsControllerImpl
import org.jetbrains.kotlinconf.storage.createSettings
import org.koin.core.module.Module
import org.koin.dsl.module

fun platformModule(
activity: ComponentActivity,
application: Application,
): Module = module {
single<ObservableSettings> { createSettings(application) }
single { NotificationManager(get()) }
single<PermissionsController> {
PermissionsControllerImpl(application).apply {
bind(activity)
}
}
single<AlarmeeScheduler> {
AlarmeeSchedulerAndroid(
context = application,
configuration = AlarmeeAndroidPlatformConfiguration(
notificationIconResId = 0,
notificationIconColor = Color.White,
notificationChannels = emptyList()
)
)
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package org.jetbrains.kotlinconf.storage

import android.app.Application
import androidx.preference.PreferenceManager
import com.russhwolf.settings.ObservableSettings
import com.russhwolf.settings.SharedPreferencesSettings
import org.jetbrains.kotlinconf.ApplicationContext

actual fun createSettings(context: ApplicationContext): ObservableSettings =
SharedPreferencesSettings(PreferenceManager.getDefaultSharedPreferences(context.application))
fun createSettings(application: Application): ObservableSettings =
SharedPreferencesSettings(PreferenceManager.getDefaultSharedPreferences(application))
12 changes: 6 additions & 6 deletions shared/src/commonMain/kotlin/org/jetbrains/kotlinconf/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,15 @@ import org.jetbrains.kotlinconf.storage.MultiplatformSettingsStorage
import org.jetbrains.kotlinconf.ui.theme.KotlinConfTheme
import org.koin.compose.KoinMultiplatformApplication
import org.koin.compose.koinInject
import org.koin.core.module.Module
import org.koin.core.module.dsl.singleOf
import org.koin.core.module.dsl.viewModelOf
import org.koin.dsl.koinConfiguration
import org.koin.dsl.module

@Composable
fun App(context: ApplicationContext) {
KoinMultiplatformApplication(koinConfiguration(context)) {
fun App(platformModule: Module = module {}) {
KoinMultiplatformApplication(koinConfiguration(platformModule)) {
DevelopmentEntryPoint {
val service = koinInject<ConferenceService>()
val currentTheme by service.getTheme().collectAsStateWithLifecycle(initialValue = Theme.SYSTEM)
Expand Down Expand Up @@ -62,11 +63,10 @@ fun App(context: ApplicationContext) {
}
}

private fun koinConfiguration(context: ApplicationContext) = koinConfiguration {
private fun koinConfiguration(platformModule: Module) = koinConfiguration {
val appModule = module {
single { APIClient(URLs.API_ENDPOINT) }
single<ApplicationStorage> { MultiplatformSettingsStorage(context) }
single { NotificationManager(context) }
single<ApplicationStorage> { MultiplatformSettingsStorage(get()) }
single<TimeProvider> { ServerBasedTimeProvider(get()) }
// single<TimeProvider> { FakeTimeProvider() }
singleOf(::ConferenceService)
Expand All @@ -82,5 +82,5 @@ private fun koinConfiguration(context: ApplicationContext) = koinConfiguration {
viewModelOf(::NewsDetailViewModel)
}

modules(appModule, viewModelModule)
modules(platformModule, appModule, viewModelModule)
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -138,13 +138,9 @@ class ConferenceService(

/**
* Request permissions to send notifications.
* @return true if permission was granted, false otherwise
*/
fun requestNotificationPermissions() {
scope.launch {
storage.setNotificationsAllowed(true)
notificationManager.requestPermission()
}
}
suspend fun requestNotificationPermissions(): Boolean = notificationManager.requestPermission()

fun getNotificationSettings(): Flow<NotificationSettings> = storage.getNotificationSettings()

Expand Down Expand Up @@ -209,47 +205,49 @@ class ConferenceService(

private fun scheduleNotification(session: SessionCardView) {
scope.launch {
val notificationsAllowed = storage.getNotificationsAllowed().first()
if (!notificationsAllowed) return@launch

val startTimestamp = session.startsAt.timestamp
val reminderTimestamp = startTimestamp - 5 * 60 * 1000
val nowTimestamp = timeProvider.now().timestamp
val delay = reminderTimestamp - nowTimestamp
val voteTimeStamp = session.endsAt.timestamp

when {
delay >= 0 -> {
notificationManager.schedule(delay, session.title, "Starts in 5 minutes.")
}
suspend fun scheduleWithLogging(delay: Long, title: String, message: String) {
notificationManager.schedule(delay, title, message)
}

nowTimestamp in reminderTimestamp..<startTimestamp -> {
notificationManager.schedule(0, session.title, "The session is about to start.")
}
try {
when {
delay >= 0 -> {
scheduleWithLogging(delay, session.title, "Starts in 5 minutes.")
}

nowTimestamp in reminderTimestamp..<startTimestamp -> {
scheduleWithLogging(0, session.title, "The session is about to start.")
}

nowTimestamp in startTimestamp..<voteTimeStamp -> {
notificationManager.schedule(0, session.title, "Hurry up! The session has already started!")
nowTimestamp in startTimestamp..<voteTimeStamp -> {
scheduleWithLogging(0, session.title, "Hurry up! The session has already started!")
}
}
}

if (nowTimestamp > voteTimeStamp) return@launch
if (nowTimestamp > voteTimeStamp) return@launch

val voteDelay = voteTimeStamp - nowTimestamp
notificationManager.schedule(
voteDelay,
"${session.title} finished",
"How was the talk?"
)
val voteDelay = voteTimeStamp - nowTimestamp
scheduleWithLogging(
voteDelay,
"${session.title} finished",
"How was the talk?"
)
} catch (e: Exception) {
println("[DEBUG_LOG] Error scheduling notifications: ${e.message}")
}
}
}

private fun cancelNotification(session: SessionCardView) {
scope.launch {
val allowed = storage.getNotificationsAllowed().first()
if (allowed) {
notificationManager.cancel(session.title)
notificationManager.cancel("${session.title} finished")
}
notificationManager.cancel(session.title)
notificationManager.cancel("${session.title} finished")
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,4 +103,6 @@ data class NotificationSettings(
val scheduleUpdates: Boolean,
val kotlinConfNews: Boolean,
val jetbrainsNews: Boolean,
)
) {
fun hasAnyEnabled() = scheduleUpdates || kotlinConfNews || jetbrainsNews
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package org.jetbrains.kotlinconf


expect class NotificationManager(context: ApplicationContext) {
fun requestPermission()
expect class NotificationManager {
suspend fun requestPermission(): Boolean

fun schedule(delay: Long, title: String, message: String): String?

fun cancel(title: String)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -183,9 +183,7 @@ fun NavGraphBuilder.startScreens(
}
composable<StartNotificationsScreen> {
StartNotificationsScreen(
onDone = { notificationSettings ->
// TODO request notification permission, save settings

onDone = {
navController.navigate(MainScreen) {
popUpTo<StartScreens> { inclusive = true }
}
Expand Down
Loading

0 comments on commit eeda6bb

Please sign in to comment.