Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 4 additions & 24 deletions core/ui/src/main/java/org/monogram/core/ui/DownloadSettings.kt
Original file line number Diff line number Diff line change
Expand Up @@ -145,9 +145,7 @@ data class AutoDownloadPreset(
}

data class DownloadState(
val lanes: Int = 8,
val speedUpUploads: Boolean = false,
val speedUpDownloads: Boolean = false,
val lanes: Int = 2,
val premium: Boolean = false,
val wifi: AutoDownloadPreset = AutoDownloadPreset.WIFI,
val mobile: AutoDownloadPreset = AutoDownloadPreset.MOBILE,
Expand All @@ -156,12 +154,12 @@ data class DownloadState(
val autoplayVideos: Boolean = true,
val activeNetwork: AutoDownloadNetwork = AutoDownloadNetwork.Wifi,
) {
val effectiveLanes: Int get() = lanes.coerceIn(1, if (premium && speedUpDownloads) 8 else 2)
val parts: Int get() = if (!premium) 2 else if (speedUpDownloads) 8 else 4
val effectiveLanes: Int get() = lanes.coerceIn(1, if (premium) 8 else 2)
val parts: Int get() = 4
val concurrency: DownloadConcurrency
get() = DownloadConcurrency(lanes = effectiveLanes, parts = parts)
val filePartKib: Int get() = 512
val downloadChunkKib: Int get() = if (premium && speedUpDownloads) 512 else 128
val downloadChunkKib: Int get() = if (premium) 512 else 256

fun presetFor(network: AutoDownloadNetwork): AutoDownloadPreset = when (network) {
AutoDownloadNetwork.Wifi -> wifi
Expand All @@ -172,8 +170,6 @@ data class DownloadState(

object DownloadSettings {
private const val PREFS = "monogram_download"
private const val KEY_SPEED_UP_UPLOADS = "speed_up_uploads"
private const val KEY_SPEED_UP_DOWNLOADS = "speed_up_downloads"
private const val KEY_WIFI = "autodownload_wifi"
private const val KEY_MOBILE = "autodownload_mobile"
private const val KEY_ROAMING = "autodownload_roaming"
Expand Down Expand Up @@ -202,8 +198,6 @@ object DownloadSettings {
this.apply = apply
val prefs = app.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
mutable.value = DownloadState(
speedUpUploads = prefs.getBoolean(KEY_SPEED_UP_UPLOADS, false),
speedUpDownloads = prefs.getBoolean(KEY_SPEED_UP_DOWNLOADS, false),
wifi = AutoDownloadPreset.decode(prefs.getString(KEY_WIFI, null), AutoDownloadPreset.WIFI),
mobile = AutoDownloadPreset.decode(prefs.getString(KEY_MOBILE, null), AutoDownloadPreset.MOBILE),
roaming = AutoDownloadPreset.decode(prefs.getString(KEY_ROAMING, null), AutoDownloadPreset.ROAMING),
Expand All @@ -219,18 +213,6 @@ object DownloadSettings {

fun activePreset(): AutoDownloadPreset = mutable.value.presetFor(network.value)

fun setSpeedUpUploads(enabled: Boolean) {
mutable.update { it.copy(speedUpUploads = enabled) }
persist()
apply?.invoke(mutable.value)
}

fun setSpeedUpDownloads(enabled: Boolean) {
mutable.update { it.copy(speedUpDownloads = enabled) }
persist()
apply?.invoke(mutable.value)
}

fun setPremium(premium: Boolean) {
if (mutable.value.premium == premium) return
mutable.update { it.copy(premium = premium) }
Expand Down Expand Up @@ -308,8 +290,6 @@ object DownloadSettings {
val prefs = appContext?.getSharedPreferences(PREFS, Context.MODE_PRIVATE) ?: return
val value = mutable.value
prefs.edit {
putBoolean(KEY_SPEED_UP_UPLOADS, value.speedUpUploads)
putBoolean(KEY_SPEED_UP_DOWNLOADS, value.speedUpDownloads)
putString(KEY_WIFI, value.wifi.encode())
putString(KEY_MOBILE, value.mobile.encode())
putString(KEY_ROAMING, value.roaming.encode())
Expand Down
26 changes: 11 additions & 15 deletions core/ui/src/test/java/org/monogram/core/ui/DownloadSettingsTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,18 @@ class DownloadSettingsTest {
}

@Test
fun downloadBoostRespectsPremiumAndConfiguredLaneCap() {
for (boost in listOf(false, true)) {
val free = DownloadState(speedUpDownloads = boost, premium = false)
assertEquals(DownloadConcurrency(2, 2), free.concurrency)
assertEquals(128, free.downloadChunkKib)
assertEquals(512, free.filePartKib)
}
val premium = DownloadState(premium = true)
assertEquals(DownloadConcurrency(2, 4), premium.concurrency)
assertEquals(128, premium.downloadChunkKib)
val boosted = premium.copy(speedUpDownloads = true, lanes = 7)
assertEquals(DownloadConcurrency(7, 8), boosted.concurrency)
assertEquals(512, boosted.downloadChunkKib)
fun premiumDownloadKeepsLargeChunksWithConservativeConcurrency() {
val free = DownloadState(premium = false, lanes = 99)
assertEquals(DownloadConcurrency(2, 4), free.concurrency)
assertEquals(256, free.downloadChunkKib)
assertEquals(512, free.filePartKib)
val premium = DownloadState(premium = true, lanes = 7)
assertEquals(DownloadConcurrency(7, 4), premium.concurrency)
assertEquals(DownloadConcurrency(2, 4), DownloadState(premium = true).concurrency)
assertEquals(512, premium.downloadChunkKib)
assertEquals(512, premium.filePartKib)
assertEquals(1, DownloadState(lanes = 1).effectiveLanes)
assertEquals(8, boosted.copy(lanes = 99).effectiveLanes)
assertEquals(1, DownloadState(lanes = 1, premium = true).effectiveLanes)
assertEquals(8, DownloadState(lanes = 99, premium = true).effectiveLanes)
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,15 +95,8 @@ internal fun DialogDownloadsSheet(
)
val total = item.totalBytes
Text(
text = if (total != null && total > 0L) {
stringResource(
R.string.dialog_media_download_progress,
formatFileSize(bytes),
formatFileSize(total),
)
} else {
stringResource(R.string.dialog_media_loading)
},
text = downloadProgressText(bytes, total)
?: stringResource(R.string.dialog_media_loading),
style = MaterialTheme.typography.labelMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ internal fun DocumentBubble(
openFailed -> stringResource(R.string.dialog_media_open_failed)
failed && file == null -> stringResource(R.string.dialog_media_failed)
uploading && loading -> stringResource(R.string.dialog_media_uploading)
loading && file == null -> formatDownloadProgress(downloadedBytes, size)
loading && file == null -> downloadProgressText(downloadedBytes, size)
else -> size?.takeIf { it > 0 }?.let(::formatFileSize)
}
sizeText?.let {
Expand Down Expand Up @@ -329,7 +329,7 @@ internal fun AudioBubble(
)
Text(
when {
downloading -> formatDownloadProgress(downloadedBytes, fileSize)
downloading -> downloadProgressText(downloadedBytes, fileSize)
?: stringResource(R.string.dialog_media_loading)

failedHere -> stringResource(R.string.dialog_media_failed)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
package org.monogram.feature.dialog.ui

import android.os.SystemClock
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableLongStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.runtime.setValue
import androidx.compose.ui.res.stringResource
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.compose.LocalLifecycleOwner
import androidx.lifecycle.repeatOnLifecycle
import kotlinx.coroutines.delay
import org.monogram.feature.dialog.R
import org.monogram.network.http.MediaPriority
import org.monogram.core.models.isStickerFileName
import org.monogram.core.ui.AutoDownloadPreset
Expand Down Expand Up @@ -28,6 +42,39 @@ internal fun formatDownloadProgress(bytes: Long, total: Long?): String? {
}
}

internal fun downloadBytesPerSecond(previous: Long, current: Long, elapsedMs: Long): Long =
if (elapsedMs <= 0L || current < previous) 0L
else ((current - previous).toDouble() * 1000.0 / elapsedMs).toLong()

@Composable
internal fun downloadProgressText(bytes: Long, total: Long?, active: Boolean = true): String? {
val latestBytes by rememberUpdatedState(bytes)
var speed by remember(active) { mutableLongStateOf(0L) }
val lifecycle = LocalLifecycleOwner.current.lifecycle
LaunchedEffect(active, lifecycle) {
if (!active) return@LaunchedEffect
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
speed = 0L
var previousBytes = latestBytes
var previousTime = SystemClock.elapsedRealtime()
while (true) {
delay(1000L)
val now = SystemClock.elapsedRealtime()
val received = latestBytes
speed = downloadBytesPerSecond(previousBytes, received, now - previousTime)
previousBytes = received
previousTime = now
}
}
}
val progress = formatDownloadProgress(bytes, total) ?: return null
return if (active) {
stringResource(R.string.dialog_media_progress_speed, progress, formatFileSize(speed))
} else {
progress
}
}

internal fun formatMediaDuration(seconds: Int): String {
val total = seconds.coerceAtLeast(0)
val hours = total / 3600
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ fun MessageMedia(
return@LaunchedEffect
}
val displayPriority = MediaPriority.VISIBLE
var fullCancelled = false
suspend fun fetch(kind: MediaFetchKind): File? = withContext(Dispatchers.IO) {
var networkTries = 0
repeat(16) {
Expand All @@ -216,7 +217,10 @@ fun MessageMedia(
when (result) {
is Outcome.Ok -> return@withContext result.value
is Outcome.Err -> {
if (result.message == "cancelled") return@withContext null
if (result.message == "cancelled") {
if (kind == MediaFetchKind.Full) fullCancelled = true
return@withContext null
}
if (kind == MediaFetchKind.Display && result.message == "no display size") {
return@withContext null
}
Expand Down Expand Up @@ -275,8 +279,11 @@ fun MessageMedia(
if (needFull && fullFile == null) {
fullFailed = false
fullFile = fetch(MediaFetchKind.Full)
fullFailed = fullFile == null && (playing || requestFull)
failed = fullFile == null && thumbFile == null && (playing || requestFull)
fullFailed = fullFile == null && !fullCancelled && (playing || requestFull)
failed = fullFile == null &&
thumbFile == null &&
!fullCancelled &&
(playing || requestFull)
}
}
previewFetchDone = true
Expand Down Expand Up @@ -378,6 +385,8 @@ fun MessageMedia(
onCancel = {
wantFull = false
playing = false
fullFailed = false
failed = false
mediaRepository?.cancel(fullKey)
},
modifier = modifier
Expand Down Expand Up @@ -414,6 +423,8 @@ fun MessageMedia(
},
onCancel = {
wantFull = false
fullFailed = false
failed = false
mediaRepository?.cancel(fullKey)
},
modifier = modifier
Expand Down
1 change: 1 addition & 0 deletions feature/dialog/src/main/res/values-es/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -352,4 +352,5 @@
<string name="dialog_editor_language">Lenguaje (opcional)</string>
<string name="dialog_editor_open">Ampliar editor</string>
<string name="dialog_rich_date_at_time">%1$s a las %2$s</string>
<string name="dialog_media_progress_speed">%1$s · %2$s/s</string>
</resources>
1 change: 1 addition & 0 deletions feature/dialog/src/main/res/values-hy/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -352,4 +352,5 @@
<string name="dialog_editor_language">Լեզու (ըստ ցանկության)</string>
<string name="dialog_editor_open">Ընդլայնել խմբագիրը</string>
<string name="dialog_rich_date_at_time">%1$s, %2$s</string>
<string name="dialog_media_progress_speed">%1$s · %2$s/վ</string>
</resources>
1 change: 1 addition & 0 deletions feature/dialog/src/main/res/values-ja/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -341,4 +341,5 @@
<string name="dialog_editor_language">言語(任意)</string>
<string name="dialog_editor_open">エディターを展開</string>
<string name="dialog_rich_date_at_time">%1$s %2$s</string>
<string name="dialog_media_progress_speed">%1$s · %2$s/秒</string>
</resources>
1 change: 1 addition & 0 deletions feature/dialog/src/main/res/values-pt-rBR/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -352,4 +352,5 @@
<string name="dialog_editor_language">Linguagem (opcional)</string>
<string name="dialog_editor_open">Expandir editor</string>
<string name="dialog_rich_date_at_time">%1$s às %2$s</string>
<string name="dialog_media_progress_speed">%1$s · %2$s/s</string>
</resources>
1 change: 1 addition & 0 deletions feature/dialog/src/main/res/values-ru/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -374,4 +374,5 @@
<string name="dialog_editor_language">Язык (необязательно)</string>
<string name="dialog_editor_open">Развернуть редактор</string>
<string name="dialog_rich_date_at_time">%1$s в %2$s</string>
<string name="dialog_media_progress_speed">%1$s · %2$s/с</string>
</resources>
1 change: 1 addition & 0 deletions feature/dialog/src/main/res/values-sk/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -374,4 +374,5 @@
<string name="dialog_editor_language">Jazyk (voliteľné)</string>
<string name="dialog_editor_open">Rozbaliť editor</string>
<string name="dialog_rich_date_at_time">%1$s o %2$s</string>
<string name="dialog_media_progress_speed">%1$s · %2$s/s</string>
</resources>
1 change: 1 addition & 0 deletions feature/dialog/src/main/res/values-tr/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -352,4 +352,5 @@
<string name="dialog_editor_language">Dil (isteğe bağlı)</string>
<string name="dialog_editor_open">Düzenleyiciyi genişlet</string>
<string name="dialog_rich_date_at_time">%1$s saat %2$s</string>
<string name="dialog_media_progress_speed">%1$s · %2$s/sn</string>
</resources>
1 change: 1 addition & 0 deletions feature/dialog/src/main/res/values-uk/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -374,4 +374,5 @@
<string name="dialog_editor_language">Мова (необов’язково)</string>
<string name="dialog_editor_open">Розгорнути редактор</string>
<string name="dialog_rich_date_at_time">%1$s о %2$s</string>
<string name="dialog_media_progress_speed">%1$s · %2$s/с</string>
</resources>
1 change: 1 addition & 0 deletions feature/dialog/src/main/res/values-zh/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -341,4 +341,5 @@
<string name="dialog_editor_language">语言(可选)</string>
<string name="dialog_editor_open">展开编辑器</string>
<string name="dialog_rich_date_at_time">%1$s %2$s</string>
<string name="dialog_media_progress_speed">%1$s · %2$s/秒</string>
</resources>
1 change: 1 addition & 0 deletions feature/dialog/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -353,4 +353,5 @@
<string name="dialog_editor_language">Language (optional)</string>
<string name="dialog_editor_open">Expand editor</string>
<string name="dialog_rich_date_at_time">%1$s at %2$s</string>
<string name="dialog_media_progress_speed">%1$s · %2$s/s</string>
</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,14 @@ class MediaDurationTest {
assertEquals("2 KB", formatFileSize(2048))
}

@Test
fun downloadSpeedUsesElapsedTimeAndResetsAfterRestart() {
assertEquals(2048L, downloadBytesPerSecond(1024, 4096, 1500))
assertEquals(0L, downloadBytesPerSecond(4096, 4096, 1000))
assertEquals(0L, downloadBytesPerSecond(4096, 1024, 1000))
assertEquals(0L, downloadBytesPerSecond(1024, 4096, 0))
}

@Test
fun downloadProgressUsesKnownTotal() {
assertEquals(0f, downloadProgressFraction(0, 2000)!!, 0.001f)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,6 @@ fun SettingsContent(
cacheMessage = state.cacheMessage,
loading = state.loading || state.loggingOut,
download = download,
onSpeedUpDownloads = DownloadSettings::setSpeedUpDownloads,
onOpenAutoDownload = { network ->
component.openPage(
SettingsPage.AutoDownload(autoDownloadNetworkKey(network)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import androidx.compose.material.icons.automirrored.outlined.InsertDriveFile
import androidx.compose.material.icons.automirrored.outlined.KeyboardArrowRight
import androidx.compose.material.icons.outlined.BugReport
import androidx.compose.material.icons.outlined.CellTower
import androidx.compose.material.icons.outlined.CloudDownload
import androidx.compose.material.icons.outlined.DeleteSweep
import androidx.compose.material.icons.outlined.EmojiEmotions
import androidx.compose.material.icons.outlined.Gif
Expand Down Expand Up @@ -169,7 +168,6 @@ internal fun LazyListScope.dataItems(
cacheMessage: String?,
loading: Boolean,
download: DownloadState,
onSpeedUpDownloads: (Boolean) -> Unit,
onOpenAutoDownload: (AutoDownloadNetwork) -> Unit,
onClear: () -> Unit,
onClearChat: (Long) -> Unit,
Expand Down Expand Up @@ -304,24 +302,6 @@ internal fun LazyListScope.dataItems(
)
}
item { Spacer(Modifier.height(8.dp)) }
item { SectionHeader(stringResource(R.string.settings_data_transfers)) }
item {
SettingsTile(
icon = Icons.Outlined.CloudDownload,
title = stringResource(R.string.settings_speed_up_downloads),
subtitle = stringResource(R.string.settings_speed_up_downloads_sub),
iconColor = MaterialTheme.colorScheme.primary,
position = ItemPosition.STANDALONE,
onClick = { onSpeedUpDownloads(!download.speedUpDownloads) },
trailingContent = {
Switch(
checked = download.speedUpDownloads,
onCheckedChange = onSpeedUpDownloads,
)
},
)
}
item { Spacer(Modifier.height(8.dp)) }
item {
val photos = cacheByKind[FileCache.KIND_PHOTOS] ?: 0L
val videos = cacheByKind[FileCache.KIND_VIDEOS] ?: 0L
Expand Down
3 changes: 0 additions & 3 deletions feature/settings/src/main/res/values-es/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,6 @@
<string name="settings_privacy_server_sub">Última conexión, llamadas y reenvío siguen los ajustes de privacidad de Telegram — abre tu perfil para más detalles</string>
<string name="settings_data">Datos y almacenamiento</string>
<string name="settings_data_sub">Descarga automática y caché</string>
<string name="settings_data_transfers">Transferencias</string>
<string name="settings_speed_up_downloads">Acelerar descargas</string>
<string name="settings_speed_up_downloads_sub">Descargar fotos, videos y archivos más rápido con buena conexión</string>
<string name="settings_autodownload">Descarga automática de medios</string>
<string name="settings_autodownload_wifi">Con Wi-Fi</string>
<string name="settings_autodownload_mobile">Con datos móviles</string>
Expand Down
3 changes: 0 additions & 3 deletions feature/settings/src/main/res/values-hy/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,6 @@
<string name="settings_privacy_server_sub">Վերջին այցը, զանգերը և վերահասցեավորումը հետևում են Telegram-ի գաղտնիության կարգավորումներին — մանրամասները պրոֆիլում</string>
<string name="settings_data">Տվյալներ և պահոց</string>
<string name="settings_data_sub">Ինքնաբեռնում և քեշ</string>
<string name="settings_data_transfers">Փոխանցումներ</string>
<string name="settings_speed_up_downloads">Արագացնել ներբեռնումը</string>
<string name="settings_speed_up_downloads_sub">Լուսանկարները, տեսանյութերը և ֆայլերը լավ կապի դեպքում ավելի արագ են ներբեռնվում</string>
<string name="settings_autodownload">Մեդիայի ինքնաբեռնում</string>
<string name="settings_autodownload_wifi">Wi-Fi-ով</string>
<string name="settings_autodownload_mobile">Բջջային ցանցով</string>
Expand Down
Loading