Jelajahi Sumber

Added update menu button

Vadik Sirekanyan 2 tahun lalu
induk
melakukan
1bbf11a373

+ 15 - 0
app/src/main/java/org/sirekanyan/outline/MainContent.kt

@@ -21,6 +21,7 @@ import androidx.compose.material.icons.filled.Add
 import androidx.compose.material.icons.filled.ArrowBack
 import androidx.compose.material.icons.filled.Delete
 import androidx.compose.material.icons.filled.Edit
+import androidx.compose.material.icons.filled.Refresh
 import androidx.compose.material.icons.filled.Search
 import androidx.compose.material3.CircularProgressIndicator
 import androidx.compose.material3.Icon
@@ -86,6 +87,15 @@ fun MainContent(state: MainState) {
                         }
                     }
                 }
+                Box(Modifier.fillMaxSize().padding(insets).alpha(0.95f)) {
+                    AnimatedVisibility(
+                        visible = page.keys is KeysLoadingState,
+                        enter = fadeIn() + expandVertically(),
+                        exit = fadeOut() + shrinkVertically(),
+                    ) {
+                        LinearProgressIndicator(Modifier.fillMaxWidth())
+                    }
+                }
                 if (search.isOpened) {
                     MainTopAppBar(
                         title = { SearchField(search.query) { search.query = it } },
@@ -116,6 +126,11 @@ fun MainContent(state: MainState) {
                         },
                         onMenuClick = state::openDrawer,
                         visibleItems = menuItems,
+                        overflowItems = listOf(
+                            MenuItem(R.string.outln_menu_update, Icons.Default.Refresh) {
+                                state.onUpdateButtonClicked()
+                            }
+                        ),
                     )
                 }
             }

+ 35 - 1
app/src/main/java/org/sirekanyan/outline/MainState.kt

@@ -13,11 +13,13 @@ import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
+import kotlinx.coroutines.withTimeout
 import kotlinx.parcelize.IgnoredOnParcel
 import kotlinx.parcelize.Parcelize
 import org.sirekanyan.outline.api.model.Key
 import org.sirekanyan.outline.api.model.Server
 import org.sirekanyan.outline.db.KeyValueDao
+import org.sirekanyan.outline.ext.asyncAll
 import org.sirekanyan.outline.ext.rememberStateScope
 import org.sirekanyan.outline.feature.keys.KeysErrorState
 import org.sirekanyan.outline.feature.keys.KeysIdleState
@@ -28,6 +30,7 @@ import org.sirekanyan.outline.repository.KeyRepository
 import org.sirekanyan.outline.repository.ServerRepository
 import org.sirekanyan.outline.ui.SearchState
 import org.sirekanyan.outline.ui.rememberSearchState
+import kotlin.time.Duration.Companion.seconds
 
 @Composable
 fun rememberMainState(router: Router): MainState {
@@ -90,12 +93,40 @@ class MainState(
         }
     }
 
+    private suspend fun refreshAllKeys() {
+        val page = page as? HelloPage ?: return
+        if (page.keys is KeysLoadingState) return
+        withContext(Dispatchers.IO) {
+            page.keys = KeysLoadingState
+            page.keys = try {
+                servers.getServers()
+                    .asyncAll { server ->
+                        runCatching {
+                            withTimeout(5.seconds) {
+                                keys.updateKeys(server)
+                            }
+                        }
+                    }
+                KeysIdleState
+            } catch (exception: Exception) {
+                exception.printStackTrace()
+                KeysErrorState
+            }
+        }
+    }
+
     fun onRetryButtonClicked() {
         launch {
             refreshCurrentKeys(showLoading = true)
         }
     }
 
+    fun onUpdateButtonClicked() {
+        launch {
+            refreshAllKeys()
+        }
+    }
+
     fun onAddKeyClicked() {
         selectedPage?.let { page ->
             launch {
@@ -135,7 +166,10 @@ class MainState(
 @Parcelize
 sealed class Page : Parcelable
 
-data object HelloPage : Page()
+data object HelloPage : Page() {
+    @IgnoredOnParcel
+    var keys by mutableStateOf<KeysState>(KeysIdleState)
+}
 
 data class SelectedPage(val server: Server) : Page() {
     @IgnoredOnParcel

+ 8 - 0
app/src/main/java/org/sirekanyan/outline/ext/Iterable.kt

@@ -0,0 +1,8 @@
+package org.sirekanyan.outline.ext
+
+import kotlinx.coroutines.async
+import kotlinx.coroutines.awaitAll
+import kotlinx.coroutines.coroutineScope
+
+suspend fun <T, R> Iterable<T>.asyncAll(block: suspend (T) -> R): List<R> =
+    coroutineScope { map { async { block(it) } }.awaitAll() }

+ 4 - 0
app/src/main/java/org/sirekanyan/outline/repository/ServerRepository.kt

@@ -10,6 +10,7 @@ import kotlinx.coroutines.withContext
 import org.sirekanyan.outline.api.OutlineApi
 import org.sirekanyan.outline.api.model.Server
 import org.sirekanyan.outline.api.model.fromEntities
+import org.sirekanyan.outline.api.model.fromEntity
 import org.sirekanyan.outline.api.model.toEntities
 import org.sirekanyan.outline.api.model.toEntity
 import org.sirekanyan.outline.db.ServerDao
@@ -17,6 +18,9 @@ import org.sirekanyan.outline.ext.logDebug
 
 class ServerRepository(private val api: OutlineApi, private val serverDao: ServerDao) {
 
+    fun getServers(): List<Server> =
+        serverDao.selectAll().map { it.fromEntity() }
+
     fun observeServers(): Flow<List<Server>> =
         serverDao.observeAll().mapToList(IO).map { it.fromEntities() }
 

+ 8 - 0
app/src/main/res/values-ru/strings.xml

@@ -19,6 +19,7 @@
     <string name="outln_menu_edit">Изменить</string>
     <string name="outln_menu_delete">Удалить</string>
     <string name="outln_menu_search">Поиск</string>
+    <string name="outln_menu_update">Обновить</string>
 
     <!-- Sorting -->
     <string name="outln_sorting_by">Сортировать по…</string>
@@ -30,6 +31,13 @@
     <string name="outln_hint_search">Поиск…</string>
     <string name="outln_text_add_server">Добавить сервер</string>
 
+    <!-- Update -->
+    <plurals name="outln_update_error">
+        <item quantity="one">Не удалось обновить %d сервер</item>
+        <item quantity="few">Не удалось обновить %d сервера</item>
+        <item quantity="many">Не удалось обновить %d серверов</item>
+    </plurals>
+
     <!-- Selected Page -->
     <string name="outln_btn_add_key">Добавить ключ</string>
     <string name="outln_error_check_network">Проверьте подключение к сети</string>

+ 7 - 0
app/src/main/res/values/strings.xml

@@ -19,6 +19,7 @@
     <string name="outln_menu_edit">Edit</string>
     <string name="outln_menu_delete">Delete</string>
     <string name="outln_menu_search">Search</string>
+    <string name="outln_menu_update">Update</string>
 
     <!-- Sorting -->
     <string name="outln_sorting_by">Sort by…</string>
@@ -30,6 +31,12 @@
     <string name="outln_hint_search">Search…</string>
     <string name="outln_text_add_server">Add server</string>
 
+    <!-- Update -->
+    <plurals name="outln_update_error">
+        <item quantity="one">Cannot update %d server</item>
+        <item quantity="other">Cannot update %d servers</item>
+    </plurals>
+
     <!-- Selected Page -->
     <string name="outln_btn_add_key">Add key</string>
     <string name="outln_error_check_network">Check your network connection</string>