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
|
package com.nextcloud.client.assistant
|
||||||
|
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.nextcloud.client.assistant.repository.AssistantRepository
|
import com.nextcloud.client.assistant.repository.AssistantRepository
|
||||||
import com.nextcloud.common.NextcloudClient
|
import com.nextcloud.common.NextcloudClient
|
||||||
|
import com.owncloud.android.R
|
||||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult
|
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.TaskList
|
||||||
import com.owncloud.android.lib.resources.assistant.model.TaskType
|
import com.owncloud.android.lib.resources.assistant.model.TaskType
|
||||||
import com.owncloud.android.lib.resources.assistant.model.TaskTypes
|
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)
|
private val _taskList = MutableStateFlow<RemoteOperationResult<TaskList>?>(null)
|
||||||
val taskList: StateFlow<RemoteOperationResult<TaskList>?> = _taskList
|
val taskList: StateFlow<RemoteOperationResult<TaskList>?> = _taskList
|
||||||
|
|
||||||
|
private val _loading = MutableStateFlow(true)
|
||||||
|
val loading: StateFlow<Boolean> = _loading
|
||||||
|
|
||||||
private val _isTaskCreated = MutableStateFlow(false)
|
private val _isTaskCreated = MutableStateFlow(false)
|
||||||
val isTaskCreated: StateFlow<Boolean> = _isTaskCreated
|
val isTaskCreated: StateFlow<Boolean> = _isTaskCreated
|
||||||
|
|
||||||
|
@ -97,6 +101,10 @@ class AssistantViewModel(client: NextcloudClient) : ViewModel() {
|
||||||
_taskList.update {
|
_taskList.update {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_loading.update {
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,34 +23,43 @@ package com.nextcloud.client.assistant
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
import com.nextcloud.client.assistant.component.AddTaskAlertDialog
|
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.TaskTypesRow
|
||||||
import com.nextcloud.client.assistant.component.TaskView
|
import com.nextcloud.client.assistant.component.TaskView
|
||||||
import com.owncloud.android.R
|
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.lib.resources.assistant.model.TaskType
|
||||||
import com.owncloud.android.utils.DisplayUtils
|
import com.owncloud.android.utils.DisplayUtils
|
||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class)
|
|
||||||
@Composable
|
@Composable
|
||||||
fun AssistantScreen(viewModel: AssistantViewModel, floatingActionButton: FloatingActionButton) {
|
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 selectedTask by viewModel.selectedTask.collectAsState()
|
||||||
val taskList by viewModel.taskList.collectAsState()
|
val taskList by viewModel.taskList.collectAsState()
|
||||||
val isTaskCreated by viewModel.isTaskCreated.collectAsState()
|
val isTaskCreated by viewModel.isTaskCreated.collectAsState()
|
||||||
|
@ -63,27 +72,12 @@ fun AssistantScreen(viewModel: AssistantViewModel, floatingActionButton: Floatin
|
||||||
showAddTaskAlertDialog = true
|
showAddTaskAlertDialog = true
|
||||||
}
|
}
|
||||||
|
|
||||||
LazyColumn(
|
if (loading) {
|
||||||
modifier = Modifier
|
CenterText(text = stringResource(id = R.string.assistant_screen_loading))
|
||||||
.fillMaxSize()
|
} else {
|
||||||
.padding(16.dp)
|
val tasks = taskList?.resultData?.tasks ?: return
|
||||||
) {
|
val types = taskTypes?.resultData?.types ?: return
|
||||||
stickyHeader {
|
AssistantContent(tasks, types, selectedTask, viewModel)
|
||||||
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 (isTaskCreated) {
|
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
|
package com.nextcloud.client.assistant.component
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.widget.Space
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
|
@ -57,10 +60,35 @@ fun TaskView(
|
||||||
.clip(RoundedCornerShape(16.dp))
|
.clip(RoundedCornerShape(16.dp))
|
||||||
.background(Color(R.color.primary))
|
.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(
|
||||||
text = if (expanded) task.output else task.output.take(100) + "...",
|
text = if (expanded) task.output else task.output.take(100) + "...",
|
||||||
|
color = Color.White,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(16.dp)
|
.padding(4.dp)
|
||||||
.clickable { expanded = !expanded }
|
.clickable { expanded = !expanded }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -72,6 +100,7 @@ fun TaskView(
|
||||||
stringResource(id = R.string.assistant_screen_task_view_show_less)
|
stringResource(id = R.string.assistant_screen_task_view_show_less)
|
||||||
},
|
},
|
||||||
textAlign = TextAlign.End,
|
textAlign = TextAlign.End,
|
||||||
|
color = Color.White,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(16.dp)
|
.padding(16.dp)
|
||||||
|
|
|
@ -546,6 +546,8 @@ public abstract class DrawerActivity extends ToolbarActivity
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
} else if (itemId == R.id.nav_assistant) {
|
} else if (itemId == R.id.nav_assistant) {
|
||||||
// FIXME Back navigation is broken, create general function to switch to Jetpack Compose
|
// FIXME Back navigation is broken, create general function to switch to Jetpack Compose
|
||||||
|
|
||||||
|
showSortListGroup(false);
|
||||||
ComposeFragment composeFragment = new ComposeFragment();
|
ComposeFragment composeFragment = new ComposeFragment();
|
||||||
Bundle bundle = new Bundle();
|
Bundle bundle = new Bundle();
|
||||||
bundle.putSerializable(ComposeFragment.destinationKey, ComposeDestinations.AssistantScreen);
|
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_biggest_first">Biggest first</string>
|
||||||
<string name="menu_item_sort_by_size_smallest_first">Smallest 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_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_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_more">Show more</string>
|
||||||
<string name="assistant_screen_task_view_show_less">Show less</string>
|
<string name="assistant_screen_task_view_show_less">Show less</string>
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue