Commit 09ddf787 by Aleksandr Tamakov

Request notification permission

parent d88818dd
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
android:required="false" /> android:required="false" />
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
......
package com.isidroid.c23.domain.use_case package com.isidroid.c23.domain.use_case
import android.content.Context
import androidx.core.app.ActivityCompat
import com.isidroid.c23.ext.hasNotificationPermission
import com.isidroid.spot.model.RichSpot
import com.isidroid.spot.repository.ActiveSpotRepository import com.isidroid.spot.repository.ActiveSpotRepository
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flow
import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@Singleton @Singleton
class ContentUseCase @Inject constructor(private val activeSpotRepository: ActiveSpotRepository) { class ContentUseCase @Inject constructor(
@ApplicationContext private val context: Context,
private val activeSpotRepository: ActiveSpotRepository
) {
fun create() = flow { fun create() = flow {
val spot = activeSpotRepository.getDefaultSpot() val spot = activeSpotRepository.getDefaultSpot()
emit(spot) val hasNotificationPermission = context.hasNotificationPermission.takeIf { spot != null }
emit(Pair(spot, hasNotificationPermission))
} }
} }
\ No newline at end of file
package com.isidroid.c23.ext package com.isidroid.c23.ext
import android.Manifest
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.core.content.ContextCompat
import com.isidroid.c23.BuildConfig import com.isidroid.c23.BuildConfig
import com.isidroid.c23.constant.AppBuildType import com.isidroid.c23.constant.AppBuildType
import com.isidroid.c23.data.source.settings.Settings import com.isidroid.c23.data.source.settings.Settings
...@@ -20,4 +25,10 @@ fun randomColor(): Color { ...@@ -20,4 +25,10 @@ fun randomColor(): Color {
blue = random.nextFloat(), blue = random.nextFloat(),
alpha = 1.0f alpha = 1.0f
) )
} }
\ No newline at end of file
val Context.hasNotificationPermission: Boolean
get() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) return true
return ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED
}
\ No newline at end of file
...@@ -30,7 +30,7 @@ internal fun TopAppBarComponent( ...@@ -30,7 +30,7 @@ internal fun TopAppBarComponent(
) { ) {
CenterAlignedTopAppBar( CenterAlignedTopAppBar(
actions = actions, actions = actions,
modifier = modifier.height(64.dp), modifier = modifier,
title = { title = {
Text( Text(
text = text, text = text,
......
...@@ -11,24 +11,26 @@ class ContentContract { ...@@ -11,24 +11,26 @@ class ContentContract {
data class PickContent(val photo: Boolean = false, val documents: Boolean = false, val word: Boolean = false) : Event data class PickContent(val photo: Boolean = false, val documents: Boolean = false, val word: Boolean = false) : Event
data class MultipleContents(val uris: List<Uri>) : Event data class MultipleContents(val uris: List<Uri>) : Event
data class OpenMap(val lat: Double? = null, val lng: Double? = null, val spotCode: String? = null) : Event data class OpenMap(val lat: Double? = null, val lng: Double? = null, val spotCode: String? = null) : Event
data object GoBack: Event data object GoBack : Event
data object ToPrintJobList: Event data object ToPrintJobList : Event
data object CheckNotificationPermission : Event
} }
sealed interface Effect : ViewSideEffect { sealed interface Effect : ViewSideEffect {
sealed interface Navigation : Effect { sealed interface Navigation : Effect {
data class ToRenderPreview(val uris: String) : Navigation data class ToRenderPreview(val uris: String) : Navigation
data class ToMap(val lat: Double? = null, val lng: Double? = null, val spotId: String? = null) : Navigation data class ToMap(val lat: Double? = null, val lng: Double? = null, val spotId: String? = null) : Navigation
data object ToBack: Navigation data object ToBack : Navigation
data object ToPrintJobList: Navigation data object ToPrintJobList : Navigation
} }
} }
data class State( data class State(
val hasNotificationPermission: Boolean? = null,
val galleryHash: String? = null, val galleryHash: String? = null,
val documentHash: String? = null, val documentHash: String? = null,
val wordHash: String? = null, val wordHash: String? = null,
val richSpot: RichSpot? = null val richSpot: RichSpot? = null,
) : ViewState ) : ViewState
} }
\ No newline at end of file
package com.isidroid.c23.ui.screen.content package com.isidroid.c23.ui.screen.content
import android.Manifest
import android.os.Build
import androidx.activity.compose.BackHandler import androidx.activity.compose.BackHandler
import androidx.activity.compose.ManagedActivityResultLauncher
import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
...@@ -43,6 +46,7 @@ import com.isidroid.c23.ui._component.ShortOfficeInfoComponent ...@@ -43,6 +46,7 @@ import com.isidroid.c23.ui._component.ShortOfficeInfoComponent
import com.isidroid.c23.ui._component.TopAppBarComponent import com.isidroid.c23.ui._component.TopAppBarComponent
import com.isidroid.core.vm.SIDE_EFFECTS_KEY import com.isidroid.core.vm.SIDE_EFFECTS_KEY
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import timber.log.Timber
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
...@@ -57,6 +61,10 @@ fun ContentScreen( ...@@ -57,6 +61,10 @@ fun ContentScreen(
onEventSent(ContentContract.Event.MultipleContents(uris)) onEventSent(ContentContract.Event.MultipleContents(uris))
} }
val notificationLauncher = rememberLauncherForActivityResult(ActivityResultContracts.RequestPermission()) {
onEventSent(ContentContract.Event.CheckNotificationPermission)
}
BackHandler { BackHandler {
onEventSent(ContentContract.Event.GoBack) onEventSent(ContentContract.Event.GoBack)
} }
...@@ -64,6 +72,7 @@ fun ContentScreen( ...@@ -64,6 +72,7 @@ fun ContentScreen(
LaunchedEffect(state.value.galleryHash) { if (state.value.galleryHash != null) launcher.launch("image/*") } LaunchedEffect(state.value.galleryHash) { if (state.value.galleryHash != null) launcher.launch("image/*") }
LaunchedEffect(state.value.documentHash) { if (state.value.documentHash != null) launcher.launch("application/pdf") } LaunchedEffect(state.value.documentHash) { if (state.value.documentHash != null) launcher.launch("application/pdf") }
LaunchedEffect(state.value.wordHash) { if (state.value.wordHash != null) launcher.launch("application/msword") } LaunchedEffect(state.value.wordHash) { if (state.value.wordHash != null) launcher.launch("application/msword") }
LaunchedEffect("not_perm_${state.value.hasNotificationPermission}") { if (state.value.hasNotificationPermission == false) notificationLauncher.launch(Manifest.permission.POST_NOTIFICATIONS) }
LaunchedEffect(SIDE_EFFECTS_KEY) { LaunchedEffect(SIDE_EFFECTS_KEY) {
......
...@@ -37,6 +37,7 @@ class ContentViewModel @Inject constructor( ...@@ -37,6 +37,7 @@ class ContentViewModel @Inject constructor(
is ContentContract.Event.OpenMap -> setEffect { ContentContract.Effect.Navigation.ToMap(event.lat, event.lng, event.spotCode) } is ContentContract.Event.OpenMap -> setEffect { ContentContract.Effect.Navigation.ToMap(event.lat, event.lng, event.spotCode) }
ContentContract.Event.GoBack -> setEffect { ContentContract.Effect.Navigation.ToBack } ContentContract.Event.GoBack -> setEffect { ContentContract.Effect.Navigation.ToBack }
ContentContract.Event.ToPrintJobList -> setEffect { ContentContract.Effect.Navigation.ToPrintJobList } ContentContract.Event.ToPrintJobList -> setEffect { ContentContract.Effect.Navigation.ToPrintJobList }
ContentContract.Event.CheckNotificationPermission -> setState { copy(hasNotificationPermission = null) }
} }
} }
...@@ -49,11 +50,13 @@ class ContentViewModel @Inject constructor( ...@@ -49,11 +50,13 @@ class ContentViewModel @Inject constructor(
} }
private suspend fun create() { private suspend fun create() {
useCase.create().flowOn(Dispatchers.IO).collect { data -> useCase.create().flowOn(Dispatchers.IO).collect {
val (data, hasPermission) = it
if (data == null) if (data == null)
setEffect { ContentContract.Effect.Navigation.ToMap() } setEffect { ContentContract.Effect.Navigation.ToMap() }
else else
setState { copy(richSpot = data) } setState { copy(richSpot = data, hasNotificationPermission = hasPermission) }
} }
} }
} }
\ No newline at end of file
...@@ -12,6 +12,7 @@ import com.isidroid.job_sender.ext.createRenderItems ...@@ -12,6 +12,7 @@ import com.isidroid.job_sender.ext.createRenderItems
import com.isidroid.job_sender.ext.decreaseCounter import com.isidroid.job_sender.ext.decreaseCounter
import com.isidroid.rendering.repository.RenderRepository import com.isidroid.rendering.repository.RenderRepository
import com.isidroid.spot.repository.SpotRepository import com.isidroid.spot.repository.SpotRepository
import kotlinx.coroutines.delay
import timber.log.Timber import timber.log.Timber
internal class JobSendRepositoryImpl( internal class JobSendRepositoryImpl(
...@@ -57,6 +58,8 @@ internal class JobSendRepositoryImpl( ...@@ -57,6 +58,8 @@ internal class JobSendRepositoryImpl(
for ((index, item) in items.withIndex()) { for ((index, item) in items.withIndex()) {
eventCollector.updateProgress(index, total) eventCollector.updateProgress(index, total)
delay(10_000)
try { try {
val uploadResult = sendJobNetworkSource.uploadPage(jobId = item.printJobId, token = item.accessToken, filePath = item.sourceFile) val uploadResult = sendJobNetworkSource.uploadPage(jobId = item.printJobId, token = item.accessToken, filePath = item.sourceFile)
if (!uploadResult) if (!uploadResult)
...@@ -80,7 +83,6 @@ internal class JobSendRepositoryImpl( ...@@ -80,7 +83,6 @@ internal class JobSendRepositoryImpl(
printJobRepository.updateJobStatus(status = JobStatus.UPLOAD_ERROR, *failedJobIds.toTypedArray()) printJobRepository.updateJobStatus(status = JobStatus.UPLOAD_ERROR, *failedJobIds.toTypedArray())
val successJobs = printJobRepository.readLocalList(ids = successJobIds.toList()) val successJobs = printJobRepository.readLocalList(ids = successJobIds.toList())
println("failedJobIds=$failedJobIds")
val failedJobs = printJobRepository.readLocalList(ids = failedJobIds.toList()) val failedJobs = printJobRepository.readLocalList(ids = failedJobIds.toList())
// notify event emitters // notify event emitters
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment