mirror of
https://github.com/nextcloud/android.git
synced 2024-11-26 15:15:51 +03:00
Add loading and empty states
Signed-off-by: alperozturk <alper_ozturk@proton.me>
This commit is contained in:
parent
f55017f077
commit
b48ddf5d44
6 changed files with 139 additions and 25 deletions
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
)
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
Loading…
Reference in a new issue