feat: add metadata stripping failure dialog to all upload ViewModels
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+5
@@ -37,6 +37,11 @@ import kotlinx.coroutines.flow.map
|
||||
import okhttp3.OkHttpClient
|
||||
import kotlin.coroutines.cancellation.CancellationException
|
||||
|
||||
data class StrippingFailureState(
|
||||
val onConfirm: () -> Unit,
|
||||
val onCancel: () -> Unit,
|
||||
)
|
||||
|
||||
sealed class UploadingState {
|
||||
data object Ready : UploadingState()
|
||||
|
||||
|
||||
@@ -39,6 +39,8 @@ import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.CurrencyBitcoin
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
@@ -125,6 +127,24 @@ fun EditPostView(
|
||||
postViewModel.load(edit, versionLookingAt)
|
||||
}
|
||||
|
||||
postViewModel.strippingFailureDialog?.let { dialogState ->
|
||||
AlertDialog(
|
||||
onDismissRequest = { dialogState.onCancel() },
|
||||
title = { Text(stringRes(R.string.metadata_strip_failed_title)) },
|
||||
text = { Text(stringRes(R.string.metadata_strip_failed_body)) },
|
||||
confirmButton = {
|
||||
Button(onClick = { dialogState.onConfirm() }) {
|
||||
Text(stringRes(R.string.metadata_strip_failed_upload))
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
Button(onClick = { dialogState.onCancel() }) {
|
||||
Text(stringRes(R.string.cancel))
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
Dialog(
|
||||
onDismissRequest = { onClose() },
|
||||
properties =
|
||||
|
||||
@@ -37,6 +37,7 @@ import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.model.User
|
||||
import com.vitorpamplona.amethyst.service.uploads.MediaCompressor
|
||||
import com.vitorpamplona.amethyst.service.uploads.MultiOrchestrator
|
||||
import com.vitorpamplona.amethyst.service.uploads.StrippingFailureState
|
||||
import com.vitorpamplona.amethyst.service.uploads.UploadOrchestrator
|
||||
import com.vitorpamplona.amethyst.ui.actions.mediaServers.ServerName
|
||||
import com.vitorpamplona.amethyst.ui.actions.uploads.MediaUploadTracker
|
||||
@@ -64,6 +65,7 @@ import com.vitorpamplona.quartz.nip94FileMetadata.size
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
|
||||
@Stable
|
||||
open class EditPostViewModel : ViewModel() {
|
||||
@@ -90,6 +92,10 @@ open class EditPostViewModel : ViewModel() {
|
||||
// Images and Videos
|
||||
var multiOrchestrator by mutableStateOf<MultiOrchestrator?>(null)
|
||||
|
||||
// Stripping failure dialog
|
||||
var strippingFailureDialog by mutableStateOf<StrippingFailureState?>(null)
|
||||
private set
|
||||
|
||||
// Codec selection: false = H264, true = H265
|
||||
var useH265Codec by mutableStateOf(false)
|
||||
|
||||
@@ -197,6 +203,21 @@ open class EditPostViewModel : ViewModel() {
|
||||
context,
|
||||
useH265Codec,
|
||||
stripMetadata,
|
||||
onStrippingFailed = {
|
||||
suspendCancellableCoroutine { continuation ->
|
||||
strippingFailureDialog =
|
||||
StrippingFailureState(
|
||||
onConfirm = {
|
||||
strippingFailureDialog = null
|
||||
continuation.resume(true) {}
|
||||
},
|
||||
onCancel = {
|
||||
strippingFailureDialog = null
|
||||
continuation.resume(false) {}
|
||||
},
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
if (results.allGood) {
|
||||
|
||||
@@ -33,6 +33,7 @@ import com.vitorpamplona.amethyst.commons.richtext.RichTextParser
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.service.uploads.MediaCompressor
|
||||
import com.vitorpamplona.amethyst.service.uploads.MultiOrchestrator
|
||||
import com.vitorpamplona.amethyst.service.uploads.StrippingFailureState
|
||||
import com.vitorpamplona.amethyst.service.uploads.UploadOrchestrator
|
||||
import com.vitorpamplona.amethyst.ui.actions.mediaServers.DEFAULT_MEDIA_SERVERS
|
||||
import com.vitorpamplona.amethyst.ui.actions.mediaServers.ServerName
|
||||
@@ -44,6 +45,7 @@ import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.joinAll
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
|
||||
@Stable
|
||||
open class NewMediaModel : ViewModel() {
|
||||
@@ -59,6 +61,10 @@ open class NewMediaModel : ViewModel() {
|
||||
var multiOrchestrator by mutableStateOf<MultiOrchestrator?>(null)
|
||||
var onceUploaded: () -> Unit = {}
|
||||
|
||||
// Stripping failure dialog
|
||||
var strippingFailureDialog by mutableStateOf<StrippingFailureState?>(null)
|
||||
private set
|
||||
|
||||
// 0 = Low, 1 = Medium, 2 = High, 3=UNCOMPRESSED
|
||||
var mediaQualitySlider by mutableIntStateOf(1)
|
||||
|
||||
@@ -120,6 +126,21 @@ open class NewMediaModel : ViewModel() {
|
||||
context,
|
||||
useH265Codec,
|
||||
stripMetadata,
|
||||
onStrippingFailed = {
|
||||
suspendCancellableCoroutine { continuation ->
|
||||
strippingFailureDialog =
|
||||
StrippingFailureState(
|
||||
onConfirm = {
|
||||
strippingFailureDialog = null
|
||||
continuation.resume(true) {}
|
||||
},
|
||||
onCancel = {
|
||||
strippingFailureDialog = null
|
||||
continuation.resume(false) {}
|
||||
},
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
if (results.allGood) {
|
||||
|
||||
@@ -32,6 +32,8 @@ import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
@@ -89,6 +91,24 @@ fun NewMediaView(
|
||||
postViewModel.load(account, uris)
|
||||
}
|
||||
|
||||
postViewModel.strippingFailureDialog?.let { dialogState ->
|
||||
AlertDialog(
|
||||
onDismissRequest = { dialogState.onCancel() },
|
||||
title = { Text(stringRes(R.string.metadata_strip_failed_title)) },
|
||||
text = { Text(stringRes(R.string.metadata_strip_failed_body)) },
|
||||
confirmButton = {
|
||||
Button(onClick = { dialogState.onConfirm() }) {
|
||||
Text(stringRes(R.string.metadata_strip_failed_upload))
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
Button(onClick = { dialogState.onCancel() }) {
|
||||
Text(stringRes(R.string.cancel))
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
Dialog(
|
||||
onDismissRequest = { onClose() },
|
||||
properties =
|
||||
|
||||
+21
@@ -42,6 +42,7 @@ import com.vitorpamplona.amethyst.model.User
|
||||
import com.vitorpamplona.amethyst.service.location.LocationState
|
||||
import com.vitorpamplona.amethyst.service.uploads.MediaCompressor
|
||||
import com.vitorpamplona.amethyst.service.uploads.MultiOrchestrator
|
||||
import com.vitorpamplona.amethyst.service.uploads.StrippingFailureState
|
||||
import com.vitorpamplona.amethyst.service.uploads.UploadOrchestrator
|
||||
import com.vitorpamplona.amethyst.ui.actions.NewMessageTagger
|
||||
import com.vitorpamplona.amethyst.ui.actions.mediaServers.ServerName
|
||||
@@ -111,6 +112,7 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
|
||||
@Stable
|
||||
open class CommentPostViewModel :
|
||||
@@ -162,6 +164,10 @@ open class CommentPostViewModel :
|
||||
// Images and Videos
|
||||
var multiOrchestrator by mutableStateOf<MultiOrchestrator?>(null)
|
||||
|
||||
// Stripping failure dialog
|
||||
var strippingFailureDialog by mutableStateOf<StrippingFailureState?>(null)
|
||||
private set
|
||||
|
||||
// Invoices
|
||||
var canAddInvoice by mutableStateOf(false)
|
||||
var wantsInvoice by mutableStateOf(false)
|
||||
@@ -503,6 +509,21 @@ open class CommentPostViewModel :
|
||||
account,
|
||||
context,
|
||||
stripMetadata = stripMetadata,
|
||||
onStrippingFailed = {
|
||||
suspendCancellableCoroutine { continuation ->
|
||||
strippingFailureDialog =
|
||||
StrippingFailureState(
|
||||
onConfirm = {
|
||||
strippingFailureDialog = null
|
||||
continuation.resume(true) {}
|
||||
},
|
||||
onCancel = {
|
||||
strippingFailureDialog = null
|
||||
continuation.resume(false) {}
|
||||
},
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
if (results.allGood) {
|
||||
|
||||
+21
@@ -34,10 +34,13 @@ import androidx.compose.foundation.layout.imePadding
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.ui.Alignment.Companion.CenterVertically
|
||||
@@ -140,6 +143,24 @@ fun GenericCommentPostScreen(
|
||||
) {
|
||||
WatchAndLoadMyEmojiList(accountViewModel)
|
||||
|
||||
postViewModel.strippingFailureDialog?.let { dialogState ->
|
||||
AlertDialog(
|
||||
onDismissRequest = { dialogState.onCancel() },
|
||||
title = { Text(stringRes(R.string.metadata_strip_failed_title)) },
|
||||
text = { Text(stringRes(R.string.metadata_strip_failed_body)) },
|
||||
confirmButton = {
|
||||
Button(onClick = { dialogState.onConfirm() }) {
|
||||
Text(stringRes(R.string.metadata_strip_failed_upload))
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
Button(onClick = { dialogState.onCancel() }) {
|
||||
Text(stringRes(R.string.cancel))
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
BackHandler {
|
||||
accountViewModel.launchSigner {
|
||||
postViewModel.sendDraftSync()
|
||||
|
||||
+28
-2
@@ -39,6 +39,7 @@ import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.model.User
|
||||
import com.vitorpamplona.amethyst.service.location.LocationState
|
||||
import com.vitorpamplona.amethyst.service.uploads.StrippingFailureState
|
||||
import com.vitorpamplona.amethyst.ui.actions.NewMessageTagger
|
||||
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.draftTags.DraftTagState
|
||||
@@ -99,6 +100,7 @@ import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
|
||||
@Stable
|
||||
class ChatNewMessageViewModel :
|
||||
@@ -133,6 +135,11 @@ class ChatNewMessageViewModel :
|
||||
val replyTo = mutableStateOf<Note?>(null)
|
||||
|
||||
var uploadState by mutableStateOf<ChatFileUploadState?>(null)
|
||||
|
||||
// Stripping failure dialog
|
||||
var strippingFailureDialog by mutableStateOf<StrippingFailureState?>(null)
|
||||
private set
|
||||
|
||||
val iMetaAttachments = IMetaAttachments()
|
||||
|
||||
var uploadsWaitingToBeSent by mutableStateOf<List<SuccessfulUploads>>(emptyList())
|
||||
@@ -395,6 +402,21 @@ class ChatNewMessageViewModel :
|
||||
return location!!
|
||||
}
|
||||
|
||||
private suspend fun showStrippingFailureDialog(): Boolean =
|
||||
suspendCancellableCoroutine { continuation ->
|
||||
strippingFailureDialog =
|
||||
StrippingFailureState(
|
||||
onConfirm = {
|
||||
strippingFailureDialog = null
|
||||
continuation.resume(true) {}
|
||||
},
|
||||
onCancel = {
|
||||
strippingFailureDialog = null
|
||||
continuation.resume(false) {}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fun uploadAndHold(
|
||||
onError: (title: String, message: String) -> Unit,
|
||||
context: Context,
|
||||
@@ -413,13 +435,14 @@ class ChatNewMessageViewModel :
|
||||
pendingRetryMode = RetryMode.HOLD
|
||||
},
|
||||
context,
|
||||
onStrippingFailed = ::showStrippingFailureDialog,
|
||||
) {
|
||||
uploadsWaitingToBeSent += it
|
||||
draftTag.newVersion()
|
||||
onceUploaded()
|
||||
}
|
||||
} else {
|
||||
ChatFileUploader(account).justUploadNIP04(uploadState, onError, context) {
|
||||
ChatFileUploader(account).justUploadNIP04(uploadState, onError, context, onStrippingFailed = ::showStrippingFailureDialog) {
|
||||
uploadsWaitingToBeSent += it
|
||||
draftTag.newVersion()
|
||||
onceUploaded()
|
||||
@@ -450,13 +473,14 @@ class ChatNewMessageViewModel :
|
||||
pendingRetryOnceUploaded = onceUploaded
|
||||
},
|
||||
context,
|
||||
onStrippingFailed = ::showStrippingFailureDialog,
|
||||
) {
|
||||
ChatFileSender(room, account).sendNIP17(it)
|
||||
draftTag.newVersion()
|
||||
onceUploaded()
|
||||
}
|
||||
} else {
|
||||
ChatFileUploader(account).justUploadNIP04(uploadState, onError, context) {
|
||||
ChatFileUploader(account).justUploadNIP04(uploadState, onError, context, onStrippingFailed = ::showStrippingFailureDialog) {
|
||||
ChatFileSender(room, account).sendNIP04(it)
|
||||
draftTag.newVersion()
|
||||
onceUploaded()
|
||||
@@ -505,6 +529,7 @@ class ChatNewMessageViewModel :
|
||||
uploadState,
|
||||
onError ?: accountViewModel.toastManager::toast,
|
||||
context,
|
||||
onStrippingFailed = ::showStrippingFailureDialog,
|
||||
) {
|
||||
uploadsWaitingToBeSent += it
|
||||
draftTag.newVersion()
|
||||
@@ -518,6 +543,7 @@ class ChatNewMessageViewModel :
|
||||
uploadState,
|
||||
onError ?: accountViewModel.toastManager::toast,
|
||||
context,
|
||||
onStrippingFailed = ::showStrippingFailureDialog,
|
||||
) {
|
||||
ChatFileSender(room, account).sendNIP17(it)
|
||||
draftTag.newVersion()
|
||||
|
||||
+18
@@ -118,6 +118,24 @@ fun PrivateMessageEditFieldRow(
|
||||
}
|
||||
}
|
||||
|
||||
channelScreenModel.strippingFailureDialog?.let { dialogState ->
|
||||
AlertDialog(
|
||||
onDismissRequest = { dialogState.onCancel() },
|
||||
title = { Text(stringRes(R.string.metadata_strip_failed_title)) },
|
||||
text = { Text(stringRes(R.string.metadata_strip_failed_body)) },
|
||||
confirmButton = {
|
||||
TextButton(onClick = { dialogState.onConfirm() }) {
|
||||
Text(stringRes(R.string.metadata_strip_failed_upload))
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(onClick = { dialogState.onCancel() }) {
|
||||
Text(stringRes(R.string.cancel))
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
channelScreenModel.encryptedUploadErrorTitle?.let { title ->
|
||||
EncryptedUploadErrorDialog(
|
||||
title = title,
|
||||
|
||||
+7
-1
@@ -41,6 +41,7 @@ class ChatFileUploader(
|
||||
onError: (title: String, message: String) -> Unit,
|
||||
onEncryptedUploadError: (title: String, message: String) -> Unit,
|
||||
context: Context,
|
||||
onStrippingFailed: suspend () -> Boolean = { true },
|
||||
onceUploaded: suspend (List<SuccessfulUploads>) -> Unit,
|
||||
) {
|
||||
val orchestrator = viewState.multiOrchestrator ?: return
|
||||
@@ -59,6 +60,7 @@ class ChatFileUploader(
|
||||
account,
|
||||
context,
|
||||
stripMetadata = viewState.stripMetadata,
|
||||
onStrippingFailed = onStrippingFailed,
|
||||
)
|
||||
|
||||
if (results.allGood) {
|
||||
@@ -82,7 +84,7 @@ class ChatFileUploader(
|
||||
)
|
||||
}
|
||||
} else {
|
||||
justUploadNIP17Unencrypted(viewState, onError, context, onceUploaded)
|
||||
justUploadNIP17Unencrypted(viewState, onError, context, onStrippingFailed, onceUploaded)
|
||||
}
|
||||
|
||||
viewState.mediaUploadTracker.finishUpload()
|
||||
@@ -92,6 +94,7 @@ class ChatFileUploader(
|
||||
viewState: ChatFileUploadState,
|
||||
onError: (title: String, message: String) -> Unit,
|
||||
context: Context,
|
||||
onStrippingFailed: suspend () -> Boolean = { true },
|
||||
onceUploaded: suspend (List<SuccessfulUploads>) -> Unit,
|
||||
) {
|
||||
val orchestrator = viewState.multiOrchestrator ?: return
|
||||
@@ -106,6 +109,7 @@ class ChatFileUploader(
|
||||
account,
|
||||
context,
|
||||
stripMetadata = viewState.stripMetadata,
|
||||
onStrippingFailed = onStrippingFailed,
|
||||
)
|
||||
|
||||
if (results.allGood) {
|
||||
@@ -137,6 +141,7 @@ class ChatFileUploader(
|
||||
viewState: ChatFileUploadState,
|
||||
onError: (title: String, message: String) -> Unit,
|
||||
context: Context,
|
||||
onStrippingFailed: suspend () -> Boolean = { true },
|
||||
onceUploaded: suspend (List<SuccessfulUploads>) -> Unit,
|
||||
) {
|
||||
val orchestrator = viewState.multiOrchestrator ?: return
|
||||
@@ -151,6 +156,7 @@ class ChatFileUploader(
|
||||
account,
|
||||
context,
|
||||
stripMetadata = viewState.stripMetadata,
|
||||
onStrippingFailed = onStrippingFailed,
|
||||
)
|
||||
|
||||
if (results.allGood) {
|
||||
|
||||
+22
@@ -46,6 +46,7 @@ import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.model.User
|
||||
import com.vitorpamplona.amethyst.service.location.LocationState
|
||||
import com.vitorpamplona.amethyst.service.uploads.MediaCompressor
|
||||
import com.vitorpamplona.amethyst.service.uploads.StrippingFailureState
|
||||
import com.vitorpamplona.amethyst.service.uploads.UploadOrchestrator
|
||||
import com.vitorpamplona.amethyst.ui.actions.NewMessageTagger
|
||||
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia
|
||||
@@ -101,6 +102,7 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
|
||||
@Stable
|
||||
open class ChannelNewMessageViewModel :
|
||||
@@ -129,6 +131,11 @@ open class ChannelNewMessageViewModel :
|
||||
val replyTo = mutableStateOf<Note?>(null)
|
||||
|
||||
var uploadState by mutableStateOf<ChatFileUploadState?>(null)
|
||||
|
||||
// Stripping failure dialog
|
||||
var strippingFailureDialog by mutableStateOf<StrippingFailureState?>(null)
|
||||
private set
|
||||
|
||||
val iMetaAttachments = IMetaAttachments()
|
||||
var nip95attachments by mutableStateOf<List<Pair<FileStorageEvent, FileStorageHeaderEvent>>>(emptyList())
|
||||
|
||||
@@ -349,6 +356,21 @@ open class ChannelNewMessageViewModel :
|
||||
account,
|
||||
context,
|
||||
stripMetadata = uploadState.stripMetadata,
|
||||
onStrippingFailed = {
|
||||
suspendCancellableCoroutine { continuation ->
|
||||
strippingFailureDialog =
|
||||
StrippingFailureState(
|
||||
onConfirm = {
|
||||
strippingFailureDialog = null
|
||||
continuation.resume(true) {}
|
||||
},
|
||||
onCancel = {
|
||||
strippingFailureDialog = null
|
||||
continuation.resume(false) {}
|
||||
},
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
if (results.allGood) {
|
||||
|
||||
+20
@@ -26,6 +26,8 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.LocalTextStyle
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
@@ -70,6 +72,24 @@ fun EditFieldRow(
|
||||
nav.popBack()
|
||||
}
|
||||
|
||||
channelScreenModel.strippingFailureDialog?.let { dialogState ->
|
||||
AlertDialog(
|
||||
onDismissRequest = { dialogState.onCancel() },
|
||||
title = { Text(stringRes(R.string.metadata_strip_failed_title)) },
|
||||
text = { Text(stringRes(R.string.metadata_strip_failed_body)) },
|
||||
confirmButton = {
|
||||
Button(onClick = { dialogState.onConfirm() }) {
|
||||
Text(stringRes(R.string.metadata_strip_failed_upload))
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
Button(onClick = { dialogState.onCancel() }) {
|
||||
Text(stringRes(R.string.cancel))
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
channelScreenModel.replyTo.value?.let {
|
||||
DisplayReplyingToNote(it, accountViewModel, nav) {
|
||||
channelScreenModel.clearReply()
|
||||
|
||||
+21
@@ -33,10 +33,13 @@ import androidx.compose.foundation.layout.imePadding
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.ui.Alignment.Companion.CenterVertically
|
||||
@@ -137,6 +140,24 @@ fun NewProductScreen(
|
||||
) {
|
||||
WatchAndLoadMyEmojiList(accountViewModel)
|
||||
|
||||
postViewModel.strippingFailureDialog?.let { dialogState ->
|
||||
AlertDialog(
|
||||
onDismissRequest = { dialogState.onCancel() },
|
||||
title = { Text(stringRes(R.string.metadata_strip_failed_title)) },
|
||||
text = { Text(stringRes(R.string.metadata_strip_failed_body)) },
|
||||
confirmButton = {
|
||||
Button(onClick = { dialogState.onConfirm() }) {
|
||||
Text(stringRes(R.string.metadata_strip_failed_upload))
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
Button(onClick = { dialogState.onCancel() }) {
|
||||
Text(stringRes(R.string.cancel))
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
BackHandler {
|
||||
accountViewModel.launchSigner {
|
||||
postViewModel.sendDraftSync()
|
||||
|
||||
+21
@@ -42,6 +42,7 @@ import com.vitorpamplona.amethyst.model.User
|
||||
import com.vitorpamplona.amethyst.service.location.LocationState
|
||||
import com.vitorpamplona.amethyst.service.uploads.MediaCompressor
|
||||
import com.vitorpamplona.amethyst.service.uploads.MultiOrchestrator
|
||||
import com.vitorpamplona.amethyst.service.uploads.StrippingFailureState
|
||||
import com.vitorpamplona.amethyst.service.uploads.UploadOrchestrator
|
||||
import com.vitorpamplona.amethyst.ui.actions.NewMessageTagger
|
||||
import com.vitorpamplona.amethyst.ui.actions.mediaServers.ServerName
|
||||
@@ -100,6 +101,7 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
|
||||
@Stable
|
||||
open class NewProductViewModel :
|
||||
@@ -146,6 +148,10 @@ open class NewProductViewModel :
|
||||
// Images and Videos
|
||||
var multiOrchestrator by mutableStateOf<MultiOrchestrator?>(null)
|
||||
|
||||
// Stripping failure dialog
|
||||
var strippingFailureDialog by mutableStateOf<StrippingFailureState?>(null)
|
||||
private set
|
||||
|
||||
// Classifieds
|
||||
var title by mutableStateOf(TextFieldValue(""))
|
||||
var price by mutableStateOf(TextFieldValue(""))
|
||||
@@ -411,6 +417,21 @@ open class NewProductViewModel :
|
||||
myAccount,
|
||||
context,
|
||||
stripMetadata = stripMetadata,
|
||||
onStrippingFailed = {
|
||||
suspendCancellableCoroutine { continuation ->
|
||||
strippingFailureDialog =
|
||||
StrippingFailureState(
|
||||
onConfirm = {
|
||||
strippingFailureDialog = null
|
||||
continuation.resume(true) {}
|
||||
},
|
||||
onCancel = {
|
||||
strippingFailureDialog = null
|
||||
continuation.resume(false) {}
|
||||
},
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
if (results.allGood) {
|
||||
|
||||
+21
@@ -39,6 +39,8 @@ import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.Poll
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
@@ -46,6 +48,7 @@ import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Switch
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
@@ -179,6 +182,24 @@ private fun NewPostScreenInner(
|
||||
) {
|
||||
WatchAndLoadMyEmojiList(accountViewModel)
|
||||
|
||||
postViewModel.strippingFailureDialog?.let { dialogState ->
|
||||
AlertDialog(
|
||||
onDismissRequest = { dialogState.onCancel() },
|
||||
title = { Text(stringRes(R.string.metadata_strip_failed_title)) },
|
||||
text = { Text(stringRes(R.string.metadata_strip_failed_body)) },
|
||||
confirmButton = {
|
||||
Button(onClick = { dialogState.onConfirm() }) {
|
||||
Text(stringRes(R.string.metadata_strip_failed_upload))
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
Button(onClick = { dialogState.onCancel() }) {
|
||||
Text(stringRes(R.string.cancel))
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
BackHandler {
|
||||
accountViewModel.launchSigner {
|
||||
postViewModel.sendDraftSync()
|
||||
|
||||
+21
@@ -45,6 +45,7 @@ import com.vitorpamplona.amethyst.service.location.LocationState
|
||||
import com.vitorpamplona.amethyst.service.uploads.CompressorQuality
|
||||
import com.vitorpamplona.amethyst.service.uploads.MediaCompressor
|
||||
import com.vitorpamplona.amethyst.service.uploads.MultiOrchestrator
|
||||
import com.vitorpamplona.amethyst.service.uploads.StrippingFailureState
|
||||
import com.vitorpamplona.amethyst.service.uploads.UploadOrchestrator
|
||||
import com.vitorpamplona.amethyst.service.uploads.UploadingState
|
||||
import com.vitorpamplona.amethyst.ui.actions.NewMessageTagger
|
||||
@@ -133,6 +134,7 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
|
||||
enum class UserSuggestionAnchor {
|
||||
MAIN_MESSAGE,
|
||||
@@ -191,6 +193,10 @@ open class ShortNotePostViewModel :
|
||||
// Images and Videos
|
||||
var multiOrchestrator by mutableStateOf<MultiOrchestrator?>(null)
|
||||
|
||||
// Stripping failure dialog
|
||||
var strippingFailureDialog by mutableStateOf<StrippingFailureState?>(null)
|
||||
private set
|
||||
|
||||
// Voice Messages
|
||||
var voiceRecording by mutableStateOf<RecordingResult?>(null)
|
||||
var voiceLocalFile by mutableStateOf<java.io.File?>(null)
|
||||
@@ -846,6 +852,21 @@ open class ShortNotePostViewModel :
|
||||
context,
|
||||
useH265,
|
||||
stripMetadata,
|
||||
onStrippingFailed = {
|
||||
suspendCancellableCoroutine { continuation ->
|
||||
strippingFailureDialog =
|
||||
StrippingFailureState(
|
||||
onConfirm = {
|
||||
strippingFailureDialog = null
|
||||
continuation.resume(true) {}
|
||||
},
|
||||
onCancel = {
|
||||
strippingFailureDialog = null
|
||||
continuation.resume(false) {}
|
||||
},
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
if (results.allGood) {
|
||||
|
||||
+20
@@ -33,6 +33,8 @@ import androidx.compose.foundation.layout.imePadding
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
@@ -131,6 +133,24 @@ fun NewPublicMessageScreen(
|
||||
|
||||
WatchAndLoadMyEmojiList(accountViewModel)
|
||||
|
||||
postViewModel.strippingFailureDialog?.let { dialogState ->
|
||||
AlertDialog(
|
||||
onDismissRequest = { dialogState.onCancel() },
|
||||
title = { Text(stringRes(R.string.metadata_strip_failed_title)) },
|
||||
text = { Text(stringRes(R.string.metadata_strip_failed_body)) },
|
||||
confirmButton = {
|
||||
Button(onClick = { dialogState.onConfirm() }) {
|
||||
Text(stringRes(R.string.metadata_strip_failed_upload))
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
Button(onClick = { dialogState.onCancel() }) {
|
||||
Text(stringRes(R.string.cancel))
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
BackHandler {
|
||||
accountViewModel.launchSigner {
|
||||
postViewModel.sendDraftSync()
|
||||
|
||||
+21
@@ -42,6 +42,7 @@ import com.vitorpamplona.amethyst.model.User
|
||||
import com.vitorpamplona.amethyst.service.location.LocationState
|
||||
import com.vitorpamplona.amethyst.service.uploads.MediaCompressor
|
||||
import com.vitorpamplona.amethyst.service.uploads.MultiOrchestrator
|
||||
import com.vitorpamplona.amethyst.service.uploads.StrippingFailureState
|
||||
import com.vitorpamplona.amethyst.service.uploads.UploadOrchestrator
|
||||
import com.vitorpamplona.amethyst.ui.actions.NewMessageTagger
|
||||
import com.vitorpamplona.amethyst.ui.actions.mediaServers.ServerName
|
||||
@@ -114,6 +115,7 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
|
||||
@Stable
|
||||
class NewPublicMessageViewModel :
|
||||
@@ -164,6 +166,10 @@ class NewPublicMessageViewModel :
|
||||
// Images and Videos
|
||||
var multiOrchestrator by mutableStateOf<MultiOrchestrator?>(null)
|
||||
|
||||
// Stripping failure dialog
|
||||
var strippingFailureDialog by mutableStateOf<StrippingFailureState?>(null)
|
||||
private set
|
||||
|
||||
// Invoices
|
||||
var canAddInvoice by mutableStateOf(false)
|
||||
var wantsInvoice by mutableStateOf(false)
|
||||
@@ -455,6 +461,21 @@ class NewPublicMessageViewModel :
|
||||
account,
|
||||
context,
|
||||
stripMetadata = stripMetadata,
|
||||
onStrippingFailed = {
|
||||
suspendCancellableCoroutine { continuation ->
|
||||
strippingFailureDialog =
|
||||
StrippingFailureState(
|
||||
onConfirm = {
|
||||
strippingFailureDialog = null
|
||||
continuation.resume(true) {}
|
||||
},
|
||||
onCancel = {
|
||||
strippingFailureDialog = null
|
||||
continuation.resume(false) {}
|
||||
},
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
if (results.allGood) {
|
||||
|
||||
Reference in New Issue
Block a user