From c11b8843b4a6f47e527a16abbfd2378d88add104 Mon Sep 17 00:00:00 2001 From: Amanpal Singh <87360222+aman-alfresco@users.noreply.github.com> Date: Mon, 18 Mar 2024 16:46:49 +0530 Subject: [PATCH 1/7] submit collected data to server --- .../details/ProcessDetailViewModel.kt | 2 +- .../ProcessDetailViewModelExtension.kt | 2 +- .../processes/list/ProcessesViewModel.kt | 6 +- .../detail/TaskDetailViewModelExtension.kt | 2 +- .../content/component/ComponentSheet.kt | 1 + .../alfresco/content/data/TaskRepository.kt | 69 ++++++++----------- gradle/libs.versions.toml | 2 +- .../alfresco/content/process/FormViewModel.kt | 15 ++++ .../content/process/ui/FormDetailScreen.kt | 2 +- .../content/process/ui/UpdateProcessData.kt | 6 ++ .../ui/components/FloatingActionButton.kt | 5 +- .../process/ui/components/FormScreen.kt | 13 +++- .../ui/components/FormViewModelExtension.kt | 15 ++++ .../content/process/ui/components/Outcomes.kt | 8 ++- 14 files changed, 94 insertions(+), 54 deletions(-) create mode 100644 process-app/src/main/kotlin/com/alfresco/content/process/ui/UpdateProcessData.kt create mode 100644 process-app/src/main/kotlin/com/alfresco/content/process/ui/components/FormViewModelExtension.kt diff --git a/browse/src/main/kotlin/com/alfresco/content/browse/processes/details/ProcessDetailViewModel.kt b/browse/src/main/kotlin/com/alfresco/content/browse/processes/details/ProcessDetailViewModel.kt index e2f6a070b..6d862cea2 100644 --- a/browse/src/main/kotlin/com/alfresco/content/browse/processes/details/ProcessDetailViewModel.kt +++ b/browse/src/main/kotlin/com/alfresco/content/browse/processes/details/ProcessDetailViewModel.kt @@ -192,7 +192,7 @@ class ProcessDetailViewModel( fun startWorkflow() = withState { state -> val items = state.listContents.joinToString(separator = ",") { it.id } viewModelScope.launch { - repository::startWorkflow.asFlow(state.parent, items).execute { + repository::startWorkflow.asFlow(state.parent, items, emptyList()).execute { when (it) { is Loading -> copy(requestStartWorkflow = Loading()) is Fail -> copy(requestStartWorkflow = Fail(it.error)) diff --git a/browse/src/main/kotlin/com/alfresco/content/browse/processes/details/ProcessDetailViewModelExtension.kt b/browse/src/main/kotlin/com/alfresco/content/browse/processes/details/ProcessDetailViewModelExtension.kt index 42327d8c2..ae06a25eb 100644 --- a/browse/src/main/kotlin/com/alfresco/content/browse/processes/details/ProcessDetailViewModelExtension.kt +++ b/browse/src/main/kotlin/com/alfresco/content/browse/processes/details/ProcessDetailViewModelExtension.kt @@ -1,7 +1,7 @@ package com.alfresco.content.browse.processes.details -import com.alfresco.content.browse.processes.list.UpdateProcessData import com.alfresco.content.browse.tasks.list.UpdateTasksData +import com.alfresco.content.process.ui.UpdateProcessData import com.alfresco.events.EventBus import kotlinx.coroutines.launch diff --git a/browse/src/main/kotlin/com/alfresco/content/browse/processes/list/ProcessesViewModel.kt b/browse/src/main/kotlin/com/alfresco/content/browse/processes/list/ProcessesViewModel.kt index 390d2ce3b..72a4d7d51 100644 --- a/browse/src/main/kotlin/com/alfresco/content/browse/processes/list/ProcessesViewModel.kt +++ b/browse/src/main/kotlin/com/alfresco/content/browse/processes/list/ProcessesViewModel.kt @@ -13,6 +13,7 @@ import com.alfresco.content.data.payloads.TaskProcessFiltersPayload import com.alfresco.content.getLocalizedName import com.alfresco.content.listview.processes.ProcessListViewModel import com.alfresco.content.listview.processes.ProcessListViewState +import com.alfresco.content.process.ui.UpdateProcessData import com.alfresco.coroutines.asFlow import com.alfresco.events.on import kotlinx.coroutines.launch @@ -117,8 +118,3 @@ class ProcessesViewModel( fetchInitial() } } - -/** - * Mark as UpdateProcessData data class - */ -data class UpdateProcessData(val isRefresh: Boolean) diff --git a/browse/src/main/kotlin/com/alfresco/content/browse/tasks/detail/TaskDetailViewModelExtension.kt b/browse/src/main/kotlin/com/alfresco/content/browse/tasks/detail/TaskDetailViewModelExtension.kt index 80aab9ea8..e52d784d9 100644 --- a/browse/src/main/kotlin/com/alfresco/content/browse/tasks/detail/TaskDetailViewModelExtension.kt +++ b/browse/src/main/kotlin/com/alfresco/content/browse/tasks/detail/TaskDetailViewModelExtension.kt @@ -1,11 +1,11 @@ package com.alfresco.content.browse.tasks.detail import com.alfresco.content.actions.Action -import com.alfresco.content.browse.processes.list.UpdateProcessData import com.alfresco.content.browse.tasks.list.UpdateTasksData import com.alfresco.content.data.Entry import com.alfresco.content.data.OfflineRepository import com.alfresco.content.data.UserGroupDetails +import com.alfresco.content.process.ui.UpdateProcessData import com.alfresco.events.EventBus import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch diff --git a/component/src/main/java/com/alfresco/content/component/ComponentSheet.kt b/component/src/main/java/com/alfresco/content/component/ComponentSheet.kt index fdd7d2ead..d8d1d3ddf 100644 --- a/component/src/main/java/com/alfresco/content/component/ComponentSheet.kt +++ b/component/src/main/java/com/alfresco/content/component/ComponentSheet.kt @@ -415,6 +415,7 @@ class ComponentSheet : BottomSheetDialogFragment(), MavericksView { id(bucket.hashCode()) data(bucket) clickListener { model, _, _, _ -> + onApply?.invoke("", "", mapOf()) dismiss() } } diff --git a/data/src/main/kotlin/com/alfresco/content/data/TaskRepository.kt b/data/src/main/kotlin/com/alfresco/content/data/TaskRepository.kt index 47d4c87f0..56b14a759 100644 --- a/data/src/main/kotlin/com/alfresco/content/data/TaskRepository.kt +++ b/data/src/main/kotlin/com/alfresco/content/data/TaskRepository.kt @@ -4,6 +4,8 @@ import android.content.SharedPreferences import androidx.preference.PreferenceManager import com.alfresco.content.data.Settings.Companion.IS_PROCESS_ENABLED_KEY import com.alfresco.content.data.payloads.CommentPayload +import com.alfresco.content.data.payloads.FieldType +import com.alfresco.content.data.payloads.FieldsData import com.alfresco.content.data.payloads.LinkContentPayload import com.alfresco.content.data.payloads.SystemPropertiesEntry import com.alfresco.content.data.payloads.TaskProcessFiltersPayload @@ -16,7 +18,6 @@ import com.alfresco.process.apis.ProcessAPI import com.alfresco.process.apis.TaskAPI import com.alfresco.process.models.AssignUserBody import com.alfresco.process.models.CommonOptionModel -import com.alfresco.process.models.GroupInfo import com.alfresco.process.models.ProfileData import com.alfresco.process.models.RequestComment import com.alfresco.process.models.RequestLinkContent @@ -26,7 +27,6 @@ import com.alfresco.process.models.RequestProcessInstancesQuery import com.alfresco.process.models.RequestSaveForm import com.alfresco.process.models.RequestTaskFilters import com.alfresco.process.models.TaskBodyCreate -import com.alfresco.process.models.UserInfo import com.alfresco.process.models.ValuesModel import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -383,55 +383,46 @@ class TaskRepository { /** * Execute the start flow integration */ - suspend fun startWorkflow(processEntry: ProcessEntry?, items: String) = ProcessEntry.with( + suspend fun startWorkflow(processEntry: ProcessEntry?, items: String, fields: List) = ProcessEntry.with( processesService.createProcessInstance( RequestProcessInstances( name = processEntry?.name, processDefinitionId = processEntry?.id, - values = ValuesModel( - due = processEntry?.formattedDueDate, - message = processEntry?.description, - priority = if (processEntry?.priority != -1) { - CommonOptionModel( - id = getTaskPriority(processEntry?.priority ?: 0).name, - name = getTaskPriority(processEntry?.priority ?: 0).name, - ) - } else { - null - }, - reviewer = getUser(processEntry?.startedBy), - reviewGroups = getGroup(processEntry?.startedBy), - items = items, - sendEmailNotifications = false, - ), + values = convertFieldsToValues(fields), ), ), ) - private fun getUser(userGroupInfo: UserGroupDetails?): UserInfo? { - return if (userGroupInfo?.isGroup == true) { - null - } else { - UserInfo( - id = userGroupInfo?.id, - firstName = userGroupInfo?.firstName, - lastName = userGroupInfo?.lastName, - email = userGroupInfo?.email, - ) + private fun convertFieldsToValues(fields: List): Map { + val values = mutableMapOf() + + fields.forEach { + if (it.type == FieldType.PEOPLE.value() || it.type == FieldType.FUNCTIONAL_GROUP.value()) { + values[it.id] = getUserOrGroup(it.value as UserGroupDetails) + } else { + values[it.id] = it.value + } } + + return values } - private fun getGroup(userGroupInfo: UserGroupDetails?): GroupInfo? { - return if (userGroupInfo?.isGroup == false) { - null + private fun getUserOrGroup(userGroupInfo: UserGroupDetails?): Map { + return if (userGroupInfo?.isGroup == true) { + mapOf( + "id" to userGroupInfo?.id, + "name" to userGroupInfo?.name, + "externalId" to userGroupInfo?.externalId, + "status" to userGroupInfo?.status, + "parentGroupId" to userGroupInfo?.parentGroupId, + "groups" to userGroupInfo?.groups, + ) } else { - GroupInfo( - id = userGroupInfo?.id, - name = userGroupInfo?.name, - externalId = userGroupInfo?.externalId, - status = userGroupInfo?.status, - parentGroupId = userGroupInfo?.parentGroupId, - groups = userGroupInfo?.groups, + mapOf( + "id" to userGroupInfo?.id, + "firstName" to userGroupInfo?.firstName, + "lastName" to userGroupInfo?.lastName, + "email" to userGroupInfo?.email, ) } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f8b1eac3b..239643921 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -17,7 +17,7 @@ ui-tooling = "1.5.4" alfresco-auth = "com.alfresco.android:auth:0.8.1-SNAPSHOT" alfresco-content = "com.alfresco.android:content:0.3.4-SNAPSHOT" alfresco-contentKtx = "com.alfresco.android:content-ktx:0.3.2-SNAPSHOT" -alfresco-process = "com.alfresco.android:process:0.1.2-SNAPSHOT" +alfresco-process = "com.alfresco.android:process:0.1.3-SNAPSHOT" android-desugar = "com.android.tools:desugar_jdk_libs:2.0.3" android-gradle = "com.android.tools.build:gradle:8.0.2" diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/FormViewModel.kt b/process-app/src/main/kotlin/com/alfresco/content/process/FormViewModel.kt index 3ac58e9ce..97ea1e1a9 100644 --- a/process-app/src/main/kotlin/com/alfresco/content/process/FormViewModel.kt +++ b/process-app/src/main/kotlin/com/alfresco/content/process/FormViewModel.kt @@ -27,6 +27,7 @@ data class FormViewState( val formFields: List = emptyList(), val processOutcomes: List = emptyList(), val enabledOutcomes: Boolean = false, + val requestStartWorkflow: Async = Uninitialized, ) : MavericksState { constructor(target: ProcessEntry) : this(parent = target) @@ -85,6 +86,7 @@ class FormViewModel( is Success -> { copy( + parent = processEntry, formFields = it().fields.flatMap { listData -> listData.fields }, processOutcomes = it().outcomes, requestStartForm = Success(it()), @@ -129,6 +131,19 @@ class FormViewModel( setState { updatedState.copy(enabledOutcomes = hasAllRequiredData) } } + fun startWorkflow() = withState { state -> + viewModelScope.launch { + repository::startWorkflow.asFlow(state.parent, "", state.formFields).execute { + when (it) { + is Loading -> copy(requestStartWorkflow = Loading()) + is Fail -> copy(requestStartWorkflow = Fail(it.error)) + is Success -> copy(requestStartWorkflow = Success(it())) + else -> this + } + } + } + } + private fun hasFieldRequiredData(state: FormViewState): Boolean { return !state.formFields.filter { it.required }.any { it.value == null } } diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/FormDetailScreen.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/FormDetailScreen.kt index 2f6050ccc..c389e255b 100644 --- a/process-app/src/main/kotlin/com/alfresco/content/process/ui/FormDetailScreen.kt +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/FormDetailScreen.kt @@ -67,7 +67,7 @@ fun FormDetailScreen(state: FormViewState, viewModel: FormViewModel, outcomes: L .fillMaxWidth() .align(alignment = Alignment.CenterHorizontally), ) { - Outcomes(outcomes = outcomes, state.enabledOutcomes) + Outcomes(outcomes = outcomes, state.enabledOutcomes, viewModel) } } } diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/UpdateProcessData.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/UpdateProcessData.kt new file mode 100644 index 000000000..c61068eb7 --- /dev/null +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/UpdateProcessData.kt @@ -0,0 +1,6 @@ +package com.alfresco.content.process.ui + +/** + * Mark as UpdateProcessData data class + */ +data class UpdateProcessData(val isRefresh: Boolean) diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/FloatingActionButton.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/FloatingActionButton.kt index a9c6f413c..a88fb4521 100644 --- a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/FloatingActionButton.kt +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/FloatingActionButton.kt @@ -12,10 +12,11 @@ import androidx.compose.ui.res.stringResource import com.alfresco.content.component.ComponentBuilder import com.alfresco.content.component.ComponentData import com.alfresco.content.data.OptionsModel +import com.alfresco.content.process.FormViewModel import com.alfresco.content.process.R @Composable -fun FloatingActionButton(outcomes: List, enabledOutcomes: Boolean) { +fun FloatingActionButton(outcomes: List, enabledOutcomes: Boolean, viewModel: FormViewModel) { val context = LocalContext.current ExtendedFloatingActionButton( @@ -28,6 +29,8 @@ fun FloatingActionButton(outcomes: List, enabledOutcomes: Boolean) ) ComponentBuilder(context, componentData) .onApply { name, query, _ -> + + viewModel.startWorkflow() } .onReset { name, query, _ -> } diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/FormScreen.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/FormScreen.kt index 71e9d44e5..28a72b104 100644 --- a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/FormScreen.kt +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/FormScreen.kt @@ -1,6 +1,7 @@ package com.alfresco.content.process.ui.components import ComposeTopBar +import android.app.Activity import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.material3.FabPosition @@ -9,9 +10,11 @@ import androidx.compose.material3.Scaffold import androidx.compose.material3.Surface import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.navigation.NavController import com.airbnb.mvrx.Loading +import com.airbnb.mvrx.Success import com.airbnb.mvrx.compose.collectAsState import com.airbnb.mvrx.compose.mavericksActivityViewModel import com.alfresco.content.data.OptionsModel @@ -24,6 +27,12 @@ fun FormScreen(navController: NavController) { // This will get or create a ViewModel scoped to the Activity. val viewModel: FormViewModel = mavericksActivityViewModel() val state by viewModel.collectAsState() + val context = LocalContext.current + + if (state.requestStartWorkflow is Success) { + viewModel.updateProcessList() + (context as Activity).finish() + } val customOutcomes = when { state.formFields.isNotEmpty() && state.processOutcomes.isEmpty() -> { @@ -62,7 +71,7 @@ fun FormScreen(navController: NavController) { else -> { Scaffold( topBar = { ComposeTopBar() }, - floatingActionButton = { FloatingActionButton(customOutcomes, state.enabledOutcomes) }, + floatingActionButton = { FloatingActionButton(customOutcomes, state.enabledOutcomes, viewModel) }, floatingActionButtonPosition = FabPosition.End, ) { padding -> val colorScheme = MaterialTheme.colorScheme @@ -74,7 +83,7 @@ fun FormScreen(navController: NavController) { color = colorScheme.background, contentColor = colorScheme.onBackground, ) { - if (state.requestStartForm is Loading) { + if (state.requestStartForm is Loading || state.requestStartWorkflow is Loading) { CustomLinearProgressIndicator(padding) } FormDetailScreen(state, viewModel, emptyList()) diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/FormViewModelExtension.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/FormViewModelExtension.kt new file mode 100644 index 000000000..f3e9dd7b2 --- /dev/null +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/FormViewModelExtension.kt @@ -0,0 +1,15 @@ +package com.alfresco.content.process.ui.components + +import com.alfresco.content.process.FormViewModel +import com.alfresco.content.process.ui.UpdateProcessData +import com.alfresco.events.EventBus +import kotlinx.coroutines.launch + +/** + * update the list of workflow if new entry created + */ +fun FormViewModel.updateProcessList() { + viewModelScope.launch { + EventBus.default.send(UpdateProcessData(isRefresh = true)) + } +} diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/Outcomes.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/Outcomes.kt index 2513585ef..df57c8d83 100644 --- a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/Outcomes.kt +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/Outcomes.kt @@ -10,16 +10,20 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp +import androidx.lifecycle.viewmodel.compose.viewModel import com.alfresco.content.data.OptionsModel +import com.alfresco.content.process.FormViewModel @Composable -fun Outcomes(outcomes: List, enabledOutcomes: Boolean) { +fun Outcomes(outcomes: List, enabledOutcomes: Boolean, viewModel: FormViewModel) { outcomes.forEach { Button( modifier = Modifier .fillMaxWidth() .padding(horizontal = 12.dp, vertical = 4.dp), - onClick = { }, + onClick = { + viewModel.startWorkflow() + }, shape = RoundedCornerShape(6.dp), enabled = enabledOutcomes, colors = ButtonDefaults.buttonColors( From 338e0be726cf4fb56ddee6924aae6d4a16a45bc5 Mon Sep 17 00:00:00 2001 From: Amanpal Singh <87360222+aman-alfresco@users.noreply.github.com> Date: Tue, 19 Mar 2024 10:38:35 +0530 Subject: [PATCH 2/7] code optimized --- .../com/alfresco/content/data/TaskRepository.kt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/data/src/main/kotlin/com/alfresco/content/data/TaskRepository.kt b/data/src/main/kotlin/com/alfresco/content/data/TaskRepository.kt index 56b14a759..1277bfa8e 100644 --- a/data/src/main/kotlin/com/alfresco/content/data/TaskRepository.kt +++ b/data/src/main/kotlin/com/alfresco/content/data/TaskRepository.kt @@ -410,12 +410,12 @@ class TaskRepository { private fun getUserOrGroup(userGroupInfo: UserGroupDetails?): Map { return if (userGroupInfo?.isGroup == true) { mapOf( - "id" to userGroupInfo?.id, - "name" to userGroupInfo?.name, - "externalId" to userGroupInfo?.externalId, - "status" to userGroupInfo?.status, - "parentGroupId" to userGroupInfo?.parentGroupId, - "groups" to userGroupInfo?.groups, + "id" to userGroupInfo.id, + "name" to userGroupInfo.name, + "externalId" to userGroupInfo.externalId, + "status" to userGroupInfo.status, + "parentGroupId" to userGroupInfo.parentGroupId, + "groups" to userGroupInfo.groups, ) } else { mapOf( From c6b9238659cba24c392df7328243556e9b90be58 Mon Sep 17 00:00:00 2001 From: Amanpal Singh <87360222+aman-alfresco@users.noreply.github.com> Date: Tue, 19 Mar 2024 15:51:45 +0530 Subject: [PATCH 3/7] added UI for attachments --- browse/src/main/res/values-de/strings.xml | 1 - browse/src/main/res/values-es/strings.xml | 1 - browse/src/main/res/values-fr/strings.xml | 1 - browse/src/main/res/values-it/strings.xml | 1 - browse/src/main/res/values-nl/strings.xml | 1 - browse/src/main/res/values/strings.xml | 1 - common/src/main/res/values-de/strings.xml | 1 + common/src/main/res/values-es/strings.xml | 1 + common/src/main/res/values-fr/strings.xml | 1 + common/src/main/res/values-it/strings.xml | 1 + common/src/main/res/values-nl/strings.xml | 1 + common/src/main/res/values/strings.xml | 1 + .../content/data/payloads/FieldsData.kt | 1 + .../process/ui/components/AttachFilesField.kt | 99 +++++++++++++++++++ .../ui/components/FormScrollContent.kt | 4 + process-app/src/main/res/values/strings.xml | 1 + 16 files changed, 111 insertions(+), 6 deletions(-) create mode 100644 process-app/src/main/kotlin/com/alfresco/content/process/ui/components/AttachFilesField.kt diff --git a/browse/src/main/res/values-de/strings.xml b/browse/src/main/res/values-de/strings.xml index 972b3bc62..9cad36de9 100755 --- a/browse/src/main/res/values-de/strings.xml +++ b/browse/src/main/res/values-de/strings.xml @@ -63,7 +63,6 @@ Alle anzeigen %d Kommentare Angehängte Dateien - %d Anhänge Keine angehängten Dateien Kein Fälligkeitsdatum Angehängte Dateien diff --git a/browse/src/main/res/values-es/strings.xml b/browse/src/main/res/values-es/strings.xml index c15d3a30c..a548aeae0 100755 --- a/browse/src/main/res/values-es/strings.xml +++ b/browse/src/main/res/values-es/strings.xml @@ -63,7 +63,6 @@ Ver todo %d comentarios Ficheros adjuntos - %d adjuntos No hay ficheros adjuntos Sin fecha de vencimiento Ficheros adjuntos diff --git a/browse/src/main/res/values-fr/strings.xml b/browse/src/main/res/values-fr/strings.xml index 2f0ef7b63..8aeef5de7 100755 --- a/browse/src/main/res/values-fr/strings.xml +++ b/browse/src/main/res/values-fr/strings.xml @@ -63,7 +63,6 @@ Afficher tout %d commentaires Fichiers joints - %d pièces jointes Aucun fichier joint Aucune date d\'échéance Fichiers joints diff --git a/browse/src/main/res/values-it/strings.xml b/browse/src/main/res/values-it/strings.xml index b6f7827c3..df385a88f 100755 --- a/browse/src/main/res/values-it/strings.xml +++ b/browse/src/main/res/values-it/strings.xml @@ -63,7 +63,6 @@ Visualizza tutto %d commenti File allegati - %d allegati Nessun file allegato Nessuna scadenza File allegati diff --git a/browse/src/main/res/values-nl/strings.xml b/browse/src/main/res/values-nl/strings.xml index 575f51886..52b44b3fa 100755 --- a/browse/src/main/res/values-nl/strings.xml +++ b/browse/src/main/res/values-nl/strings.xml @@ -63,7 +63,6 @@ Alle weergeven %d opmerkingen Bijgevoegde bestanden - %d bijlagen Geen bijgevoegde bestanden Geen vervaldatum Bijgevoegde bestanden diff --git a/browse/src/main/res/values/strings.xml b/browse/src/main/res/values/strings.xml index 5a2a21b4c..2b473ebca 100644 --- a/browse/src/main/res/values/strings.xml +++ b/browse/src/main/res/values/strings.xml @@ -63,7 +63,6 @@ View all %d comments Attached files - %d attachments No Attached Files No due date Attached files diff --git a/common/src/main/res/values-de/strings.xml b/common/src/main/res/values-de/strings.xml index 7eb4c7b51..a138f0ee1 100755 --- a/common/src/main/res/values-de/strings.xml +++ b/common/src/main/res/values-de/strings.xml @@ -30,4 +30,5 @@ %d Ausgewählt Bitte überprüfen Sie Ihre Internetverbindung und starten anschließend den Vorgang erneut. ...Alle anzeigen + %d Anhänge diff --git a/common/src/main/res/values-es/strings.xml b/common/src/main/res/values-es/strings.xml index f9b91786b..71729d164 100755 --- a/common/src/main/res/values-es/strings.xml +++ b/common/src/main/res/values-es/strings.xml @@ -30,4 +30,5 @@ %d Seleccionado Verifique su conexión a Internet y vuelva a intentarlo. ...Ver todo + %d adjuntos diff --git a/common/src/main/res/values-fr/strings.xml b/common/src/main/res/values-fr/strings.xml index 843b09a56..b2d550618 100755 --- a/common/src/main/res/values-fr/strings.xml +++ b/common/src/main/res/values-fr/strings.xml @@ -30,4 +30,5 @@ %d Sélectionné Veuillez vérifier votre connexion Internet et réessayer. …Afficher tout + %d pièces jointes diff --git a/common/src/main/res/values-it/strings.xml b/common/src/main/res/values-it/strings.xml index f4f4c7881..9f2e431fd 100755 --- a/common/src/main/res/values-it/strings.xml +++ b/common/src/main/res/values-it/strings.xml @@ -30,4 +30,5 @@ %d Selezionato Controlla la connessione Internet e riprova. ...Visualizza tutto + %d allegati diff --git a/common/src/main/res/values-nl/strings.xml b/common/src/main/res/values-nl/strings.xml index b1120ac49..bf519b1a6 100755 --- a/common/src/main/res/values-nl/strings.xml +++ b/common/src/main/res/values-nl/strings.xml @@ -30,4 +30,5 @@ %d Geselecteerd Controleer uw internetverbinding en probeer het opnieuw. ...Alle weergeven + %d bijlagen diff --git a/common/src/main/res/values/strings.xml b/common/src/main/res/values/strings.xml index ddba320d3..6ee8f87a5 100644 --- a/common/src/main/res/values/strings.xml +++ b/common/src/main/res/values/strings.xml @@ -31,4 +31,5 @@ Please check your internet connection and Try again. …View all Workflow + %d attachments diff --git a/data/src/main/kotlin/com/alfresco/content/data/payloads/FieldsData.kt b/data/src/main/kotlin/com/alfresco/content/data/payloads/FieldsData.kt index 667e7e62a..960f8dfe2 100644 --- a/data/src/main/kotlin/com/alfresco/content/data/payloads/FieldsData.kt +++ b/data/src/main/kotlin/com/alfresco/content/data/payloads/FieldsData.kt @@ -88,6 +88,7 @@ enum class FieldType { PEOPLE, FUNCTIONAL_GROUP, HYPERLINK, + UPLOAD, ; fun value() = name.lowercase() diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/AttachFilesField.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/AttachFilesField.kt new file mode 100644 index 000000000..174ade4e6 --- /dev/null +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/AttachFilesField.kt @@ -0,0 +1,99 @@ +package com.alfresco.content.process.ui.components + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Attachment +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +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.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.text.withStyle +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.alfresco.content.data.Entry +import com.alfresco.content.data.ProcessEntry +import com.alfresco.content.data.payloads.FieldsData +import com.alfresco.content.process.R +import com.alfresco.content.process.ui.theme.AlfrescoBlue300 +import com.alfresco.content.process.ui.theme.AlfrescoError + +@Composable +fun AttachFilesField( + contents: List = emptyList(), + onContentUpdate: (List) -> Unit = { }, + fieldsData: FieldsData = FieldsData(), + processEntry: ProcessEntry = ProcessEntry(), +) { + val labelWithAsterisk = buildAnnotatedString { + append(fieldsData.name) + if (fieldsData.required) { + withStyle(style = SpanStyle(color = AlfrescoError)) { + append(" *") // Adding a red asterisk for mandatory fields + } + } + } + + val contentValue = if (contents.isEmpty()) { + stringResource(id = R.string.no_attachments) + } else { + stringResource(id = R.string.text_multiple_attachment, contents.size) + } + + val context = LocalContext.current + Column( + modifier = Modifier + .fillMaxSize() + .padding(top = 16.dp, bottom = 0.dp, start = 16.dp, end = 16.dp), + ) { + Row( + horizontalArrangement = Arrangement.SpaceBetween, + modifier = Modifier.fillMaxWidth(), + ) { + Text( + text = labelWithAsterisk, + modifier = Modifier + .padding(end = 4.dp) + .align(alignment = Alignment.CenterVertically), + ) + + IconButton(onClick = { + }) { + Icon( + imageVector = Icons.Default.Attachment, + tint = AlfrescoBlue300, + contentDescription = "", + ) + } + } + Text( + text = contentValue, + style = TextStyle( + color = MaterialTheme.colorScheme.onSurfaceVariant, + fontSize = 8.sp, + ), + modifier = Modifier + .padding(end = 4.dp) + .align(alignment = Alignment.Start), + ) + } +} + +@Preview +@Composable +fun AttachFilesFieldPreview() { + AttachFilesField() +} diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/FormScrollContent.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/FormScrollContent.kt index e8bb74690..03473b6cf 100644 --- a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/FormScrollContent.kt +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/FormScrollContent.kt @@ -131,5 +131,9 @@ fun FormScrollContent(field: FieldsData, viewModel: FormViewModel, state: FormVi FieldType.HYPERLINK.value() -> { HyperLinkField(field) } + + FieldType.UPLOAD.value() -> { + AttachFilesField(fieldsData = field) + } } } diff --git a/process-app/src/main/res/values/strings.xml b/process-app/src/main/res/values/strings.xml index 4f64f389d..38c7c3e99 100644 --- a/process-app/src/main/res/values/strings.xml +++ b/process-app/src/main/res/values/strings.xml @@ -9,4 +9,5 @@ This is a required field. Actions Process Actions Button + No Attachments From 808c6fc4e04a45d092d33ef7837425bd702f3a53 Mon Sep 17 00:00:00 2001 From: Amanpal Singh <87360222+aman-alfresco@users.noreply.github.com> Date: Thu, 21 Mar 2024 14:14:23 +0530 Subject: [PATCH 4/7] added attach files component --- .../actions/sheet/ProcessDefinitionsSheet.kt | 2 +- .../ProcessDetailViewModelExtension.kt | 2 +- .../processes/list/ProcessesViewModel.kt | 2 +- .../detail/TaskDetailViewModelExtension.kt | 2 +- browse/src/main/res/values-de/strings.xml | 4 - browse/src/main/res/values-es/strings.xml | 4 - browse/src/main/res/values-fr/strings.xml | 4 - browse/src/main/res/values-it/strings.xml | 4 - browse/src/main/res/values-nl/strings.xml | 4 - browse/src/main/res/values/strings.xml | 4 - .../src/main/res/drawable/ic_add_fab.xml | 0 common/src/main/res/values-de/strings.xml | 4 + common/src/main/res/values-es/strings.xml | 4 + common/src/main/res/values-fr/strings.xml | 4 + common/src/main/res/values-it/strings.xml | 4 + common/src/main/res/values-nl/strings.xml | 4 + common/src/main/res/values/strings.xml | 4 + gradle/libs.versions.toml | 1 + process-app/build.gradle | 18 ++- process-app/src/main/AndroidManifest.xml | 2 +- .../content/process/NavigationComponent.kt | 25 ---- .../content/process/ProcessFormActivity.kt | 68 --------- .../content/process/ui/ProcessFormActivity.kt | 37 +++++ .../content/process/ui/ProcessFormFragment.kt | 36 ----- .../process/ui/components/AttachFilesField.kt | 15 +- .../process/ui/components/ComposeTopBar.kt | 2 +- .../ui/components/FloatingActionButton.kt | 2 +- .../ui/components/FormViewModelExtension.kt | 4 +- .../content/process/ui/components/Outcomes.kt | 3 +- .../ui/{ => composeviews}/FormDetailScreen.kt | 14 +- .../FormScreen.kt | 12 +- .../FormScrollContent.kt | 26 +++- .../ui/composeviews/NavigationComponent.kt | 78 +++++++++++ .../ui/composeviews/ProcessAttachedFiles.kt | 30 ++++ .../process/ui/epoxy/ListViewAttachmentRow.kt | 107 ++++++++++++++ .../ui/fragments/BaseDetailFragment.kt | 99 +++++++++++++ .../{ => ui/fragments}/FormViewModel.kt | 79 ++++++----- .../process/ui/fragments/FormViewState.kt | 93 +++++++++++++ .../fragments/ProcessAttachedFilesFragment.kt | 130 ++++++++++++++++++ .../ui/{ => models}/UpdateProcessData.kt | 2 +- .../res/layout/fragment_attached_files.xml | 80 +++++++++++ .../res/layout/fragment_container_view.xml | 8 ++ .../res/layout/view_list_attachment_row.xml | 78 +++++++++++ process-app/src/main/res/values/dimens.xml | 5 + 44 files changed, 890 insertions(+), 220 deletions(-) rename {browse => common}/src/main/res/drawable/ic_add_fab.xml (100%) delete mode 100644 process-app/src/main/kotlin/com/alfresco/content/process/NavigationComponent.kt delete mode 100644 process-app/src/main/kotlin/com/alfresco/content/process/ProcessFormActivity.kt create mode 100644 process-app/src/main/kotlin/com/alfresco/content/process/ui/ProcessFormActivity.kt delete mode 100644 process-app/src/main/kotlin/com/alfresco/content/process/ui/ProcessFormFragment.kt rename process-app/src/main/kotlin/com/alfresco/content/process/ui/{ => composeviews}/FormDetailScreen.kt (85%) rename process-app/src/main/kotlin/com/alfresco/content/process/ui/{components => composeviews}/FormScreen.kt (90%) rename process-app/src/main/kotlin/com/alfresco/content/process/ui/{components => composeviews}/FormScrollContent.kt (81%) create mode 100644 process-app/src/main/kotlin/com/alfresco/content/process/ui/composeviews/NavigationComponent.kt create mode 100644 process-app/src/main/kotlin/com/alfresco/content/process/ui/composeviews/ProcessAttachedFiles.kt create mode 100644 process-app/src/main/kotlin/com/alfresco/content/process/ui/epoxy/ListViewAttachmentRow.kt create mode 100644 process-app/src/main/kotlin/com/alfresco/content/process/ui/fragments/BaseDetailFragment.kt rename process-app/src/main/kotlin/com/alfresco/content/process/{ => ui/fragments}/FormViewModel.kt (75%) create mode 100644 process-app/src/main/kotlin/com/alfresco/content/process/ui/fragments/FormViewState.kt create mode 100644 process-app/src/main/kotlin/com/alfresco/content/process/ui/fragments/ProcessAttachedFilesFragment.kt rename process-app/src/main/kotlin/com/alfresco/content/process/ui/{ => models}/UpdateProcessData.kt (68%) create mode 100644 process-app/src/main/res/layout/fragment_attached_files.xml create mode 100644 process-app/src/main/res/layout/fragment_container_view.xml create mode 100644 process-app/src/main/res/layout/view_list_attachment_row.xml create mode 100644 process-app/src/main/res/values/dimens.xml diff --git a/actions/src/main/kotlin/com/alfresco/content/actions/sheet/ProcessDefinitionsSheet.kt b/actions/src/main/kotlin/com/alfresco/content/actions/sheet/ProcessDefinitionsSheet.kt index cd9682bbc..5f37bf4e9 100644 --- a/actions/src/main/kotlin/com/alfresco/content/actions/sheet/ProcessDefinitionsSheet.kt +++ b/actions/src/main/kotlin/com/alfresco/content/actions/sheet/ProcessDefinitionsSheet.kt @@ -83,7 +83,7 @@ class ProcessDefinitionsSheet : BottomSheetDialogFragment(), MavericksView { val intent = Intent( requireActivity(), - Class.forName("com.alfresco.content.process.ProcessFormActivity"), + Class.forName("com.alfresco.content.process.ui.ProcessFormActivity"), ) intent.putExtra(Mavericks.KEY_ARG, processEntry) startActivity(intent) diff --git a/browse/src/main/kotlin/com/alfresco/content/browse/processes/details/ProcessDetailViewModelExtension.kt b/browse/src/main/kotlin/com/alfresco/content/browse/processes/details/ProcessDetailViewModelExtension.kt index ae06a25eb..1c0cb2612 100644 --- a/browse/src/main/kotlin/com/alfresco/content/browse/processes/details/ProcessDetailViewModelExtension.kt +++ b/browse/src/main/kotlin/com/alfresco/content/browse/processes/details/ProcessDetailViewModelExtension.kt @@ -1,7 +1,7 @@ package com.alfresco.content.browse.processes.details import com.alfresco.content.browse.tasks.list.UpdateTasksData -import com.alfresco.content.process.ui.UpdateProcessData +import com.alfresco.content.process.ui.models.UpdateProcessData import com.alfresco.events.EventBus import kotlinx.coroutines.launch diff --git a/browse/src/main/kotlin/com/alfresco/content/browse/processes/list/ProcessesViewModel.kt b/browse/src/main/kotlin/com/alfresco/content/browse/processes/list/ProcessesViewModel.kt index 72a4d7d51..c4474e037 100644 --- a/browse/src/main/kotlin/com/alfresco/content/browse/processes/list/ProcessesViewModel.kt +++ b/browse/src/main/kotlin/com/alfresco/content/browse/processes/list/ProcessesViewModel.kt @@ -13,7 +13,7 @@ import com.alfresco.content.data.payloads.TaskProcessFiltersPayload import com.alfresco.content.getLocalizedName import com.alfresco.content.listview.processes.ProcessListViewModel import com.alfresco.content.listview.processes.ProcessListViewState -import com.alfresco.content.process.ui.UpdateProcessData +import com.alfresco.content.process.ui.models.UpdateProcessData import com.alfresco.coroutines.asFlow import com.alfresco.events.on import kotlinx.coroutines.launch diff --git a/browse/src/main/kotlin/com/alfresco/content/browse/tasks/detail/TaskDetailViewModelExtension.kt b/browse/src/main/kotlin/com/alfresco/content/browse/tasks/detail/TaskDetailViewModelExtension.kt index e52d784d9..803ee7516 100644 --- a/browse/src/main/kotlin/com/alfresco/content/browse/tasks/detail/TaskDetailViewModelExtension.kt +++ b/browse/src/main/kotlin/com/alfresco/content/browse/tasks/detail/TaskDetailViewModelExtension.kt @@ -5,7 +5,7 @@ import com.alfresco.content.browse.tasks.list.UpdateTasksData import com.alfresco.content.data.Entry import com.alfresco.content.data.OfflineRepository import com.alfresco.content.data.UserGroupDetails -import com.alfresco.content.process.ui.UpdateProcessData +import com.alfresco.content.process.ui.models.UpdateProcessData import com.alfresco.events.EventBus import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch diff --git a/browse/src/main/res/values-de/strings.xml b/browse/src/main/res/values-de/strings.xml index 9cad36de9..8727ba111 100755 --- a/browse/src/main/res/values-de/strings.xml +++ b/browse/src/main/res/values-de/strings.xml @@ -46,7 +46,6 @@ Account Symbol für Fälligkeitsdatum Symbol für Benutzerprofil - Symbol für Datei Symbol für Priorität Zugewiesenes Symbol Symbol für Status @@ -65,7 +64,6 @@ Angehängte Dateien Keine angehängten Dateien Kein Fälligkeitsdatum - Angehängte Dateien Abgeschlossen Aufgabe abschließen Sind Sie sicher, dass Sie diese Aufgabe abschließen wollen? Sie werden keine Änderungen mehr vornehmen können. @@ -86,9 +84,7 @@ Aufgabe erstellen Verwerfen Sollen die Änderungen verworfen werden? - Symbol \'Anhang löschen\' Eine Datei löschen? - Anhänge hinzufügen Symbol \'Anhang hinzufügen\' Sind Sie sicher, dass Sie die Aufgabe abschließen wollen? Nach Abschluss der Aufgabe können einige Dateien nicht hochgeladen werden und es können keine Änderungen vorgenommen werden. diff --git a/browse/src/main/res/values-es/strings.xml b/browse/src/main/res/values-es/strings.xml index a548aeae0..839911077 100755 --- a/browse/src/main/res/values-es/strings.xml +++ b/browse/src/main/res/values-es/strings.xml @@ -46,7 +46,6 @@ Cuenta Icono de fecha de vencimiento Icono de perfil de usuario - Icono de fichero Icono de prioridad Icono de usuario asignado Icono de estado @@ -65,7 +64,6 @@ Ficheros adjuntos No hay ficheros adjuntos Sin fecha de vencimiento - Ficheros adjuntos Por completar Completar tarea ¿Está seguro de que desea completar esta tarea? Ya no podrá realizar ningún cambio. @@ -87,9 +85,7 @@ Crear tarea Descartar ¿Desea descartar los cambios? - Icono de eliminación de adjuntos ¿Eliminar un fichero? - Añadir adjuntos Añadir icono adjunto ¿Está seguro de que quiere completar la tarea? Una vez completada, algunos ficheros no se pudieron cargar y no se pueden realizar cambios. diff --git a/browse/src/main/res/values-fr/strings.xml b/browse/src/main/res/values-fr/strings.xml index 8aeef5de7..7557175cf 100755 --- a/browse/src/main/res/values-fr/strings.xml +++ b/browse/src/main/res/values-fr/strings.xml @@ -46,7 +46,6 @@ Compte Icône Date d\'échéance Icône du profil d\'utilisateur - Icône de fichier Icône de priorité Icône Assigné Icône du statut @@ -65,7 +64,6 @@ Fichiers joints Aucun fichier joint Aucune date d\'échéance - Fichiers joints Terminé Terminer la tâche Voulez-vous vraiment terminer cette tâche ? Vous ne pourrez plus faire de modifications. @@ -86,9 +84,7 @@ Créer une tâche Ignorer Voulez-vous ignorer les modifications ? - Icône Supprimer la pièce jointe Supprimer un fichier ? - Ajouter des pièces jointes Icône Ajouter une pièce jointe Voulez-vous vraiment terminer la tâche ? Une fois terminée, certains fichiers ne pourront plus être importés et aucun changement ne pourra être effectué. diff --git a/browse/src/main/res/values-it/strings.xml b/browse/src/main/res/values-it/strings.xml index df385a88f..beb5d6bc8 100755 --- a/browse/src/main/res/values-it/strings.xml +++ b/browse/src/main/res/values-it/strings.xml @@ -46,7 +46,6 @@ Account Icona scadenza Icona profilo utente - Icona file Icona priorità Icona assegnazione Icona stato @@ -65,7 +64,6 @@ File allegati Nessun file allegato Nessuna scadenza - File allegati Completato Completa compito Vuoi completare il compito? Non potrai più apportare modifiche. @@ -86,9 +84,7 @@ Crea compito Ignora Vuoi ignorare le modifiche? - Icona Elimina allegato Vuoi eliminare un file? - Aggiungi allegati Icona Aggiungi allegati Vuoi completare il compito? Una volta completato, non sarà possibile caricare alcuni file né apportare modifiche. diff --git a/browse/src/main/res/values-nl/strings.xml b/browse/src/main/res/values-nl/strings.xml index 52b44b3fa..0b87d6c7d 100755 --- a/browse/src/main/res/values-nl/strings.xml +++ b/browse/src/main/res/values-nl/strings.xml @@ -46,7 +46,6 @@ Account Pictogram Vervaldatum Pictogram Gebruikersprofiel - Pictogram Bestand Pictogram Prioriteit Pictogram Toegewezen Pictogram Status @@ -65,7 +64,6 @@ Bijgevoegde bestanden Geen bijgevoegde bestanden Geen vervaldatum - Bijgevoegde bestanden Voltooien Taak voltooien Weet u zeker dat u de taak wilt voltooien? U kunt geen wijzigingen meer aanbrengen. @@ -86,9 +84,7 @@ Taak creëren Negeren Wilt u de wijzigingen negeren? - Pictogram Bijlage verwijderen Bestand verwijderen? - Bijlagen toevoegen Pictogram Bijlage toevoegen Weet u zeker dat u de taak wilt voltooien? Nadat de taak is voltooid, kunnen sommige bestanden niet worden geüpload en kunnen geen wijzigingen worden aangebracht. diff --git a/browse/src/main/res/values/strings.xml b/browse/src/main/res/values/strings.xml index 2b473ebca..26f5c7220 100644 --- a/browse/src/main/res/values/strings.xml +++ b/browse/src/main/res/values/strings.xml @@ -46,7 +46,6 @@ Account Due date icon User profile icon - File icon Priority icon Assigned icon Status icon @@ -65,7 +64,6 @@ Attached files No Attached Files No due date - Attached files Complete Complete Task Are you sure you want to complete this task? You will no longer be able to make any changes. @@ -86,9 +84,7 @@ Create task Discard Do you want to discard the changes? - Icon delete attachment Delete a file? - Add attachments Add attachment icon Are you sure you want to complete the task? Once completed, some files could not be uploaded and no changes can be made. diff --git a/browse/src/main/res/drawable/ic_add_fab.xml b/common/src/main/res/drawable/ic_add_fab.xml similarity index 100% rename from browse/src/main/res/drawable/ic_add_fab.xml rename to common/src/main/res/drawable/ic_add_fab.xml diff --git a/common/src/main/res/values-de/strings.xml b/common/src/main/res/values-de/strings.xml index a138f0ee1..e6db325be 100755 --- a/common/src/main/res/values-de/strings.xml +++ b/common/src/main/res/values-de/strings.xml @@ -31,4 +31,8 @@ Bitte überprüfen Sie Ihre Internetverbindung und starten anschließend den Vorgang erneut. ...Alle anzeigen %d Anhänge + Anhänge hinzufügen + Angehängte Dateien + Symbol für Datei + Symbol \'Anhang löschen\' diff --git a/common/src/main/res/values-es/strings.xml b/common/src/main/res/values-es/strings.xml index 71729d164..89672eb0f 100755 --- a/common/src/main/res/values-es/strings.xml +++ b/common/src/main/res/values-es/strings.xml @@ -31,4 +31,8 @@ Verifique su conexión a Internet y vuelva a intentarlo. ...Ver todo %d adjuntos + Añadir adjuntos + Ficheros adjuntos + Icono de fichero + Icono de eliminación de adjuntos diff --git a/common/src/main/res/values-fr/strings.xml b/common/src/main/res/values-fr/strings.xml index b2d550618..cbba780df 100755 --- a/common/src/main/res/values-fr/strings.xml +++ b/common/src/main/res/values-fr/strings.xml @@ -31,4 +31,8 @@ Veuillez vérifier votre connexion Internet et réessayer. …Afficher tout %d pièces jointes + Ajouter des pièces jointes + Fichiers joints + Icône de fichier + Icône Supprimer la pièce jointe diff --git a/common/src/main/res/values-it/strings.xml b/common/src/main/res/values-it/strings.xml index 9f2e431fd..4d281964e 100755 --- a/common/src/main/res/values-it/strings.xml +++ b/common/src/main/res/values-it/strings.xml @@ -31,4 +31,8 @@ Controlla la connessione Internet e riprova. ...Visualizza tutto %d allegati + Aggiungi allegati + File allegati + Icona file + Icona Elimina allegato diff --git a/common/src/main/res/values-nl/strings.xml b/common/src/main/res/values-nl/strings.xml index bf519b1a6..baab4753c 100755 --- a/common/src/main/res/values-nl/strings.xml +++ b/common/src/main/res/values-nl/strings.xml @@ -31,4 +31,8 @@ Controleer uw internetverbinding en probeer het opnieuw. ...Alle weergeven %d bijlagen + Bijlagen toevoegen + Bijgevoegde bestanden + Pictogram Bestand + Pictogram Bijlage verwijderen diff --git a/common/src/main/res/values/strings.xml b/common/src/main/res/values/strings.xml index 6ee8f87a5..c165c6621 100644 --- a/common/src/main/res/values/strings.xml +++ b/common/src/main/res/values/strings.xml @@ -32,4 +32,8 @@ …View all Workflow %d attachments + Add attachments + Attached files + File icon + Icon delete attachment diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 239643921..066fff2df 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -128,6 +128,7 @@ ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" } ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" } material3 = { group = "androidx.compose.material3", name = "material3" } androidx-compose-material-iconsExtended = { module = "androidx.compose.material:material-icons-extended" } +ui-compose-viewbinding = "androidx.compose.ui:ui-viewbinding:1.6.3" navigation-compose = "androidx.navigation:navigation-compose:2.7.6" compose-runtime = "androidx.compose.runtime:runtime:1.5.4" diff --git a/process-app/build.gradle b/process-app/build.gradle index e376b6bf8..ea1707bfa 100644 --- a/process-app/build.gradle +++ b/process-app/build.gradle @@ -1,6 +1,7 @@ plugins { id 'com.android.library' id 'org.jetbrains.kotlin.android' + id 'kotlin-kapt' } android { @@ -29,7 +30,8 @@ android { } buildFeatures { - compose = true + compose true + viewBinding true } composeOptions { @@ -48,8 +50,15 @@ dependencies { implementation project(':common') implementation project(':actions') implementation project(':data') + implementation project(':listview') implementation project(':component') + implementation project(':viewer-common') + implementation project(':viewer-image') + implementation project(':viewer-media') + implementation project(':viewer-pdf') + implementation project(':viewer-text') implementation project(':viewer') + implementation project(':mimetype') implementation libs.androidx.core implementation libs.androidx.appcompat @@ -59,6 +68,7 @@ dependencies { implementation libs.ui implementation libs.activity.compose implementation libs.ui.graphics + implementation libs.ui.compose.viewbinding implementation libs.ui.tooling.preview implementation libs.material3 @@ -67,4 +77,10 @@ dependencies { implementation libs.androidx.compose.material.iconsExtended debugImplementation libs.androidx.ui.tooling + + implementation libs.androidx.swiperefreshlayout + implementation libs.mavericks + implementation libs.epoxy.core + kapt libs.epoxy.processor + } diff --git a/process-app/src/main/AndroidManifest.xml b/process-app/src/main/AndroidManifest.xml index 577f4d8ba..a1c319b56 100644 --- a/process-app/src/main/AndroidManifest.xml +++ b/process-app/src/main/AndroidManifest.xml @@ -3,7 +3,7 @@ diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/NavigationComponent.kt b/process-app/src/main/kotlin/com/alfresco/content/process/NavigationComponent.kt deleted file mode 100644 index a1e59b333..000000000 --- a/process-app/src/main/kotlin/com/alfresco/content/process/NavigationComponent.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.alfresco.content.process - -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.material3.Surface -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.navigation.compose.NavHost -import androidx.navigation.compose.composable -import androidx.navigation.compose.rememberNavController -import com.alfresco.content.process.ui.components.FormScreen - -@Composable -fun NavigationComponent() { - val navController = rememberNavController() - - Surface(modifier = Modifier.fillMaxSize()) { - NavHost(navController = navController, startDestination = "first_screen") { - composable("first_screen") { - // Replace with the content of your first fragment - FormScreen(navController) - } - // Add more composable entries for other fragments in your navigation graph - } - } -} diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ProcessFormActivity.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ProcessFormActivity.kt deleted file mode 100644 index 622dfc8ac..000000000 --- a/process-app/src/main/kotlin/com/alfresco/content/process/ProcessFormActivity.kt +++ /dev/null @@ -1,68 +0,0 @@ -package com.alfresco.content.process - -import android.os.Bundle -import android.view.ViewGroup -import androidx.activity.compose.setContent -import androidx.appcompat.app.AppCompatActivity -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Surface -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.tooling.preview.Preview -import androidx.fragment.app.FragmentContainerView -import com.alfresco.content.process.ui.ProcessFormFragment -import com.alfresco.content.process.ui.theme.AlfrescoBaseTheme - -class ProcessFormActivity : AppCompatActivity() { - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContent { - AlfrescoBaseTheme { - Surface( - modifier = Modifier.fillMaxSize(), - color = MaterialTheme.colorScheme.background, - ) { - composeApp() - } - } - } - } - - private fun composeApp() { - val fragmentManager = supportFragmentManager - val containerId = resources.getIdentifier("frame_container", "id", packageName) - - // Check if the fragment is already added - - // Create FragmentContainerView and add it to the activity - val fragmentContainer = FragmentContainerView(this).apply { - id = containerId - layoutParams = ViewGroup.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT, - ) - } - setContentView(fragmentContainer) - - fragmentManager - .beginTransaction() - .replace( - fragmentContainer.id, - ProcessFormFragment().apply { - // Set your data using intent extras - arguments = intent.extras - }, - "firstFragment", - ) - .commit() - } -} - -@Preview(showBackground = true) -@Composable -fun GreetingPreview() { - AlfrescoBaseTheme { - NavigationComponent() - } -} diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/ProcessFormActivity.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/ProcessFormActivity.kt new file mode 100644 index 000000000..d0049972b --- /dev/null +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/ProcessFormActivity.kt @@ -0,0 +1,37 @@ +package com.alfresco.content.process.ui + +import android.os.Bundle +import androidx.activity.compose.setContent +import androidx.appcompat.app.AppCompatActivity +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import com.alfresco.content.process.ui.composeviews.NavigationComponent +import com.alfresco.content.process.ui.theme.AlfrescoBaseTheme + +class ProcessFormActivity : AppCompatActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContent { + AlfrescoBaseTheme { + Surface( + modifier = Modifier.fillMaxSize(), + color = MaterialTheme.colorScheme.background, + ) { + NavigationComponent() + } + } + } + } +} + +@Preview(showBackground = true) +@Composable +fun GreetingPreview() { + AlfrescoBaseTheme { + NavigationComponent() + } +} diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/ProcessFormFragment.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/ProcessFormFragment.kt deleted file mode 100644 index a048b15f7..000000000 --- a/process-app/src/main/kotlin/com/alfresco/content/process/ui/ProcessFormFragment.kt +++ /dev/null @@ -1,36 +0,0 @@ -package com.alfresco.content.process.ui - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.ArrowBack -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.runtime.Composable -import androidx.compose.ui.platform.ComposeView -import androidx.fragment.app.Fragment -import com.alfresco.content.process.NavigationComponent -import com.alfresco.content.process.ui.theme.AlfrescoBaseTheme - -class ProcessFormFragment : Fragment() { - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { - return ComposeView(requireContext()).apply { - layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT) - setContent { - AlfrescoBaseTheme { - NavigationComponent() - } - } - } - } -} - -@Composable -fun BackButton(onClick: () -> Unit) { - IconButton(onClick = onClick) { - Icon(imageVector = Icons.Default.ArrowBack, contentDescription = "Back") - } -} diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/AttachFilesField.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/AttachFilesField.kt index 174ade4e6..26285c200 100644 --- a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/AttachFilesField.kt +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/AttachFilesField.kt @@ -24,19 +24,19 @@ import androidx.compose.ui.text.withStyle import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import androidx.navigation.NavController import com.alfresco.content.data.Entry -import com.alfresco.content.data.ProcessEntry import com.alfresco.content.data.payloads.FieldsData import com.alfresco.content.process.R +import com.alfresco.content.process.ui.composeviews.NavigationScreen import com.alfresco.content.process.ui.theme.AlfrescoBlue300 import com.alfresco.content.process.ui.theme.AlfrescoError @Composable fun AttachFilesField( contents: List = emptyList(), - onContentUpdate: (List) -> Unit = { }, fieldsData: FieldsData = FieldsData(), - processEntry: ProcessEntry = ProcessEntry(), + navController: NavController, ) { val labelWithAsterisk = buildAnnotatedString { append(fieldsData.name) @@ -71,6 +71,9 @@ fun AttachFilesField( ) IconButton(onClick = { + navController.navigate( + NavigationScreen.ATTACHED_FILES_SCREEN.value(), + ) }) { Icon( imageVector = Icons.Default.Attachment, @@ -83,10 +86,10 @@ fun AttachFilesField( text = contentValue, style = TextStyle( color = MaterialTheme.colorScheme.onSurfaceVariant, - fontSize = 8.sp, + fontSize = 12.sp, ), modifier = Modifier - .padding(end = 4.dp) + .padding(start = 4.dp, top = 0.dp) .align(alignment = Alignment.Start), ) } @@ -95,5 +98,5 @@ fun AttachFilesField( @Preview @Composable fun AttachFilesFieldPreview() { - AttachFilesField() +// AttachFilesField() } diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/ComposeTopBar.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/ComposeTopBar.kt index 1ffc975d3..8a5da1fd5 100644 --- a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/ComposeTopBar.kt +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/ComposeTopBar.kt @@ -9,7 +9,7 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import com.alfresco.content.process.R -import com.alfresco.content.process.ui.BackButton +import com.alfresco.content.process.ui.composeviews.BackButton import com.alfresco.content.process.ui.theme.SeparateColorGrayLT @OptIn(ExperimentalMaterial3Api::class) diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/FloatingActionButton.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/FloatingActionButton.kt index a88fb4521..1f12c2668 100644 --- a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/FloatingActionButton.kt +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/FloatingActionButton.kt @@ -12,8 +12,8 @@ import androidx.compose.ui.res.stringResource import com.alfresco.content.component.ComponentBuilder import com.alfresco.content.component.ComponentData import com.alfresco.content.data.OptionsModel -import com.alfresco.content.process.FormViewModel import com.alfresco.content.process.R +import com.alfresco.content.process.ui.fragments.FormViewModel @Composable fun FloatingActionButton(outcomes: List, enabledOutcomes: Boolean, viewModel: FormViewModel) { diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/FormViewModelExtension.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/FormViewModelExtension.kt index f3e9dd7b2..c3b8ddd66 100644 --- a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/FormViewModelExtension.kt +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/FormViewModelExtension.kt @@ -1,7 +1,7 @@ package com.alfresco.content.process.ui.components -import com.alfresco.content.process.FormViewModel -import com.alfresco.content.process.ui.UpdateProcessData +import com.alfresco.content.process.ui.fragments.FormViewModel +import com.alfresco.content.process.ui.models.UpdateProcessData import com.alfresco.events.EventBus import kotlinx.coroutines.launch diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/Outcomes.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/Outcomes.kt index df57c8d83..b17561ec0 100644 --- a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/Outcomes.kt +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/Outcomes.kt @@ -10,9 +10,8 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp -import androidx.lifecycle.viewmodel.compose.viewModel import com.alfresco.content.data.OptionsModel -import com.alfresco.content.process.FormViewModel +import com.alfresco.content.process.ui.fragments.FormViewModel @Composable fun Outcomes(outcomes: List, enabledOutcomes: Boolean, viewModel: FormViewModel) { diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/FormDetailScreen.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/composeviews/FormDetailScreen.kt similarity index 85% rename from process-app/src/main/kotlin/com/alfresco/content/process/ui/FormDetailScreen.kt rename to process-app/src/main/kotlin/com/alfresco/content/process/ui/composeviews/FormDetailScreen.kt index c389e255b..192738bc3 100644 --- a/process-app/src/main/kotlin/com/alfresco/content/process/ui/FormDetailScreen.kt +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/composeviews/FormDetailScreen.kt @@ -1,4 +1,4 @@ -package com.alfresco.content.process.ui +package com.alfresco.content.process.ui.composeviews import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -18,16 +18,17 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.tooling.preview.Preview +import androidx.navigation.NavController +import androidx.navigation.compose.rememberNavController import com.alfresco.content.data.OptionsModel import com.alfresco.content.data.TaskRepository -import com.alfresco.content.process.FormViewModel -import com.alfresco.content.process.FormViewState -import com.alfresco.content.process.ui.components.FormScrollContent import com.alfresco.content.process.ui.components.Outcomes +import com.alfresco.content.process.ui.fragments.FormViewModel +import com.alfresco.content.process.ui.fragments.FormViewState @OptIn(ExperimentalComposeUiApi::class) @Composable -fun FormDetailScreen(state: FormViewState, viewModel: FormViewModel, outcomes: List) { +fun FormDetailScreen(state: FormViewState, viewModel: FormViewModel, outcomes: List, navController: NavController) { val keyboardController = LocalSoftwareKeyboardController.current val focusManager = LocalFocusManager.current @@ -57,7 +58,7 @@ fun FormDetailScreen(state: FormViewState, viewModel: FormViewModel, outcomes: L }, items = formList, ) { field -> - FormScrollContent(field, viewModel, state) + FormScrollContent(field, viewModel, state, navController) } } @@ -85,5 +86,6 @@ fun PreviewProcessDetailScreen() { TaskRepository(), ), emptyList(), + rememberNavController(), ) } diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/FormScreen.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/composeviews/FormScreen.kt similarity index 90% rename from process-app/src/main/kotlin/com/alfresco/content/process/ui/components/FormScreen.kt rename to process-app/src/main/kotlin/com/alfresco/content/process/ui/composeviews/FormScreen.kt index 28a72b104..e70223dd9 100644 --- a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/FormScreen.kt +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/composeviews/FormScreen.kt @@ -1,4 +1,4 @@ -package com.alfresco.content.process.ui.components +package com.alfresco.content.process.ui.composeviews import ComposeTopBar import android.app.Activity @@ -18,9 +18,11 @@ import com.airbnb.mvrx.Success import com.airbnb.mvrx.compose.collectAsState import com.airbnb.mvrx.compose.mavericksActivityViewModel import com.alfresco.content.data.OptionsModel -import com.alfresco.content.process.FormViewModel import com.alfresco.content.process.R -import com.alfresco.content.process.ui.FormDetailScreen +import com.alfresco.content.process.ui.components.CustomLinearProgressIndicator +import com.alfresco.content.process.ui.components.FloatingActionButton +import com.alfresco.content.process.ui.components.updateProcessList +import com.alfresco.content.process.ui.fragments.FormViewModel @Composable fun FormScreen(navController: NavController) { @@ -63,7 +65,7 @@ fun FormScreen(navController: NavController) { if (state.requestStartForm is Loading) { CustomLinearProgressIndicator(padding) } - FormDetailScreen(state, viewModel, customOutcomes) + FormDetailScreen(state, viewModel, customOutcomes, navController) } } } @@ -86,7 +88,7 @@ fun FormScreen(navController: NavController) { if (state.requestStartForm is Loading || state.requestStartWorkflow is Loading) { CustomLinearProgressIndicator(padding) } - FormDetailScreen(state, viewModel, emptyList()) + FormDetailScreen(state, viewModel, emptyList(), navController) } } } diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/FormScrollContent.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/composeviews/FormScrollContent.kt similarity index 81% rename from process-app/src/main/kotlin/com/alfresco/content/process/ui/components/FormScrollContent.kt rename to process-app/src/main/kotlin/com/alfresco/content/process/ui/composeviews/FormScrollContent.kt index 03473b6cf..492f6a9cf 100644 --- a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/FormScrollContent.kt +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/composeviews/FormScrollContent.kt @@ -1,4 +1,4 @@ -package com.alfresco.content.process.ui.components +package com.alfresco.content.process.ui.composeviews import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -7,17 +7,29 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.res.stringResource +import androidx.navigation.NavController import com.alfresco.content.data.ProcessEntry import com.alfresco.content.data.UserGroupDetails import com.alfresco.content.data.payloads.FieldType import com.alfresco.content.data.payloads.FieldsData -import com.alfresco.content.process.FormViewModel -import com.alfresco.content.process.FormViewState import com.alfresco.content.process.R +import com.alfresco.content.process.ui.components.AmountInputField +import com.alfresco.content.process.ui.components.AttachFilesField +import com.alfresco.content.process.ui.components.CheckBoxField +import com.alfresco.content.process.ui.components.DateTimeField +import com.alfresco.content.process.ui.components.DropdownField +import com.alfresco.content.process.ui.components.HyperLinkField +import com.alfresco.content.process.ui.components.IntegerInputField +import com.alfresco.content.process.ui.components.MultiLineInputField +import com.alfresco.content.process.ui.components.PeopleField +import com.alfresco.content.process.ui.components.ReadOnlyField +import com.alfresco.content.process.ui.components.SingleLineInputField +import com.alfresco.content.process.ui.fragments.FormViewModel +import com.alfresco.content.process.ui.fragments.FormViewState @OptIn(ExperimentalComposeUiApi::class) @Composable -fun FormScrollContent(field: FieldsData, viewModel: FormViewModel, state: FormViewState) { +fun FormScrollContent(field: FieldsData, viewModel: FormViewModel, state: FormViewState, navController: NavController) { when (field.type) { FieldType.TEXT.value() -> { var textFieldValue by remember { mutableStateOf(field.value as? String ?: "") } @@ -133,7 +145,11 @@ fun FormScrollContent(field: FieldsData, viewModel: FormViewModel, state: FormVi } FieldType.UPLOAD.value() -> { - AttachFilesField(fieldsData = field) + AttachFilesField( + contents = state.listContents, + fieldsData = field, + navController = navController, + ) } } } diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/composeviews/NavigationComponent.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/composeviews/NavigationComponent.kt new file mode 100644 index 000000000..427d6c34e --- /dev/null +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/composeviews/NavigationComponent.kt @@ -0,0 +1,78 @@ +package com.alfresco.content.process.ui.composeviews + +import android.view.View +import android.view.ViewGroup +import androidx.appcompat.app.AppCompatActivity +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material3.Surface +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.viewinterop.AndroidViewBinding +import androidx.navigation.NavHostController +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.rememberNavController +import com.alfresco.content.process.R +import com.alfresco.content.process.databinding.FragmentContainerViewBinding +import com.alfresco.content.process.ui.fragments.ProcessAttachedFilesFragment + +@Composable +fun NavigationComponent() { + val navController = rememberNavController() + + Surface(modifier = Modifier.fillMaxSize()) { + NavHost(navController = navController, startDestination = NavigationScreen.FIRST_SCREEN.value()) { + composable(NavigationScreen.FIRST_SCREEN.value()) { + // Replace with the content of your first fragment + FormScreen(navController) + } + // Add more composable entries for other fragments in your navigation graph + composable(NavigationScreen.ATTACHED_FILES_SCREEN.value()) { + // Replace with the content of ProcessAttachedFilesFragment + ProcessAttachedFilesScreen(navController) + } + } + } +} + +@Composable +fun ProcessAttachedFilesScreen(navController: NavHostController) { + val context = LocalContext.current + AndroidViewBinding( + FragmentContainerViewBinding::inflate, + ) { + // Adjust layout properties + fragmentContainerView.layoutParams = ViewGroup.MarginLayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT, + ) + + val contextApp = (context as? AppCompatActivity) + + println(".ProcessAttachedFilesScreen $contextApp") + + // Adjust system UI visibility + contextApp?.window?.decorView?.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or + View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or + View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + + fragmentContainerView.setPadding( + fragmentContainerView.paddingLeft, + context.resources.getDimensionPixelSize(R.dimen.default_status_bar_height), + fragmentContainerView.paddingRight, + context.resources.getDimensionPixelSize(R.dimen.default_bottom_controller_height), + ) + + val myFragment = fragmentContainerView.getFragment() + // ... + } +} + +enum class NavigationScreen() { + FIRST_SCREEN, + ATTACHED_FILES_SCREEN, + ; + + fun value() = this.name.lowercase() +} diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/composeviews/ProcessAttachedFiles.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/composeviews/ProcessAttachedFiles.kt new file mode 100644 index 000000000..51b618076 --- /dev/null +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/composeviews/ProcessAttachedFiles.kt @@ -0,0 +1,30 @@ +package com.alfresco.content.process.ui.composeviews + +import android.view.LayoutInflater +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.viewinterop.AndroidView +import com.alfresco.content.process.R + +@Composable +fun ProcessAttachedFiles() { + AndroidView( + modifier = Modifier.fillMaxSize(), + factory = { context -> + // Inflate your XML layout here + LayoutInflater.from(context).inflate(R.layout.fragment_attached_files, null) + }, + ) +} + +@Composable +fun BackButton(onClick: () -> Unit) { + IconButton(onClick = onClick) { + Icon(imageVector = Icons.Default.ArrowBack, contentDescription = "Back") + } +} diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/epoxy/ListViewAttachmentRow.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/epoxy/ListViewAttachmentRow.kt new file mode 100644 index 000000000..07e098b88 --- /dev/null +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/epoxy/ListViewAttachmentRow.kt @@ -0,0 +1,107 @@ +package com.alfresco.content.process.ui.epoxy + +import android.content.Context +import android.graphics.drawable.AnimatedVectorDrawable +import android.util.AttributeSet +import android.view.LayoutInflater +import android.view.View +import android.widget.FrameLayout +import androidx.core.content.res.ResourcesCompat +import androidx.core.view.isVisible +import com.airbnb.epoxy.CallbackProp +import com.airbnb.epoxy.ModelProp +import com.airbnb.epoxy.ModelView +import com.alfresco.content.data.Entry +import com.alfresco.content.data.OfflineStatus +import com.alfresco.content.listview.R +import com.alfresco.content.mimetype.MimeType +import com.alfresco.content.process.databinding.ViewListAttachmentRowBinding + +/** + * Marked as ListViewAttachmentRow class + */ +@ModelView(autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT) +class ListViewAttachmentRow @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0, +) : FrameLayout(context, attrs, defStyleAttr) { + + private val binding = ViewListAttachmentRowBinding.inflate(LayoutInflater.from(context), this) + + /** + * set the content data on list row + */ + @ModelProp + fun setData(data: Entry) { + binding.tvName.text = data.name + binding.iconFile.setImageDrawable(ResourcesCompat.getDrawable(resources, MimeType.with(data.mimeType).icon, context.theme)) + + configureOfflineStatus(data) + + binding.deleteContentButton.visibility = if (actionButtonVisibility(data)) View.VISIBLE else View.INVISIBLE + } + + private fun configureOfflineStatus(entry: Entry) { + // Offline screen items and uploads + if (entry.isFile && entry.hasOfflineStatus) { + val drawableRes = makeOfflineStatusConfig(entry) + if (drawableRes != null) { + val drawable = + ResourcesCompat.getDrawable(resources, drawableRes, context.theme) + if (drawable is AnimatedVectorDrawable) { + drawable.start() + } + binding.offlineIcon.setImageDrawable(drawable) + binding.offlineIcon.isVisible = true + } else { + binding.offlineIcon.isVisible = false + } + } else { + binding.offlineIcon.isVisible = false + } + } + + private fun makeOfflineStatusConfig(entry: Entry): Int? = + when (entry.offlineStatus) { + OfflineStatus.PENDING -> + if (entry.isUpload) { + R.drawable.ic_offline_upload + } else { + R.drawable.ic_offline_status_pending + } + + OfflineStatus.SYNCING -> + R.drawable.ic_offline_status_in_progress_anim + + OfflineStatus.SYNCED -> + R.drawable.ic_offline_status_synced + + OfflineStatus.ERROR -> + R.drawable.ic_offline_status_error + + else -> + R.drawable.ic_offline_status_synced + } + + private fun actionButtonVisibility(entry: Entry) = + !entry.isLink && !entry.isUpload && + // Child folder in offline tab + !(entry.isFolder && entry.hasOfflineStatus && !entry.isOffline) && !entry.isReadOnly + + /** + * list row click listener + */ + @CallbackProp + fun setClickListener(listener: OnClickListener?) { + setOnClickListener(listener) + } + + /** + * delete icon click listener + */ + @CallbackProp + fun setDeleteContentClickListener(listener: OnClickListener?) { + binding.deleteContentButton.setOnClickListener(listener) + } +} diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/fragments/BaseDetailFragment.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/fragments/BaseDetailFragment.kt new file mode 100644 index 000000000..e03a6beec --- /dev/null +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/fragments/BaseDetailFragment.kt @@ -0,0 +1,99 @@ +package com.alfresco.content.process.ui.fragments + +import android.content.Intent +import android.os.Bundle +import android.view.View +import androidx.appcompat.app.AlertDialog +import androidx.fragment.app.Fragment +import com.alfresco.content.REMOTE +import com.alfresco.content.actions.CreateActionsSheet +import com.alfresco.content.data.AnalyticsManager +import com.alfresco.content.data.Entry +import com.alfresco.content.data.EventName +import com.alfresco.content.viewer.ViewerActivity +import com.google.android.material.snackbar.Snackbar +import java.lang.ref.WeakReference + +/** + * Marked as BaseDetailFragment class + */ +abstract class BaseDetailFragment : Fragment(), DeleteContentListener { + + private var deleteContentDialog = WeakReference(null) + lateinit var listener: DeleteContentListener + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + listener = this + } + + /** + * confirmation dialog before deleting the content related to task. + */ + /*fun deleteContentPrompt(contentEntry: Entry) { + AnalyticsManager().taskEvent(EventName.DeleteTaskAttachment) + val oldDialog = deleteContentDialog.get() + if (oldDialog != null && oldDialog.isShowing) return + val dialog = MaterialAlertDialogBuilder(requireContext()) + .setCancelable(false) + .setTitle(getString(R.string.dialog_title_delete_content)) + .setMessage(contentEntry.name) + .setNegativeButton(getString(R.string.dialog_negative_button_task), null) + .setPositiveButton(getString(R.string.dialog_positive_button_task)) { _, _ -> + listener.onConfirmDelete(contentEntry.id.toString()) + } + .show() + deleteContentDialog = WeakReference(dialog) + }*/ + + internal fun showCreateSheet(state: FormViewState, observerID: String) { + AnalyticsManager().taskEvent(EventName.UploadProcessAttachment) + CreateActionsSheet.with(Entry.defaultWorkflowEntry(observerID)).show(childFragmentManager, null) + } + + /** + * return the stable id of uploading contents + */ + fun stableId(entry: Entry): String = + if (entry.isUpload) { + entry.boxId.toString() + } else entry.id + + /** + * This intent will open the remote file + */ + fun remoteViewerIntent(entry: Entry) = startActivity( + Intent(requireActivity(), ViewerActivity::class.java) + .putExtra(ViewerActivity.KEY_ID, entry.id) + .putExtra(ViewerActivity.KEY_TITLE, entry.name) + .putExtra(ViewerActivity.KEY_MODE, REMOTE), + ) + + /** + * This intent will open the local file + */ +// fun localViewerIntent(contentEntry: Entry) = startActivity( +// Intent(requireActivity(), LocalPreviewActivity::class.java) +// .putExtra(LocalPreviewActivity.KEY_ENTRY_OBJ, contentEntry), +// ) + + /** + * showing Snackbar + */ + fun showSnackar(snackView: View, message: String) = Snackbar.make( + snackView, + message, + Snackbar.LENGTH_SHORT, + ).show() +} + +/** + * Marked as DeleteContentListener interface + */ +interface DeleteContentListener { + + /** + * It will get call on confirm delete. + */ + fun onConfirmDelete(contentId: String) +} diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/FormViewModel.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/fragments/FormViewModel.kt similarity index 75% rename from process-app/src/main/kotlin/com/alfresco/content/process/FormViewModel.kt rename to process-app/src/main/kotlin/com/alfresco/content/process/ui/fragments/FormViewModel.kt index 97ea1e1a9..cdcb22d97 100644 --- a/process-app/src/main/kotlin/com/alfresco/content/process/FormViewModel.kt +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/fragments/FormViewModel.kt @@ -1,47 +1,22 @@ -package com.alfresco.content.process +package com.alfresco.content.process.ui.fragments import android.content.Context -import com.airbnb.mvrx.Async import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.MavericksViewModel import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success -import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.ViewModelContext -import com.alfresco.content.data.OptionsModel +import com.alfresco.content.common.EntryListener +import com.alfresco.content.data.OfflineRepository import com.alfresco.content.data.ProcessEntry -import com.alfresco.content.data.ResponseListForm -import com.alfresco.content.data.ResponseListProcessDefinition import com.alfresco.content.data.TaskRepository +import com.alfresco.content.data.UploadServerType import com.alfresco.content.data.UserGroupDetails -import com.alfresco.content.data.payloads.FieldsData import com.alfresco.coroutines.asFlow +import kotlinx.coroutines.Job import kotlinx.coroutines.launch - -data class FormViewState( - val parent: ProcessEntry = ProcessEntry(), - val requestStartForm: Async = Uninitialized, - val requestProcessDefinition: Async = Uninitialized, - val formFields: List = emptyList(), - val processOutcomes: List = emptyList(), - val enabledOutcomes: Boolean = false, - val requestStartWorkflow: Async = Uninitialized, -) : MavericksState { - constructor(target: ProcessEntry) : this(parent = target) - - /** - * update the single process definition entry - */ - fun updateSingleProcessDefinition(response: ResponseListProcessDefinition): FormViewState { - if (parent == null) { - return this - } - val processEntry = ProcessEntry.with(response.listProcessDefinitions.first(), parent) - return copy(parent = processEntry) - } -} +import java.util.UUID class FormViewModel( val state: FormViewState, @@ -49,10 +24,47 @@ class FormViewModel( private val repository: TaskRepository, ) : MavericksViewModel(state) { + private var observeUploadsJob: Job? = null + var entryListener: EntryListener? = null + var observerID: String = "" + private var isExecuted = false + init { + observerID = UUID.randomUUID().toString() singleProcessDefinition(state.parent.id) } + /** + * returns the current logged in APS user profile data + */ + fun getAPSUser() = repository.getAPSUser() + + /** + * delete content locally + */ + fun deleteAttachment(contentId: String) = stateFlow.execute { + deleteUploads(contentId) + } + + private fun observeUploads(state: FormViewState) { + requireNotNull(state.parent) + + val repo = OfflineRepository() + + // On refresh clean completed uploads + repo.removeCompletedUploads() + + observeUploadsJob?.cancel() + observeUploadsJob = repo.observeUploads(observerID, UploadServerType.UPLOAD_TO_PROCESS) + .execute { + if (it is Success) { + updateUploads(it()) + } else { + this + } + } + } + private fun singleProcessDefinition(appDefinitionId: String) = withState { state -> viewModelScope.launch { repository::singleProcessDefinition.asFlow(appDefinitionId).execute { @@ -61,7 +73,10 @@ class FormViewModel( is Fail -> copy(requestProcessDefinition = Fail(it.error)) is Success -> { val updatedState = updateSingleProcessDefinition(it()) - getStartForm(updatedState.parent) + observeUploads(updatedState) + updatedState.parent.let { processEntry -> + getStartForm(processEntry) + } copy(requestProcessDefinition = Success(it())) } diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/fragments/FormViewState.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/fragments/FormViewState.kt new file mode 100644 index 000000000..77c64e8b4 --- /dev/null +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/fragments/FormViewState.kt @@ -0,0 +1,93 @@ +package com.alfresco.content.process.ui.fragments + +import com.airbnb.mvrx.Async +import com.airbnb.mvrx.MavericksState +import com.airbnb.mvrx.Uninitialized +import com.alfresco.content.data.Entry +import com.alfresco.content.data.OfflineStatus +import com.alfresco.content.data.OptionsModel +import com.alfresco.content.data.ProcessEntry +import com.alfresco.content.data.ResponseListForm +import com.alfresco.content.data.ResponseListProcessDefinition +import com.alfresco.content.data.payloads.FieldsData + +data class FormViewState( + val parent: ProcessEntry = ProcessEntry(), + val requestStartForm: Async = Uninitialized, + val requestProcessDefinition: Async = Uninitialized, + val formFields: List = emptyList(), + val processOutcomes: List = emptyList(), + val enabledOutcomes: Boolean = false, + val requestStartWorkflow: Async = Uninitialized, + val listContents: List = emptyList(), + val baseEntries: List = emptyList(), + val uploads: List = emptyList(), +) : MavericksState { + constructor(target: ProcessEntry) : this(parent = target) + + /** + * update the single process definition entry + */ + fun updateSingleProcessDefinition(response: ResponseListProcessDefinition): FormViewState { + if (parent == null) { + return this + } + val processEntry = ProcessEntry.with(response.listProcessDefinitions.first(), parent) + return copy(parent = processEntry) + } + + /** + * delete content locally and update UI + */ + fun deleteUploads(contentId: String): FormViewState { + val listBaseEntries = baseEntries.filter { it.id != contentId } + val listUploads = uploads.filter { it.id != contentId } + return copyIncludingUploads(listBaseEntries, listUploads) + } + + /** + * updating the uploads entries with the server entries. + */ + fun updateUploads(uploads: List): FormViewState { + // Merge data only after at least the first page loaded + // [parent] is a good enough flag for the initial load. + return if (parent != null) { + copyIncludingUploads(baseEntries, uploads) + } else { + copy(uploads = uploads) + } + } + + private fun copyIncludingUploads( + entries: List, + uploads: List, + ): FormViewState { + val mixedUploads = uploads.transformCompletedUploads() + val mergedEntries = mergeInUploads(entries, mixedUploads) + val baseEntries = mergedEntries.filter { !it.isUpload } + + return copy( + listContents = mergedEntries, + baseEntries = baseEntries, + uploads = uploads, + ) + } + + private fun mergeInUploads(base: List, uploads: List): List { + return (uploads + base).distinctBy { it.id.ifEmpty { it.boxId } } + } + + /* + * Transforms completed uploads into network items, so further interaction with them + * doesn't require special logic. + */ + private fun List.transformCompletedUploads(): List = + map { + if (it.isUpload && it.isSynced) { + // Marking as partial avoids needing to store allowableOperations + it.copy(isUpload = false, offlineStatus = OfflineStatus.UNDEFINED, isPartial = true) + } else { + it + } + } +} diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/fragments/ProcessAttachedFilesFragment.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/fragments/ProcessAttachedFilesFragment.kt new file mode 100644 index 000000000..e72b66957 --- /dev/null +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/fragments/ProcessAttachedFilesFragment.kt @@ -0,0 +1,130 @@ +package com.alfresco.content.process.ui.fragments + +import android.os.Bundle +import android.os.Handler +import android.os.Looper +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.core.view.isVisible +import androidx.recyclerview.widget.RecyclerView +import com.airbnb.epoxy.AsyncEpoxyController +import com.airbnb.mvrx.MavericksView +import com.airbnb.mvrx.activityViewModel +import com.airbnb.mvrx.withState +import com.alfresco.content.common.EntryListener +import com.alfresco.content.data.AnalyticsManager +import com.alfresco.content.data.Entry +import com.alfresco.content.data.PageView +import com.alfresco.content.data.ParentEntry +import com.alfresco.content.data.UploadServerType +import com.alfresco.content.mimetype.MimeType +import com.alfresco.content.process.R +import com.alfresco.content.process.databinding.FragmentAttachedFilesBinding +import com.alfresco.content.process.ui.epoxy.listViewAttachmentRow +import com.alfresco.content.simpleController +import com.alfresco.ui.getDrawableForAttribute + +/** + * Marked as ProcessAttachedFilesFragment class + */ +class ProcessAttachedFilesFragment : BaseDetailFragment(), MavericksView, EntryListener { + + val viewModel: FormViewModel by activityViewModel() + private lateinit var binding: FragmentAttachedFilesBinding + private val epoxyController: AsyncEpoxyController by lazy { epoxyController() } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle?, + ): View { + binding = FragmentAttachedFilesBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + AnalyticsManager().screenViewEvent(PageView.AttachedFiles) + binding.refreshLayout.isEnabled = false + binding.toolbar.apply { + navigationContentDescription = getString(R.string.label_navigation_back) + navigationIcon = requireContext().getDrawableForAttribute(R.attr.homeAsUpIndicator) + setNavigationOnClickListener { requireActivity().onBackPressed() } + title = resources.getString(R.string.title_attached_files) + } + + binding.recyclerView.setController(epoxyController) + + epoxyController.adapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() { + override fun onItemRangeInserted(positionStart: Int, itemCount: Int) { + if (positionStart == 0) { + // @see: https://github.com/airbnb/epoxy/issues/224 + binding.recyclerView.layoutManager?.scrollToPosition(0) + } + } + }) + } + + override fun onConfirmDelete(contentId: String) { + viewModel.deleteAttachment(contentId) + } + + override fun invalidate() = withState(viewModel) { state -> + val handler = Handler(Looper.getMainLooper()) + binding.refreshLayout.isRefreshing = false + binding.loading.isVisible = false + handler.post { + if (state.listContents.size > 0) { + binding.tvNoOfAttachments.visibility = View.VISIBLE + binding.tvNoOfAttachments.text = getString(R.string.text_multiple_attachment, state.listContents.size) + } else { + binding.tvNoOfAttachments.visibility = View.GONE + } + } + + binding.fabAddAttachments.visibility = View.VISIBLE + binding.fabAddAttachments.setOnClickListener { + showCreateSheet(state, viewModel.observerID) + } + +// if (state.listContents.isEmpty()) requireActivity().onBackPressed() + + epoxyController.requestModelBuild() + } + + private fun epoxyController() = simpleController(viewModel) { state -> + + if (state.listContents.isNotEmpty()) { + state.listContents.forEach { obj -> + listViewAttachmentRow { + id(stableId(obj)) + data(obj) + deleteContentClickListener { model, _, _, _ -> onConfirmDelete(model.data().id) } + } + } + } + } + + private fun onItemClicked(contentEntry: Entry) { + if (!contentEntry.isUpload) { + if (!contentEntry.source.isNullOrEmpty()) { + val entry = Entry.convertContentEntryToEntry( + contentEntry, + MimeType.isDocFile(contentEntry.mimeType), + UploadServerType.UPLOAD_TO_PROCESS, + ) + remoteViewerIntent(entry) + } + } else { +// localViewerIntent(contentEntry) + } + } + + override fun onEntryCreated(entry: ParentEntry) { + if (isAdded) { +// localViewerIntent(entry as Entry) + } + } +} diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/UpdateProcessData.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/models/UpdateProcessData.kt similarity index 68% rename from process-app/src/main/kotlin/com/alfresco/content/process/ui/UpdateProcessData.kt rename to process-app/src/main/kotlin/com/alfresco/content/process/ui/models/UpdateProcessData.kt index c61068eb7..2cdd507f2 100644 --- a/process-app/src/main/kotlin/com/alfresco/content/process/ui/UpdateProcessData.kt +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/models/UpdateProcessData.kt @@ -1,4 +1,4 @@ -package com.alfresco.content.process.ui +package com.alfresco.content.process.ui.models /** * Mark as UpdateProcessData data class diff --git a/process-app/src/main/res/layout/fragment_attached_files.xml b/process-app/src/main/res/layout/fragment_attached_files.xml new file mode 100644 index 000000000..4597c4127 --- /dev/null +++ b/process-app/src/main/res/layout/fragment_attached_files.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/process-app/src/main/res/layout/fragment_container_view.xml b/process-app/src/main/res/layout/fragment_container_view.xml new file mode 100644 index 000000000..63cd22aa1 --- /dev/null +++ b/process-app/src/main/res/layout/fragment_container_view.xml @@ -0,0 +1,8 @@ + + + + diff --git a/process-app/src/main/res/layout/view_list_attachment_row.xml b/process-app/src/main/res/layout/view_list_attachment_row.xml new file mode 100644 index 000000000..3d1cfaccd --- /dev/null +++ b/process-app/src/main/res/layout/view_list_attachment_row.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/process-app/src/main/res/values/dimens.xml b/process-app/src/main/res/values/dimens.xml new file mode 100644 index 000000000..31013e734 --- /dev/null +++ b/process-app/src/main/res/values/dimens.xml @@ -0,0 +1,5 @@ + + + 24dp + 56dp + From 9080024fe812f723cdea58c10ef7cf01fcdf5745 Mon Sep 17 00:00:00 2001 From: Amanpal Singh <87360222+aman-alfresco@users.noreply.github.com> Date: Thu, 21 Mar 2024 20:20:01 +0530 Subject: [PATCH 5/7] code optimize --- .../details/ProcessDetailViewModel.kt | 2 +- .../alfresco/content/data/TaskRepository.kt | 32 +++---- .../ui/composeviews/FormDetailScreen.kt | 2 +- .../ui/composeviews/FormScrollContent.kt | 7 +- .../ui/composeviews/NavigationComponent.kt | 3 +- .../process/ui/fragments/FormViewModel.kt | 91 ++++++++++++++----- 6 files changed, 88 insertions(+), 49 deletions(-) diff --git a/browse/src/main/kotlin/com/alfresco/content/browse/processes/details/ProcessDetailViewModel.kt b/browse/src/main/kotlin/com/alfresco/content/browse/processes/details/ProcessDetailViewModel.kt index 6d862cea2..4c942332a 100644 --- a/browse/src/main/kotlin/com/alfresco/content/browse/processes/details/ProcessDetailViewModel.kt +++ b/browse/src/main/kotlin/com/alfresco/content/browse/processes/details/ProcessDetailViewModel.kt @@ -192,7 +192,7 @@ class ProcessDetailViewModel( fun startWorkflow() = withState { state -> val items = state.listContents.joinToString(separator = ",") { it.id } viewModelScope.launch { - repository::startWorkflow.asFlow(state.parent, items, emptyList()).execute { + repository::startWorkflow.asFlow(state.parent, items, mapOf()).execute { when (it) { is Loading -> copy(requestStartWorkflow = Loading()) is Fail -> copy(requestStartWorkflow = Fail(it.error)) diff --git a/data/src/main/kotlin/com/alfresco/content/data/TaskRepository.kt b/data/src/main/kotlin/com/alfresco/content/data/TaskRepository.kt index 1277bfa8e..55a43a0e7 100644 --- a/data/src/main/kotlin/com/alfresco/content/data/TaskRepository.kt +++ b/data/src/main/kotlin/com/alfresco/content/data/TaskRepository.kt @@ -4,7 +4,6 @@ import android.content.SharedPreferences import androidx.preference.PreferenceManager import com.alfresco.content.data.Settings.Companion.IS_PROCESS_ENABLED_KEY import com.alfresco.content.data.payloads.CommentPayload -import com.alfresco.content.data.payloads.FieldType import com.alfresco.content.data.payloads.FieldsData import com.alfresco.content.data.payloads.LinkContentPayload import com.alfresco.content.data.payloads.SystemPropertiesEntry @@ -383,31 +382,17 @@ class TaskRepository { /** * Execute the start flow integration */ - suspend fun startWorkflow(processEntry: ProcessEntry?, items: String, fields: List) = ProcessEntry.with( + suspend fun startWorkflow(processEntry: ProcessEntry?, items: String, values: Map) = ProcessEntry.with( processesService.createProcessInstance( RequestProcessInstances( name = processEntry?.name, processDefinitionId = processEntry?.id, - values = convertFieldsToValues(fields), + values = values, ), ), ) - private fun convertFieldsToValues(fields: List): Map { - val values = mutableMapOf() - - fields.forEach { - if (it.type == FieldType.PEOPLE.value() || it.type == FieldType.FUNCTIONAL_GROUP.value()) { - values[it.id] = getUserOrGroup(it.value as UserGroupDetails) - } else { - values[it.id] = it.value - } - } - - return values - } - - private fun getUserOrGroup(userGroupInfo: UserGroupDetails?): Map { + fun getUserOrGroup(userGroupInfo: UserGroupDetails?): Map { return if (userGroupInfo?.isGroup == true) { mapOf( "id" to userGroupInfo.id, @@ -427,6 +412,17 @@ class TaskRepository { } } + fun mapStringToOptionValues(fieldsData: FieldsData): Map { + val id = fieldsData.options.find { it.name == fieldsData.value }?.id + + requireNotNull(id) + + return mapOf( + "id" to id, + "name" to fieldsData.name, + ) + } + /** * saving the accountInfo data in preferences */ diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/composeviews/FormDetailScreen.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/composeviews/FormDetailScreen.kt index 192738bc3..2b7f8619b 100644 --- a/process-app/src/main/kotlin/com/alfresco/content/process/ui/composeviews/FormDetailScreen.kt +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/composeviews/FormDetailScreen.kt @@ -42,7 +42,7 @@ fun FormDetailScreen(state: FormViewState, viewModel: FormViewModel, outcomes: L .clickable { // Hide the keyboard on click outside of input fields // keyboardController?.hide() -// focusManager.clearFocus() + focusManager.clearFocus() }, ) { LazyColumn( diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/composeviews/FormScrollContent.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/composeviews/FormScrollContent.kt index 492f6a9cf..16db8f035 100644 --- a/process-app/src/main/kotlin/com/alfresco/content/process/ui/composeviews/FormScrollContent.kt +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/composeviews/FormScrollContent.kt @@ -5,7 +5,6 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue -import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.res.stringResource import androidx.navigation.NavController import com.alfresco.content.data.ProcessEntry @@ -27,7 +26,6 @@ import com.alfresco.content.process.ui.components.SingleLineInputField import com.alfresco.content.process.ui.fragments.FormViewModel import com.alfresco.content.process.ui.fragments.FormViewState -@OptIn(ExperimentalComposeUiApi::class) @Composable fun FormScrollContent(field: FieldsData, viewModel: FormViewModel, state: FormViewState, navController: NavController) { when (field.type) { @@ -105,8 +103,9 @@ fun FormScrollContent(field: FieldsData, viewModel: FormViewModel, state: FormVi } FieldType.DROPDOWN.value(), FieldType.RADIO_BUTTONS.value() -> { - var textFieldValue by remember { mutableStateOf(field.placeHolder ?: "") } - var textFieldQuery by remember { mutableStateOf("") } + var textFieldValue by remember { mutableStateOf(field.value as? String ?: "") } + var textFieldQuery by remember { mutableStateOf(field.options.find { it.name == textFieldValue }?.id ?: "") } + DropdownField( nameText = textFieldValue, queryText = textFieldQuery, diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/composeviews/NavigationComponent.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/composeviews/NavigationComponent.kt index 427d6c34e..66c70d778 100644 --- a/process-app/src/main/kotlin/com/alfresco/content/process/ui/composeviews/NavigationComponent.kt +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/composeviews/NavigationComponent.kt @@ -64,8 +64,7 @@ fun ProcessAttachedFilesScreen(navController: NavHostController) { context.resources.getDimensionPixelSize(R.dimen.default_bottom_controller_height), ) - val myFragment = fragmentContainerView.getFragment() - // ... + fragmentContainerView.getFragment() } } diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/fragments/FormViewModel.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/fragments/FormViewModel.kt index cdcb22d97..a12f9e4e2 100644 --- a/process-app/src/main/kotlin/com/alfresco/content/process/ui/fragments/FormViewModel.kt +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/fragments/FormViewModel.kt @@ -7,12 +7,18 @@ import com.airbnb.mvrx.MavericksViewModel import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.ViewModelContext +import com.alfresco.content.DATE_FORMAT_4 +import com.alfresco.content.DATE_FORMAT_5 import com.alfresco.content.common.EntryListener import com.alfresco.content.data.OfflineRepository +import com.alfresco.content.data.OptionsModel import com.alfresco.content.data.ProcessEntry import com.alfresco.content.data.TaskRepository import com.alfresco.content.data.UploadServerType import com.alfresco.content.data.UserGroupDetails +import com.alfresco.content.data.payloads.FieldType +import com.alfresco.content.data.payloads.FieldsData +import com.alfresco.content.getFormattedDate import com.alfresco.coroutines.asFlow import kotlinx.coroutines.Job import kotlinx.coroutines.launch @@ -100,12 +106,14 @@ class FormViewModel( } is Success -> { - copy( + val updatedState = copy( parent = processEntry, formFields = it().fields.flatMap { listData -> listData.fields }, processOutcomes = it().outcomes, requestStartForm = Success(it()), ) + enableDisableActions(updatedState) + updatedState } else -> { @@ -117,38 +125,42 @@ class FormViewModel( } fun updateFieldValue(fieldId: String, newValue: Any?, state: FormViewState) { - val updatedState = state.copy( - formFields = state.formFields.map { field -> - if (field.id == fieldId) { - var updateValue = newValue - when { - (updateValue is String) && updateValue.isEmpty() -> { - updateValue = null - } + val updatedFieldList = state.formFields.map { field -> + if (field.id == fieldId) { + var updatedValue = newValue + when { + (updatedValue is String) && updatedValue.isEmpty() -> { + updatedValue = null + } - (updateValue is Boolean) && !updateValue -> { - updateValue = null - } + (updatedValue is Boolean) && !updatedValue -> { + updatedValue = null + } - (updateValue is UserGroupDetails) && updateValue.id == 0 -> { - updateValue = null - } + (updatedValue is UserGroupDetails) && updatedValue.id == 0 -> { + updatedValue = null + } + + (updatedValue is OptionsModel) && updatedValue.id.isEmpty() -> { + updatedValue = null } - field.copy(value = updateValue) - } else { - field } - }, - ) + field.copy(value = updatedValue) + } else { + field + } + } - val hasAllRequiredData = hasFieldRequiredData(updatedState) + val updatedState = state.copy( + formFields = updatedFieldList, + ) - setState { updatedState.copy(enabledOutcomes = hasAllRequiredData) } + enableDisableActions(updatedState) } fun startWorkflow() = withState { state -> viewModelScope.launch { - repository::startWorkflow.asFlow(state.parent, "", state.formFields).execute { + repository::startWorkflow.asFlow(state.parent, "", convertFieldsToValues(state.formFields)).execute { when (it) { is Loading -> copy(requestStartWorkflow = Loading()) is Fail -> copy(requestStartWorkflow = Fail(it.error)) @@ -159,6 +171,39 @@ class FormViewModel( } } + private fun convertFieldsToValues(fields: List): Map { + val values = mutableMapOf() + + fields.forEach { + when (it.type) { + FieldType.PEOPLE.value(), FieldType.FUNCTIONAL_GROUP.value() -> { + values[it.id] = repository.getUserOrGroup(it.value as UserGroupDetails) + } + + FieldType.DATETIME.value(), FieldType.DATE.value() -> { + val convertedDate = (it.value as? String)?.getFormattedDate(DATE_FORMAT_4, DATE_FORMAT_5) + values[it.id] = convertedDate + } + + FieldType.RADIO_BUTTONS.value(), FieldType.DROPDOWN.value() -> { + values[it.id] = repository.mapStringToOptionValues(it) + } + + else -> { + values[it.id] = it.value + } + } + } + + return values + } + + private fun enableDisableActions(state: FormViewState) { + val hasAllRequiredData = hasFieldRequiredData(state) + + setState { state.copy(enabledOutcomes = hasAllRequiredData) } + } + private fun hasFieldRequiredData(state: FormViewState): Boolean { return !state.formFields.filter { it.required }.any { it.value == null } } From 44d7ee93bb6b144e065fd8948f1baa44b01fd0fe Mon Sep 17 00:00:00 2001 From: Amanpal Singh <87360222+aman-alfresco@users.noreply.github.com> Date: Thu, 21 Mar 2024 21:45:36 +0530 Subject: [PATCH 6/7] code optimize --- .../alfresco/content/process/ui/fragments/FormViewModel.kt | 4 ++++ .../process/ui/fragments/ProcessAttachedFilesFragment.kt | 7 ++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/fragments/FormViewModel.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/fragments/FormViewModel.kt index a12f9e4e2..b3f76bf75 100644 --- a/process-app/src/main/kotlin/com/alfresco/content/process/ui/fragments/FormViewModel.kt +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/fragments/FormViewModel.kt @@ -189,6 +189,10 @@ class FormViewModel( values[it.id] = repository.mapStringToOptionValues(it) } + FieldType.UPLOAD.value() -> { + values[it.id] = state.listContents.joinToString(separator = ",") { content -> content.id } + } + else -> { values[it.id] = it.value } diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/fragments/ProcessAttachedFilesFragment.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/fragments/ProcessAttachedFilesFragment.kt index e72b66957..6d8d827e6 100644 --- a/process-app/src/main/kotlin/com/alfresco/content/process/ui/fragments/ProcessAttachedFilesFragment.kt +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/fragments/ProcessAttachedFilesFragment.kt @@ -18,6 +18,7 @@ import com.alfresco.content.data.Entry import com.alfresco.content.data.PageView import com.alfresco.content.data.ParentEntry import com.alfresco.content.data.UploadServerType +import com.alfresco.content.data.payloads.FieldType import com.alfresco.content.mimetype.MimeType import com.alfresco.content.process.R import com.alfresco.content.process.databinding.FragmentAttachedFilesBinding @@ -75,8 +76,12 @@ class ProcessAttachedFilesFragment : BaseDetailFragment(), MavericksView, EntryL val handler = Handler(Looper.getMainLooper()) binding.refreshLayout.isRefreshing = false binding.loading.isVisible = false + + val fields = state.formFields.find { it.type == FieldType.UPLOAD.value() }!! + handler.post { - if (state.listContents.size > 0) { + if (state.listContents.isNotEmpty()) { + viewModel.updateFieldValue(fields.id, state.listContents, state) binding.tvNoOfAttachments.visibility = View.VISIBLE binding.tvNoOfAttachments.text = getString(R.string.text_multiple_attachment, state.listContents.size) } else { From 23acd58eb0d88e968b833fbbe1ad26c921f3fab2 Mon Sep 17 00:00:00 2001 From: Amanpal Singh <87360222+aman-alfresco@users.noreply.github.com> Date: Fri, 22 Mar 2024 11:41:32 +0530 Subject: [PATCH 7/7] code optimize --- .../browse/preview/LocalPreviewActivity.kt | 5 +-- .../browse/tasks/BaseDetailFragment.kt | 3 +- .../attachments/AttachedFilesFragment.kt | 3 +- browse/src/main/res/values-de/strings.xml | 3 -- browse/src/main/res/values-es/strings.xml | 3 -- browse/src/main/res/values-fr/strings.xml | 3 -- browse/src/main/res/values-it/strings.xml | 3 -- browse/src/main/res/values-nl/strings.xml | 3 -- browse/src/main/res/values/strings.xml | 3 -- common/src/main/res/values-de/strings.xml | 3 ++ common/src/main/res/values-es/strings.xml | 3 ++ common/src/main/res/values-fr/strings.xml | 4 +++ common/src/main/res/values-it/strings.xml | 3 ++ common/src/main/res/values-nl/strings.xml | 3 ++ common/src/main/res/values/strings.xml | 3 ++ .../ui/fragments/BaseDetailFragment.kt | 35 +++++++------------ .../fragments/ProcessAttachedFilesFragment.kt | 6 ++-- 17 files changed, 38 insertions(+), 51 deletions(-) diff --git a/browse/src/main/kotlin/com/alfresco/content/browse/preview/LocalPreviewActivity.kt b/browse/src/main/kotlin/com/alfresco/content/browse/preview/LocalPreviewActivity.kt index bc0e95e5c..28f4a73ca 100644 --- a/browse/src/main/kotlin/com/alfresco/content/browse/preview/LocalPreviewActivity.kt +++ b/browse/src/main/kotlin/com/alfresco/content/browse/preview/LocalPreviewActivity.kt @@ -8,6 +8,7 @@ import com.alfresco.content.actions.Action import com.alfresco.content.browse.R import com.alfresco.content.browse.databinding.ActivityLocalPreviewBinding import com.alfresco.content.data.Entry +import com.alfresco.content.process.ui.fragments.BaseDetailFragment.Companion.KEY_ENTRY_OBJ /** * Mark as Preview Activity @@ -45,8 +46,4 @@ class LocalPreviewActivity : AppCompatActivity() { fragment.arguments = intent.extras } } - - companion object { - const val KEY_ENTRY_OBJ = "entryObj" - } } diff --git a/browse/src/main/kotlin/com/alfresco/content/browse/tasks/BaseDetailFragment.kt b/browse/src/main/kotlin/com/alfresco/content/browse/tasks/BaseDetailFragment.kt index ad6dbc032..eca91e07c 100644 --- a/browse/src/main/kotlin/com/alfresco/content/browse/tasks/BaseDetailFragment.kt +++ b/browse/src/main/kotlin/com/alfresco/content/browse/tasks/BaseDetailFragment.kt @@ -14,6 +14,7 @@ import com.alfresco.content.browse.tasks.detail.TaskDetailViewState import com.alfresco.content.data.AnalyticsManager import com.alfresco.content.data.Entry import com.alfresco.content.data.EventName +import com.alfresco.content.process.ui.fragments.BaseDetailFragment.Companion.KEY_ENTRY_OBJ import com.alfresco.content.viewer.ViewerActivity import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.snackbar.Snackbar @@ -84,7 +85,7 @@ abstract class BaseDetailFragment : Fragment(), DeleteContentListener { */ fun localViewerIntent(contentEntry: Entry) = startActivity( Intent(requireActivity(), LocalPreviewActivity::class.java) - .putExtra(LocalPreviewActivity.KEY_ENTRY_OBJ, contentEntry), + .putExtra(KEY_ENTRY_OBJ, contentEntry), ) /** diff --git a/browse/src/main/kotlin/com/alfresco/content/browse/tasks/attachments/AttachedFilesFragment.kt b/browse/src/main/kotlin/com/alfresco/content/browse/tasks/attachments/AttachedFilesFragment.kt index 20b4424d4..a7174d323 100644 --- a/browse/src/main/kotlin/com/alfresco/content/browse/tasks/attachments/AttachedFilesFragment.kt +++ b/browse/src/main/kotlin/com/alfresco/content/browse/tasks/attachments/AttachedFilesFragment.kt @@ -30,6 +30,7 @@ import com.alfresco.content.data.PageView import com.alfresco.content.data.ParentEntry import com.alfresco.content.data.UploadServerType import com.alfresco.content.mimetype.MimeType +import com.alfresco.content.process.ui.fragments.BaseDetailFragment.Companion.KEY_ENTRY_OBJ import com.alfresco.content.simpleController import com.alfresco.ui.getDrawableForAttribute @@ -148,7 +149,7 @@ class AttachedFilesFragment : BaseDetailFragment(), MavericksView, EntryListener if (isAdded) { startActivity( Intent(requireActivity(), LocalPreviewActivity::class.java) - .putExtra(LocalPreviewActivity.KEY_ENTRY_OBJ, entry as Entry), + .putExtra(KEY_ENTRY_OBJ, entry as Entry), ) } } diff --git a/browse/src/main/res/values-de/strings.xml b/browse/src/main/res/values-de/strings.xml index 8727ba111..4975652ab 100755 --- a/browse/src/main/res/values-de/strings.xml +++ b/browse/src/main/res/values-de/strings.xml @@ -67,8 +67,6 @@ Abgeschlossen Aufgabe abschließen Sind Sie sicher, dass Sie diese Aufgabe abschließen wollen? Sie werden keine Änderungen mehr vornehmen können. - Abbrechen - Bestätigen Schaltfläche „Senden“ Keine Beschreibung Abgeschlossen-Symbol @@ -84,7 +82,6 @@ Aufgabe erstellen Verwerfen Sollen die Änderungen verworfen werden? - Eine Datei löschen? Symbol \'Anhang hinzufügen\' Sind Sie sicher, dass Sie die Aufgabe abschließen wollen? Nach Abschluss der Aufgabe können einige Dateien nicht hochgeladen werden und es können keine Änderungen vorgenommen werden. diff --git a/browse/src/main/res/values-es/strings.xml b/browse/src/main/res/values-es/strings.xml index 839911077..3b2174e55 100755 --- a/browse/src/main/res/values-es/strings.xml +++ b/browse/src/main/res/values-es/strings.xml @@ -67,8 +67,6 @@ Por completar Completar tarea ¿Está seguro de que desea completar esta tarea? Ya no podrá realizar ningún cambio. - Cancelar - Confirmar Botón Enviar Sin descripción Icono completado @@ -85,7 +83,6 @@ Crear tarea Descartar ¿Desea descartar los cambios? - ¿Eliminar un fichero? Añadir icono adjunto ¿Está seguro de que quiere completar la tarea? Una vez completada, algunos ficheros no se pudieron cargar y no se pueden realizar cambios. diff --git a/browse/src/main/res/values-fr/strings.xml b/browse/src/main/res/values-fr/strings.xml index 7557175cf..110a523f8 100755 --- a/browse/src/main/res/values-fr/strings.xml +++ b/browse/src/main/res/values-fr/strings.xml @@ -67,8 +67,6 @@ Terminé Terminer la tâche Voulez-vous vraiment terminer cette tâche ? Vous ne pourrez plus faire de modifications. - Annuler - Confirmer Bouton Envoyer Aucune description Icône Terminé @@ -84,7 +82,6 @@ Créer une tâche Ignorer Voulez-vous ignorer les modifications ? - Supprimer un fichier ? Icône Ajouter une pièce jointe Voulez-vous vraiment terminer la tâche ? Une fois terminée, certains fichiers ne pourront plus être importés et aucun changement ne pourra être effectué. diff --git a/browse/src/main/res/values-it/strings.xml b/browse/src/main/res/values-it/strings.xml index beb5d6bc8..c85359602 100755 --- a/browse/src/main/res/values-it/strings.xml +++ b/browse/src/main/res/values-it/strings.xml @@ -82,9 +82,6 @@ Icona Modifica assegnatario Icona Modifica nome e descrizione Crea compito - Ignora - Vuoi ignorare le modifiche? - Vuoi eliminare un file? Icona Aggiungi allegati Vuoi completare il compito? Una volta completato, non sarà possibile caricare alcuni file né apportare modifiche. diff --git a/browse/src/main/res/values-nl/strings.xml b/browse/src/main/res/values-nl/strings.xml index 0b87d6c7d..2580d8d5a 100755 --- a/browse/src/main/res/values-nl/strings.xml +++ b/browse/src/main/res/values-nl/strings.xml @@ -67,8 +67,6 @@ Voltooien Taak voltooien Weet u zeker dat u de taak wilt voltooien? U kunt geen wijzigingen meer aanbrengen. - Annuleren - Bevestigen Knop Verzenden Geen beschrijving Pictogram Voltooid @@ -84,7 +82,6 @@ Taak creëren Negeren Wilt u de wijzigingen negeren? - Bestand verwijderen? Pictogram Bijlage toevoegen Weet u zeker dat u de taak wilt voltooien? Nadat de taak is voltooid, kunnen sommige bestanden niet worden geüpload en kunnen geen wijzigingen worden aangebracht. diff --git a/browse/src/main/res/values/strings.xml b/browse/src/main/res/values/strings.xml index 26f5c7220..308a7d023 100644 --- a/browse/src/main/res/values/strings.xml +++ b/browse/src/main/res/values/strings.xml @@ -67,8 +67,6 @@ Complete Complete Task Are you sure you want to complete this task? You will no longer be able to make any changes. - Cancel - Confirm Send Button No description Completed icon @@ -84,7 +82,6 @@ Create task Discard Do you want to discard the changes? - Delete a file? Add attachment icon Are you sure you want to complete the task? Once completed, some files could not be uploaded and no changes can be made. diff --git a/common/src/main/res/values-de/strings.xml b/common/src/main/res/values-de/strings.xml index e6db325be..e0f14d872 100755 --- a/common/src/main/res/values-de/strings.xml +++ b/common/src/main/res/values-de/strings.xml @@ -35,4 +35,7 @@ Angehängte Dateien Symbol für Datei Symbol \'Anhang löschen\' + Eine Datei löschen? + Abbrechen + Bestätigen diff --git a/common/src/main/res/values-es/strings.xml b/common/src/main/res/values-es/strings.xml index 89672eb0f..8bb2593b2 100755 --- a/common/src/main/res/values-es/strings.xml +++ b/common/src/main/res/values-es/strings.xml @@ -35,4 +35,7 @@ Ficheros adjuntos Icono de fichero Icono de eliminación de adjuntos + ¿Eliminar un fichero? + Cancelar + Confirmar diff --git a/common/src/main/res/values-fr/strings.xml b/common/src/main/res/values-fr/strings.xml index cbba780df..88553c8ed 100755 --- a/common/src/main/res/values-fr/strings.xml +++ b/common/src/main/res/values-fr/strings.xml @@ -35,4 +35,8 @@ Fichiers joints Icône de fichier Icône Supprimer la pièce jointe + Supprimer un fichier ? + Annuler + Confirmer + diff --git a/common/src/main/res/values-it/strings.xml b/common/src/main/res/values-it/strings.xml index 4d281964e..0b96f77ce 100755 --- a/common/src/main/res/values-it/strings.xml +++ b/common/src/main/res/values-it/strings.xml @@ -35,4 +35,7 @@ File allegati Icona file Icona Elimina allegato + Vuoi eliminare un file? + Ignora + Vuoi ignorare le modifiche? diff --git a/common/src/main/res/values-nl/strings.xml b/common/src/main/res/values-nl/strings.xml index baab4753c..5195da14c 100755 --- a/common/src/main/res/values-nl/strings.xml +++ b/common/src/main/res/values-nl/strings.xml @@ -35,4 +35,7 @@ Bijgevoegde bestanden Pictogram Bestand Pictogram Bijlage verwijderen + Bestand verwijderen? + Annuleren + Bevestigen diff --git a/common/src/main/res/values/strings.xml b/common/src/main/res/values/strings.xml index c165c6621..71840605d 100644 --- a/common/src/main/res/values/strings.xml +++ b/common/src/main/res/values/strings.xml @@ -36,4 +36,7 @@ Attached files File icon Icon delete attachment + Delete a file? + Cancel + Confirm diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/fragments/BaseDetailFragment.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/fragments/BaseDetailFragment.kt index e03a6beec..1905df134 100644 --- a/process-app/src/main/kotlin/com/alfresco/content/process/ui/fragments/BaseDetailFragment.kt +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/fragments/BaseDetailFragment.kt @@ -27,25 +27,6 @@ abstract class BaseDetailFragment : Fragment(), DeleteContentListener { listener = this } - /** - * confirmation dialog before deleting the content related to task. - */ - /*fun deleteContentPrompt(contentEntry: Entry) { - AnalyticsManager().taskEvent(EventName.DeleteTaskAttachment) - val oldDialog = deleteContentDialog.get() - if (oldDialog != null && oldDialog.isShowing) return - val dialog = MaterialAlertDialogBuilder(requireContext()) - .setCancelable(false) - .setTitle(getString(R.string.dialog_title_delete_content)) - .setMessage(contentEntry.name) - .setNegativeButton(getString(R.string.dialog_negative_button_task), null) - .setPositiveButton(getString(R.string.dialog_positive_button_task)) { _, _ -> - listener.onConfirmDelete(contentEntry.id.toString()) - } - .show() - deleteContentDialog = WeakReference(dialog) - }*/ - internal fun showCreateSheet(state: FormViewState, observerID: String) { AnalyticsManager().taskEvent(EventName.UploadProcessAttachment) CreateActionsSheet.with(Entry.defaultWorkflowEntry(observerID)).show(childFragmentManager, null) @@ -72,10 +53,14 @@ abstract class BaseDetailFragment : Fragment(), DeleteContentListener { /** * This intent will open the local file */ -// fun localViewerIntent(contentEntry: Entry) = startActivity( -// Intent(requireActivity(), LocalPreviewActivity::class.java) -// .putExtra(LocalPreviewActivity.KEY_ENTRY_OBJ, contentEntry), -// ) + fun localViewerIntent(contentEntry: Entry) { + val intent = Intent( + requireActivity(), + Class.forName("com.alfresco.content.browse.preview.LocalPreviewActivity"), + ) + intent.putExtra(KEY_ENTRY_OBJ, contentEntry) + startActivity(intent) + } /** * showing Snackbar @@ -85,6 +70,10 @@ abstract class BaseDetailFragment : Fragment(), DeleteContentListener { message, Snackbar.LENGTH_SHORT, ).show() + + companion object { + const val KEY_ENTRY_OBJ = "entryObj" + } } /** diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/fragments/ProcessAttachedFilesFragment.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/fragments/ProcessAttachedFilesFragment.kt index 6d8d827e6..33d2dfcaa 100644 --- a/process-app/src/main/kotlin/com/alfresco/content/process/ui/fragments/ProcessAttachedFilesFragment.kt +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/fragments/ProcessAttachedFilesFragment.kt @@ -94,8 +94,6 @@ class ProcessAttachedFilesFragment : BaseDetailFragment(), MavericksView, EntryL showCreateSheet(state, viewModel.observerID) } -// if (state.listContents.isEmpty()) requireActivity().onBackPressed() - epoxyController.requestModelBuild() } @@ -123,13 +121,13 @@ class ProcessAttachedFilesFragment : BaseDetailFragment(), MavericksView, EntryL remoteViewerIntent(entry) } } else { -// localViewerIntent(contentEntry) + localViewerIntent(contentEntry) } } override fun onEntryCreated(entry: ParentEntry) { if (isAdded) { -// localViewerIntent(entry as Entry) + localViewerIntent(entry as Entry) } } }