diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testBottomSheet.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testBottomSheet.png index e0156daaab..69957a6c21 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testBottomSheet.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testBottomSheet.png differ diff --git a/app/src/androidTest/java/com/nextcloud/client/assistant/AssistantRepositoryTests.kt b/app/src/androidTest/java/com/nextcloud/client/assistant/AssistantRepositoryTests.kt index aa3eefb8c2..cd86391620 100644 --- a/app/src/androidTest/java/com/nextcloud/client/assistant/AssistantRepositoryTests.kt +++ b/app/src/androidTest/java/com/nextcloud/client/assistant/AssistantRepositoryTests.kt @@ -9,6 +9,7 @@ package com.nextcloud.client.assistant import com.nextcloud.client.assistant.repository.AssistantRepository import com.owncloud.android.AbstractOnServerIT +import com.owncloud.android.lib.resources.assistant.model.TaskTypeData import com.owncloud.android.lib.resources.status.NextcloudVersion import org.junit.Assert.assertTrue import org.junit.Before @@ -35,7 +36,7 @@ class AssistantRepositoryTests : AbstractOnServerIT() { val result = sut?.getTaskTypes() assertTrue(result?.isSuccess == true) - val taskTypes = result?.resultData?.types + val taskTypes = result?.resultData assertTrue(taskTypes?.isNotEmpty() == true) } @@ -63,8 +64,14 @@ class AssistantRepositoryTests : AbstractOnServerIT() { } val input = "Give me some random output for test purpose" - val type = "OCP\\TextProcessing\\FreePromptTaskType" - val result = sut?.createTask(input, type) + val taskType = TaskTypeData( + "core:text2text", + "Free text to text prompt", + "Runs an arbitrary prompt through a language model that returns a reply", + null, + null + ) + val result = sut?.createTask(input, taskType) assertTrue(result?.isSuccess == true) } diff --git a/app/src/main/java/com/nextcloud/client/assistant/AssistantViewModel.kt b/app/src/main/java/com/nextcloud/client/assistant/AssistantViewModel.kt index b7894b6d12..5d9c6156d8 100644 --- a/app/src/main/java/com/nextcloud/client/assistant/AssistantViewModel.kt +++ b/app/src/main/java/com/nextcloud/client/assistant/AssistantViewModel.kt @@ -7,60 +7,53 @@ */ package com.nextcloud.client.assistant -import android.content.Context import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.nextcloud.client.assistant.model.ScreenOverlayState +import com.nextcloud.client.assistant.model.ScreenState import com.nextcloud.client.assistant.repository.AssistantRepositoryType 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.TaskTypeData import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch -import java.lang.ref.WeakReference class AssistantViewModel( - private val repository: AssistantRepositoryType, - private val context: WeakReference + private val repository: AssistantRepositoryType ) : ViewModel() { - sealed class State { - data object Idle : State() - data object Loading : State() - data class Error(val messageId: Int) : State() - data class TaskCreated(val messageId: Int) : State() - data class TaskDeleted(val messageId: Int) : State() - } + private val _screenState = MutableStateFlow(null) + val screenState: StateFlow = _screenState - private val _state = MutableStateFlow(State.Loading) - val state: StateFlow = _state + private val _screenOverlayState = MutableStateFlow(null) + val screenOverlayState: StateFlow = _screenOverlayState - private val _selectedTaskType = MutableStateFlow(null) - val selectedTaskType: StateFlow = _selectedTaskType + private val _snackbarMessageId = MutableStateFlow(null) + val snackbarMessageId: StateFlow = _snackbarMessageId - private val _taskTypes = MutableStateFlow?>(null) - val taskTypes: StateFlow?> = _taskTypes + private val _selectedTaskType = MutableStateFlow(null) + val selectedTaskType: StateFlow = _selectedTaskType + + private val _taskTypes = MutableStateFlow?>(null) + val taskTypes: StateFlow?> = _taskTypes private var taskList: List? = null private val _filteredTaskList = MutableStateFlow?>(null) val filteredTaskList: StateFlow?> = _filteredTaskList - private val _isRefreshing = MutableStateFlow(false) - val isRefreshing: StateFlow = _isRefreshing - init { fetchTaskTypes() - fetchTaskList() } @Suppress("MagicNumber") - fun createTask(input: String, type: String) { + fun createTask(input: String, taskType: TaskTypeData) { viewModelScope.launch(Dispatchers.IO) { - val result = repository.createTask(input, type) + val result = repository.createTask(input, taskType) val messageId = if (result.isSuccess) { R.string.assistant_screen_task_create_success_message @@ -68,68 +61,68 @@ class AssistantViewModel( R.string.assistant_screen_task_create_fail_message } - _state.update { - State.TaskCreated(messageId) - } + updateSnackbarMessage(messageId) delay(2000L) fetchTaskList() } } - fun selectTaskType(task: TaskType) { + fun selectTaskType(task: TaskTypeData) { _selectedTaskType.update { - filterTaskList(task.id) task } + + fetchTaskList() } private fun fetchTaskTypes() { viewModelScope.launch(Dispatchers.IO) { - val allTaskType = context.get()?.getString(R.string.assistant_screen_all_task_type) - val excludedIds = listOf("OCA\\ContextChat\\TextProcessing\\ContextChatTaskType") - val result = arrayListOf(TaskType(null, allTaskType, null)) val taskTypesResult = repository.getTaskTypes() if (taskTypesResult.isSuccess) { - val excludedTaskTypes = taskTypesResult.resultData.types.filter { item -> item.id !in excludedIds } - result.addAll(excludedTaskTypes) + val result = taskTypesResult.resultData _taskTypes.update { - result.toList() + result } selectTaskType(result.first()) } else { - _state.update { - State.Error(R.string.assistant_screen_task_types_error_state_message) - } + updateSnackbarMessage(R.string.assistant_screen_task_types_error_state_message) } } } - fun fetchTaskList(appId: String = "assistant") { + fun fetchTaskList() { viewModelScope.launch(Dispatchers.IO) { - _isRefreshing.update { - true + _screenState.update { + ScreenState.Refreshing } - val result = repository.getTaskList(appId) + val taskType = _selectedTaskType.value?.id ?: return@launch + val result = repository.getTaskList(taskType) if (result.isSuccess) { - taskList = result.resultData.tasks - - filterTaskList(_selectedTaskType.value?.id) - - _state.update { - State.Idle + taskList = result.resultData.tasks.filter { it.appId == "assistant" } + _filteredTaskList.update { + taskList?.sortedByDescending { task -> + task.id + } } + updateSnackbarMessage(null) } else { - _state.update { - State.Error(R.string.assistant_screen_task_list_error_state_message) - } + updateSnackbarMessage(R.string.assistant_screen_task_list_error_state_message) } - _isRefreshing.update { - false + updateScreenState() + } + } + + private fun updateScreenState() { + _screenState.update { + if (_filteredTaskList.value?.isEmpty() == true) { + ScreenState.EmptyContent + } else { + ScreenState.Content } } } @@ -144,9 +137,7 @@ class AssistantViewModel( R.string.assistant_screen_task_delete_fail_message } - _state.update { - State.TaskDeleted(messageId) - } + updateSnackbarMessage(messageId) if (result.isSuccess) { removeTaskFromList(id) @@ -154,27 +145,15 @@ class AssistantViewModel( } } - fun resetState() { - _state.update { - State.Idle + fun updateSnackbarMessage(value: Int?) { + _snackbarMessageId.update { + value } } - private fun filterTaskList(taskTypeId: String?) { - if (taskTypeId == null) { - _filteredTaskList.update { - taskList - } - } else { - _filteredTaskList.update { - taskList?.filter { it.type == taskTypeId } - } - } - - _filteredTaskList.update { - it?.sortedByDescending { task -> - task.id - } + fun updateScreenState(value: ScreenOverlayState?) { + _screenOverlayState.update { + value } } diff --git a/app/src/main/java/com/nextcloud/client/assistant/AsssistantScreen.kt b/app/src/main/java/com/nextcloud/client/assistant/AsssistantScreen.kt index 70c85cae91..e28ffdd726 100644 --- a/app/src/main/java/com/nextcloud/client/assistant/AsssistantScreen.kt +++ b/app/src/main/java/com/nextcloud/client/assistant/AsssistantScreen.kt @@ -8,7 +8,6 @@ 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.Column import androidx.compose.foundation.layout.Spacer @@ -25,215 +24,256 @@ import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.Icon import androidx.compose.material3.LinearProgressIndicator import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.pulltorefresh.PullToRefreshState import androidx.compose.material3.pulltorefresh.pullToRefresh import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState 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.rememberCoroutineScope -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.nextcloud.client.assistant.component.AddTaskAlertDialog import com.nextcloud.client.assistant.component.CenterText +import com.nextcloud.client.assistant.extensions.getInputTitle +import com.nextcloud.client.assistant.model.ScreenOverlayState +import com.nextcloud.client.assistant.model.ScreenState import com.nextcloud.client.assistant.repository.AssistantMockRepository import com.nextcloud.client.assistant.task.TaskView import com.nextcloud.client.assistant.taskTypes.TaskTypesRow import com.nextcloud.ui.composeActivity.ComposeActivity import com.nextcloud.ui.composeComponents.alertDialog.SimpleAlertDialog +import com.nextcloud.ui.composeComponents.bottomSheet.MoreActionsBottomSheet 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.TaskTypeData import com.owncloud.android.utils.DisplayUtils import kotlinx.coroutines.delay import kotlinx.coroutines.launch -import java.lang.ref.WeakReference @Suppress("LongMethod") @OptIn(ExperimentalMaterial3Api::class) @Composable fun AssistantScreen(viewModel: AssistantViewModel, activity: Activity) { - val state by viewModel.state.collectAsState() + val messageId by viewModel.snackbarMessageId.collectAsState() + val screenOverlayState by viewModel.screenOverlayState.collectAsState() + val selectedTaskType by viewModel.selectedTaskType.collectAsState() val filteredTaskList by viewModel.filteredTaskList.collectAsState() - val isRefreshing by viewModel.isRefreshing.collectAsState() + val screenState by viewModel.screenState.collectAsState() val taskTypes by viewModel.taskTypes.collectAsState() - var showAddTaskAlertDialog by remember { mutableStateOf(false) } - var showDeleteTaskAlertDialog by remember { mutableStateOf(false) } - var taskIdToDeleted: Long? by remember { - mutableStateOf(null) - } val scope = rememberCoroutineScope() val pullRefreshState = rememberPullToRefreshState() @Suppress("MagicNumber") Box( - modifier = Modifier.pullToRefresh(isRefreshing, pullRefreshState, onRefresh = { - scope.launch { - delay(1500) - viewModel.fetchTaskList() + modifier = Modifier.pullToRefresh( + screenState == ScreenState.Refreshing, + pullRefreshState, + onRefresh = { + scope.launch { + delay(1500) + viewModel.fetchTaskList() + } } - }) + ) ) { - if (state == AssistantViewModel.State.Loading || isRefreshing) { + ShowScreenState(screenState, selectedTaskType, taskTypes, viewModel, filteredTaskList) + + ShowLinearProgressIndicator(screenState, pullRefreshState) + + AddFloatingActionButton( + modifier = Modifier + .align(Alignment.BottomEnd) + .padding(16.dp), + selectedTaskType, + viewModel + ) + } + + showSnackBarMessage(messageId, activity, viewModel) + ShowOverlayState(screenOverlayState, activity, viewModel) +} + +@Composable +private fun ShowScreenState( + screenState: ScreenState?, + selectedTaskType: TaskTypeData?, + taskTypes: List?, + viewModel: AssistantViewModel, + filteredTaskList: List? +) { + when (screenState) { + ScreenState.Refreshing -> { CenterText(text = stringResource(id = R.string.assistant_screen_loading)) - } else { - if (filteredTaskList.isNullOrEmpty()) { - EmptyTaskList(selectedTaskType, taskTypes, viewModel) - } else { - AssistantContent( - filteredTaskList!!, - taskTypes, - selectedTaskType, - viewModel, - showDeleteTaskAlertDialog = { taskId -> - taskIdToDeleted = taskId - showDeleteTaskAlertDialog = true - } - ) - } } - if (isRefreshing) { - LinearProgressIndicator(modifier = Modifier.fillMaxWidth()) - } else { - LinearProgressIndicator( - progress = { pullRefreshState.distanceFraction }, - modifier = Modifier.fillMaxWidth() + ScreenState.EmptyContent -> { + EmptyTaskList(selectedTaskType, taskTypes, viewModel) + } + + ScreenState.Content -> { + AssistantContent( + filteredTaskList ?: listOf(), + taskTypes, + selectedTaskType, + viewModel ) } - if (selectedTaskType?.name != stringResource(id = R.string.assistant_screen_all_task_type)) { - FloatingActionButton( - modifier = Modifier - .align(Alignment.BottomEnd) - .padding(16.dp), - onClick = { - showAddTaskAlertDialog = true - } - ) { - Icon(Icons.Filled.Add, "Add Task Icon") - } - } + null -> Unit } +} - ScreenState(state, activity, viewModel) - - if (showDeleteTaskAlertDialog) { - taskIdToDeleted?.let { id -> - SimpleAlertDialog( - title = stringResource(id = R.string.assistant_screen_delete_task_alert_dialog_title), - description = stringResource(id = R.string.assistant_screen_delete_task_alert_dialog_description), - dismiss = { showDeleteTaskAlertDialog = false }, - onComplete = { viewModel.deleteTask(id) } - ) - } - } - - if (showAddTaskAlertDialog) { - selectedTaskType?.let { taskType -> - AddTaskAlertDialog( - title = taskType.name, - description = taskType.description, - addTask = { input -> - taskType.id?.let { - viewModel.createTask(input = input, type = it) - } - }, - dismiss = { - showAddTaskAlertDialog = false - } - ) - } +@OptIn(ExperimentalMaterial3Api::class) +@Composable +private fun ShowLinearProgressIndicator(screenState: ScreenState?, pullToRefreshState: PullToRefreshState) { + if (screenState == ScreenState.Refreshing) { + LinearProgressIndicator(modifier = Modifier.fillMaxWidth()) + } else { + LinearProgressIndicator( + progress = { pullToRefreshState.distanceFraction }, + modifier = Modifier.fillMaxWidth() + ) } } @Composable -private fun ScreenState(state: AssistantViewModel.State, activity: Activity, viewModel: AssistantViewModel) { - val messageId: Int? = when (state) { - is AssistantViewModel.State.Error -> { - state.messageId - } - - is AssistantViewModel.State.TaskCreated -> { - state.messageId - } - - is AssistantViewModel.State.TaskDeleted -> { - state.messageId - } - - else -> { - null +private fun AddFloatingActionButton( + modifier: Modifier, + selectedTaskType: TaskTypeData?, + viewModel: AssistantViewModel +) { + FloatingActionButton( + modifier = modifier, + onClick = { + selectedTaskType?.let { + val newState = ScreenOverlayState.AddTask(it, "") + viewModel.updateScreenState(newState) + } } + ) { + Icon(Icons.Filled.Add, "Add Task Icon") } +} +private fun showSnackBarMessage(messageId: Int?, activity: Activity, viewModel: AssistantViewModel) { messageId?.let { DisplayUtils.showSnackMessage( activity, - stringResource(id = messageId) + activity.getString(it) ) - viewModel.resetState() + viewModel.updateSnackbarMessage(null) + } +} + +@Suppress("LongMethod") +@Composable +private fun ShowOverlayState(state: ScreenOverlayState?, activity: Activity, viewModel: AssistantViewModel) { + when (state) { + is ScreenOverlayState.AddTask -> { + AddTaskAlertDialog( + title = state.taskType.name, + description = state.taskType.description, + defaultInput = state.input, + addTask = { input -> + state.taskType.let { taskType -> + viewModel.createTask(input = input, taskType = taskType) + } + }, + dismiss = { + viewModel.updateScreenState(null) + } + ) + } + + is ScreenOverlayState.DeleteTask -> { + SimpleAlertDialog( + title = stringResource(id = R.string.assistant_screen_delete_task_alert_dialog_title), + description = stringResource(id = R.string.assistant_screen_delete_task_alert_dialog_description), + dismiss = { viewModel.updateScreenState(null) }, + onComplete = { viewModel.deleteTask(state.id) } + ) + } + + is ScreenOverlayState.TaskActions -> { + val actions = state.getActions(activity, onEditCompleted = { addTask -> + viewModel.updateScreenState(addTask) + }, onDeleteCompleted = { deleteTask -> + viewModel.updateScreenState(deleteTask) + }) + + MoreActionsBottomSheet( + title = state.task.getInputTitle(), + actions = actions, + dismiss = { viewModel.updateScreenState(null) } + ) + } + + else -> Unit } } -@OptIn(ExperimentalFoundationApi::class) @Composable private fun AssistantContent( taskList: List, - taskTypes: List?, - selectedTaskType: TaskType?, - viewModel: AssistantViewModel, - showDeleteTaskAlertDialog: (Long) -> Unit + taskTypes: List?, + selectedTaskType: TaskTypeData?, + viewModel: AssistantViewModel ) { - LazyColumn( - modifier = Modifier - .fillMaxSize() - .padding(16.dp) - ) { - stickyHeader { + Column(modifier = Modifier.fillMaxSize()) { + taskTypes?.let { TaskTypesRow(selectedTaskType, data = taskTypes) { task -> viewModel.selectTaskType(task) } - - Spacer(modifier = Modifier.height(8.dp)) } - items(taskList) { task -> - TaskView(task, showDeleteTaskAlertDialog = { showDeleteTaskAlertDialog(task.id) }) - Spacer(modifier = Modifier.height(8.dp)) + LazyColumn( + modifier = Modifier + .fillMaxSize() + .padding(12.dp) + ) { + items(taskList) { task -> + TaskView( + task, + showTaskActions = { + val newState = ScreenOverlayState.TaskActions(task) + viewModel.updateScreenState(newState) + } + ) + Spacer(modifier = Modifier.height(8.dp)) + } } } } @Composable -private fun EmptyTaskList(selectedTaskType: TaskType?, taskTypes: List?, viewModel: AssistantViewModel) { - val text = if (selectedTaskType?.name == stringResource(id = R.string.assistant_screen_all_task_type)) { - stringResource(id = R.string.assistant_screen_no_task_available_for_all_task_filter_text) - } else { - stringResource( - id = R.string.assistant_screen_no_task_available_text, - selectedTaskType?.name ?: "" - ) - } +private fun EmptyTaskList( + selectedTaskType: TaskTypeData?, + taskTypes: List?, + viewModel: AssistantViewModel +) { + val text = stringResource( + id = R.string.assistant_screen_no_task_available_text, + selectedTaskType?.name ?: "" + ) Column( modifier = Modifier .fillMaxSize() .padding(16.dp) ) { - TaskTypesRow(selectedTaskType, data = taskTypes) { task -> - viewModel.selectTaskType(task) - } + taskTypes?.let { + TaskTypesRow(selectedTaskType, data = taskTypes) { task -> + viewModel.selectTaskType(task) + } - Spacer(modifier = Modifier.height(8.dp)) + Spacer(modifier = Modifier.height(8.dp)) + } CenterText(text = text) } @@ -246,10 +286,7 @@ private fun AssistantScreenPreview() { MaterialTheme( content = { AssistantScreen( - viewModel = AssistantViewModel( - repository = mockRepository, - context = WeakReference(LocalContext.current) - ), + viewModel = AssistantViewModel(repository = mockRepository), activity = ComposeActivity() ) } @@ -263,10 +300,7 @@ private fun AssistantEmptyScreenPreview() { MaterialTheme( content = { AssistantScreen( - viewModel = AssistantViewModel( - repository = mockRepository, - context = WeakReference(LocalContext.current) - ), + viewModel = AssistantViewModel(repository = mockRepository), activity = ComposeActivity() ) } diff --git a/app/src/main/java/com/nextcloud/client/assistant/component/AddTaskAlertDialog.kt b/app/src/main/java/com/nextcloud/client/assistant/component/AddTaskAlertDialog.kt index 9dfdae0465..d6a4aa2dce 100644 --- a/app/src/main/java/com/nextcloud/client/assistant/component/AddTaskAlertDialog.kt +++ b/app/src/main/java/com/nextcloud/client/assistant/component/AddTaskAlertDialog.kt @@ -22,9 +22,15 @@ import com.nextcloud.ui.composeComponents.alertDialog.SimpleAlertDialog import com.owncloud.android.R @Composable -fun AddTaskAlertDialog(title: String?, description: String?, addTask: (String) -> Unit, dismiss: () -> Unit) { +fun AddTaskAlertDialog( + title: String?, + description: String?, + defaultInput: String = "", + addTask: (String) -> Unit, + dismiss: () -> Unit +) { var input by remember { - mutableStateOf("") + mutableStateOf(defaultInput) } SimpleAlertDialog( diff --git a/app/src/main/java/com/nextcloud/client/assistant/component/CenterText.kt b/app/src/main/java/com/nextcloud/client/assistant/component/CenterText.kt index 3831b785e9..cf3cefb617 100644 --- a/app/src/main/java/com/nextcloud/client/assistant/component/CenterText.kt +++ b/app/src/main/java/com/nextcloud/client/assistant/component/CenterText.kt @@ -9,13 +9,14 @@ package com.nextcloud.client.assistant.component import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.res.colorResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.sp +import com.owncloud.android.R @Composable fun CenterText(text: String) { @@ -24,7 +25,7 @@ fun CenterText(text: String) { text = text, fontSize = 18.sp, textAlign = TextAlign.Center, - color = MaterialTheme.colorScheme.onPrimaryContainer + color = colorResource(R.color.text_color) ) } } diff --git a/app/src/main/java/com/nextcloud/client/assistant/extensions/TaskExtensions.kt b/app/src/main/java/com/nextcloud/client/assistant/extensions/TaskExtensions.kt index 4df63f69a9..50544e2490 100644 --- a/app/src/main/java/com/nextcloud/client/assistant/extensions/TaskExtensions.kt +++ b/app/src/main/java/com/nextcloud/client/assistant/extensions/TaskExtensions.kt @@ -9,34 +9,97 @@ package com.nextcloud.client.assistant.extensions +import android.content.Context +import com.nextcloud.utils.date.DateFormatPattern +import com.nextcloud.utils.date.DateFormatter import com.owncloud.android.R import com.owncloud.android.lib.resources.assistant.model.Task +import java.util.concurrent.TimeUnit + +fun Task.getInputAndOutput(): String { + val inputText = input?.input ?: "" + val outputText = output?.output ?: "" + + return "$inputText\n\n$outputText" +} + +fun Task.getInput(): String? = input?.input @Suppress("MagicNumber") -fun Task.statusData(): Pair { +fun Task.getInputTitle(): String { + val maxTitleLength = 20 + val title = getInput() ?: "" + + return if (title.length > maxTitleLength) { + title.take(maxTitleLength) + "..." + } else { + title + } +} + +@Suppress("MagicNumber") +fun Task.getStatusIcon(): Int { return when (status) { - 0L -> { - Pair(R.drawable.ic_unknown, R.string.assistant_screen_unknown_task_status_text) + "STATUS_UNKNOWN" -> { + R.drawable.ic_unknown } - 1L -> { - Pair(R.drawable.ic_clock, R.string.assistant_screen_scheduled_task_status_text) + "STATUS_SCHEDULED" -> { + R.drawable.ic_clock } - 2L -> { - Pair(R.drawable.ic_modification_desc, R.string.assistant_screen_running_task_text) + "STATUS_RUNNING" -> { + R.drawable.ic_modification_desc } - 3L -> { - Pair(R.drawable.ic_info, R.string.assistant_screen_successful_task_text) + "STATUS_SUCCESSFUL" -> { + R.drawable.ic_check_circle_outline } - 4L -> { - Pair(R.drawable.image_fail, R.string.assistant_screen_failed_task_text) + "STATUS_FAILED" -> { + R.drawable.image_fail } else -> { - Pair(R.drawable.ic_unknown, R.string.assistant_screen_unknown_task_status_text) + R.drawable.ic_unknown } } } -// TODO add -fun Task.completionDateRepresentation(): String { - return completionExpectedAt ?: "TODO IMPLEMENT IT" +@Suppress("MagicNumber") +fun Task.getModifiedAtRepresentation(context: Context): String? { + if (lastUpdated == null) { + return null + } + + val modifiedAt = lastUpdated!!.toLong() + val currentTime = System.currentTimeMillis() / 1000 + val timeDifference = (currentTime - modifiedAt).toInt() + val timeDifferenceInMinutes = (timeDifference / 60) + val timeDifferenceInHours = (timeDifference / 3600) + + return when { + timeDifference < 0 -> { + context.getString(R.string.common_now) + } + + timeDifference < TimeUnit.MINUTES.toSeconds(1) -> { + context.resources.getQuantityString(R.plurals.time_seconds_ago, timeDifference, timeDifference) + } + + timeDifference < TimeUnit.HOURS.toSeconds(1) -> { + context.resources.getQuantityString( + R.plurals.time_minutes_ago, + timeDifferenceInMinutes, + timeDifferenceInMinutes + ) + } + + timeDifference < TimeUnit.DAYS.toSeconds(1) -> { + context.resources.getQuantityString( + R.plurals.time_hours_ago, + timeDifferenceInHours, + timeDifferenceInHours + ) + } + + else -> { + DateFormatter.timestampToDateRepresentation(modifiedAt, DateFormatPattern.MonthWithDate) + } + } } diff --git a/app/src/main/java/com/nextcloud/client/assistant/model/ScreenOverlayState.kt b/app/src/main/java/com/nextcloud/client/assistant/model/ScreenOverlayState.kt new file mode 100644 index 0000000000..a051885e9b --- /dev/null +++ b/app/src/main/java/com/nextcloud/client/assistant/model/ScreenOverlayState.kt @@ -0,0 +1,88 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2024 Alper Ozturk + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +package com.nextcloud.client.assistant.model + +import android.app.Activity +import com.nextcloud.client.assistant.extensions.getInput +import com.nextcloud.client.assistant.extensions.getInputAndOutput +import com.nextcloud.utils.extensions.showShareIntent +import com.owncloud.android.R +import com.owncloud.android.lib.resources.assistant.model.Task +import com.owncloud.android.lib.resources.assistant.model.TaskTypeData +import com.owncloud.android.utils.ClipboardUtil + +sealed class ScreenOverlayState { + data class DeleteTask(val id: Long) : ScreenOverlayState() + data class AddTask(val taskType: TaskTypeData, val input: String) : ScreenOverlayState() + data class TaskActions(val task: Task) : ScreenOverlayState() { + private fun getInputAndOutput(): String = task.getInputAndOutput() + private fun getInput(): String? = task.getInput() + + private fun getCopyToClipboardAction(activity: Activity): Triple Unit> { + return Triple( + R.drawable.ic_content_copy, + R.string.common_copy + ) { + ClipboardUtil.copyToClipboard(activity, getInputAndOutput(), showToast = false) + } + } + + private fun getShareAction(activity: Activity): Triple Unit> { + return Triple( + R.drawable.ic_share, + R.string.common_share + ) { + activity.showShareIntent(getInputAndOutput()) + } + } + + private fun getEditAction(activity: Activity, onComplete: (AddTask) -> Unit): Triple Unit> { + return Triple( + R.drawable.ic_edit, + R.string.action_edit + ) { + val taskType = TaskTypeData( + task.type, + activity.getString(R.string.assistant_screen_add_task_alert_dialog_title), + null, + null, + null + ) + val newState = AddTask(taskType, getInput() ?: "") + onComplete(newState) + } + } + + private fun getDeleteAction(onComplete: (DeleteTask) -> Unit): Triple Unit> { + return Triple( + R.drawable.ic_delete, + R.string.assistant_screen_task_more_actions_bottom_sheet_delete_action + ) { + val newState = DeleteTask(task.id) + onComplete(newState) + } + } + + fun getActions( + activity: Activity, + onEditCompleted: (AddTask) -> Unit, + onDeleteCompleted: (DeleteTask) -> Unit + ): List Unit>> { + return listOf( + getShareAction(activity), + getCopyToClipboardAction(activity), + getEditAction(activity, onComplete = { + onEditCompleted(it) + }), + getDeleteAction(onComplete = { + onDeleteCompleted(it) + }) + ) + } + } +} diff --git a/app/src/main/java/com/nextcloud/client/assistant/model/ScreenState.kt b/app/src/main/java/com/nextcloud/client/assistant/model/ScreenState.kt new file mode 100644 index 0000000000..33e206c9d0 --- /dev/null +++ b/app/src/main/java/com/nextcloud/client/assistant/model/ScreenState.kt @@ -0,0 +1,14 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2024 Alper Ozturk + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +package com.nextcloud.client.assistant.model + +enum class ScreenState { + Refreshing, + EmptyContent, + Content +} diff --git a/app/src/main/java/com/nextcloud/client/assistant/repository/AssistantMockRepository.kt b/app/src/main/java/com/nextcloud/client/assistant/repository/AssistantMockRepository.kt index d1c4b6172f..4821760f15 100644 --- a/app/src/main/java/com/nextcloud/client/assistant/repository/AssistantMockRepository.kt +++ b/app/src/main/java/com/nextcloud/client/assistant/repository/AssistantMockRepository.kt @@ -10,29 +10,24 @@ package com.nextcloud.client.assistant.repository import com.nextcloud.utils.extensions.getRandomString 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.TaskInput 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 +import com.owncloud.android.lib.resources.assistant.model.TaskOutput +import com.owncloud.android.lib.resources.assistant.model.TaskTypeData @Suppress("MagicNumber") class AssistantMockRepository(private val giveEmptyTasks: Boolean = false) : AssistantRepositoryType { - override fun getTaskTypes(): RemoteOperationResult { - return RemoteOperationResult(RemoteOperationResult.ResultCode.OK).apply { - resultData = TaskTypes( - listOf( - TaskType("1", "FreePrompt", "You can create free prompt text"), - TaskType("2", "Generate Headline", "You can create generate headline text") - ) - ) + override fun getTaskTypes(): RemoteOperationResult> { + return RemoteOperationResult>(RemoteOperationResult.ResultCode.OK).apply { + resultData = null } } - override fun createTask(input: String, type: String): RemoteOperationResult { + override fun createTask(input: String, taskType: TaskTypeData): RemoteOperationResult { return RemoteOperationResult(RemoteOperationResult.ResultCode.OK) } - @Suppress("LongMethod") - override fun getTaskList(appId: String): RemoteOperationResult { + override fun getTaskList(taskType: String): RemoteOperationResult { val taskList = if (giveEmptyTasks) { TaskList(listOf()) } else { @@ -44,75 +39,13 @@ class AssistantMockRepository(private val giveEmptyTasks: Boolean = false) : Ass null, "12", "", - "Give me some long text 1", - "Lorem ipsum".getRandomString(100), - "" - ), - Task( - 2, - "GenerateHeadline", - null, - "12", - "", - "Give me some text 2", - "Lorem".getRandomString(100), - "", - "" - ), - Task( - 3, - "FreePrompt", - null, - "12", - "", - "Give me some text 3", - "Lorem".getRandomString(300), - "", - "" - ), - Task( - 4, - "FreePrompt", - null, - "12", - "", - "Give me some text 4", - "Lorem".getRandomString(300), - "", - "" - ), - Task( - 5, - "FreePrompt", - null, - "12", - "", - "Give me some text 5", - "Lorem".getRandomString(300), - "", - "" - ), - Task( - 6, - "FreePrompt", - null, - "12", - "", - "Give me some text 6", - "Lorem".getRandomString(300), - "", - "" - ), - Task( - 7, - "FreePrompt", - null, - "12", - "", - "Give me some text 7", - "Lorem".getRandomString(300), - "", - "" + TaskInput("Give me some long text 1"), + TaskOutput("Lorem ipsum".getRandomString(100)), + 1707692337, + 1707692337, + 1707692337, + 1707692337, + 1707692337 ) ) ) diff --git a/app/src/main/java/com/nextcloud/client/assistant/repository/AssistantRepository.kt b/app/src/main/java/com/nextcloud/client/assistant/repository/AssistantRepository.kt index 1cb32ff43c..5da5e56473 100644 --- a/app/src/main/java/com/nextcloud/client/assistant/repository/AssistantRepository.kt +++ b/app/src/main/java/com/nextcloud/client/assistant/repository/AssistantRepository.kt @@ -14,20 +14,20 @@ import com.owncloud.android.lib.resources.assistant.DeleteTaskRemoteOperation import com.owncloud.android.lib.resources.assistant.GetTaskListRemoteOperation import com.owncloud.android.lib.resources.assistant.GetTaskTypesRemoteOperation import com.owncloud.android.lib.resources.assistant.model.TaskList -import com.owncloud.android.lib.resources.assistant.model.TaskTypes +import com.owncloud.android.lib.resources.assistant.model.TaskTypeData class AssistantRepository(private val client: NextcloudClient) : AssistantRepositoryType { - override fun getTaskTypes(): RemoteOperationResult { + override fun getTaskTypes(): RemoteOperationResult> { return GetTaskTypesRemoteOperation().execute(client) } - override fun createTask(input: String, type: String): RemoteOperationResult { - return CreateTaskRemoteOperation(input, type).execute(client) + override fun createTask(input: String, taskType: TaskTypeData): RemoteOperationResult { + return CreateTaskRemoteOperation(input, taskType).execute(client) } - override fun getTaskList(appId: String): RemoteOperationResult { - return GetTaskListRemoteOperation(appId).execute(client) + override fun getTaskList(taskType: String): RemoteOperationResult { + return GetTaskListRemoteOperation(taskType).execute(client) } override fun deleteTask(id: Long): RemoteOperationResult { diff --git a/app/src/main/java/com/nextcloud/client/assistant/repository/AssistantRepositoryType.kt b/app/src/main/java/com/nextcloud/client/assistant/repository/AssistantRepositoryType.kt index 8bb9808863..2d031a87c4 100644 --- a/app/src/main/java/com/nextcloud/client/assistant/repository/AssistantRepositoryType.kt +++ b/app/src/main/java/com/nextcloud/client/assistant/repository/AssistantRepositoryType.kt @@ -9,14 +9,14 @@ package com.nextcloud.client.assistant.repository import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.lib.resources.assistant.model.TaskList -import com.owncloud.android.lib.resources.assistant.model.TaskTypes +import com.owncloud.android.lib.resources.assistant.model.TaskTypeData interface AssistantRepositoryType { - fun getTaskTypes(): RemoteOperationResult + fun getTaskTypes(): RemoteOperationResult> - fun createTask(input: String, type: String): RemoteOperationResult + fun createTask(input: String, taskType: TaskTypeData): RemoteOperationResult - fun getTaskList(appId: String): RemoteOperationResult + fun getTaskList(taskType: String): RemoteOperationResult fun deleteTask(id: Long): RemoteOperationResult } diff --git a/app/src/main/java/com/nextcloud/client/assistant/task/TaskStatus.kt b/app/src/main/java/com/nextcloud/client/assistant/task/TaskStatus.kt deleted file mode 100644 index f3de443b42..0000000000 --- a/app/src/main/java/com/nextcloud/client/assistant/task/TaskStatus.kt +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Nextcloud - Android Client - * - * SPDX-FileCopyrightText: 2024 Alper Ozturk - * SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only - */ - -package com.nextcloud.client.assistant.task - -import androidx.compose.foundation.Image -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.width -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.graphics.ColorFilter -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.unit.dp -import com.nextcloud.client.assistant.extensions.statusData -import com.owncloud.android.lib.resources.assistant.model.Task - -@Composable -fun TaskStatus(task: Task, foregroundColor: Color) { - Row( - modifier = Modifier - .fillMaxWidth() - .padding(vertical = 16.dp), - verticalAlignment = Alignment.CenterVertically - ) { - val (iconId, descriptionId) = task.statusData() - - Image( - painter = painterResource(id = iconId), - modifier = Modifier.size(16.dp), - colorFilter = ColorFilter.tint(foregroundColor), - contentDescription = "status icon" - ) - - Spacer(modifier = Modifier.width(6.dp)) - - Text(text = stringResource(id = descriptionId), color = foregroundColor) - - /* - Spacer(modifier = Modifier.weight(1f)) - - Text(text = task.completionDateRepresentation(), color = foregroundColor) - - Spacer(modifier = Modifier.width(6.dp)) - */ - } -} diff --git a/app/src/main/java/com/nextcloud/client/assistant/task/TaskStatusView.kt b/app/src/main/java/com/nextcloud/client/assistant/task/TaskStatusView.kt new file mode 100644 index 0000000000..145ee57c53 --- /dev/null +++ b/app/src/main/java/com/nextcloud/client/assistant/task/TaskStatusView.kt @@ -0,0 +1,144 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2024 Alper Ozturk + * SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only + */ + +package com.nextcloud.client.assistant.task + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +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.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.nextcloud.client.assistant.extensions.getModifiedAtRepresentation +import com.nextcloud.client.assistant.extensions.getStatusIcon +import com.owncloud.android.lib.resources.assistant.model.Task +import com.owncloud.android.lib.resources.assistant.model.TaskInput +import com.owncloud.android.lib.resources.assistant.model.TaskOutput +import java.util.concurrent.TimeUnit + +@Composable +fun TaskStatusView(task: Task, foregroundColor: Color) { + val context = LocalContext.current + + Row( + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 16.dp), + verticalAlignment = Alignment.CenterVertically + ) { + val iconId = task.getStatusIcon() + val description = task.getModifiedAtRepresentation(context) + + Image( + painter = painterResource(id = iconId), + modifier = Modifier.size(16.dp), + colorFilter = ColorFilter.tint(foregroundColor), + contentDescription = "status icon" + ) + + description?.let { + Spacer(modifier = Modifier.width(6.dp)) + Text(text = description, color = foregroundColor) + } + } +} + +@Suppress("LongMethod", "MagicNumber") +@Composable +@Preview +private fun TaskStatusViewPreview() { + val currentTime = System.currentTimeMillis() / 1000 + + val tasks = listOf( + Task( + id = 1L, + type = "type1", + status = "STATUS_RUNNING", + userId = "user1", + appId = "app1", + input = TaskInput("input1"), + output = TaskOutput("output1"), + scheduledAt = currentTime.toInt(), + lastUpdated = currentTime.toInt() + ), + + Task( + id = 2L, + type = "type2", + status = "STATUS_SUCCESSFUL", + userId = "user2", + appId = "app2", + input = TaskInput("input2"), + output = TaskOutput("output2"), + lastUpdated = (currentTime - TimeUnit.MINUTES.toSeconds(5)).toInt() + ), + + Task( + id = 3L, + type = "type3", + status = "STATUS_RUNNING", + userId = "user3", + appId = "app3", + input = TaskInput("input3"), + output = TaskOutput("output3"), + lastUpdated = (currentTime - TimeUnit.HOURS.toSeconds(5)).toInt() + ), + + Task( + id = 4L, + type = "type4", + status = "STATUS_SUCCESSFUL", + userId = "user4", + appId = "app4", + input = TaskInput("input4"), + output = TaskOutput("output4"), + lastUpdated = (currentTime - TimeUnit.DAYS.toSeconds(5)).toInt() + ), + + Task( + id = 5L, + type = "type5", + status = "STATUS_SUCCESSFUL", + userId = "user5", + appId = "app5", + input = TaskInput("input5"), + output = TaskOutput("output5"), + lastUpdated = (currentTime - TimeUnit.DAYS.toSeconds(60)).toInt() + ), + + Task( + id = 7L, + type = "type7", + status = "STATUS_UNKNOWN", + userId = "user7", + appId = "app7", + input = TaskInput("input7"), + output = TaskOutput("output7"), + scheduledAt = null, + lastUpdated = null + ) + ) + + LazyColumn { + items(tasks) { + TaskStatusView(it, foregroundColor = Color.White) + } + } +} diff --git a/app/src/main/java/com/nextcloud/client/assistant/task/TaskView.kt b/app/src/main/java/com/nextcloud/client/assistant/task/TaskView.kt index cdc5c28476..c01c15a581 100644 --- a/app/src/main/java/com/nextcloud/client/assistant/task/TaskView.kt +++ b/app/src/main/java/com/nextcloud/client/assistant/task/TaskView.kt @@ -9,107 +9,116 @@ package com.nextcloud.client.assistant.task import androidx.compose.animation.animateContentSize import androidx.compose.animation.core.Spring import androidx.compose.animation.core.spring -import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background -import androidx.compose.foundation.combinedClickable +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box 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.layout.width import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.HorizontalDivider -import androidx.compose.material3.MaterialTheme +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.MoreVert +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton import androidx.compose.material3.Text import androidx.compose.runtime.Composable 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.draw.clip import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.colorResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.nextcloud.client.assistant.taskDetail.TaskDetailBottomSheet -import com.nextcloud.ui.composeComponents.bottomSheet.MoreActionsBottomSheet -import com.nextcloud.utils.extensions.getRandomString import com.owncloud.android.R import com.owncloud.android.lib.resources.assistant.model.Task +import com.owncloud.android.lib.resources.assistant.model.TaskInput +import com.owncloud.android.lib.resources.assistant.model.TaskOutput -@OptIn(ExperimentalFoundationApi::class) @Suppress("LongMethod", "MagicNumber") @Composable -fun TaskView(task: Task, showDeleteTaskAlertDialog: (Long) -> Unit) { +fun TaskView(task: Task, showTaskActions: () -> Unit) { var showTaskDetailBottomSheet by remember { mutableStateOf(false) } - var showMoreActionsBottomSheet by remember { mutableStateOf(false) } - Column( - modifier = Modifier - .fillMaxWidth() - .clip(RoundedCornerShape(16.dp)) - .background(MaterialTheme.colorScheme.primary) - .combinedClickable(onClick = { - showTaskDetailBottomSheet = true - }, onLongClick = { - showMoreActionsBottomSheet = true - }) - .padding(start = 8.dp) - ) { - Spacer(modifier = Modifier.height(8.dp)) - - task.input?.let { - Text( - text = it, - color = Color.White, - fontSize = 18.sp - ) - } - - Spacer(modifier = Modifier.height(16.dp)) - - task.output?.let { - HorizontalDivider(modifier = Modifier.padding(horizontal = 4.dp, vertical = 8.dp)) - - Text( - text = it.take(100), - fontSize = 12.sp, - color = Color.White, - modifier = Modifier - .height(100.dp) - .animateContentSize( - animationSpec = spring( - dampingRatio = Spring.DampingRatioLowBouncy, - stiffness = Spring.StiffnessLow - ) - ) - ) - } - - TaskStatus(task, foregroundColor = Color.White) - - if (showMoreActionsBottomSheet) { - val bottomSheetAction = listOf( - Triple( - R.drawable.ic_delete, - R.string.assistant_screen_task_more_actions_bottom_sheet_delete_action - ) { - showDeleteTaskAlertDialog(task.id) + Box { + Column( + modifier = Modifier + .fillMaxWidth() + .clip(RoundedCornerShape(8.dp)) + .background(colorResource(R.color.primary)) + .clickable { + showTaskDetailBottomSheet = true } - ) + .padding(16.dp) + ) { + Spacer(modifier = Modifier.height(8.dp)) - MoreActionsBottomSheet( - title = task.input, - actions = bottomSheetAction, - dismiss = { showMoreActionsBottomSheet = false } - ) + task.input?.input?.let { + Text( + text = it, + color = Color.White, + fontSize = 18.sp, + textAlign = TextAlign.Left, + fontWeight = FontWeight.Bold, + modifier = Modifier.width(300.dp) + ) + } + + Spacer(modifier = Modifier.height(12.dp)) + + task.output?.output?.let { + val output = if (it.length >= 100) { + it.take(100) + "..." + } else { + it + } + + Text( + text = output, + fontSize = 18.sp, + color = Color.White, + textAlign = TextAlign.Left, + modifier = Modifier + .animateContentSize( + animationSpec = spring( + dampingRatio = Spring.DampingRatioLowBouncy, + stiffness = Spring.StiffnessLow + ) + ) + ) + } + + TaskStatusView(task, foregroundColor = Color.White) + + if (showTaskDetailBottomSheet) { + TaskDetailBottomSheet(task, showTaskActions = { + showTaskDetailBottomSheet = false + showTaskActions() + }) { + showTaskDetailBottomSheet = false + } + } } - if (showTaskDetailBottomSheet) { - TaskDetailBottomSheet(task) { - showTaskDetailBottomSheet = false - } + IconButton( + modifier = Modifier.align(Alignment.TopEnd), + onClick = showTaskActions + ) { + Icon( + imageVector = Icons.Filled.MoreVert, + contentDescription = "More button", + tint = Color.White + ) } } } @@ -118,20 +127,25 @@ fun TaskView(task: Task, showDeleteTaskAlertDialog: (Long) -> Unit) { @Preview @Composable private fun TaskViewPreview() { - val output = "Lorem".getRandomString(100) - TaskView( task = Task( 1, "Free Prompt", - 0, + "STATUS_COMPLETED", "1", "1", - "Give me text", - output, - "", - "" - ) - ) { - } + TaskInput("What about other promising tokens like"), + TaskOutput( + "Several tokens show promise for future growth in the" + + "cryptocurrency market" + ), + 1707692337, + 1707692337, + 1707692337, + 1707692337, + 1707692337 + ), + showTaskActions = { + } + ) } diff --git a/app/src/main/java/com/nextcloud/client/assistant/taskDetail/TaskDetailBottomSheet.kt b/app/src/main/java/com/nextcloud/client/assistant/taskDetail/TaskDetailBottomSheet.kt index 5912b332dc..07e5bc2d1b 100644 --- a/app/src/main/java/com/nextcloud/client/assistant/taskDetail/TaskDetailBottomSheet.kt +++ b/app/src/main/java/com/nextcloud/client/assistant/taskDetail/TaskDetailBottomSheet.kt @@ -22,9 +22,13 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.MoreVert import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.Text @@ -40,31 +44,53 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.nextcloud.client.assistant.task.TaskStatus +import com.nextcloud.client.assistant.task.TaskStatusView import com.nextcloud.utils.extensions.getRandomString import com.owncloud.android.R import com.owncloud.android.lib.resources.assistant.model.Task +import com.owncloud.android.lib.resources.assistant.model.TaskInput +import com.owncloud.android.lib.resources.assistant.model.TaskOutput @Suppress("LongMethod") @OptIn(ExperimentalFoundationApi::class, ExperimentalMaterial3Api::class) @Composable -fun TaskDetailBottomSheet(task: Task, dismiss: () -> Unit) { +fun TaskDetailBottomSheet(task: Task, showTaskActions: () -> Unit, dismiss: () -> Unit) { var showInput by remember { mutableStateOf(true) } val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) ModalBottomSheet( modifier = Modifier.padding(top = 32.dp), - containerColor = MaterialTheme.colorScheme.surface, + containerColor = colorResource(R.color.bg_default), onDismissRequest = { dismiss() }, sheetState = sheetState ) { - LazyColumn(modifier = Modifier.fillMaxSize().padding(16.dp)) { + LazyColumn( + modifier = Modifier + .fillMaxSize() + .padding(16.dp) + ) { stickyHeader { Row( - modifier = Modifier.fillMaxWidth().background( - color = colorResource(id = R.color.light_grey), - shape = RoundedCornerShape(8.dp) - ) + modifier = Modifier.fillMaxWidth() + ) { + Spacer(modifier = Modifier.weight(1f)) + + IconButton(onClick = showTaskActions) { + Icon( + imageVector = Icons.Filled.MoreVert, + contentDescription = "More button", + tint = colorResource(R.color.text_color) + ) + } + } + + Row( + modifier = Modifier + .fillMaxWidth() + .background( + color = colorResource(id = R.color.light_grey), + shape = RoundedCornerShape(8.dp) + ) ) { TextInputSelectButton( Modifier.weight(1f), @@ -90,16 +116,19 @@ fun TaskDetailBottomSheet(task: Task, dismiss: () -> Unit) { Spacer(modifier = Modifier.height(16.dp)) Column( - modifier = Modifier.fillMaxSize().background( - color = MaterialTheme.colorScheme.secondaryContainer, - shape = RoundedCornerShape(8.dp) - ).padding(16.dp) + modifier = Modifier + .fillMaxSize() + .background( + color = MaterialTheme.colorScheme.secondaryContainer, + shape = RoundedCornerShape(8.dp) + ) + .padding(16.dp) ) { Text( text = if (showInput) { - task.input ?: "" + task.input?.input ?: "" } else { - task.output ?: stringResource(R.string.assistant_screen_task_output_empty_text) + task.output?.output ?: stringResource(R.string.assistant_screen_task_output_empty_text) }, fontSize = 12.sp, color = MaterialTheme.colorScheme.onPrimaryContainer, @@ -113,7 +142,7 @@ fun TaskDetailBottomSheet(task: Task, dismiss: () -> Unit) { ) } - TaskStatus(task, foregroundColor = MaterialTheme.colorScheme.onPrimaryContainer) + TaskStatusView(task, foregroundColor = colorResource(R.color.text_color)) Spacer(modifier = Modifier.height(32.dp)) } @@ -147,14 +176,19 @@ private fun TaskDetailScreenPreview() { task = Task( 1, "Free Prompt", - 0, + null, "1", "1", - "Give me text".getRandomString(100), - "output".getRandomString(300), - "", - "" - ) + TaskInput("Give me text".getRandomString(100)), + TaskOutput("output".getRandomString(300)), + 1707692337, + 1707692337, + 1707692337, + 1707692337, + 1707692337 + ), + showTaskActions = { + } ) { } } diff --git a/app/src/main/java/com/nextcloud/client/assistant/taskTypes/TaskTypesRow.kt b/app/src/main/java/com/nextcloud/client/assistant/taskTypes/TaskTypesRow.kt index db7e2ac2eb..08f6883fb5 100644 --- a/app/src/main/java/com/nextcloud/client/assistant/taskTypes/TaskTypesRow.kt +++ b/app/src/main/java/com/nextcloud/client/assistant/taskTypes/TaskTypesRow.kt @@ -7,45 +7,60 @@ */ package com.nextcloud.client.assistant.taskTypes -import androidx.compose.foundation.horizontalScroll -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.rememberScrollState -import androidx.compose.material3.ButtonDefaults -import androidx.compose.material3.FilledTonalButton +import android.annotation.SuppressLint +import androidx.compose.material3.ScrollableTabRow +import androidx.compose.material3.Tab +import androidx.compose.material3.TabRowDefaults +import androidx.compose.material3.TabRowDefaults.tabIndicatorOffset import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.colorResource +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import com.owncloud.android.lib.resources.assistant.model.TaskType +import com.owncloud.android.R +import com.owncloud.android.lib.resources.assistant.model.TaskTypeData +@SuppressLint("ResourceType") @Composable -fun TaskTypesRow(selectedTaskType: TaskType?, data: List?, selectTaskType: (TaskType) -> Unit) { - Row( - modifier = Modifier - .fillMaxWidth() - .horizontalScroll(rememberScrollState()) - ) { - data?.forEach { taskType -> - taskType.name?.let { taskTypeName -> - FilledTonalButton( - onClick = { selectTaskType(taskType) }, - colors = ButtonDefaults.buttonColors( - containerColor = if (selectedTaskType?.id == taskType.id) { - Color.Unspecified - } else { - Color.Gray - } - ) - ) { - Text(text = taskTypeName) - } +fun TaskTypesRow(selectedTaskType: TaskTypeData?, data: List, selectTaskType: (TaskTypeData) -> Unit) { + val selectedTabIndex = data.indexOfFirst { it.id == selectedTaskType?.id }.takeIf { it >= 0 } ?: 0 - Spacer(modifier = Modifier.padding(end = 8.dp)) + ScrollableTabRow( + selectedTabIndex = selectedTabIndex, + edgePadding = 0.dp, + containerColor = colorResource(R.color.actionbar_color), + indicator = { + TabRowDefaults.SecondaryIndicator( + Modifier.tabIndicatorOffset(it[selectedTabIndex]), + color = colorResource(R.color.primary) + ) + } + ) { + data.forEach { taskType -> + taskType.name?.let { taskTypeName -> + Tab( + selected = selectedTaskType?.id == taskType.id, + onClick = { selectTaskType(taskType) }, + selectedContentColor = colorResource(R.color.text_color), + unselectedContentColor = colorResource(R.color.disabled_text), + text = { Text(text = taskTypeName) } + ) } } } } + +@Composable +@Preview +private fun TaskTypesRowPreview() { + val selectedTaskType = TaskTypeData("1", "Free text to text prompt", "", null, null) + val taskTypes = listOf( + TaskTypeData("1", "Free text to text prompt", "", null, null), + TaskTypeData("2", "Extract topics", "", null, null), + TaskTypeData("3", "Generate Headline", "", null, null), + TaskTypeData("4", "Summarize", "", null, null) + ) + + TaskTypesRow(selectedTaskType, taskTypes) { } +} diff --git a/app/src/main/java/com/nextcloud/ui/composeActivity/ComposeActivity.kt b/app/src/main/java/com/nextcloud/ui/composeActivity/ComposeActivity.kt index d341769208..d310e6e37c 100644 --- a/app/src/main/java/com/nextcloud/ui/composeActivity/ComposeActivity.kt +++ b/app/src/main/java/com/nextcloud/ui/composeActivity/ComposeActivity.kt @@ -31,7 +31,6 @@ import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.ui.activity.DrawerActivity import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext -import java.lang.ref.WeakReference class ComposeActivity : DrawerActivity() { @@ -88,8 +87,7 @@ class ComposeActivity : DrawerActivity() { nextcloudClient?.let { client -> AssistantScreen( viewModel = AssistantViewModel( - repository = AssistantRepository(client), - context = WeakReference(this) + repository = AssistantRepository(client) ), activity = this ) diff --git a/app/src/main/java/com/nextcloud/ui/composeComponents/bottomSheet/MoreActionsBottomSheet.kt b/app/src/main/java/com/nextcloud/ui/composeComponents/bottomSheet/MoreActionsBottomSheet.kt index 16131db380..b3d409aee0 100644 --- a/app/src/main/java/com/nextcloud/ui/composeComponents/bottomSheet/MoreActionsBottomSheet.kt +++ b/app/src/main/java/com/nextcloud/ui/composeComponents/bottomSheet/MoreActionsBottomSheet.kt @@ -43,6 +43,7 @@ fun MoreActionsBottomSheet(title: String? = null, actions: List + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +package com.nextcloud.utils.date + +import android.icu.text.SimpleDateFormat +import java.util.Date +import java.util.Locale + +object DateFormatter { + + /** + * Converts a Unix timestamp (in milliseconds) into a formatted date string. + * For example, input 1733309160885 with "MMM d" pattern outputs "Dec 4". + */ + @Suppress("MagicNumber") + fun timestampToDateRepresentation(timestamp: Long, formatPattern: DateFormatPattern): String { + val date = Date(timestamp * 1000) + val format = SimpleDateFormat(formatPattern.pattern, Locale.getDefault()) + return format.format(date) + } +} diff --git a/app/src/main/java/com/nextcloud/utils/extensions/ActivityExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/ActivityExtensions.kt index 0bdbbbd0cb..bba32fe392 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/ActivityExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/ActivityExtensions.kt @@ -7,6 +7,8 @@ package com.nextcloud.utils.extensions +import android.app.Activity +import android.content.Intent import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.Fragment @@ -17,3 +19,13 @@ fun AppCompatActivity.isActive(): Boolean = !isFinishing && !isDestroyed fun AppCompatActivity.fragments(): List = supportFragmentManager.fragments fun AppCompatActivity.lastFragment(): Fragment = fragments().last() + +fun Activity.showShareIntent(text: String?) { + val sendIntent = Intent(Intent.ACTION_SEND).apply { + putExtra(Intent.EXTRA_TEXT, text) + type = "text/plain" + } + + val shareIntent = Intent.createChooser(sendIntent, null) + startActivity(shareIntent) +} diff --git a/app/src/main/res/drawable/ic_info.xml b/app/src/main/res/drawable/ic_info.xml deleted file mode 100644 index 345147ea17..0000000000 --- a/app/src/main/res/drawable/ic_info.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index b5be74127c..daa3a089de 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -46,17 +46,11 @@ منفذ البروكسي عرض أداة واحدة من لوحة القيادة بحث في %s - الكل أكتُب أيَّ نص هل أنت متأكد أنك ترغب بحذف هذه المهمة؟ حذف مهمة - فشل يتم الآن تحميل قائمة المهام؛ يرجى الانتظار... - لا توجد أي مهام متوفرة. حدِّد نوع المهمة لإنشاء واحدة جديدة. لا توجد أي مهام متوفرة من النوع %s. يمكنك إنشاء مهمة جديدة من الشريط السفلي الجانبي. - قيد التجهيز - مُجدول - مُكتمل حدث خطأ أثناء إنشاء المهمة تمّ إنشاء المهمة بنجاح حدث خطأ أثناء حذف المهمة @@ -66,7 +60,6 @@ نتيجة المهمة غير جاهة بعدُ. تعذّر جلب أنواع المهام. قم رجاءً بالتحقُّق من اتصالك بالإنترنت. المُساعِد - غير معروف مُدخَلات المُخرَجَات الحساب المرتبط غير موجود! diff --git a/app/src/main/res/values-ast/strings.xml b/app/src/main/res/values-ast/strings.xml index 024a3b1fe2..dc2c545684 100644 --- a/app/src/main/res/values-ast/strings.xml +++ b/app/src/main/res/values-ast/strings.xml @@ -24,15 +24,10 @@ URL base Puertu del proxy Buscar en: %s - Too Escribi daqué - Falló - Planificóse - Completóse Nun ye posible dir en cata de la llista de xeres. Comprueba la conexón a internet. Nun ye posible dir en cata de los tipos de xeres. Comprueba la conexón a internet. Asistente - Desconocí­u Entrada Salida Yá esiste nel preséu una cuenta pal mesmu usuariu y sirvidor diff --git a/app/src/main/res/values-b+en+001/strings.xml b/app/src/main/res/values-b+en+001/strings.xml index 9d2a448b6f..d997603ae6 100644 --- a/app/src/main/res/values-b+en+001/strings.xml +++ b/app/src/main/res/values-b+en+001/strings.xml @@ -46,17 +46,11 @@ Proxy Port Shows one widget from dashboard Search in %s - All Type some text Are you sure you want to delete this task? Delete Task - Failed Task List are loading, please wait - No task available. Select a task type to create a new task. No task available for %s task type, you can create a new task from bottom right. - In Progress - Scheduled - Completed An error occurred while creating the task Task successfully created An error occurred while deleting the task @@ -66,7 +60,6 @@ The task output is not ready yet. Unable to fetch task types, please check your internet connection. Assistant - Unknown Input Output Associated account not found! diff --git a/app/src/main/res/values-bg-rBG/strings.xml b/app/src/main/res/values-bg-rBG/strings.xml index f3bf9cd3d3..bbb9751a87 100644 --- a/app/src/main/res/values-bg-rBG/strings.xml +++ b/app/src/main/res/values-bg-rBG/strings.xml @@ -36,12 +36,7 @@ Порт на прокси сървъра Показва един изпълним модул от таблото за управление Търсене в %s - Всички - Неуспешно - Планирано - Завършен Задачата е успешно изтрита - Неизвестен Свързания профил не е намерен! Достъп неуспешен: %1$s Профилът все още не съществува на устройството diff --git a/app/src/main/res/values-br/strings.xml b/app/src/main/res/values-br/strings.xml index 038992b03c..002b61502f 100644 --- a/app/src/main/res/values-br/strings.xml +++ b/app/src/main/res/values-br/strings.xml @@ -37,17 +37,11 @@ Porzh Proksi Diskouez a ra ur widget dre daolenn-vourzh Klask e %s - Pep tra Skrivañ un tamm testenn Ha sur oc\'h e fell deoc\'h dilemel an trevell-mañ ? Dilemel an trevell - C\'hwitet O kargañ roll an trevelloù, gortozit ur pennadig - N\'eus trevell ebet evit c\'hoazh. Diuzit ur seurt trevell evit krouiñ unan nevez. N\'eus trevell ebet evit %s seurt trevell, gallout a rit krouiñ unan nevez en traoñ a-zehoùt. - War ar stern - Raktreset - Echu C\'hoarvezet ez eus ur fazi en ur grouiñ an trevell Trevell bet krouet ervat C\'hoarvezet ez eus ur fazi en ur zilemel an trevell @@ -56,7 +50,6 @@ Dilemel an trevell N\'eus ket bet gallet tizhout ar seurtoù trevelloù, gwiriit ho kevreadenn genrouedad. Skoazeller - Dianv Enmont Ezvont N\'eo ket bet kavet ar gont stag ! diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml index b233effbdb..509f19d4d2 100644 --- a/app/src/main/res/values-ca/strings.xml +++ b/app/src/main/res/values-ca/strings.xml @@ -45,17 +45,11 @@ Port del proxy Mostra un giny del tauler Cerca a %s - Totes Escriu una mica de text Segur que voleu suprimir aquesta tasca? Suprimeix la tasca - Ha fallat S\'està carregant la llista de tasques, espereu - No hi ha cap tasca disponible. Seleccioneu un tipus de tasca per a crear una tasca nova. No hi ha cap tasca disponible per al tipus de tasca %s. Podeu crear una tasca nova des de baix a la dreta. - En curs - Planificat - S\'ha completat S\'ha produït un error en crear la tasca La tasca s\'ha creat correctament S\'ha produït un error en suprimir la tasca @@ -65,7 +59,6 @@ La sortida de la tasca encara no està a punt. No s\'han pogut obtenir els tipus de tasques. Comproveu la connexió a Internet. Assistent - Desconegut Entrada Sortida No s\'ha trobat el compte associat! diff --git a/app/src/main/res/values-cs-rCZ/strings.xml b/app/src/main/res/values-cs-rCZ/strings.xml index 1558ecf62f..c4ef2f725e 100644 --- a/app/src/main/res/values-cs-rCZ/strings.xml +++ b/app/src/main/res/values-cs-rCZ/strings.xml @@ -46,17 +46,11 @@ Port proxy Zobrazuje jeden ovládací prvek z nástěnky Hledat v %s - Vše Zadejte nějaký text Opravdu chcete tuto úlohu smazat? Smazat úkol - Nezdařilo se Načítá se seznam úkolů – vyčkejte - Není k dispozici žádný úkol. Aby bylo možné vytvořit nový úkol, vyberte jeho typ. Pro typ úkolu %s nejsou k dispozici žádné úkoly – nový úkol je možné vytvořit vpravo dole. - Probíhá - Naplánováno - Dokončeno Při vytváření úlohy se vyskytla chyba Úloha byla úspěšně vytvořena Při mazání úlohy se vyskytla chyba @@ -66,7 +60,6 @@ Výstup z úkolu ještě není připraven. Nedaří se získat typy úloh – zkontrolujte připojení k Internetu. Asistent - Neznámé Vstup Výstup Související účet nenalezen! diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml index 4d9ce7958f..16fe3f3556 100644 --- a/app/src/main/res/values-da/strings.xml +++ b/app/src/main/res/values-da/strings.xml @@ -36,21 +36,15 @@ Tillad videredeling Viser én widget fra dashboard Søg i %s - Alle Skriv noget tekst Er du sikker på du vil slette denne opgave? Slet opgave - Mislykkede Opgavelisten indlæser, vent venligst - I gang - Planlagt - Fuldført Opgaven er oprettet En fejl opstod under sletning af opgaven Opgaven er slettet Slet opgave Assistent - Ukendt Forbundet konto blev ikke fundet! Adgang fejlede: %1$s Kontoen findes endnu ikke på enheden diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index f35eab33c8..4d83c5074d 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -46,17 +46,11 @@ Proxy-Port Zeigt ein Widget aus dem Dashboard an Suche in %s - Alle Bitte einen Text eingeben Möchten Sie diese Aufgabe wirklich löschen? Aufgabe löschen - Fehlgeschlagen Aufgabenlisten werden geladen, bitte warten - Keine Aufgabe verfügbar. Aufgabentyp auswählen, um eine neue Aufgabe zu erstellen. Für den Aufgabentyp %s ist keine Aufgabe verfügbar. Sie können unten rechts eine neue Aufgabe erstellen. - In Bearbeitung - Geplant - Fertiggestellt Es ist ein Fehler beim Erstellen der Aufgabe aufgetreten Aufgabe erfolgreich erstellt Es ist ein Fehler beim Löschen der Aufgabe aufgetreten @@ -66,7 +60,6 @@ Die Aufgabenausgabe ist noch nicht fertig. Die Aufgabentypen können nicht abgerufen werden. Bitte überprüfen Sie Ihre Internetverbindung. Assistent - Unbekannt Eingabe Ausgabe Verknüpftes Konto nicht gefunden! diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index da9cd10d30..3c9584738f 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -35,11 +35,7 @@ Θύρα διαμεσολαβητή Εμφάνιση ενός γραφικού στοιχείου από τον πίνακα ελέγχου Αναζήτηση στο %s - \'Ολα Πληκτρολογήστε κάποιο κείμενο - Απέτυχε - Ολοκληρωμένες - Άγνωστο Δεν βρέθηκε ο συνδεδεμένος λογαριασμός! Αποτυχία πρόσβασης: %1$s Ο λογαριασμός δεν υπάρχει ακόμα στη συσκευή diff --git a/app/src/main/res/values-eo/strings.xml b/app/src/main/res/values-eo/strings.xml index 41aa8b73d2..2f997d4471 100644 --- a/app/src/main/res/values-eo/strings.xml +++ b/app/src/main/res/values-eo/strings.xml @@ -31,9 +31,6 @@ Detalaj agordoj Permesi rekunhavigon Serĉi en 1%s - Ĉiuj - Plenumita - Nekonata Aliro malsukcesis: %1$s La konto ankoraŭ ne aldoniĝis al tiu ĉi aparato Konto pri samaj uzanto kaj servilo jam ekzistas tiuaparate diff --git a/app/src/main/res/values-es-rAR/strings.xml b/app/src/main/res/values-es-rAR/strings.xml index 39e68285ea..f6567d75cd 100644 --- a/app/src/main/res/values-es-rAR/strings.xml +++ b/app/src/main/res/values-es-rAR/strings.xml @@ -37,17 +37,11 @@ Puerto del Proxy Muestra un widget del panel Buscar en %s - Todos Escriba un texto ¿Está seguro que desea eliminar esta tarea? Eliminar tarea - Error Las listas de tareas están cargando, por favor espere - No hay tareas disponibles. Seleccione un tipo de tarea para crear una nueva. No hay tareas del tipo %s, puede crear una nueva tarea desde la parte inferior derecha - En progreso - Programado - Completado Ocurrió un error al crear la tarea Tarea creada exitosamente Ocurrió un error al eliminar la tarea @@ -56,7 +50,6 @@ Eliminar tarea No se pudieron obtener los tipos de tareas, por favor, revise su conexión a internet. Asistente - Desconocido Entrada Salida ¡Cuenta asociada no encontrada! diff --git a/app/src/main/res/values-es-rCL/strings.xml b/app/src/main/res/values-es-rCL/strings.xml index d10f842d9e..135b2548a0 100644 --- a/app/src/main/res/values-es-rCL/strings.xml +++ b/app/src/main/res/values-es-rCL/strings.xml @@ -37,17 +37,11 @@ Puerto del Proxy Muestra un widget del panel de control Buscar en %s - Todos Escribe un texto ¿Está seguro que desea eliminar esta tarea? Tarea eliminada - Falló Lista de Tareas en lectura, espere por favor. - No hay tareas disponibles. Seleccione un tipo de tarea para crear una nueva. No hay tareas del tipo %s, puede crear una nueva tarea desde la parte inferior derecha - En progreso - Programado - Completado Ocurrió un error mientras creaba la tarea Tarea creada con éxito Ocurrió un error mientras eliminaba la tarea @@ -56,7 +50,6 @@ Tarea eliminada No se puede recuperar los tipos de tareas, comprueba la conexión a Internet. Asistente - Desconocido Entrada Salida ¡Cuenta asociada no encontrada! diff --git a/app/src/main/res/values-es-rCO/strings.xml b/app/src/main/res/values-es-rCO/strings.xml index 6df403977b..b3350f677e 100644 --- a/app/src/main/res/values-es-rCO/strings.xml +++ b/app/src/main/res/values-es-rCO/strings.xml @@ -31,9 +31,6 @@ Configuración avanzada Permitir volver a compartir Buscar en %s - Todos - Completado - Desconocido ¡No se encontró la cuenta asociada! Error de acceso: %1$s La cuenta aún no ha sido agregada a este dispositivo diff --git a/app/src/main/res/values-es-rDO/strings.xml b/app/src/main/res/values-es-rDO/strings.xml index 852854810a..12daad5a75 100644 --- a/app/src/main/res/values-es-rDO/strings.xml +++ b/app/src/main/res/values-es-rDO/strings.xml @@ -30,9 +30,6 @@ Agregar a %1$s Permitir volver a compartir Buscar en %s - Todos - Completado - Desconocido ¡Cuenta asociada no encontrada! Error de acceso: %1$s La cuenta aún no ha sido agregada a este dispositivo diff --git a/app/src/main/res/values-es-rEC/strings.xml b/app/src/main/res/values-es-rEC/strings.xml index 03317462ae..5e3983ef25 100644 --- a/app/src/main/res/values-es-rEC/strings.xml +++ b/app/src/main/res/values-es-rEC/strings.xml @@ -36,12 +36,7 @@ Puerto del proxy Muestra un widget del panel de control Compartir en %s - Todos - Error - Programado - Completado Tarea eliminada con éxito - Desconocido ¡Cuenta asociada no encontrada! Acceso fallido: %1$s La cuenta aún no ha sido agregada a este dispositivo diff --git a/app/src/main/res/values-es-rMX/strings.xml b/app/src/main/res/values-es-rMX/strings.xml index 49ba3ae57f..f8bc5e50ba 100644 --- a/app/src/main/res/values-es-rMX/strings.xml +++ b/app/src/main/res/values-es-rMX/strings.xml @@ -37,17 +37,11 @@ Puerto del proxy Muestra un widget del panel Buscar en %s - Todos Escriba algo de texto ¿Está seguro de eliminar esta tarea? Eliminar tarea - Falló Las listas de tareas están cargando, por favor espere - No hay tareas disponibles. Seleccione un tipo de tarea para crear una nueva. No hay tareas disponibles para el tipo de tarea %s, puede crear una nueva tarea abajo a la derecha. - En proceso - Programado - Completado Ocurrió un error al crear la tarea Tarea creada exitosamente Ocurrió un error al eliminar la tarea @@ -56,7 +50,6 @@ Eliminar tarea No se pudieron obtener los tipos de tareas, por favor, revise su conexión a internet. Asistente - Desconocido Entrada Salida ¡No se encontró la cuenta asociada! diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index c4a9bc5307..1e10ea1519 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -38,17 +38,11 @@ Puerto del proxy Muestra un widget del tablero Buscar en %s - Todo Escriba algo de texto ¿Está seguro de querer eliminar esta tarea? Eliminar tarea - Falló Las listas de tareas están cargando, por favor espere - No hay tareas disponibles. Seleccione un tipo de tarea para crear una nueva. No hay tareas disponibles para el tipo de tarea %s, puede crear una nueva tarea abajo a la derecha. - En progreso - Programado - Completado Ocurrió un error al crear la tarea Tarea creada exitosamente Ocurrió un error al eliminar la tarea @@ -57,7 +51,6 @@ Eliminar tarea No se pudieron obtener los tipos de tareas, por favor, revise su conexión a internet. Asistente - Desconocido Entrada Salida ¡Cuenta asociada no encontrada! diff --git a/app/src/main/res/values-eu/strings.xml b/app/src/main/res/values-eu/strings.xml index ae0cdf9d98..73c710dad4 100644 --- a/app/src/main/res/values-eu/strings.xml +++ b/app/src/main/res/values-eu/strings.xml @@ -46,17 +46,11 @@ Proxy-ataka Paneleko trepeta bat erakusten du Bilatu %s(e)n - Denak Idatzi testu bat Ziur zeregin hau ezabatu nahi duzula? Ezabatu zeregina - Huts egin du Zereginen zerrenda kargatzen ari da, itxaron mesedez - Ez dago zereginik. Hautatu zeregin mota bat zeregin berri bat sortzeko. Ez dago zereginik %s zeregin motarako, zeregin berri bat sor dezakezu behean eskuinean. - Abian - Antolatuta - Osatua Errore bat gertatu da zeregina sortzean Zeregina behar bezala sortu da Errore bat gertatu da zeregina ezabatzean @@ -66,7 +60,6 @@ Zereginaren irteera ez dago prest oraindik. Ezin dira zeregin motak eskuratu, egiaztatu Interneteko konexioa. Morroia - Ezezaguna Sarrera Irteera Ez da aurkitu lotutako konturik diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml index d5e324ea28..808928b55f 100644 --- a/app/src/main/res/values-fa/strings.xml +++ b/app/src/main/res/values-fa/strings.xml @@ -38,13 +38,8 @@ پورت پروکسی نمایش یک ابزارک از پیشخوان جستجو در %s - همه مقداری متن را تایپ کنید - Failed - Scheduled - نکمیل شده Task successfully deleted - ناشناخته حساب مرتبط یافت نشد! دسترسی خطای %1$s حساب به این وسیله اضافه نشده است diff --git a/app/src/main/res/values-fi-rFI/strings.xml b/app/src/main/res/values-fi-rFI/strings.xml index 4c917c8e5f..aa73721eb1 100644 --- a/app/src/main/res/values-fi-rFI/strings.xml +++ b/app/src/main/res/values-fi-rFI/strings.xml @@ -36,14 +36,10 @@ Välityspalvelimen portti Näyttää yhden pienoissovelluksen konsolista Etsi kohteesta %s - Kaikki Syötä tekstiä Haluatko varmasti poistaa tämän tehtävän? Poista tehtävä - Epäonnistui Tehtävälista latautuu, odota - Aikataulutettu - Valmistui Tehtävän luonti epäonnistui Tehtävä luotu Tehtävän poisto epäonnistui @@ -52,7 +48,6 @@ Poista tehtävä Tehtävätyyppen haku epäonnistui, tarkista internetyhteytesi. Avustaja - Tuntematon Liitettyä tiliä ei löydy! Pääsy epäonnistui: %1$s Tälle laitteelle ei ole vielä asennettu tiliä. diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 20021336b1..9e457276bb 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -46,17 +46,11 @@ Port Proxy Affiche un widget du tableau de bord Recherche dans %s - Tout Tapez du texte Êtes-vous sûr de vouloir supprimer cette tâche ? Supprimer la tâche - Échec La liste des tâches charge, veuillez patienter - Aucune tâche disponible. Sélectionner un type de tâche pour créer une nouvelle tâche. Aucune tâche disponible pour le type de tâche %s, vous pouvez créer une nouvelle tâche en bas à droite. - En cours - Planifié - Terminé Une erreur est survenue lors de la création de la tâche La tâche a bien été créée Une erreur est survenue lors de la suppression de la tâche @@ -66,7 +60,6 @@ Le résultat de la tâche n\'est pas encore prêt. Impossible de récupérer les types des tâches, veuillez vérifier votre connexion Internet. Assistant - Inconnu Entrée Sortie Compte associé introuvable ! diff --git a/app/src/main/res/values-ga/strings.xml b/app/src/main/res/values-ga/strings.xml index c2ea1c2992..652ed0d642 100644 --- a/app/src/main/res/values-ga/strings.xml +++ b/app/src/main/res/values-ga/strings.xml @@ -46,17 +46,11 @@ Port Seachfhreastalaí Taispeáin giuirléid amháin ón deais Cuardaigh i %s - Gach Clóscríobh roinnt téacs An bhfuil tú cinnte gur mhaith leat an tasc seo a scriosadh? Scrios Tasc - Theip Tá an Liosta Tasc á lódáil, fan go fóill, le do thoil - Níl aon tasc ar fáil. Roghnaigh cineál taisc chun tasc nua a chruthú. Níl aon tasc ar fáil do chineál taisc %s, is féidir leat tasc nua a chruthú ón mbun ar dheis. - Ar Siúl - Sceidealta - Críochnaithe Tharla earráid agus an tasc á chruthú D\'éirigh leis an tasc a chruthú Tharla earráid agus an tasc á scriosadh @@ -66,7 +60,6 @@ Níl an t-aschur tasc réidh fós. Ní féidir cineálacha tascanna a fháil, seiceáil do nasc idirlín le do thoil. Cúntóir - Anaithnid Ionchur Aschur Cuntas gaolmhar gan aimsiú! diff --git a/app/src/main/res/values-gd/strings.xml b/app/src/main/res/values-gd/strings.xml index b50dee945c..7e8a048311 100644 --- a/app/src/main/res/values-gd/strings.xml +++ b/app/src/main/res/values-gd/strings.xml @@ -31,8 +31,6 @@ Cuir ri %1$s Ceadaich co-roinneadh às ùr Lorg am broinn %s - Coileanta - Chan eil fhios Cha deach an cunntas co-cheangailte a lorg! Dh’fhàillig leis an inntrigeadh: %1$s Cha deach an cunntas a chur ris air an uidheam seo fhathast diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml index 67f1549dfb..22112df16f 100644 --- a/app/src/main/res/values-gl/strings.xml +++ b/app/src/main/res/values-gl/strings.xml @@ -46,17 +46,11 @@ Porto do proxy Amosa un trebello do taboleiro Buscar en %s - Todo Escriba algún texto Confirma que quere eliminar esta tarefa? Eliminar tarefa - Fallado Estase a cargar a lista de tarefas, agarde - Non hai ningunha tarefa dispoñíbel. Seleccione un tipo de tarefa para crear unha nova tarefa. Non hai ningunha tarefa dispoñible para o tipo de tarefa %s, pode crear unha nova desde a parte inferior dereita. - En proceso - Programado - Completado Produciuse un erro ao crear a tarefa A tarefa creouse satisfactoriamente Produciuse un erro ao eliminar a tarefa @@ -66,7 +60,6 @@ A saída da tarefa aínda non está preparada. Non é posíbel recuperar os tipos de tarefas. Comprobe a conexión a Internet. Asistente - Descoñecido Entrada Saída Non se atopou unha conta asociada! diff --git a/app/src/main/res/values-hr/strings.xml b/app/src/main/res/values-hr/strings.xml index 53f588a9f8..41ef92176f 100644 --- a/app/src/main/res/values-hr/strings.xml +++ b/app/src/main/res/values-hr/strings.xml @@ -34,9 +34,6 @@ Osnovni URL Proxy port Traži u %s - Sve - Završeno - Nepoznata pogreška Pripadajući račun nije pronađen! Neuspjeli pristup: %1$s Račun još nije dodan na ovaj uređaj diff --git a/app/src/main/res/values-hu-rHU/strings.xml b/app/src/main/res/values-hu-rHU/strings.xml index f95ab65b84..9cea3e1ed9 100644 --- a/app/src/main/res/values-hu-rHU/strings.xml +++ b/app/src/main/res/values-hu-rHU/strings.xml @@ -40,13 +40,8 @@ Proxy portja Egy modult jelenít meg a irányítópultról Keresés itt: %s - Összes Gépeljen be szöveget - Sikertelen - Ütemezve - Teljesített Feladat sikeresen törölve - Ismeretlen A kapcsolódó fiók nem található! Hozzáférési hiba: %1$s Az eszközön még nem létezik a fiók diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index a67029d9b9..add87fff21 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -35,17 +35,11 @@ Izinkan pembagian ulang Menampilkan satu gawit dari dasbor Cari dalam %s - Semua Tulis beberapa teks Apakah Anda yakin ingin menghapus tugas ini? Hapus Tugas - Gagal Daftar Tugas sedang dimuat, mohon tunggu - Tidak ada tugas yang tersedia. Pilih jenis tugas untuk membuat tugas baru. Tidak ada tugas yang tersedia untuk jenis tugas %s, Anda dapat membuat tugas baru dari pojok kanan bawah. - Sedang Berlangsung - Dijadwalkan - Selesai Terjadi kesalahan saat membuat tugas Tugas berhasil dibuat Terjadi kesalahan saat menghapus tugas @@ -54,7 +48,6 @@ Hapus Tugas Tidak dapat memperoleh jenis tugas, mohon periksa koneksi internet Anda. Asisten - Tidak diketahui Input Output Akun terkait tidak ditemukan! diff --git a/app/src/main/res/values-is/strings.xml b/app/src/main/res/values-is/strings.xml index e15d7d88c0..45087d1b28 100644 --- a/app/src/main/res/values-is/strings.xml +++ b/app/src/main/res/values-is/strings.xml @@ -35,9 +35,6 @@ Gátt milliþjóns Sýnir einn viðmótshluta af stjórnborði Leita í %s - Allt - Lokið - Óþekkt Tengdur notandaaðgangur fannst ekki! Aðgangur mistókst: %1$s Aðgangur er ekki ennþá til á tækinu diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 3ec6517f45..aa9050e433 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -46,17 +46,11 @@ Porta proxy Mostra un widget dal cruscotto Cerca in %s - Tutti Aggiungi del testo Sei sicuro di voler rimuovere questa attività? Elimina attività - Non riuscito Lista dei Task in caricamento, si prega di attendere - Nessun task disponibile. Scegli un tipo di Task per crearne uno nuovo. Nessun task disponibile per la tipologia %s, puoi crearne uno nuovo in basso a destra. - In corso - Programmato - Completato Un errore è intercorso durante la creazione del task Task creato con successo Un errore è intercorso durante la cancellazione del task @@ -66,7 +60,6 @@ Il risultato del task non è ancora pronto. Impossibile recuperare i tipi di task, per favore verifica la tua connessione a internet. Assistente - Sconosciuto Input Output Account associato non trovato. diff --git a/app/src/main/res/values-iw/strings.xml b/app/src/main/res/values-iw/strings.xml index 4cb19df0ce..790d024575 100644 --- a/app/src/main/res/values-iw/strings.xml +++ b/app/src/main/res/values-iw/strings.xml @@ -35,9 +35,6 @@ פתחת מתווך מצג וידג׳ט אחד מלוח הבקרה חפש ב %s - הכול - הושלם - לא ידוע לא נמצא חשבון משויך! גישה נכשלה: %1$s החשבון לא נוסף למכשיר הזה עדיין diff --git a/app/src/main/res/values-ja-rJP/strings.xml b/app/src/main/res/values-ja-rJP/strings.xml index ee616d46ed..282cba667c 100644 --- a/app/src/main/res/values-ja-rJP/strings.xml +++ b/app/src/main/res/values-ja-rJP/strings.xml @@ -46,17 +46,11 @@ プロキシポート ダッシュボードから一つのウィジェットを表示 %s の中を検索 - すべて テキストを入力 本当にこのタスクを削除しますか? タスクを削除 - 失敗 タスクリストを読み込み中です。しばらくお待ちください - 利用可能なタスクがありません。タスクの種類を選択して、新しいタスクを作成してください。 タスクタイプ%sに使用できるタスクがありません。右下から新しいタスクを作成できます。 - 進行中 - スケジュール済 - 完了 タスクの作成中にエラーが発生しました。 タスクは正常に作成されました。 タスクの削除中にエラーが発生しました。 @@ -66,7 +60,6 @@ タスクの出力はまだ準備ができていません。 タスクタイプを取得できません。インターネット接続を確認してください。 アシスタント - 不明 入力 出力 関連付けられたアカウントが見つかりません! diff --git a/app/src/main/res/values-ka/strings.xml b/app/src/main/res/values-ka/strings.xml index 0bf9ee5e44..03c8021bd9 100644 --- a/app/src/main/res/values-ka/strings.xml +++ b/app/src/main/res/values-ka/strings.xml @@ -35,10 +35,6 @@ Allow resharing Shows one widget from dashboard Search in %s - All - Failed - Completed - Unknown Associated account not found! Access failed: %1$s The account is not added on this device yet diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index e84e072565..0b7925d811 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -38,17 +38,11 @@ 프록시 포트 대시보드에 위젯 하나만 표시 %s에서 검색 - 모두 텍스트 입력 이 작업을 삭제하시겠습니까? 작업 삭제 - 실패 작업 목록을 로드하는 중입니다. 잠시 기다려 주세요. - 사용할 수 있는 작업이 없습니다. 새 작업을 생성하려면 작업 유형을 선택하세요. %s작업 유형을 위해 사용 가능한 작업이 없습니다, 오른쪽 하단에서 새 작업을 만들 수 있습니다. - 진행 중 - 예정됨 - 완료됨 작업을 생성하는 중에 오류가 발생했습니다. 작업이 성공적으로 생성됨 작업을 삭제하는 중에 오류가 발생했습니다. @@ -57,7 +51,6 @@ 작업 삭제 작업 유형을 가져올 수 없습니다. 인터넷 연결을 확인하세요. 어시스턴트 - 알 수 없음 입력 출력 관련 계정을 찾을 수 없습니다! diff --git a/app/src/main/res/values-lo/strings.xml b/app/src/main/res/values-lo/strings.xml index 6c63a9645c..0991847461 100644 --- a/app/src/main/res/values-lo/strings.xml +++ b/app/src/main/res/values-lo/strings.xml @@ -34,8 +34,6 @@ ອະນຸຍາດໃຫ້ ການແບ່ງປັນຄືນ ສະແດງໜຶ່ງລາຍການຈາກໜ້າປັດ ຄົ້ນຫາໃນ%s - ສຳເລັດ - ບໍ່ຮູ້ ບໍ່ພົບບັນຊີທີ່ກ່ຽວຂ້ອງ! ການເຂົ້າເຖິງໄດ້ບໍ່ສຳເລັດ%1$s: ຍັງບໍ່ໄດ້ເພີ່ມບັນຊີໃສ່ໃນອຸປະກອນນີ້ diff --git a/app/src/main/res/values-lt-rLT/strings.xml b/app/src/main/res/values-lt-rLT/strings.xml index d1638648c0..82cbd6eee4 100644 --- a/app/src/main/res/values-lt-rLT/strings.xml +++ b/app/src/main/res/values-lt-rLT/strings.xml @@ -37,19 +37,15 @@ Įgaliotojo serverio prievadas Rodo vieną valdiklį iš skydelio Ieškoti %s - Visos Įrašykite kokį nors tekstą Ar tikrai norite ištrinti šią užduotį? Ištrinti užduotį - Nepavyko - Užbaigta Kuriant užduotį, įvyko klaida Užduotis sėkmingai sukurta Ištrinant užduotį, įvyko klaida Užduotis sėkmingai ištrinta Nepavyko gauti užduočių sąrašo, patikrinkite savo interneto ryšį. Ištrinti užduotį - Nežinoma Išvestis Susieta paskyra nerasta! Prieiga nepavyko: %1$s diff --git a/app/src/main/res/values-lv/strings.xml b/app/src/main/res/values-lv/strings.xml index 467e141b95..e845fe8114 100644 --- a/app/src/main/res/values-lv/strings.xml +++ b/app/src/main/res/values-lv/strings.xml @@ -33,12 +33,8 @@ Atļaut atkārtotu koplietošanu Starpniekservera ports Meklēt %s - Visi Dzēst uzdevumu - Neizdevās - Pabeigts Dzēst uzdevumu - Nezināms Saistītais konts nav atrasts! Piekļuve neizdevās: %1$s Konts vēl nav pievienots šai iekārtai diff --git a/app/src/main/res/values-mk/strings.xml b/app/src/main/res/values-mk/strings.xml index 7c14988bff..907a2396d7 100644 --- a/app/src/main/res/values-mk/strings.xml +++ b/app/src/main/res/values-mk/strings.xml @@ -34,10 +34,6 @@ Proxy порта Прикажува еден виџет од контролната табла Барај во %s - Сите - Неуспешно - Завршено - Непознат Не е пронајдена поврзана сметка! Неуспешен пристап: %1$s Сметката сеуште не е додадена на овој уред diff --git a/app/src/main/res/values-nb-rNO/strings.xml b/app/src/main/res/values-nb-rNO/strings.xml index 37d886a278..f3f37c3e97 100644 --- a/app/src/main/res/values-nb-rNO/strings.xml +++ b/app/src/main/res/values-nb-rNO/strings.xml @@ -38,17 +38,11 @@ Proxy-port Viser en widget fra dashbordet Søk i %s - Alle Skriv inn litt tekst Er du sikker på at du vil slette denne oppgaven? Slett oppgave - Mislyktes Oppgaveliste lastes inn, vennligst vent - Ingen oppgave tilgjengelig. Velg en oppgavetype for å opprette en ny oppgave. Ingen oppgave tilgjengelig for %s-oppgavetype, du kan opprette en ny oppgave fra nede til høyre. - Pågår - Planlagt - Ferdig Det oppstod en feil under oppretting av oppgaven Oppgave opprettet Det oppstod en feil under sletting av oppgaven @@ -57,7 +51,6 @@ Slett oppgave Kan ikke hente oppgavetyper, vennligst sjekk internettforbindelsen din. Assistent - Ukjent Inndata Utdata Tilknyttet bruker ikke funnet! diff --git a/app/src/main/res/values-night/colors.xml b/app/src/main/res/values-night/colors.xml index 1ce3f0da4f..8972d2bb67 100644 --- a/app/src/main/res/values-night/colors.xml +++ b/app/src/main/res/values-night/colors.xml @@ -36,4 +36,6 @@ #1E1E1E @android:color/white + + #101418 diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 19b6a387b4..572dc4b7ee 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -46,17 +46,11 @@ Proxy poort Toont één widget van dashboard Zoeken in %s - Alle Geef wat tekst in Bent u zeker dat u deze taak wilt verwijderen? Verwijder taak - Mislukt Takenlijst wordt geladen, even geduld - Geen taak beschikbaar. Selecteer een taaktype om een nieuwe aan te maken. Geen taak beschikbaar voor %s taaktype, u kunt rechts onder een nieuwe taak aanmaken. - Bezig - Ingepland - Voltooid Er is een fout opgetreden bij het aanmaken van de taak Taak succesvol aangemaakt Er is een fout opgetreden bij het verwijderen van de taak @@ -65,7 +59,6 @@ Verwijder taak Kan taken types niet ophalen. Controleer je internetverbinding. Assistent - Onbekend Input Output Bijbehorend account niet gevonden! diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 8c164208ef..28227e7dbd 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -45,17 +45,11 @@ Port proxy Pokazuje jeden widżet z pulpitu nawigacyjnego Szukaj w %s - Wszystkie Wpisz jakiś tekst Czy na pewno chcesz usunąć to zadanie? Usuń zadanie - Nie powiodło się Trwa wczytywanie listy zadań. Proszę czekać - Brak dostępnych zadań. Wybierz typ zadania, aby utworzyć nowe zadanie. Brak dostępnych zadań dla typu zadania %s. Możesz utworzyć nowe zadanie w prawym dolnym rogu. - W trakcie - Zaplanowane - Zakończone Wystąpił błąd podczas tworzenia zadania Zadanie pomyślnie utworzone Wystąpił błąd podczas usuwania zadania @@ -65,7 +59,6 @@ Wynik zadanie nie jest jeszcze gotowy Nie można pobrać typów zadań. Sprawdź swoje połączenie internetowe. Asystent - Nieznany Wejście Wyjście Nie znaleziono powiązanego konta! diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 69cf7f5e18..fcf9a64743 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -39,17 +39,11 @@ Porta do Proxy Mostra um widget do painel Pesquisar em %s - Tudos Digite algum texto Tem certeza de que deseja excluir esta tarefa? Excluir tarefa - Falhou A lista de tarefas está carregando, aguarde - Nenhuma tarefa disponível. Selecione um tipo de tarefa para criar uma nova tarefa. Nenhuma tarefa disponível para o tipo de tarefa %s. Você pode criar uma nova tarefa no canto inferior direito. - Em Andamento - Agendada - Finalizado Ocorreu um erro ao criar a tarefa Tarefa criada com sucesso Ocorreu um erro ao excluir a tarefa @@ -59,7 +53,6 @@ O resultado da tarefa ainda não está pronto. Não foi possível buscar os tipos de tarefas. Verifique sua conexão com a Internet. Assistente - Desconhecido Entrada Saída Conta associada não encontrada! diff --git a/app/src/main/res/values-pt-rPT/strings.xml b/app/src/main/res/values-pt-rPT/strings.xml index 3a666664cd..c5abe36ddf 100644 --- a/app/src/main/res/values-pt-rPT/strings.xml +++ b/app/src/main/res/values-pt-rPT/strings.xml @@ -34,9 +34,6 @@ Permitir repartilha Mostra um \'\'widget\'\' do painel Procurar em %s - Todos - Concluída - Desconhecido Conta associada não encontrada! Acesso falhou: %1$s A conta ainda não foi adicionada a este dispositivo diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml index 823c07aa0c..c6b7731283 100644 --- a/app/src/main/res/values-ro/strings.xml +++ b/app/src/main/res/values-ro/strings.xml @@ -37,17 +37,11 @@ Port proxy Arată un singur widget din panoul principal Caută in %s - Toate Tastează un text Sigur doriți să ștergeți acest task? Şterge task - Eșuat Lista de taskuri se încarcă, așteptați - Nici un task disponibil. Selectați un tip de task pentru a crea unul nou. Niciun task disponibil pentru tipul de task %s, puteți crea un task nou din dreapta jos. - În curs de desfășurare - Programat - Terminat A apărut o eroare la crearea taskului Task creat cu succes A apărut o eroare la ștergerea taskului @@ -56,7 +50,6 @@ Şterge task Nu se pot prelua tipurile taskurilor, vă rugăm să verificați conexiunea la internet. Asistent - Necunoscut Intrare Rezultat Contul asociat nu a fost găsit! diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 3a915d309c..cb5cd7ab84 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -40,17 +40,11 @@ Порт прокси Показывает один виджет с главного экрана. Искать в %s - Все Наберите какой-то текст Вы уверены, что хотите удалить эту задачу? Удалить задачу - Не удалось Список задач загружается, пожалуйста подождите - Нет доступных задач. Выберите тип задачи, чтобы создать новую задачу. Нет доступной задачи для типа задачи %s, вы можете создать новую задачу в правом нижнем углу. - Выполянется - Запланированное - Выполнено Произошла ошибка при создании задачи Задача успешно создана Произошла ошибка во время удаления задачи @@ -59,7 +53,6 @@ Удалить задачу Не удается получить список задач, проверьте ваше подключение к Интернету. Помощник - Неизвестно Ввод Вывод Связанный аккаунт не найден! diff --git a/app/src/main/res/values-sc/strings.xml b/app/src/main/res/values-sc/strings.xml index 4f72789c87..42d92faafb 100644 --- a/app/src/main/res/values-sc/strings.xml +++ b/app/src/main/res/values-sc/strings.xml @@ -35,11 +35,7 @@ URL de base Port serbidore intermèdiu Chirca in %s - Totu - Peruna faina a disponimentu. Seletziona sa genia de faina pro nde creare una noa. Peruna faina a disponimentu pro sa genia %s. Nde podes creare una noa dae su cugione in bassu a dereta. - Cumpletadu - Disconnotu Contu assotziadu no agatadu! Atzessu faddidu: %1$s Su contu non s\'agatat ancora in custu dispositivu diff --git a/app/src/main/res/values-sk-rSK/strings.xml b/app/src/main/res/values-sk-rSK/strings.xml index 26132f0f3e..02a42ab565 100644 --- a/app/src/main/res/values-sk-rSK/strings.xml +++ b/app/src/main/res/values-sk-rSK/strings.xml @@ -46,17 +46,11 @@ Brána proxy Zobrazí jeden widget z hlavného panela Hľadať v %s - Všetko Napíšte nejaký text Naozaj chcete vymazať túto úlohu? Vymazať Úlohu - Zlyhalo Zoznam úloh sa nahráva, prosím čakajte - Žiadne úlohy nie su dostupné. Vyberte typ úlohy pre vytvorenie novej. Pre typ úlohy %s nie je k dispozícii žiadna úloha, môžete vytvoriť novú úlohu vpravo dole. - Prebieha - Naplánované - Dokončené Pri vytváraní úlohy nastala chyba Úloha bola úspešne vytvorená Pri odstraňovaní úlohy nastala chyba @@ -65,7 +59,6 @@ Vymazať Úlohu Nie je možné načítať typy úloh, skontrolujte svoje internetové pripojenie. Asistent - Neznámy Vstup Výstup Priradený účet sa nenašiel diff --git a/app/src/main/res/values-sl/strings.xml b/app/src/main/res/values-sl/strings.xml index 886464bb71..44136a723f 100644 --- a/app/src/main/res/values-sl/strings.xml +++ b/app/src/main/res/values-sl/strings.xml @@ -38,11 +38,6 @@ Vrata posredniškega strežnika Pokaži en gradnik iz nadzorne plošče Poišči v %s - Vse - Opravilo je spodletelo! - Načrtovano - Končano - Neznano Povezanega računa ni mogoče najti! Dostop je spodletel: %1$s Račun še ni dodan na to napravo. diff --git a/app/src/main/res/values-sq/strings.xml b/app/src/main/res/values-sq/strings.xml index ce77e5b62b..d726998145 100644 --- a/app/src/main/res/values-sq/strings.xml +++ b/app/src/main/res/values-sq/strings.xml @@ -29,9 +29,6 @@ Cilësime të Avancuara Lejo rindarje Kërkoni në %s - Të gjithë - Të plotësuara - I panjohur Llogaria e lidhur nuk u gjet! Hyrja dështoi: %1$s Kjo llogari nuk është shtuar në këtë paisje akoma diff --git a/app/src/main/res/values-sr-rSP/strings.xml b/app/src/main/res/values-sr-rSP/strings.xml index 652431135b..79ee3ef7bb 100644 --- a/app/src/main/res/values-sr-rSP/strings.xml +++ b/app/src/main/res/values-sr-rSP/strings.xml @@ -30,16 +30,10 @@ Dodaj u %1$s Napredna podešavanja Pretraga u %s - Sve Da li ste sigurni da želite da izbrišete ovaj zadatak? Izbriši zadatak - Nije uspelo Lista zadataka se učitava, molimo sačekajte - Nijedan zadatak nije dostupan. Izaberite tip zadatka da biste kreirali novi zadatak. Nijedan zadatak nije dostupan za %s tip zadatka, možete kreirati novi zadatak dole desno. - U toku - Zakazano - Završeno Izbriši zadatak Pridruženi nalog nije nađen! Neuspeo pristup: %1$s diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml index e89f8d589d..0af0b6b879 100644 --- a/app/src/main/res/values-sr/strings.xml +++ b/app/src/main/res/values-sr/strings.xml @@ -46,17 +46,11 @@ Прокси порт Приказује један виџет са контролне табле Тражи у %s - Све Откуцајте неки текст Да ли сте сигурни да желите да обришете овај задатак? Обриши задатак - Није успело Листа задатака се учитава, молимо вас сачекајте - Не постоји ниједан задатак. Да бисте креирали нови задатак, изаберите тип задатка. Не постоји ниједан задатак типа %s, нови задатак можете да креирате доле десно. - Напредује - Заказано - Завршено Дошло је до грешке током креирања задатка Задатак је успешно креиран Дошло је до грешке током брисања задатка @@ -66,7 +60,6 @@ Излаз задатка још увек није спреман. Не могу да се преузму типови задатака, молимо вас да проверите везу са интернетом. Асистент - Непознато Унос Излаз Придружени налог није нађен! diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 8299cc8578..f924d8b38d 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -46,17 +46,11 @@ Proxyport Visa en widget från dashboard Sök i %s - Alla Skriv någon text Är du säker på att du vill ta bort den här uppgiften? Ta bort uppgift - Misslyckades Uppgiftslistan laddas, vänta - Ingen uppgift tillgänglig. Välj en uppgiftstyp för att skapa en ny uppgift. Ingen uppgift tillgänglig för uppgiftstyp %s, du kan skapa en ny uppgift längst ner till höger. - Pågående - Schemalagd - Slutförd Ett fel uppstod när uppgiften skapades Uppgiften har skapats Ett fel uppstod när uppgiften skulle tas bort @@ -66,7 +60,6 @@ Uppgiftens resultat är inte redo än. Det går inte att hämta uppgiftstyper, kontrollera din internetanslutning. Assistent - Okänd Inmatning Utdata Associerat konto kunde inte hittas! diff --git a/app/src/main/res/values-th-rTH/strings.xml b/app/src/main/res/values-th-rTH/strings.xml index 848d04a9de..a6ee47d653 100644 --- a/app/src/main/res/values-th-rTH/strings.xml +++ b/app/src/main/res/values-th-rTH/strings.xml @@ -34,11 +34,7 @@ อนุญาตให้แชร์ซ้ำ แสดงหนึ่งวิดเจ็ตจากแดชบอร์ด ค้นหาใน %s - ทั้งหมด พิมพ์ข้อความของคุณ - อยู่ระหว่างการดำเนินการ - เสร็จแล้ว - ไม่ทราบ ไม่พบบัญชีที่เกี่ยวข้อง! การเข้าถึงล้มเหลว: %1$s บัญชียังไม่ถูกเพิ่มบนอุปกรณ์นี้ diff --git a/app/src/main/res/values-tk/strings.xml b/app/src/main/res/values-tk/strings.xml index 5cff2f37bd..6428f5a6a4 100644 --- a/app/src/main/res/values-tk/strings.xml +++ b/app/src/main/res/values-tk/strings.xml @@ -30,8 +30,6 @@ Goşuň%1$s Täzeden paýlaşmaga rugsat beriň Gözlemek%siçinde - Tamamlanan - Näbelli Baglanyşyk hasaby tapylmady! Şowsuz Giriş%1$s: Akaunt entek bu enjamda goşulmaýar diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 395832b90d..8bde18db21 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -38,17 +38,11 @@ Vekil sunucu bağlantı noktası Panodan bir pano bileşeni görüntüler %s içinde arama - Tümü Bir şeyler yazın Bu görevi silmek istediğinize emin misiniz? Görevi sil - Tamamlanamadı Lütfen görev listesi yüklenirken bekleyin - Herhangi bir görev yok.Yeni bir görev eklemek için bir görev türü seçin. %s türünde bir görev yok. Sağ alttan yeni bir görev ekleyebilirsiniz. - Yapılıyor - Zamanlanmış - Tamamlanmış Görev oluşturulurken bir sorun çıktı Görev oluşturuldu Görev silinirken bir sorun çıktı @@ -57,7 +51,6 @@ Görevi sil Görev türleri alınamadı. Lütfen İnternet bağlantınızı denetleyin. Yardımcı - Bilinmiyor Giriş Çıkış İlişkili hesap bulunamadı! diff --git a/app/src/main/res/values-ug/strings.xml b/app/src/main/res/values-ug/strings.xml index bb64d4b20f..1d9ce44c2f 100644 --- a/app/src/main/res/values-ug/strings.xml +++ b/app/src/main/res/values-ug/strings.xml @@ -38,17 +38,11 @@ ۋاكالەتچى ئېغىز باشقۇرۇش تاختىسىدىكى بىر كىچىك قورالنى كۆرسىتىدۇ % S دىن ئىزدەڭ - ھەممىسى بەزى تېكىستلەرنى كىرگۈزۈڭ بۇ ۋەزىپىنى ئۆچۈرمەكچىمۇ؟ ۋەزىپىنى ئۆچۈرۈڭ - مەغلۇب بولدى ۋەزىپە تىزىملىكى يۈكلىنىۋاتىدۇ ، ساقلاپ تۇرۇڭ - ھېچقانداق ۋەزىپە يوق. يېڭى ۋەزىپە يارىتىش ئۈچۈن ۋەزىپە تۈرىنى تاللاڭ. % S ۋەزىپە تىپىغا ماس كېلىدىغان ۋەزىپە يوق ، ئاستىدىن ئوڭدىن يېڭى ۋەزىپە قۇرالايسىز. - ئىلگىرىلەۋاتىدۇ - پىلانلانغان - تاماملاندى ۋەزىپە قۇرغاندا خاتالىق كۆرۈلدى ۋەزىپە مۇۋەپپەقىيەتلىك قۇرۇلدى ۋەزىپىنى ئۆچۈرگەندە خاتالىق كۆرۈلدى @@ -57,7 +51,6 @@ ۋەزىپىنى ئۆچۈرۈڭ ۋەزىپە تۈرلىرىنى ئېلىپ كېتەلمىدىڭىز ، تور ئۇلىنىشىڭىزنى تەكشۈرۈپ بېقىڭ. ياردەمچى - نامەلۇم كىرگۈزۈش چىقىرىش بىرلەشمە ھېسابات تېپىلمىدى! diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index f6ba502de8..57876d62dc 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -46,17 +46,11 @@ Порт проксі-сервера Показувати один віджет з панелі віджетів Пошук у %s - Всі Вставте будь-який текст Дійсно вилучити це завдання? Вилучити завдання - Не вдалося Отримання переліку завдань, зачекайте - Відсутні завдання. Виберіть вид завдань для додавання нового завдання Відсутні завдання для завдань типу %s. Ви можете додати нове завдання праворуч внизу. - В процесі - Заплановано - Виконано Помилка під час додавання завдання Успішно додано завдання Помилка під час вилучення завдання @@ -66,7 +60,6 @@ Поки неможливо показати завдання Не вдалося отримати типи завдань. Перевірте з\'єднання з мережею. Помічник - Невідомо Введення Виведення Пов\'язаний обліковий запис не знайдено! diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index 703030f62c..d7eb116cd8 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -33,10 +33,6 @@ Cho phép chia sẻ lại Hiện thị lối tắt từ dashboard Tìm kiếm trong %s - Tất cả - Lên kế hoạch - Hoàn thành - Không xác định Không tìm thấy tài khoản được liên kết! Lỗi truy cập: %1$s Tài khoản chưa được thêm vào thiết bị này. diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 30efb9373d..0c34561c3a 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -46,17 +46,11 @@ 代理端口 显示仪表盘中的一个小部件 在 %s 中搜索 - 所有 输入一些文字 您确定要删除这些任务吗? 删除任务 - 失败了 任务列表加载中,请稍等 - 没有可用任务。选择任务类型以创建新任务。 %s任务类型没有可用任务,你可以从右下角创建新任务。 - 进行中 - 已排程 - 已完成 创建任务时发生错误 任务已创建 删除任务时发生错误 @@ -66,7 +60,6 @@ 任务输出尚未就绪。 无法获取任务类型,请检查您的网络连接。 助手 - 未知 输入 输出结果 相关账号未找到! diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml index a3ccd239a3..e6ed734ce3 100644 --- a/app/src/main/res/values-zh-rHK/strings.xml +++ b/app/src/main/res/values-zh-rHK/strings.xml @@ -46,17 +46,11 @@ proxy代理伺服器連接埠 顯示儀表板中的一個小部件 %s內搜尋 - 全部 輸入一些文字 您確定要刪除此工作項目嗎? 刪除任務 - 失敗了 任務清單加載中,請稍候 - 無可用的工作項目。選取工作項目類型以建立新工作項目。 沒有可用於 %s 任務項目類型的任務項目,您可以從右下角建立新任務項目。 - 進行中 - 預定 - 已完成 建立任務項目時發生錯誤 已成功建立任務項目 刪除任務時發生了錯誤 @@ -66,7 +60,6 @@ 任務輸出尚未就緒。 無法擷取任務類型,請檢查您的網際網路連線。 助手 - 不詳 輸入 輸出 無法找到連結帳戶 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index c85a54adb4..87e90feee2 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -46,17 +46,11 @@ proxy代理伺服器連接埠 顯示儀表板中的一個小工具 搜尋 %s - 全部 輸入一些文字 您確定要刪除此工作項目嗎? 刪除工作項目 - 失敗 未載入工作項目清單,請稍候 - 無可用的工作項目。選取工作項目類型以建立新工作項目。 沒有可用於 %s 工作項目類型的工作項目,您可以從右下角建立新工作項目。 - 進行中 - 已安排 - 已完成 建立工作項目時發生錯誤 已成功建立工作項目 刪除工作項目時發生錯誤 @@ -66,7 +60,6 @@ 任務輸出尚未就緒。 無法擷取工作項目類型,請檢查您的網際網路連線。 助理 - 未知 輸入 輸出 找不到相關的帳號! diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index efefff8f3b..e0da603d4f 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -76,4 +76,6 @@ @android:color/white #666666 #A5A5A5 + + #F7F9FF diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e48003d717..f0b93bdd5f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -51,10 +51,10 @@ Assistant Task List are loading, please wait The task output is not ready yet. - No task available. Select a task type to create a new task. No task available for %s task type, you can create a new task from bottom right. Delete Task Are you sure you want to delete this task? + Add new task Delete Task @@ -66,17 +66,9 @@ Type some text - Unknown - Scheduled - Completed - Failed - In Progress - Input Output - All - Assistant All files Personal files @@ -134,6 +126,21 @@ %d minutes + + 1 second ago + %d seconds ago + + + + 1 minute ago + %d minutes ago + + + + 1 hour ago + %d hours ago + + Try %1$s on your device! I want to invite you to use %1$s on your device.\nDownload here: %2$s %1$s or %2$s @@ -190,6 +197,7 @@ Yes No OK + Now Cancel sync Cancel Back diff --git a/build.gradle b/build.gradle index f52ac868e2..e9a1ee0404 100644 --- a/build.gradle +++ b/build.gradle @@ -10,7 +10,7 @@ */ buildscript { ext { - androidLibraryVersion ="4a95888afc472369e85fccae3d3573ff9e36fb50" + androidLibraryVersion ="f174c1ee78" androidPluginVersion = '8.7.3' androidxMediaVersion = '1.4.1' androidxTestVersion = "1.6.1" diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 257a761c7c..a41b59df97 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -7934,6 +7934,14 @@ + + + + + + + +