Преглед изворни кода

Add loading and empty states

Signed-off-by: alperozturk <alper_ozturk@proton.me>
alperozturk пре 1 година
родитељ
комит
b48ddf5d44

+ 9 - 1
app/src/main/java/com/nextcloud/client/assistant/AssistantViewModel.kt

@@ -21,12 +21,13 @@
 
 package com.nextcloud.client.assistant
 
+import androidx.compose.ui.res.stringResource
 import androidx.lifecycle.ViewModel
 import androidx.lifecycle.viewModelScope
 import com.nextcloud.client.assistant.repository.AssistantRepository
 import com.nextcloud.common.NextcloudClient
+import com.owncloud.android.R
 import com.owncloud.android.lib.common.operations.RemoteOperationResult
-import com.owncloud.android.lib.resources.assistant.model.Task
 import com.owncloud.android.lib.resources.assistant.model.TaskList
 import com.owncloud.android.lib.resources.assistant.model.TaskType
 import com.owncloud.android.lib.resources.assistant.model.TaskTypes
@@ -49,6 +50,9 @@ class AssistantViewModel(client: NextcloudClient) : ViewModel() {
     private val _taskList = MutableStateFlow<RemoteOperationResult<TaskList>?>(null)
     val taskList: StateFlow<RemoteOperationResult<TaskList>?> = _taskList
 
+    private val _loading = MutableStateFlow(true)
+    val loading: StateFlow<Boolean> = _loading
+
     private val _isTaskCreated = MutableStateFlow(false)
     val isTaskCreated: StateFlow<Boolean> = _isTaskCreated
 
@@ -97,6 +101,10 @@ class AssistantViewModel(client: NextcloudClient) : ViewModel() {
             _taskList.update {
                 result
             }
+
+            _loading.update {
+                false
+            }
         }
     }
 

+ 49 - 23
app/src/main/java/com/nextcloud/client/assistant/AsssistantScreen.kt

@@ -23,34 +23,43 @@ package com.nextcloud.client.assistant
 
 import android.app.Activity
 import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Spacer
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.lazy.LazyColumn
 import androidx.compose.foundation.lazy.items
+import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.style.TextAlign
 import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
 import com.google.android.material.floatingactionbutton.FloatingActionButton
 import com.nextcloud.client.assistant.component.AddTaskAlertDialog
+import com.nextcloud.client.assistant.component.CenterText
 import com.nextcloud.client.assistant.component.TaskTypesRow
 import com.nextcloud.client.assistant.component.TaskView
 import com.owncloud.android.R
+import com.owncloud.android.lib.resources.assistant.model.Task
 import com.owncloud.android.lib.resources.assistant.model.TaskType
 import com.owncloud.android.utils.DisplayUtils
 
-@OptIn(ExperimentalFoundationApi::class)
 @Composable
 fun AssistantScreen(viewModel: AssistantViewModel, floatingActionButton: FloatingActionButton) {
-    // TODO hide sort group, floating action and search bar
+    // TODO hide sort group, search bar
+    // TODO top bar, back button causes crash
+    val loading by viewModel.loading.collectAsState()
     val selectedTask by viewModel.selectedTask.collectAsState()
     val taskList by viewModel.taskList.collectAsState()
     val isTaskCreated by viewModel.isTaskCreated.collectAsState()
@@ -63,27 +72,12 @@ fun AssistantScreen(viewModel: AssistantViewModel, floatingActionButton: Floatin
         showAddTaskAlertDialog = true
     }
 
-    LazyColumn(
-        modifier = Modifier
-            .fillMaxSize()
-            .padding(16.dp)
-    ) {
-        stickyHeader {
-            taskTypes?.let { taskTypes ->
-                taskTypes.resultData?.types.let {
-                    TaskTypesRow(selectedTask, data = it) { task->
-                        viewModel.selectTask(task)
-                    }
-                }
-            }
-
-            Spacer(modifier = Modifier.height(8.dp))
-        }
-
-        items(taskList?.resultData?.tasks ?: listOf()) {
-            TaskView(task = it)
-            Spacer(modifier = Modifier.height(8.dp))
-        }
+    if (loading) {
+        CenterText(text = stringResource(id = R.string.assistant_screen_loading))
+    } else {
+        val tasks = taskList?.resultData?.tasks ?: return
+        val types = taskTypes?.resultData?.types ?: return
+        AssistantContent(tasks, types, selectedTask, viewModel)
     }
 
     if (isTaskCreated) {
@@ -101,3 +95,35 @@ fun AssistantScreen(viewModel: AssistantViewModel, floatingActionButton: Floatin
         }
     }
 }
+
+@OptIn(ExperimentalFoundationApi::class)
+@Composable
+private fun AssistantContent(
+    taskList: List<Task>,
+    taskTypes: List<TaskType>,
+    selectedTask: TaskType?,
+    viewModel: AssistantViewModel
+) {
+    LazyColumn(
+        modifier = Modifier
+            .fillMaxSize()
+            .padding(16.dp)
+    ) {
+        stickyHeader {
+            TaskTypesRow(selectedTask, data = taskTypes) { task ->
+                viewModel.selectTask(task)
+            }
+
+            Spacer(modifier = Modifier.height(8.dp))
+        }
+
+        items(taskList) {
+            if (taskList.isEmpty()) {
+                CenterText(text = stringResource(id = R.string.assistant_screen_no_task_available_text))
+            } else {
+                TaskView(task = it)
+                Spacer(modifier = Modifier.height(8.dp))
+            }
+        }
+    }
+}

+ 44 - 0
app/src/main/java/com/nextcloud/client/assistant/component/CenterText.kt

@@ -0,0 +1,44 @@
+/*
+ * Nextcloud Android client application
+ *
+ * @author Alper Ozturk
+ * Copyright (C) 2024 Alper Ozturk
+ * Copyright (C) 2024 Nextcloud GmbH
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package com.nextcloud.client.assistant.component
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.unit.sp
+
+@Composable
+fun CenterText(text: String) {
+    Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
+        Text(
+            text = text,
+            fontSize = 18.sp,
+            color = Color.Black,
+            textAlign = TextAlign.Center
+        )
+    }
+}

+ 30 - 1
app/src/main/java/com/nextcloud/client/assistant/component/TaskView.kt

@@ -22,10 +22,13 @@
 package com.nextcloud.client.assistant.component
 
 import android.annotation.SuppressLint
+import android.widget.Space
 import androidx.compose.foundation.background
 import androidx.compose.foundation.clickable
 import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Spacer
 import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.material3.Text
@@ -57,10 +60,35 @@ fun TaskView(
             .clip(RoundedCornerShape(16.dp))
             .background(Color(R.color.primary))
     ) {
+        Spacer(modifier = Modifier.height(8.dp))
+
+        Text(
+            text = stringResource(id = R.string.assistant_screen_task_view_input),
+            modifier = Modifier.padding(4.dp),
+            color = Color.White
+        )
+
+        Text(
+            text = task.input,
+            modifier = Modifier.padding(4.dp),
+            color = Color.White
+        )
+
+        Spacer(modifier = Modifier.height(16.dp))
+
+        Text(
+            text = stringResource(id = R.string.assistant_screen_task_view_output),
+            color = Color.White,
+            modifier = Modifier
+                .padding(4.dp)
+                .clickable { expanded = !expanded }
+        )
+
         Text(
             text = if (expanded) task.output else task.output.take(100) + "...",
+            color = Color.White,
             modifier = Modifier
-                .padding(16.dp)
+                .padding(4.dp)
                 .clickable { expanded = !expanded }
         )
 
@@ -72,6 +100,7 @@ fun TaskView(
                     stringResource(id = R.string.assistant_screen_task_view_show_less)
                 },
                 textAlign = TextAlign.End,
+                color = Color.White,
                 modifier = Modifier
                     .fillMaxWidth()
                     .padding(16.dp)

+ 2 - 0
app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java

@@ -546,6 +546,8 @@ public abstract class DrawerActivity extends ToolbarActivity
             startActivity(intent);
         } else if (itemId == R.id.nav_assistant) {
             // FIXME Back navigation is broken, create general function to switch to Jetpack Compose
+
+            showSortListGroup(false);
             ComposeFragment composeFragment = new ComposeFragment();
             Bundle bundle = new Bundle();
             bundle.putSerializable(ComposeFragment.destinationKey, ComposeDestinations.AssistantScreen);

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

@@ -18,9 +18,14 @@
     <string name="menu_item_sort_by_size_biggest_first">Biggest first</string>
     <string name="menu_item_sort_by_size_smallest_first">Smallest first</string>
 
+    <string name="assistant_screen_loading">Task List are loading, please wait</string>
+    <string name="assistant_screen_no_task_available_text">No task available, you can create a new task from bottom right.</string>
+
     <string name="assistant_screen_task_create_success_message">Task successfully created</string>
     <string name="assistant_screen_create_task_alert_dialog_input_field_placeholder">Type some text</string>
 
+    <string name="assistant_screen_task_view_input">Input: </string>
+    <string name="assistant_screen_task_view_output">Output: </string>
     <string name="assistant_screen_task_view_show_more">Show more</string>
     <string name="assistant_screen_task_view_show_less">Show less</string>