Merge pull request #1636 from davotoula/reduce-sonarcube-warnings
Reduce sonarcube warnings
This commit is contained in:
@@ -248,10 +248,8 @@ object LocalPreferences {
|
|||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
val prefsDir = File(prefsDirPath)
|
val prefsDir = File(prefsDirPath)
|
||||||
prefsDir.list()?.forEach {
|
prefsDir.list()?.forEach {
|
||||||
if (it.contains(npub)) {
|
if (it.contains(npub) && !File(prefsDir, it).delete()) {
|
||||||
if (!File(prefsDir, it).delete()) {
|
Log.w("LocalPreferences", "Failed to delete preference file: $it")
|
||||||
Log.w("LocalPreferences", "Failed to delete preference file: $it")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ package com.vitorpamplona.amethyst.service.relays
|
|||||||
|
|
||||||
import androidx.collection.LruCache
|
import androidx.collection.LruCache
|
||||||
import com.vitorpamplona.amethyst.model.User
|
import com.vitorpamplona.amethyst.model.User
|
||||||
import com.vitorpamplona.amethyst.service.relays.MutableTime
|
|
||||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||||
|
|
||||||
typealias SincePerRelayMap = MutableMap<NormalizedRelayUrl, MutableTime>
|
typealias SincePerRelayMap = MutableMap<NormalizedRelayUrl, MutableTime>
|
||||||
|
|||||||
+135
-94
@@ -74,64 +74,23 @@ fun VoiceMessagePreview(
|
|||||||
var progress by remember { mutableFloatStateOf(0f) }
|
var progress by remember { mutableFloatStateOf(0f) }
|
||||||
var mediaPlayer by remember { mutableStateOf<MediaPlayer?>(null) }
|
var mediaPlayer by remember { mutableStateOf<MediaPlayer?>(null) }
|
||||||
|
|
||||||
// Initialize MediaPlayer
|
ManageMediaPlayer(
|
||||||
DisposableEffect(voiceMetadata.url, localFile) {
|
voiceMetadata = voiceMetadata,
|
||||||
val player = createMediaPlayer(voiceMetadata.url, localFile)
|
localFile = localFile,
|
||||||
player?.setOnCompletionListener {
|
onCompletion = {
|
||||||
isPlaying = false
|
isPlaying = false
|
||||||
progress = 0f
|
progress = 0f
|
||||||
}
|
},
|
||||||
mediaPlayer = player
|
onPlayerChanged = { mediaPlayer = it },
|
||||||
|
onRelease = { isPlaying = false },
|
||||||
|
)
|
||||||
|
|
||||||
onDispose {
|
TrackPlaybackProgress(
|
||||||
// Stop playback and clean up
|
mediaPlayer = mediaPlayer,
|
||||||
try {
|
isPlaying = isPlaying,
|
||||||
player?.stop()
|
onProgressUpdate = { progress = it },
|
||||||
} catch (e: IllegalStateException) {
|
onInvalidState = { isPlaying = false },
|
||||||
// Player might already be stopped
|
)
|
||||||
Log.d("VoiceMessagePreview", "MediaPlayer stop failed (already stopped)", e)
|
|
||||||
}
|
|
||||||
player?.release()
|
|
||||||
mediaPlayer = null
|
|
||||||
isPlaying = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update progress while playing
|
|
||||||
LaunchedEffect(mediaPlayer, isPlaying) {
|
|
||||||
// Capture player reference to avoid reading volatile state repeatedly
|
|
||||||
val player = mediaPlayer
|
|
||||||
if (player != null && isPlaying) {
|
|
||||||
while (isActive) {
|
|
||||||
try {
|
|
||||||
if (player.isPlaying) {
|
|
||||||
val current = player.currentPosition.toFloat()
|
|
||||||
val duration = player.duration.toFloat()
|
|
||||||
// Validate values before calculating progress
|
|
||||||
val newProgress =
|
|
||||||
if (duration > 0 && current >= 0) {
|
|
||||||
(current / duration).coerceIn(0f, 1f)
|
|
||||||
} else {
|
|
||||||
0f
|
|
||||||
}
|
|
||||||
// Only update if value is valid (not NaN or Infinity)
|
|
||||||
if (newProgress.isFinite()) {
|
|
||||||
progress = newProgress
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Player stopped, exit loop and let LaunchedEffect restart
|
|
||||||
break
|
|
||||||
}
|
|
||||||
} catch (e: IllegalStateException) {
|
|
||||||
// Player in invalid state, stop tracking
|
|
||||||
Log.w("VoiceMessagePreview", "MediaPlayer in invalid state during progress tracking", e)
|
|
||||||
isPlaying = false
|
|
||||||
break
|
|
||||||
}
|
|
||||||
delay(100)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Box(
|
Box(
|
||||||
modifier =
|
modifier =
|
||||||
@@ -150,27 +109,13 @@ fun VoiceMessagePreview(
|
|||||||
// Play/Pause Button
|
// Play/Pause Button
|
||||||
IconButton(
|
IconButton(
|
||||||
onClick = {
|
onClick = {
|
||||||
val player = mediaPlayer
|
handlePlayPauseClick(
|
||||||
if (player != null) {
|
mediaPlayer = mediaPlayer,
|
||||||
try {
|
isPlaying = isPlaying,
|
||||||
if (isPlaying) {
|
progress = progress,
|
||||||
player.pause()
|
onProgressReset = { progress = 0f },
|
||||||
isPlaying = false
|
onPlayingChanged = { isPlaying = it },
|
||||||
} else {
|
)
|
||||||
// Validate progress before comparison
|
|
||||||
if (progress.isFinite() && progress >= 1f) {
|
|
||||||
player.seekTo(0)
|
|
||||||
progress = 0f
|
|
||||||
}
|
|
||||||
player.start()
|
|
||||||
isPlaying = true
|
|
||||||
}
|
|
||||||
} catch (e: IllegalStateException) {
|
|
||||||
// MediaPlayer in invalid state, ignore
|
|
||||||
Log.w("VoiceMessagePreview", "MediaPlayer operation failed in onClick handler", e)
|
|
||||||
isPlaying = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
modifier = Modifier.size(48.dp),
|
modifier = Modifier.size(48.dp),
|
||||||
) {
|
) {
|
||||||
@@ -194,24 +139,11 @@ fun VoiceMessagePreview(
|
|||||||
waveformBrush = Brush.linearGradient(listOf(MaterialTheme.colorScheme.onSurfaceVariant, MaterialTheme.colorScheme.onSurfaceVariant)),
|
waveformBrush = Brush.linearGradient(listOf(MaterialTheme.colorScheme.onSurfaceVariant, MaterialTheme.colorScheme.onSurfaceVariant)),
|
||||||
progressBrush = Brush.linearGradient(listOf(MaterialTheme.colorScheme.primary, MaterialTheme.colorScheme.primary)),
|
progressBrush = Brush.linearGradient(listOf(MaterialTheme.colorScheme.primary, MaterialTheme.colorScheme.primary)),
|
||||||
onProgressChange = { newProgress ->
|
onProgressChange = { newProgress ->
|
||||||
// Validate incoming progress value
|
handleWaveformScrub(
|
||||||
if (newProgress.isFinite() && newProgress >= 0f && newProgress <= 1f) {
|
newProgress = newProgress,
|
||||||
val player = mediaPlayer
|
mediaPlayer = mediaPlayer,
|
||||||
if (player != null) {
|
onProgressChanged = { progress = it },
|
||||||
try {
|
)
|
||||||
val duration = player.duration
|
|
||||||
// Only seek if duration is valid
|
|
||||||
if (duration > 0) {
|
|
||||||
val newPosition = (newProgress * duration).toInt()
|
|
||||||
player.seekTo(newPosition)
|
|
||||||
progress = newProgress
|
|
||||||
}
|
|
||||||
} catch (e: IllegalStateException) {
|
|
||||||
// MediaPlayer in invalid state, ignore
|
|
||||||
Log.w("VoiceMessagePreview", "MediaPlayer seek failed in onProgressChange", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -240,6 +172,115 @@ fun VoiceMessagePreview(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ManageMediaPlayer(
|
||||||
|
voiceMetadata: AudioMeta,
|
||||||
|
localFile: File?,
|
||||||
|
onCompletion: () -> Unit,
|
||||||
|
onPlayerChanged: (MediaPlayer?) -> Unit,
|
||||||
|
onRelease: () -> Unit,
|
||||||
|
) {
|
||||||
|
DisposableEffect(voiceMetadata.url, localFile) {
|
||||||
|
val player = createMediaPlayer(voiceMetadata.url, localFile)
|
||||||
|
player?.setOnCompletionListener { onCompletion() }
|
||||||
|
onPlayerChanged(player)
|
||||||
|
|
||||||
|
onDispose {
|
||||||
|
try {
|
||||||
|
player?.stop()
|
||||||
|
} catch (e: IllegalStateException) {
|
||||||
|
Log.d("VoiceMessagePreview", "MediaPlayer stop failed (already stopped)", e)
|
||||||
|
}
|
||||||
|
player?.release()
|
||||||
|
onPlayerChanged(null)
|
||||||
|
onRelease()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun TrackPlaybackProgress(
|
||||||
|
mediaPlayer: MediaPlayer?,
|
||||||
|
isPlaying: Boolean,
|
||||||
|
onProgressUpdate: (Float) -> Unit,
|
||||||
|
onInvalidState: () -> Unit,
|
||||||
|
) {
|
||||||
|
LaunchedEffect(mediaPlayer, isPlaying) {
|
||||||
|
val player = mediaPlayer ?: return@LaunchedEffect
|
||||||
|
if (!isPlaying) return@LaunchedEffect
|
||||||
|
|
||||||
|
while (isActive) {
|
||||||
|
try {
|
||||||
|
if (!player.isPlaying) break
|
||||||
|
calculateProgress(player.currentPosition.toFloat(), player.duration.toFloat())?.let { onProgressUpdate(it) }
|
||||||
|
} catch (e: IllegalStateException) {
|
||||||
|
Log.w("VoiceMessagePreview", "MediaPlayer in invalid state during progress tracking", e)
|
||||||
|
onInvalidState()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
delay(100)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun calculateProgress(
|
||||||
|
current: Float,
|
||||||
|
duration: Float,
|
||||||
|
): Float? {
|
||||||
|
val progress =
|
||||||
|
if (duration > 0 && current >= 0) {
|
||||||
|
(current / duration).coerceIn(0f, 1f)
|
||||||
|
} else {
|
||||||
|
0f
|
||||||
|
}
|
||||||
|
return progress.takeIf { it.isFinite() }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handlePlayPauseClick(
|
||||||
|
mediaPlayer: MediaPlayer?,
|
||||||
|
isPlaying: Boolean,
|
||||||
|
progress: Float,
|
||||||
|
onProgressReset: () -> Unit,
|
||||||
|
onPlayingChanged: (Boolean) -> Unit,
|
||||||
|
) {
|
||||||
|
val player = mediaPlayer ?: return
|
||||||
|
try {
|
||||||
|
if (isPlaying) {
|
||||||
|
player.pause()
|
||||||
|
onPlayingChanged(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (progress.isFinite() && progress >= 1f) {
|
||||||
|
player.seekTo(0)
|
||||||
|
onProgressReset()
|
||||||
|
}
|
||||||
|
player.start()
|
||||||
|
onPlayingChanged(true)
|
||||||
|
} catch (e: IllegalStateException) {
|
||||||
|
Log.w("VoiceMessagePreview", "MediaPlayer operation failed in onClick handler", e)
|
||||||
|
onPlayingChanged(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleWaveformScrub(
|
||||||
|
newProgress: Float,
|
||||||
|
mediaPlayer: MediaPlayer?,
|
||||||
|
onProgressChanged: (Float) -> Unit,
|
||||||
|
) {
|
||||||
|
if (!newProgress.isFinite() || newProgress < 0f || newProgress > 1f) return
|
||||||
|
val player = mediaPlayer ?: return
|
||||||
|
try {
|
||||||
|
val duration = player.duration
|
||||||
|
if (duration > 0) {
|
||||||
|
val newPosition = (newProgress * duration).toInt()
|
||||||
|
player.seekTo(newPosition)
|
||||||
|
onProgressChanged(newProgress)
|
||||||
|
}
|
||||||
|
} catch (e: IllegalStateException) {
|
||||||
|
Log.w("VoiceMessagePreview", "MediaPlayer seek failed in onProgressChange", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun createMediaPlayer(
|
private fun createMediaPlayer(
|
||||||
url: String,
|
url: String,
|
||||||
localFile: File?,
|
localFile: File?,
|
||||||
|
|||||||
-1
@@ -972,7 +972,6 @@ open class ShortNotePostViewModel :
|
|||||||
val uploadErrorTitle = stringRes(appContext, R.string.upload_error_title)
|
val uploadErrorTitle = stringRes(appContext, R.string.upload_error_title)
|
||||||
val uploadVoiceNip95NotSupported = stringRes(appContext, R.string.upload_error_voice_message_nip95_not_supported)
|
val uploadVoiceNip95NotSupported = stringRes(appContext, R.string.upload_error_voice_message_nip95_not_supported)
|
||||||
val uploadVoiceFailed = stringRes(appContext, R.string.upload_error_voice_message_failed)
|
val uploadVoiceFailed = stringRes(appContext, R.string.upload_error_voice_message_failed)
|
||||||
val uploadVoiceUnexpected = stringRes(appContext, R.string.upload_error_voice_message_unexpected_state)
|
|
||||||
val uploadVoiceExceptionMessage: (String) -> String = { detail ->
|
val uploadVoiceExceptionMessage: (String) -> String = { detail ->
|
||||||
stringRes(appContext, R.string.upload_error_voice_message_exception, detail)
|
stringRes(appContext, R.string.upload_error_voice_message_exception, detail)
|
||||||
}
|
}
|
||||||
|
|||||||
-2
@@ -30,8 +30,6 @@ import com.vitorpamplona.quartz.nip01Core.core.isAddressable
|
|||||||
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
|
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
|
||||||
import com.vitorpamplona.quartz.nip01Core.store.sqlite.sql.where
|
import com.vitorpamplona.quartz.nip01Core.store.sqlite.sql.where
|
||||||
import com.vitorpamplona.quartz.utils.EventFactory
|
import com.vitorpamplona.quartz.utils.EventFactory
|
||||||
import kotlin.collections.component1
|
|
||||||
import kotlin.collections.component2
|
|
||||||
|
|
||||||
class QueryBuilder(
|
class QueryBuilder(
|
||||||
val fts: FullTextSearchModule,
|
val fts: FullTextSearchModule,
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ import kotlinx.cinterop.ExperimentalForeignApi
|
|||||||
import kotlinx.cinterop.refTo
|
import kotlinx.cinterop.refTo
|
||||||
import platform.Security.SecRandomCopyBytes
|
import platform.Security.SecRandomCopyBytes
|
||||||
import platform.Security.kSecRandomDefault
|
import platform.Security.kSecRandomDefault
|
||||||
import kotlin.random.Random.Default.nextBytes
|
|
||||||
|
|
||||||
actual class SecureRandom {
|
actual class SecureRandom {
|
||||||
actual fun nextInt(): Int {
|
actual fun nextInt(): Int {
|
||||||
|
|||||||
-1
@@ -59,7 +59,6 @@ import com.vitorpamplona.quartz.nip47WalletConnect.jackson.ResponseDeserializer
|
|||||||
import com.vitorpamplona.quartz.nip59Giftwrap.rumors.Rumor
|
import com.vitorpamplona.quartz.nip59Giftwrap.rumors.Rumor
|
||||||
import com.vitorpamplona.quartz.nip59Giftwrap.rumors.jackson.RumorDeserializer
|
import com.vitorpamplona.quartz.nip59Giftwrap.rumors.jackson.RumorDeserializer
|
||||||
import com.vitorpamplona.quartz.nip59Giftwrap.rumors.jackson.RumorSerializer
|
import com.vitorpamplona.quartz.nip59Giftwrap.rumors.jackson.RumorSerializer
|
||||||
import kotlinx.serialization.json.JsonNull.content
|
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
|
|
||||||
class JacksonMapper {
|
class JacksonMapper {
|
||||||
|
|||||||
Reference in New Issue
Block a user