|
|
|
|
@ -946,17 +946,21 @@ class ChatViewModel : ViewModel() {
|
|
|
|
|
r.joinChannel(channelId, nodeId, joinKey, pubkey, addrs, addrCount) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fun startVoiceRecording() { |
|
|
|
|
val ch = _currentChannel.value ?: return |
|
|
|
|
if (!audioRecorder.startRecording(ch.id)) { |
|
|
|
|
private var recordingStopping = false |
|
|
|
|
private var recordingTarget: ConversationTarget? = null |
|
|
|
|
|
|
|
|
|
fun startVoiceRecording(target: ConversationTarget) { |
|
|
|
|
if (recordingStopping) { LogManager.addLog("WARN", "VM", "recording is still stopping"); return } |
|
|
|
|
if (!audioRecorder.startRecording(target.nativeId)) { |
|
|
|
|
LogManager.addLog("ERROR", "VM", "voice recording failed to start") |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
_isRecording.value = true |
|
|
|
|
recordingTarget = target |
|
|
|
|
_isRecordingLocked.value = false |
|
|
|
|
recordingStartTimeMs = System.currentTimeMillis() |
|
|
|
|
_recordingDurationMs.value = 0 |
|
|
|
|
LogManager.addLog("INFO", "VM", "voice recording started ch=${ch.id}") |
|
|
|
|
LogManager.addLog("INFO", "VM", "voice recording started target=${target.nativeId}") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fun lockVoiceRecording() { |
|
|
|
|
@ -964,42 +968,44 @@ class ChatViewModel : ViewModel() {
|
|
|
|
|
LogManager.addLog("DEBUG", "VM", "voice recording locked") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fun stopVoiceRecording(): Int { |
|
|
|
|
if (!_isRecording.value) return 0 |
|
|
|
|
val duration = audioRecorder.stopRecording() |
|
|
|
|
fun stopVoiceRecording() { |
|
|
|
|
if (!_isRecording.value || recordingStopping) return |
|
|
|
|
recordingStopping = true |
|
|
|
|
_isRecording.value = false |
|
|
|
|
_isRecordingLocked.value = false |
|
|
|
|
_recordingDurationMs.value = 0 |
|
|
|
|
val ch = _currentChannel.value |
|
|
|
|
if (ch != null && duration >= 500) { |
|
|
|
|
viewModelScope.launch { |
|
|
|
|
delay(500) |
|
|
|
|
refreshMessages(ch.id) |
|
|
|
|
refreshChannels() |
|
|
|
|
try { |
|
|
|
|
val duration = withContext(Dispatchers.IO) { audioRecorder.stopRecording() } |
|
|
|
|
LogManager.addLog("INFO", "VM", "voice detached target=${recordingTarget?.nativeId} duration=$duration") |
|
|
|
|
} finally { |
|
|
|
|
recordingStopping = false |
|
|
|
|
recordingTarget = null |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
LogManager.addLog("INFO", "VM", "voice recording stopped dur=${duration}ms") |
|
|
|
|
return duration |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fun cancelVoiceRecording() { |
|
|
|
|
audioRecorder.cancelRecording() |
|
|
|
|
if (recordingStopping) return |
|
|
|
|
recordingStopping = true |
|
|
|
|
_isRecording.value = false |
|
|
|
|
_isRecordingLocked.value = false |
|
|
|
|
_recordingDurationMs.value = 0 |
|
|
|
|
LogManager.addLog("INFO", "VM", "voice recording cancelled") |
|
|
|
|
viewModelScope.launch { |
|
|
|
|
try { withContext(Dispatchers.IO) { audioRecorder.cancelRecording() } } |
|
|
|
|
finally { recordingStopping = false; recordingTarget = null } |
|
|
|
|
} |
|
|
|
|
LogManager.addLog("INFO", "VM", "voice recording cancelled target=${recordingTarget?.nativeId}") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fun sendVoiceMessage() { |
|
|
|
|
val duration = stopVoiceRecording() |
|
|
|
|
if (duration < 1000) { |
|
|
|
|
LogManager.addLog("INFO", "VM", "voice too short (${duration}ms), discarded") |
|
|
|
|
} |
|
|
|
|
stopVoiceRecording() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fun sendAttachment(filePath: String) { |
|
|
|
|
fun sendAttachment(filePath: String, target: ConversationTarget, name: String = File(filePath).name) { |
|
|
|
|
val r = repo ?: return |
|
|
|
|
val ch = _currentChannel.value ?: return |
|
|
|
|
if (target is ConversationTarget.Pm) { NativeLib.dmSendFile(target.id, filePath, name); return } |
|
|
|
|
val chId = target.id |
|
|
|
|
val ext = filePath.substringAfterLast('.', "").lowercase() |
|
|
|
|
if (ext in IMAGE_EXTENSIONS) { |
|
|
|
|
viewModelScope.launch { |
|
|
|
|
@ -1010,29 +1016,28 @@ class ChatViewModel : ViewModel() {
|
|
|
|
|
} |
|
|
|
|
val (w, h) = dims |
|
|
|
|
if (w > 0 && h > 0) { |
|
|
|
|
LogManager.addLog("INFO", "VM", "sendAttachment(image) ch=${ch.id} ext=$ext ${w}x${h}") |
|
|
|
|
r.sendPhoto(ch.id, filePath, w, h) |
|
|
|
|
LogManager.addLog("INFO", "VM", "sendAttachment(image) ch=$chId ext=$ext ${w}x${h}") |
|
|
|
|
r.sendPhoto(chId, filePath, w, h) |
|
|
|
|
} else { |
|
|
|
|
LogManager.addLog("WARN", "VM", "image decode failed, sent as file: $filePath") |
|
|
|
|
r.sendAttachment(ch.id, filePath) |
|
|
|
|
r.sendAttachment(chId, filePath) |
|
|
|
|
} |
|
|
|
|
delay(500) |
|
|
|
|
refreshMessages(ch.id) |
|
|
|
|
refreshMessages(chId) |
|
|
|
|
refreshChannels() |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
r.sendAttachment(ch.id, filePath) |
|
|
|
|
r.sendAttachment(chId, filePath) |
|
|
|
|
viewModelScope.launch { |
|
|
|
|
delay(500) |
|
|
|
|
refreshMessages(ch.id) |
|
|
|
|
refreshMessages(chId) |
|
|
|
|
refreshChannels() |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fun sendVideoMessage(filePath: String) { |
|
|
|
|
fun sendVideoMessage(filePath: String, target: ConversationTarget) { |
|
|
|
|
val r = repo ?: return |
|
|
|
|
val ch = _currentChannel.value ?: return |
|
|
|
|
viewModelScope.launch { |
|
|
|
|
val meta = withContext(Dispatchers.IO) { |
|
|
|
|
var dur = 0; var w = 0; var h = 0 |
|
|
|
|
@ -1049,11 +1054,8 @@ class ChatViewModel : ViewModel() {
|
|
|
|
|
} |
|
|
|
|
Triple(dur, w, h) |
|
|
|
|
} |
|
|
|
|
LogManager.addLog("INFO", "VM", "sendVideoMessage ch=${ch.id} dur=${meta.first} ${meta.second}x${meta.third}") |
|
|
|
|
r.sendVideo(ch.id, filePath, meta.first, meta.second, meta.third) |
|
|
|
|
delay(500) |
|
|
|
|
refreshMessages(ch.id) |
|
|
|
|
refreshChannels() |
|
|
|
|
LogManager.addLog("INFO", "VM", "sendVideoMessage target=${target.nativeId} dur=${meta.first} ${meta.second}x${meta.third}") |
|
|
|
|
r.sendVideo(target.nativeId, filePath, meta.first, meta.second, meta.third) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|