- Hide privacy toggle when video compression is selected (compression
already handles metadata stripping) - Pass stripMetadata=false when toggle is hidden for compressed video - Hide compression quality for audio and other non-compressible media types - refactor
This commit is contained in:
+42
-26
@@ -252,11 +252,7 @@ class MetadataStripper {
|
|||||||
return StrippingResult(uri, false)
|
return StrippingResult(uri, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
val extension =
|
val extension = ".m4a"
|
||||||
when {
|
|
||||||
primaryMime.contains("mp4a") || primaryMime.contains("aac") -> ".m4a"
|
|
||||||
else -> ".mp4"
|
|
||||||
}
|
|
||||||
|
|
||||||
tempOutputFile = File.createTempFile("stripped_audio_", extension, context.cacheDir)
|
tempOutputFile = File.createTempFile("stripped_audio_", extension, context.cacheDir)
|
||||||
muxer = MediaMuxer(tempOutputFile.absolutePath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4)
|
muxer = MediaMuxer(tempOutputFile.absolutePath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4)
|
||||||
@@ -321,41 +317,61 @@ class MetadataStripper {
|
|||||||
}
|
}
|
||||||
} ?: return StrippingResult(uri, false)
|
} ?: return StrippingResult(uri, false)
|
||||||
|
|
||||||
val bytes = tempInputFile.readBytes()
|
val fileSize = tempInputFile.length().toInt()
|
||||||
var startOffset = 0
|
var startOffset = 0
|
||||||
var endOffset = bytes.size
|
var endOffset = fileSize
|
||||||
|
|
||||||
// Strip ID3v2 header (at beginning of file)
|
// Read first 10 bytes to check for ID3v2 header
|
||||||
if (bytes.size >= 10 &&
|
val header = ByteArray(10)
|
||||||
bytes[0] == 'I'.code.toByte() &&
|
tempInputFile.inputStream().use { it.read(header) }
|
||||||
bytes[1] == 'D'.code.toByte() &&
|
|
||||||
bytes[2] == '3'.code.toByte()
|
if (fileSize >= 10 &&
|
||||||
|
header[0] == 'I'.code.toByte() &&
|
||||||
|
header[1] == 'D'.code.toByte() &&
|
||||||
|
header[2] == '3'.code.toByte()
|
||||||
) {
|
) {
|
||||||
val size =
|
val size =
|
||||||
(bytes[6].toInt() and 0x7F shl 21) or
|
(header[6].toInt() and 0x7F shl 21) or
|
||||||
(bytes[7].toInt() and 0x7F shl 14) or
|
(header[7].toInt() and 0x7F shl 14) or
|
||||||
(bytes[8].toInt() and 0x7F shl 7) or
|
(header[8].toInt() and 0x7F shl 7) or
|
||||||
(bytes[9].toInt() and 0x7F)
|
(header[9].toInt() and 0x7F)
|
||||||
startOffset = 10 + size
|
startOffset = 10 + size
|
||||||
}
|
}
|
||||||
|
|
||||||
// Strip ID3v1 tag (last 128 bytes)
|
// Read last 128 bytes to check for ID3v1 tag
|
||||||
if (endOffset - startOffset >= 128 &&
|
if (endOffset - startOffset >= 128) {
|
||||||
bytes[endOffset - 128] == 'T'.code.toByte() &&
|
val tail = ByteArray(128)
|
||||||
bytes[endOffset - 127] == 'A'.code.toByte() &&
|
java.io.RandomAccessFile(tempInputFile, "r").use { raf ->
|
||||||
bytes[endOffset - 126] == 'G'.code.toByte()
|
raf.seek((endOffset - 128).toLong())
|
||||||
) {
|
raf.readFully(tail)
|
||||||
endOffset -= 128
|
}
|
||||||
|
if (tail[0] == 'T'.code.toByte() &&
|
||||||
|
tail[1] == 'A'.code.toByte() &&
|
||||||
|
tail[2] == 'G'.code.toByte()
|
||||||
|
) {
|
||||||
|
endOffset -= 128
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (startOffset == 0 && endOffset == bytes.size) {
|
if (startOffset == 0 && endOffset == fileSize) {
|
||||||
tempInputFile.delete()
|
tempInputFile.delete()
|
||||||
return StrippingResult(uri, true) // no tags found, already clean
|
return StrippingResult(uri, true) // no tags found, already clean
|
||||||
}
|
}
|
||||||
|
|
||||||
val tempOutputFile = File.createTempFile("stripped_mp3_", ".mp3", context.cacheDir)
|
val tempOutputFile = File.createTempFile("stripped_mp3_", ".mp3", context.cacheDir)
|
||||||
tempOutputFile.outputStream().use { output ->
|
java.io.RandomAccessFile(tempInputFile, "r").use { raf ->
|
||||||
output.write(bytes, startOffset, endOffset - startOffset)
|
raf.seek(startOffset.toLong())
|
||||||
|
tempOutputFile.outputStream().use { output ->
|
||||||
|
val buffer = ByteArray(8192)
|
||||||
|
var remaining = endOffset - startOffset
|
||||||
|
while (remaining > 0) {
|
||||||
|
val toRead = minOf(buffer.size, remaining)
|
||||||
|
val read = raf.read(buffer, 0, toRead)
|
||||||
|
if (read <= 0) break
|
||||||
|
output.write(buffer, 0, read)
|
||||||
|
remaining -= read
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
tempInputFile.delete()
|
tempInputFile.delete()
|
||||||
|
|
||||||
|
|||||||
@@ -39,8 +39,6 @@ import androidx.compose.foundation.text.KeyboardOptions
|
|||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.CurrencyBitcoin
|
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.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
@@ -127,23 +125,7 @@ fun EditPostView(
|
|||||||
postViewModel.load(edit, versionLookingAt)
|
postViewModel.load(edit, versionLookingAt)
|
||||||
}
|
}
|
||||||
|
|
||||||
postViewModel.strippingFailureDialog?.let { dialogState ->
|
StrippingFailureDialog(postViewModel.strippingFailureDialog)
|
||||||
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(
|
Dialog(
|
||||||
onDismissRequest = { onClose() },
|
onDismissRequest = { onClose() },
|
||||||
|
|||||||
@@ -96,6 +96,21 @@ open class EditPostViewModel : ViewModel() {
|
|||||||
var strippingFailureDialog by mutableStateOf<StrippingFailureState?>(null)
|
var strippingFailureDialog by mutableStateOf<StrippingFailureState?>(null)
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
private suspend fun showStrippingFailureDialog(): Boolean =
|
||||||
|
suspendCancellableCoroutine { continuation ->
|
||||||
|
strippingFailureDialog =
|
||||||
|
StrippingFailureState(
|
||||||
|
onConfirm = {
|
||||||
|
strippingFailureDialog = null
|
||||||
|
continuation.resume(true) {}
|
||||||
|
},
|
||||||
|
onCancel = {
|
||||||
|
strippingFailureDialog = null
|
||||||
|
continuation.resume(false) {}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// Codec selection: false = H264, true = H265
|
// Codec selection: false = H264, true = H265
|
||||||
var useH265Codec by mutableStateOf(false)
|
var useH265Codec by mutableStateOf(false)
|
||||||
|
|
||||||
@@ -203,21 +218,7 @@ open class EditPostViewModel : ViewModel() {
|
|||||||
context,
|
context,
|
||||||
useH265Codec,
|
useH265Codec,
|
||||||
stripMetadata,
|
stripMetadata,
|
||||||
onStrippingFailed = {
|
onStrippingFailed = ::showStrippingFailureDialog,
|
||||||
suspendCancellableCoroutine { continuation ->
|
|
||||||
strippingFailureDialog =
|
|
||||||
StrippingFailureState(
|
|
||||||
onConfirm = {
|
|
||||||
strippingFailureDialog = null
|
|
||||||
continuation.resume(true) {}
|
|
||||||
},
|
|
||||||
onCancel = {
|
|
||||||
strippingFailureDialog = null
|
|
||||||
continuation.resume(false) {}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if (results.allGood) {
|
if (results.allGood) {
|
||||||
|
|||||||
@@ -65,6 +65,21 @@ open class NewMediaModel : ViewModel() {
|
|||||||
var strippingFailureDialog by mutableStateOf<StrippingFailureState?>(null)
|
var strippingFailureDialog by mutableStateOf<StrippingFailureState?>(null)
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
private suspend fun showStrippingFailureDialog(): Boolean =
|
||||||
|
suspendCancellableCoroutine { continuation ->
|
||||||
|
strippingFailureDialog =
|
||||||
|
StrippingFailureState(
|
||||||
|
onConfirm = {
|
||||||
|
strippingFailureDialog = null
|
||||||
|
continuation.resume(true) {}
|
||||||
|
},
|
||||||
|
onCancel = {
|
||||||
|
strippingFailureDialog = null
|
||||||
|
continuation.resume(false) {}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// 0 = Low, 1 = Medium, 2 = High, 3=UNCOMPRESSED
|
// 0 = Low, 1 = Medium, 2 = High, 3=UNCOMPRESSED
|
||||||
var mediaQualitySlider by mutableIntStateOf(1)
|
var mediaQualitySlider by mutableIntStateOf(1)
|
||||||
|
|
||||||
@@ -126,21 +141,7 @@ open class NewMediaModel : ViewModel() {
|
|||||||
context,
|
context,
|
||||||
useH265Codec,
|
useH265Codec,
|
||||||
stripMetadata,
|
stripMetadata,
|
||||||
onStrippingFailed = {
|
onStrippingFailed = ::showStrippingFailureDialog,
|
||||||
suspendCancellableCoroutine { continuation ->
|
|
||||||
strippingFailureDialog =
|
|
||||||
StrippingFailureState(
|
|
||||||
onConfirm = {
|
|
||||||
strippingFailureDialog = null
|
|
||||||
continuation.resume(true) {}
|
|
||||||
},
|
|
||||||
onCancel = {
|
|
||||||
strippingFailureDialog = null
|
|
||||||
continuation.resume(false) {}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if (results.allGood) {
|
if (results.allGood) {
|
||||||
|
|||||||
@@ -32,8 +32,6 @@ import androidx.compose.foundation.layout.padding
|
|||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.text.KeyboardOptions
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material3.AlertDialog
|
|
||||||
import androidx.compose.material3.Button
|
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.OutlinedTextField
|
import androidx.compose.material3.OutlinedTextField
|
||||||
@@ -91,23 +89,7 @@ fun NewMediaView(
|
|||||||
postViewModel.load(account, uris)
|
postViewModel.load(account, uris)
|
||||||
}
|
}
|
||||||
|
|
||||||
postViewModel.strippingFailureDialog?.let { dialogState ->
|
StrippingFailureDialog(postViewModel.strippingFailureDialog)
|
||||||
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(
|
Dialog(
|
||||||
onDismissRequest = { onClose() },
|
onDismissRequest = { onClose() },
|
||||||
|
|||||||
+50
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Vitor Pamplona
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to use,
|
||||||
|
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||||
|
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||||
|
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package com.vitorpamplona.amethyst.ui.actions
|
||||||
|
|
||||||
|
import androidx.compose.material3.AlertDialog
|
||||||
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import com.vitorpamplona.amethyst.R
|
||||||
|
import com.vitorpamplona.amethyst.service.uploads.StrippingFailureState
|
||||||
|
import com.vitorpamplona.amethyst.ui.stringRes
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun StrippingFailureDialog(dialogState: StrippingFailureState?) {
|
||||||
|
dialogState ?: return
|
||||||
|
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
+44
-36
@@ -250,47 +250,52 @@ fun ImageVideoDescription(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingSwitchItem(
|
// Hide privacy toggle when video compression is selected (compression already strips metadata)
|
||||||
title = R.string.strip_metadata_label,
|
val isVideoWithCompression =
|
||||||
description = R.string.strip_metadata_description,
|
uris.first().media.isVideo() == true && mediaQualitySlider != 3
|
||||||
modifier =
|
|
||||||
Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(top = 8.dp),
|
|
||||||
checked = stripMetadata,
|
|
||||||
onCheckedChange = { stripMetadata = it },
|
|
||||||
)
|
|
||||||
|
|
||||||
Row(
|
if (!isVideoWithCompression) {
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
SettingSwitchItem(
|
||||||
modifier =
|
title = R.string.strip_metadata_label,
|
||||||
Modifier
|
description = R.string.strip_metadata_description,
|
||||||
.fillMaxWidth()
|
modifier =
|
||||||
.windowInsetsPadding(WindowInsets(0.dp, 0.dp, 0.dp, 0.dp))
|
Modifier
|
||||||
.padding(vertical = 8.dp),
|
.fillMaxWidth()
|
||||||
) {
|
.padding(top = 8.dp),
|
||||||
Column(
|
checked = stripMetadata,
|
||||||
modifier = Modifier.weight(1.0f),
|
onCheckedChange = { stripMetadata = it },
|
||||||
verticalArrangement = Arrangement.spacedBy(Size5dp),
|
)
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = stringRes(R.string.media_compression_quality_label),
|
|
||||||
maxLines = 1,
|
|
||||||
overflow = TextOverflow.Ellipsis,
|
|
||||||
)
|
|
||||||
Text(
|
|
||||||
text = stringRes(R.string.media_compression_quality_explainer),
|
|
||||||
style = MaterialTheme.typography.bodySmall,
|
|
||||||
color = Color.Gray,
|
|
||||||
maxLines = 5,
|
|
||||||
overflow = TextOverflow.Ellipsis,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val firstMedia = uris.first().media
|
val firstMedia = uris.first().media
|
||||||
|
|
||||||
if (firstMedia.isVideo() == true || firstMedia.isImage() == true) {
|
if (firstMedia.isVideo() == true || firstMedia.isImage() == true) {
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
modifier =
|
||||||
|
Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.windowInsetsPadding(WindowInsets(0.dp, 0.dp, 0.dp, 0.dp))
|
||||||
|
.padding(vertical = 8.dp),
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.weight(1.0f),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(Size5dp),
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = stringRes(R.string.media_compression_quality_label),
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = stringRes(R.string.media_compression_quality_explainer),
|
||||||
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
color = Color.Gray,
|
||||||
|
maxLines = 5,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||||
Box(modifier = Modifier.fillMaxWidth()) {
|
Box(modifier = Modifier.fillMaxWidth()) {
|
||||||
Text(
|
Text(
|
||||||
@@ -334,7 +339,10 @@ fun ImageVideoDescription(
|
|||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(vertical = 10.dp),
|
.padding(vertical = 10.dp),
|
||||||
enabled = !isUploading,
|
enabled = !isUploading,
|
||||||
onClick = { onAdd(message, selectedServer, sensitiveContent, mediaQualitySlider, useH265Codec, stripMetadata) },
|
onClick = {
|
||||||
|
val effectiveStripMetadata = if (isVideoWithCompression) false else stripMetadata
|
||||||
|
onAdd(message, selectedServer, sensitiveContent, mediaQualitySlider, useH265Codec, effectiveStripMetadata)
|
||||||
|
},
|
||||||
shape = QuoteBorder,
|
shape = QuoteBorder,
|
||||||
colors =
|
colors =
|
||||||
ButtonDefaults.buttonColors(
|
ButtonDefaults.buttonColors(
|
||||||
|
|||||||
+16
-15
@@ -168,6 +168,21 @@ open class CommentPostViewModel :
|
|||||||
var strippingFailureDialog by mutableStateOf<StrippingFailureState?>(null)
|
var strippingFailureDialog by mutableStateOf<StrippingFailureState?>(null)
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
private suspend fun showStrippingFailureDialog(): Boolean =
|
||||||
|
suspendCancellableCoroutine { continuation ->
|
||||||
|
strippingFailureDialog =
|
||||||
|
StrippingFailureState(
|
||||||
|
onConfirm = {
|
||||||
|
strippingFailureDialog = null
|
||||||
|
continuation.resume(true) {}
|
||||||
|
},
|
||||||
|
onCancel = {
|
||||||
|
strippingFailureDialog = null
|
||||||
|
continuation.resume(false) {}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// Invoices
|
// Invoices
|
||||||
var canAddInvoice by mutableStateOf(false)
|
var canAddInvoice by mutableStateOf(false)
|
||||||
var wantsInvoice by mutableStateOf(false)
|
var wantsInvoice by mutableStateOf(false)
|
||||||
@@ -509,21 +524,7 @@ open class CommentPostViewModel :
|
|||||||
account,
|
account,
|
||||||
context,
|
context,
|
||||||
stripMetadata = stripMetadata,
|
stripMetadata = stripMetadata,
|
||||||
onStrippingFailed = {
|
onStrippingFailed = ::showStrippingFailureDialog,
|
||||||
suspendCancellableCoroutine { continuation ->
|
|
||||||
strippingFailureDialog =
|
|
||||||
StrippingFailureState(
|
|
||||||
onConfirm = {
|
|
||||||
strippingFailureDialog = null
|
|
||||||
continuation.resume(true) {}
|
|
||||||
},
|
|
||||||
onCancel = {
|
|
||||||
strippingFailureDialog = null
|
|
||||||
continuation.resume(false) {}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if (results.allGood) {
|
if (results.allGood) {
|
||||||
|
|||||||
+2
-20
@@ -34,13 +34,10 @@ import androidx.compose.foundation.layout.imePadding
|
|||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material3.AlertDialog
|
|
||||||
import androidx.compose.material3.Button
|
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Surface
|
import androidx.compose.material3.Surface
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.ui.Alignment.Companion.CenterVertically
|
import androidx.compose.ui.Alignment.Companion.CenterVertically
|
||||||
@@ -51,6 +48,7 @@ import androidx.compose.ui.unit.dp
|
|||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import com.vitorpamplona.amethyst.R
|
import com.vitorpamplona.amethyst.R
|
||||||
import com.vitorpamplona.amethyst.model.Note
|
import com.vitorpamplona.amethyst.model.Note
|
||||||
|
import com.vitorpamplona.amethyst.ui.actions.StrippingFailureDialog
|
||||||
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromFiles
|
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromFiles
|
||||||
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromGallery
|
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromGallery
|
||||||
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia
|
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia
|
||||||
@@ -143,23 +141,7 @@ fun GenericCommentPostScreen(
|
|||||||
) {
|
) {
|
||||||
WatchAndLoadMyEmojiList(accountViewModel)
|
WatchAndLoadMyEmojiList(accountViewModel)
|
||||||
|
|
||||||
postViewModel.strippingFailureDialog?.let { dialogState ->
|
StrippingFailureDialog(postViewModel.strippingFailureDialog)
|
||||||
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 {
|
BackHandler {
|
||||||
accountViewModel.launchSigner {
|
accountViewModel.launchSigner {
|
||||||
|
|||||||
+2
-18
@@ -20,7 +20,6 @@
|
|||||||
*/
|
*/
|
||||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.send
|
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.send
|
||||||
|
|
||||||
import android.R.attr.maxLines
|
|
||||||
import androidx.activity.compose.BackHandler
|
import androidx.activity.compose.BackHandler
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
@@ -42,6 +41,7 @@ import androidx.compose.ui.tooling.preview.Preview
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import com.vitorpamplona.amethyst.R
|
import com.vitorpamplona.amethyst.R
|
||||||
|
import com.vitorpamplona.amethyst.ui.actions.StrippingFailureDialog
|
||||||
import com.vitorpamplona.amethyst.ui.actions.UrlUserTagTransformation
|
import com.vitorpamplona.amethyst.ui.actions.UrlUserTagTransformation
|
||||||
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromGallery
|
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromGallery
|
||||||
import com.vitorpamplona.amethyst.ui.components.ThinPaddingTextField
|
import com.vitorpamplona.amethyst.ui.components.ThinPaddingTextField
|
||||||
@@ -118,23 +118,7 @@ fun PrivateMessageEditFieldRow(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
channelScreenModel.strippingFailureDialog?.let { dialogState ->
|
StrippingFailureDialog(channelScreenModel.strippingFailureDialog)
|
||||||
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 ->
|
channelScreenModel.encryptedUploadErrorTitle?.let { title ->
|
||||||
EncryptedUploadErrorDialog(
|
EncryptedUploadErrorDialog(
|
||||||
|
|||||||
+16
-15
@@ -136,6 +136,21 @@ open class ChannelNewMessageViewModel :
|
|||||||
var strippingFailureDialog by mutableStateOf<StrippingFailureState?>(null)
|
var strippingFailureDialog by mutableStateOf<StrippingFailureState?>(null)
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
private suspend fun showStrippingFailureDialog(): Boolean =
|
||||||
|
suspendCancellableCoroutine { continuation ->
|
||||||
|
strippingFailureDialog =
|
||||||
|
StrippingFailureState(
|
||||||
|
onConfirm = {
|
||||||
|
strippingFailureDialog = null
|
||||||
|
continuation.resume(true) {}
|
||||||
|
},
|
||||||
|
onCancel = {
|
||||||
|
strippingFailureDialog = null
|
||||||
|
continuation.resume(false) {}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
val iMetaAttachments = IMetaAttachments()
|
val iMetaAttachments = IMetaAttachments()
|
||||||
var nip95attachments by mutableStateOf<List<Pair<FileStorageEvent, FileStorageHeaderEvent>>>(emptyList())
|
var nip95attachments by mutableStateOf<List<Pair<FileStorageEvent, FileStorageHeaderEvent>>>(emptyList())
|
||||||
|
|
||||||
@@ -356,21 +371,7 @@ open class ChannelNewMessageViewModel :
|
|||||||
account,
|
account,
|
||||||
context,
|
context,
|
||||||
stripMetadata = uploadState.stripMetadata,
|
stripMetadata = uploadState.stripMetadata,
|
||||||
onStrippingFailed = {
|
onStrippingFailed = ::showStrippingFailureDialog,
|
||||||
suspendCancellableCoroutine { continuation ->
|
|
||||||
strippingFailureDialog =
|
|
||||||
StrippingFailureState(
|
|
||||||
onConfirm = {
|
|
||||||
strippingFailureDialog = null
|
|
||||||
continuation.resume(true) {}
|
|
||||||
},
|
|
||||||
onCancel = {
|
|
||||||
strippingFailureDialog = null
|
|
||||||
continuation.resume(false) {}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if (results.allGood) {
|
if (results.allGood) {
|
||||||
|
|||||||
+2
-19
@@ -26,8 +26,6 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
|||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.text.KeyboardOptions
|
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.LocalTextStyle
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
@@ -39,6 +37,7 @@ import androidx.compose.ui.text.input.KeyboardCapitalization
|
|||||||
import androidx.compose.ui.text.style.TextDirection
|
import androidx.compose.ui.text.style.TextDirection
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.vitorpamplona.amethyst.R
|
import com.vitorpamplona.amethyst.R
|
||||||
|
import com.vitorpamplona.amethyst.ui.actions.StrippingFailureDialog
|
||||||
import com.vitorpamplona.amethyst.ui.actions.UrlUserTagTransformation
|
import com.vitorpamplona.amethyst.ui.actions.UrlUserTagTransformation
|
||||||
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromGallery
|
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromGallery
|
||||||
import com.vitorpamplona.amethyst.ui.components.ThinPaddingTextField
|
import com.vitorpamplona.amethyst.ui.components.ThinPaddingTextField
|
||||||
@@ -72,23 +71,7 @@ fun EditFieldRow(
|
|||||||
nav.popBack()
|
nav.popBack()
|
||||||
}
|
}
|
||||||
|
|
||||||
channelScreenModel.strippingFailureDialog?.let { dialogState ->
|
StrippingFailureDialog(channelScreenModel.strippingFailureDialog)
|
||||||
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 {
|
channelScreenModel.replyTo.value?.let {
|
||||||
DisplayReplyingToNote(it, accountViewModel, nav) {
|
DisplayReplyingToNote(it, accountViewModel, nav) {
|
||||||
|
|||||||
+2
-20
@@ -33,13 +33,10 @@ import androidx.compose.foundation.layout.imePadding
|
|||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material3.AlertDialog
|
|
||||||
import androidx.compose.material3.Button
|
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Surface
|
import androidx.compose.material3.Surface
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.ui.Alignment.Companion.CenterVertically
|
import androidx.compose.ui.Alignment.Companion.CenterVertically
|
||||||
@@ -50,6 +47,7 @@ import androidx.compose.ui.unit.dp
|
|||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import com.vitorpamplona.amethyst.R
|
import com.vitorpamplona.amethyst.R
|
||||||
import com.vitorpamplona.amethyst.model.Note
|
import com.vitorpamplona.amethyst.model.Note
|
||||||
|
import com.vitorpamplona.amethyst.ui.actions.StrippingFailureDialog
|
||||||
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromFiles
|
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromFiles
|
||||||
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromGallery
|
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromGallery
|
||||||
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia
|
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia
|
||||||
@@ -140,23 +138,7 @@ fun NewProductScreen(
|
|||||||
) {
|
) {
|
||||||
WatchAndLoadMyEmojiList(accountViewModel)
|
WatchAndLoadMyEmojiList(accountViewModel)
|
||||||
|
|
||||||
postViewModel.strippingFailureDialog?.let { dialogState ->
|
StrippingFailureDialog(postViewModel.strippingFailureDialog)
|
||||||
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 {
|
BackHandler {
|
||||||
accountViewModel.launchSigner {
|
accountViewModel.launchSigner {
|
||||||
|
|||||||
+16
-15
@@ -152,6 +152,21 @@ open class NewProductViewModel :
|
|||||||
var strippingFailureDialog by mutableStateOf<StrippingFailureState?>(null)
|
var strippingFailureDialog by mutableStateOf<StrippingFailureState?>(null)
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
private suspend fun showStrippingFailureDialog(): Boolean =
|
||||||
|
suspendCancellableCoroutine { continuation ->
|
||||||
|
strippingFailureDialog =
|
||||||
|
StrippingFailureState(
|
||||||
|
onConfirm = {
|
||||||
|
strippingFailureDialog = null
|
||||||
|
continuation.resume(true) {}
|
||||||
|
},
|
||||||
|
onCancel = {
|
||||||
|
strippingFailureDialog = null
|
||||||
|
continuation.resume(false) {}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// Classifieds
|
// Classifieds
|
||||||
var title by mutableStateOf(TextFieldValue(""))
|
var title by mutableStateOf(TextFieldValue(""))
|
||||||
var price by mutableStateOf(TextFieldValue(""))
|
var price by mutableStateOf(TextFieldValue(""))
|
||||||
@@ -417,21 +432,7 @@ open class NewProductViewModel :
|
|||||||
myAccount,
|
myAccount,
|
||||||
context,
|
context,
|
||||||
stripMetadata = stripMetadata,
|
stripMetadata = stripMetadata,
|
||||||
onStrippingFailed = {
|
onStrippingFailed = ::showStrippingFailureDialog,
|
||||||
suspendCancellableCoroutine { continuation ->
|
|
||||||
strippingFailureDialog =
|
|
||||||
StrippingFailureState(
|
|
||||||
onConfirm = {
|
|
||||||
strippingFailureDialog = null
|
|
||||||
continuation.resume(true) {}
|
|
||||||
},
|
|
||||||
onCancel = {
|
|
||||||
strippingFailureDialog = null
|
|
||||||
continuation.resume(false) {}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if (results.allGood) {
|
if (results.allGood) {
|
||||||
|
|||||||
+2
-20
@@ -39,8 +39,6 @@ import androidx.compose.foundation.rememberScrollState
|
|||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.outlined.Poll
|
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.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
@@ -48,7 +46,6 @@ import androidx.compose.material3.MaterialTheme
|
|||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Surface
|
import androidx.compose.material3.Surface
|
||||||
import androidx.compose.material3.Switch
|
import androidx.compose.material3.Switch
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.DisposableEffect
|
import androidx.compose.runtime.DisposableEffect
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
@@ -63,6 +60,7 @@ import androidx.core.util.Consumer
|
|||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import com.vitorpamplona.amethyst.R
|
import com.vitorpamplona.amethyst.R
|
||||||
import com.vitorpamplona.amethyst.model.Note
|
import com.vitorpamplona.amethyst.model.Note
|
||||||
|
import com.vitorpamplona.amethyst.ui.actions.StrippingFailureDialog
|
||||||
import com.vitorpamplona.amethyst.ui.actions.mediaServers.FileServerSelectionRow
|
import com.vitorpamplona.amethyst.ui.actions.mediaServers.FileServerSelectionRow
|
||||||
import com.vitorpamplona.amethyst.ui.actions.uploads.MAX_VOICE_RECORD_SECONDS
|
import com.vitorpamplona.amethyst.ui.actions.uploads.MAX_VOICE_RECORD_SECONDS
|
||||||
import com.vitorpamplona.amethyst.ui.actions.uploads.RecordVoiceButton
|
import com.vitorpamplona.amethyst.ui.actions.uploads.RecordVoiceButton
|
||||||
@@ -182,23 +180,7 @@ private fun NewPostScreenInner(
|
|||||||
) {
|
) {
|
||||||
WatchAndLoadMyEmojiList(accountViewModel)
|
WatchAndLoadMyEmojiList(accountViewModel)
|
||||||
|
|
||||||
postViewModel.strippingFailureDialog?.let { dialogState ->
|
StrippingFailureDialog(postViewModel.strippingFailureDialog)
|
||||||
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 {
|
BackHandler {
|
||||||
accountViewModel.launchSigner {
|
accountViewModel.launchSigner {
|
||||||
|
|||||||
+16
-15
@@ -197,6 +197,21 @@ open class ShortNotePostViewModel :
|
|||||||
var strippingFailureDialog by mutableStateOf<StrippingFailureState?>(null)
|
var strippingFailureDialog by mutableStateOf<StrippingFailureState?>(null)
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
private suspend fun showStrippingFailureDialog(): Boolean =
|
||||||
|
suspendCancellableCoroutine { continuation ->
|
||||||
|
strippingFailureDialog =
|
||||||
|
StrippingFailureState(
|
||||||
|
onConfirm = {
|
||||||
|
strippingFailureDialog = null
|
||||||
|
continuation.resume(true) {}
|
||||||
|
},
|
||||||
|
onCancel = {
|
||||||
|
strippingFailureDialog = null
|
||||||
|
continuation.resume(false) {}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// Voice Messages
|
// Voice Messages
|
||||||
var voiceRecording by mutableStateOf<RecordingResult?>(null)
|
var voiceRecording by mutableStateOf<RecordingResult?>(null)
|
||||||
var voiceLocalFile by mutableStateOf<java.io.File?>(null)
|
var voiceLocalFile by mutableStateOf<java.io.File?>(null)
|
||||||
@@ -852,21 +867,7 @@ open class ShortNotePostViewModel :
|
|||||||
context,
|
context,
|
||||||
useH265,
|
useH265,
|
||||||
stripMetadata,
|
stripMetadata,
|
||||||
onStrippingFailed = {
|
onStrippingFailed = ::showStrippingFailureDialog,
|
||||||
suspendCancellableCoroutine { continuation ->
|
|
||||||
strippingFailureDialog =
|
|
||||||
StrippingFailureState(
|
|
||||||
onConfirm = {
|
|
||||||
strippingFailureDialog = null
|
|
||||||
continuation.resume(true) {}
|
|
||||||
},
|
|
||||||
onCancel = {
|
|
||||||
strippingFailureDialog = null
|
|
||||||
continuation.resume(false) {}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if (results.allGood) {
|
if (results.allGood) {
|
||||||
|
|||||||
+2
-19
@@ -33,8 +33,6 @@ import androidx.compose.foundation.layout.imePadding
|
|||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material3.AlertDialog
|
|
||||||
import androidx.compose.material3.Button
|
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.HorizontalDivider
|
import androidx.compose.material3.HorizontalDivider
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
@@ -58,6 +56,7 @@ import androidx.compose.ui.unit.dp
|
|||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import com.vitorpamplona.amethyst.R
|
import com.vitorpamplona.amethyst.R
|
||||||
import com.vitorpamplona.amethyst.model.Note
|
import com.vitorpamplona.amethyst.model.Note
|
||||||
|
import com.vitorpamplona.amethyst.ui.actions.StrippingFailureDialog
|
||||||
import com.vitorpamplona.amethyst.ui.actions.UrlUserTagTransformation
|
import com.vitorpamplona.amethyst.ui.actions.UrlUserTagTransformation
|
||||||
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromFiles
|
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromFiles
|
||||||
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromGallery
|
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromGallery
|
||||||
@@ -133,23 +132,7 @@ fun NewPublicMessageScreen(
|
|||||||
|
|
||||||
WatchAndLoadMyEmojiList(accountViewModel)
|
WatchAndLoadMyEmojiList(accountViewModel)
|
||||||
|
|
||||||
postViewModel.strippingFailureDialog?.let { dialogState ->
|
StrippingFailureDialog(postViewModel.strippingFailureDialog)
|
||||||
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 {
|
BackHandler {
|
||||||
accountViewModel.launchSigner {
|
accountViewModel.launchSigner {
|
||||||
|
|||||||
+16
-15
@@ -170,6 +170,21 @@ class NewPublicMessageViewModel :
|
|||||||
var strippingFailureDialog by mutableStateOf<StrippingFailureState?>(null)
|
var strippingFailureDialog by mutableStateOf<StrippingFailureState?>(null)
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
private suspend fun showStrippingFailureDialog(): Boolean =
|
||||||
|
suspendCancellableCoroutine { continuation ->
|
||||||
|
strippingFailureDialog =
|
||||||
|
StrippingFailureState(
|
||||||
|
onConfirm = {
|
||||||
|
strippingFailureDialog = null
|
||||||
|
continuation.resume(true) {}
|
||||||
|
},
|
||||||
|
onCancel = {
|
||||||
|
strippingFailureDialog = null
|
||||||
|
continuation.resume(false) {}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// Invoices
|
// Invoices
|
||||||
var canAddInvoice by mutableStateOf(false)
|
var canAddInvoice by mutableStateOf(false)
|
||||||
var wantsInvoice by mutableStateOf(false)
|
var wantsInvoice by mutableStateOf(false)
|
||||||
@@ -461,21 +476,7 @@ class NewPublicMessageViewModel :
|
|||||||
account,
|
account,
|
||||||
context,
|
context,
|
||||||
stripMetadata = stripMetadata,
|
stripMetadata = stripMetadata,
|
||||||
onStrippingFailed = {
|
onStrippingFailed = ::showStrippingFailureDialog,
|
||||||
suspendCancellableCoroutine { continuation ->
|
|
||||||
strippingFailureDialog =
|
|
||||||
StrippingFailureState(
|
|
||||||
onConfirm = {
|
|
||||||
strippingFailureDialog = null
|
|
||||||
continuation.resume(true) {}
|
|
||||||
},
|
|
||||||
onCancel = {
|
|
||||||
strippingFailureDialog = null
|
|
||||||
continuation.resume(false) {}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if (results.allGood) {
|
if (results.allGood) {
|
||||||
|
|||||||
Reference in New Issue
Block a user