mirror of
https://github.com/Myzel394/Alibi.git
synced 2025-06-18 23:05:26 +02:00
feat: Add custom notification support
This commit is contained in:
parent
81520c48ba
commit
37a8a9871e
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user