feat: Add custom notification support

This commit is contained in:
Myzel394 2023-10-24 12:47:46 +02:00
parent 81520c48ba
commit 37a8a9871e
No known key found for this signature in database
GPG Key ID: 50098FCA22080F0F
5 changed files with 105 additions and 15 deletions

View File

@ -8,7 +8,9 @@ import androidx.core.app.NotificationCompat
import app.myzel394.alibi.MainActivity
import app.myzel394.alibi.NotificationHelper
import app.myzel394.alibi.R
import app.myzel394.alibi.db.NotificationSettings
import app.myzel394.alibi.enums.RecorderState
import kotlinx.serialization.Serializable
import java.time.LocalDateTime
import java.time.ZoneId
import java.util.Calendar
@ -18,12 +20,36 @@ data class RecorderNotificationHelper(
val context: Context,
val details: NotificationDetails? = null,
) {
@Serializable
data class NotificationDetails(
val title: String,
val description: String,
val icon: Int,
val isOngoing: Boolean,
)
) {
companion object {
fun fromNotificationSettings(
context: Context,
settings: NotificationSettings,
): NotificationDetails {
return if (settings.preset == null) {
NotificationDetails(
settings.title,
settings.message,
settings.iconID,
settings.showOngoing,
)
} else {
NotificationDetails(
context.getString(settings.preset.titleID),
context.getString(settings.preset.messageID),
settings.preset.iconID,
settings.preset.showOngoing,
)
}
}
}
}
private fun getNotificationChangeStateIntent(
newState: RecorderState,

View File

@ -14,6 +14,7 @@ import app.myzel394.alibi.NotificationHelper
import app.myzel394.alibi.R
import app.myzel394.alibi.enums.RecorderState
import app.myzel394.alibi.ui.utils.PermissionHelper
import kotlinx.serialization.json.Json
import java.time.LocalDateTime
import java.time.ZoneId
import java.util.Calendar
@ -51,6 +52,15 @@ abstract class RecorderService : Service() {
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
when (intent?.action) {
"init" -> {
notificationDetails = intent.getStringExtra("notificationDetails")?.let {
Json.decodeFromString(
RecorderNotificationHelper.NotificationDetails.serializer(),
it
)
}
}
"changeState" -> {
val newState = intent.getStringExtra("newState")?.let {
RecorderState.valueOf(it)

View File

@ -20,8 +20,15 @@ import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.rememberStandardBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
@ -31,22 +38,51 @@ import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import app.myzel394.alibi.NotificationHelper
import app.myzel394.alibi.R
import app.myzel394.alibi.dataStore
import app.myzel394.alibi.db.AppSettings
import app.myzel394.alibi.services.RecorderNotificationHelper
import app.myzel394.alibi.ui.BIG_PRIMARY_BUTTON_SIZE
import app.myzel394.alibi.ui.components.atoms.PermissionRequester
import app.myzel394.alibi.ui.models.AudioRecorderModel
import app.myzel394.alibi.ui.utils.rememberFileSaverDialog
import kotlinx.coroutines.flow.last
import kotlinx.coroutines.flow.lastOrNull
import kotlinx.coroutines.launch
import java.time.format.DateTimeFormatter
import java.time.format.FormatStyle
@Composable
fun StartRecording(
audioRecorder: AudioRecorderModel,
// Loading this from parent, because if we load it ourselves
// and permissions have already been granted, initial
// settings will be used, instead of the actual settings.
appSettings: AppSettings
) {
val context = LocalContext.current
// We can't get the current `notificationDetails` inside the
// `onPermissionAvailable` function. We'll instead use this hack
// with `LaunchedEffect` to get the current value.
var startRecording by rememberSaveable { mutableStateOf(false) }
LaunchedEffect(startRecording) {
if (startRecording) {
startRecording = false
audioRecorder.notificationDetails = appSettings.notificationSettings.let {
if (it == null)
null
else
RecorderNotificationHelper.NotificationDetails.fromNotificationSettings(
context,
it
)
}
audioRecorder.startRecording(context)
}
}
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.SpaceBetween,
@ -57,14 +93,12 @@ fun StartRecording(
permission = Manifest.permission.RECORD_AUDIO,
icon = Icons.Default.Mic,
onPermissionAvailable = {
audioRecorder.startRecording(context)
startRecording = true
},
) { trigger ->
val label = stringResource(R.string.ui_audioRecorder_action_start_label)
Button(
onClick = {
trigger()
},
onClick = trigger,
modifier = Modifier
.semantics {
contentDescription = label
@ -98,7 +132,10 @@ fun StartRecording(
.value
Text(
stringResource(R.string.ui_audioRecorder_action_start_description, settings.audioRecorderSettings.maxDuration / 1000 / 60),
stringResource(
R.string.ui_audioRecorder_action_start_description,
settings.audioRecorderSettings.maxDuration / 1000 / 60
),
style = MaterialTheme.typography.bodySmall.copy(
color = MaterialTheme.colorScheme.onSurfaceVariant,
),
@ -115,7 +152,8 @@ fun StartRecording(
) {
val label = stringResource(
R.string.ui_audioRecorder_action_saveOldRecording_label,
DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL).format(audioRecorder.lastRecording!!.recordingStart),
DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL)
.format(audioRecorder.lastRecording!!.recordingStart),
)
Button(
modifier = Modifier
@ -140,8 +178,7 @@ fun StartRecording(
Text(label)
}
}
}
else
} else
Spacer(modifier = Modifier.weight(1f))
}
}

View File

@ -13,10 +13,14 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.core.content.ContextCompat
import androidx.lifecycle.ViewModel
import app.myzel394.alibi.dataStore
import app.myzel394.alibi.db.LastRecording
import app.myzel394.alibi.enums.RecorderState
import app.myzel394.alibi.services.AudioRecorderService
import app.myzel394.alibi.services.RecorderNotificationHelper
import app.myzel394.alibi.services.RecorderService
import kotlinx.coroutines.flow.last
import kotlinx.serialization.json.Json
class AudioRecorderModel : ViewModel() {
var recorderState by mutableStateOf(RecorderState.IDLE)
@ -45,6 +49,7 @@ class AudioRecorderModel : ViewModel() {
var onRecordingSave: () -> Unit = {}
var onError: () -> Unit = {}
var notificationDetails: RecorderNotificationHelper.NotificationDetails? = null
private val connection = object : ServiceConnection {
override fun onServiceConnected(className: ComponentName, service: IBinder) {
@ -90,7 +95,19 @@ class AudioRecorderModel : ViewModel() {
context.unbindService(connection)
}
val intent = Intent(context, AudioRecorderService::class.java)
val intent = Intent(context, AudioRecorderService::class.java).apply {
action = "init"
if (notificationDetails != null) {
putExtra(
"notificationDetails",
Json.encodeToString(
RecorderNotificationHelper.NotificationDetails.serializer(),
notificationDetails!!,
),
)
}
}
ContextCompat.startForegroundService(context, intent)
context.bindService(intent, connection, Context.BIND_AUTO_CREATE)
}
@ -118,10 +135,6 @@ class AudioRecorderModel : ViewModel() {
recorderService!!.changeState(RecorderState.RECORDING)
}
fun setNotificationDetails(details: RecorderService.NotificationDetails) {
recorderService?.notificationDetails = details
}
fun setMaxAmplitudesAmount(amount: Int) {
recorderService?.amplitudesAmount = amount
}

View File

@ -38,6 +38,7 @@ import app.myzel394.alibi.R
import app.myzel394.alibi.dataStore
import app.myzel394.alibi.db.AppSettings
import app.myzel394.alibi.db.LastRecording
import app.myzel394.alibi.services.RecorderNotificationHelper
import app.myzel394.alibi.ui.effects.rememberSettings
import app.myzel394.alibi.ui.models.AudioRecorderModel
import kotlinx.coroutines.launch
@ -171,10 +172,13 @@ fun AudioRecorder(
.fillMaxSize()
.padding(padding),
) {
val appSettings =
context.dataStore.data.collectAsState(AppSettings.getDefaultInstance()).value
if (audioRecorder.isInRecording)
RecordingStatus(audioRecorder = audioRecorder)
else
StartRecording(audioRecorder = audioRecorder)
StartRecording(audioRecorder = audioRecorder, appSettings = appSettings)
}
}
}