From 1a76143c2eee0f728915bbac63f3174e17e5b282 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D1=83=D1=80=D0=BD=D0=B0=D1=82=20=D0=90=D0=BD=D0=B4?= =?UTF-8?q?=D1=80=D0=B5=D0=B9?= Date: Wed, 10 Jun 2026 07:05:27 +0300 Subject: [PATCH] Add Android backup status summary --- .../AutomaticUploadStatusFormatter.kt | 74 +++++++++++++++++++ .../SettingsPictureUploadsFragment.kt | 15 ++++ .../SettingsVideoUploadsFragment.kt | 15 ++++ .../src/main/res/values-ru/strings.xml | 15 ++++ .../qsferaApp/src/main/res/values/strings.xml | 13 ++++ .../main/res/xml/settings_picture_uploads.xml | 6 ++ .../main/res/xml/settings_video_uploads.xml | 6 ++ PRODUCTION_READINESS.md | 3 +- 8 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 Android/qsferaApp/src/main/java/eu/qsfera/android/presentation/settings/automaticuploads/AutomaticUploadStatusFormatter.kt diff --git a/Android/qsferaApp/src/main/java/eu/qsfera/android/presentation/settings/automaticuploads/AutomaticUploadStatusFormatter.kt b/Android/qsferaApp/src/main/java/eu/qsfera/android/presentation/settings/automaticuploads/AutomaticUploadStatusFormatter.kt new file mode 100644 index 00000000..73d39ad2 --- /dev/null +++ b/Android/qsferaApp/src/main/java/eu/qsfera/android/presentation/settings/automaticuploads/AutomaticUploadStatusFormatter.kt @@ -0,0 +1,74 @@ +/** + * qsfera Android client application + * + * Copyright (C) 2026 QSfera. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + */ + +package eu.qsfera.android.presentation.settings.automaticuploads + +import android.content.Context +import eu.qsfera.android.R +import eu.qsfera.android.domain.automaticuploads.model.FolderBackUpConfiguration + +internal object AutomaticUploadStatusFormatter { + + fun format( + context: Context, + configuration: FolderBackUpConfiguration?, + sourcePaths: List, + lastSyncSummary: String, + ): String { + if (configuration == null) { + return context.getString(R.string.prefs_camera_upload_status_off) + } + + return listOf( + context.getString(R.string.prefs_camera_upload_status_on), + formatSourceCount(context, sourcePaths.size), + formatConditions(context, configuration), + context.getString(R.string.prefs_camera_upload_status_last_scan, lastSyncSummary), + ).joinToString(separator = "\n") + } + + private fun formatSourceCount(context: Context, sourceCount: Int): String = + if (sourceCount == 0) { + context.getString(R.string.prefs_camera_upload_source_paths_empty) + } else { + context.resources.getQuantityString( + R.plurals.prefs_camera_upload_status_source_count, + sourceCount, + sourceCount + ) + } + + private fun formatConditions(context: Context, configuration: FolderBackUpConfiguration): String { + val conditions = mutableListOf() + if (configuration.wifiOnly) { + conditions += context.getString(R.string.prefs_camera_upload_status_wifi_only) + } else { + conditions += context.getString( + R.string.prefs_camera_upload_status_mobile_data, + formatMobileDataLimit(context, configuration.mobileDataLimitBytes) + ) + if (configuration.allowRoaming) { + conditions += context.getString(R.string.prefs_camera_upload_status_roaming_allowed) + } + } + if (configuration.chargingOnly) { + conditions += context.getString(R.string.prefs_camera_upload_status_charging_only) + } + return conditions.joinToString(separator = " • ") + } + + private fun formatMobileDataLimit(context: Context, mobileDataLimitBytes: Long): String { + val values = context.resources.getStringArray(R.array.prefs_camera_upload_mobile_data_limit_values) + val entries = context.resources.getStringArray(R.array.prefs_camera_upload_mobile_data_limit_entries) + val index = values.indexOf(mobileDataLimitBytes.toString()) + return entries.getOrNull(index) + ?: context.getString(R.string.prefs_camera_upload_status_custom_mobile_data_limit, mobileDataLimitBytes) + } +} diff --git a/Android/qsferaApp/src/main/java/eu/qsfera/android/presentation/settings/automaticuploads/SettingsPictureUploadsFragment.kt b/Android/qsferaApp/src/main/java/eu/qsfera/android/presentation/settings/automaticuploads/SettingsPictureUploadsFragment.kt index 529a32ab..f8e1a0f1 100644 --- a/Android/qsferaApp/src/main/java/eu/qsfera/android/presentation/settings/automaticuploads/SettingsPictureUploadsFragment.kt +++ b/Android/qsferaApp/src/main/java/eu/qsfera/android/presentation/settings/automaticuploads/SettingsPictureUploadsFragment.kt @@ -67,6 +67,7 @@ class SettingsPictureUploadsFragment : PreferenceFragmentCompat() { private val picturesViewModel by viewModel() private val manageAccountsViewModel by viewModel() + private var prefPictureUploadsStatus: Preference? = null private var prefEnablePictureUploads: SwitchPreferenceCompat? = null private var prefPictureUploadsPath: Preference? = null private var prefPictureUploadsOnWifi: CheckBoxPreference? = null @@ -101,6 +102,7 @@ class SettingsPictureUploadsFragment : PreferenceFragmentCompat() { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { setPreferencesFromResource(R.xml.settings_picture_uploads, rootKey) + prefPictureUploadsStatus = findPreference(PREF_PICTURE_UPLOADS_STATUS) prefEnablePictureUploads = findPreference(PREF__CAMERA_PICTURE_UPLOADS_ENABLED) prefPictureUploadsPath = findPreference(PREF__CAMERA_PICTURE_UPLOADS_PATH) prefPictureUploadsOnWifi = findPreference(PREF__CAMERA_PICTURE_UPLOADS_WIFI_ONLY) @@ -162,6 +164,12 @@ class SettingsPictureUploadsFragment : PreferenceFragmentCompat() { prefPictureUploadsAccount?.value = it.accountName prefPictureUploadsPath?.summary = picturesViewModel.getUploadPathString() val sourcePaths = picturesViewModel.getPictureUploadsSourcePaths() + prefPictureUploadsStatus?.summary = AutomaticUploadStatusFormatter.format( + context = requireContext(), + configuration = it, + sourcePaths = sourcePaths, + lastSyncSummary = formatLastSyncSummary(it.lastSyncTimestamp), + ) prefPictureUploadsSourcePath?.summary = getSourcePathsSummary(sourcePaths) prefPictureUploadsClearSourcePaths?.isEnabled = sourcePaths.isNotEmpty() prefPictureUploadsOnWifi?.isChecked = it.wifiOnly @@ -314,6 +322,12 @@ class SettingsPictureUploadsFragment : PreferenceFragmentCompat() { } private fun resetFields() { + prefPictureUploadsStatus?.summary = AutomaticUploadStatusFormatter.format( + context = requireContext(), + configuration = null, + sourcePaths = emptyList(), + lastSyncSummary = getString(R.string.prefs_camera_upload_last_sync_never), + ) prefPictureUploadsAccount?.value = null prefPictureUploadsPath?.summary = null prefPictureUploadsSourcePath?.summary = getString(R.string.prefs_camera_upload_source_paths_empty) @@ -343,6 +357,7 @@ class SettingsPictureUploadsFragment : PreferenceFragmentCompat() { } companion object { + private const val PREF_PICTURE_UPLOADS_STATUS = "picture_uploads_status" private const val PREF_PICTURE_UPLOADS_CLEAR_SOURCE_PATHS = "picture_uploads_clear_source_paths" } } diff --git a/Android/qsferaApp/src/main/java/eu/qsfera/android/presentation/settings/automaticuploads/SettingsVideoUploadsFragment.kt b/Android/qsferaApp/src/main/java/eu/qsfera/android/presentation/settings/automaticuploads/SettingsVideoUploadsFragment.kt index 010c13e3..0ff44ecc 100644 --- a/Android/qsferaApp/src/main/java/eu/qsfera/android/presentation/settings/automaticuploads/SettingsVideoUploadsFragment.kt +++ b/Android/qsferaApp/src/main/java/eu/qsfera/android/presentation/settings/automaticuploads/SettingsVideoUploadsFragment.kt @@ -67,6 +67,7 @@ class SettingsVideoUploadsFragment : PreferenceFragmentCompat() { private val videosViewModel by viewModel() private val manageAccountsViewModel by viewModel() + private var prefVideoUploadsStatus: Preference? = null private var prefEnableVideoUploads: SwitchPreferenceCompat? = null private var prefVideoUploadsPath: Preference? = null private var prefVideoUploadsOnWifi: CheckBoxPreference? = null @@ -101,6 +102,7 @@ class SettingsVideoUploadsFragment : PreferenceFragmentCompat() { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { setPreferencesFromResource(R.xml.settings_video_uploads, rootKey) + prefVideoUploadsStatus = findPreference(PREF_VIDEO_UPLOADS_STATUS) prefEnableVideoUploads = findPreference(PREF__CAMERA_VIDEO_UPLOADS_ENABLED) prefVideoUploadsPath = findPreference(PREF__CAMERA_VIDEO_UPLOADS_PATH) prefVideoUploadsOnWifi = findPreference(PREF__CAMERA_VIDEO_UPLOADS_WIFI_ONLY) @@ -160,6 +162,12 @@ class SettingsVideoUploadsFragment : PreferenceFragmentCompat() { prefVideoUploadsAccount?.value = it.accountName prefVideoUploadsPath?.summary = videosViewModel.getUploadPathString() val sourcePaths = videosViewModel.getVideoUploadsSourcePaths() + prefVideoUploadsStatus?.summary = AutomaticUploadStatusFormatter.format( + context = requireContext(), + configuration = it, + sourcePaths = sourcePaths, + lastSyncSummary = formatLastSyncSummary(it.lastSyncTimestamp), + ) prefVideoUploadsSourcePath?.summary = getSourcePathsSummary(sourcePaths) prefVideoUploadsClearSourcePaths?.isEnabled = sourcePaths.isNotEmpty() prefVideoUploadsOnWifi?.isChecked = it.wifiOnly @@ -312,6 +320,12 @@ class SettingsVideoUploadsFragment : PreferenceFragmentCompat() { } private fun resetFields() { + prefVideoUploadsStatus?.summary = AutomaticUploadStatusFormatter.format( + context = requireContext(), + configuration = null, + sourcePaths = emptyList(), + lastSyncSummary = getString(R.string.prefs_camera_upload_last_sync_never), + ) prefVideoUploadsAccount?.value = null prefVideoUploadsPath?.summary = null prefVideoUploadsSourcePath?.summary = getString(R.string.prefs_camera_upload_source_paths_empty) @@ -341,6 +355,7 @@ class SettingsVideoUploadsFragment : PreferenceFragmentCompat() { } companion object { + private const val PREF_VIDEO_UPLOADS_STATUS = "video_uploads_status" private const val PREF_VIDEO_UPLOADS_CLEAR_SOURCE_PATHS = "video_uploads_clear_source_paths" } } diff --git a/Android/qsferaApp/src/main/res/values-ru/strings.xml b/Android/qsferaApp/src/main/res/values-ru/strings.xml index 27f7f2d3..4e239c6f 100644 --- a/Android/qsferaApp/src/main/res/values-ru/strings.xml +++ b/Android/qsferaApp/src/main/res/values-ru/strings.xml @@ -563,6 +563,21 @@ Папки телефона не выбраны Убрать выбранные папки Копирование перестанет проверять папки телефона, пока вы снова не добавите папку. + Состояние копирования + Выключено + Включено + + %d папка телефона + %d папки телефона + %d папок телефона + %d папки телефона + + Только Wi-Fi + Мобильные данные: %1$s + %1$d байт в день + роуминг разрешён + только во время зарядки + Последняя проверка: %1$s Разрешить копирование в роуминге Применяется только если копирование только по Wi-Fi выключено Исходный файл после копирования diff --git a/Android/qsferaApp/src/main/res/values/strings.xml b/Android/qsferaApp/src/main/res/values/strings.xml index 379dc8ff..324e5d88 100644 --- a/Android/qsferaApp/src/main/res/values/strings.xml +++ b/Android/qsferaApp/src/main/res/values/strings.xml @@ -602,6 +602,19 @@ No phone folders selected Remove selected folders Backup will stop scanning phone folders until you add a folder again. + Backup status + Off + On + + %d phone folder + %d phone folders + + Wi-Fi only + Mobile data: %1$s + %1$d bytes per day + roaming allowed + charging only + Last scan: %1$s Allow backup while roaming Only applies when Wi-Fi-only backup is off Mobile data daily limit diff --git a/Android/qsferaApp/src/main/res/xml/settings_picture_uploads.xml b/Android/qsferaApp/src/main/res/xml/settings_picture_uploads.xml index 6a6fac66..5722771d 100644 --- a/Android/qsferaApp/src/main/res/xml/settings_picture_uploads.xml +++ b/Android/qsferaApp/src/main/res/xml/settings_picture_uploads.xml @@ -25,6 +25,12 @@ app:key="enable_picture_uploads" app:summary="@string/prefs_camera_picture_upload_summary" app:title="@string/prefs_camera_picture_upload" /> + +