From a99b18a6d8d994557dd30c27821d7c875e1a2ece Mon Sep 17 00:00:00 2001 From: Amanpal Singh <87360222+aman-alfresco@users.noreply.github.com> Date: Mon, 1 Apr 2024 22:38:42 +0530 Subject: [PATCH] ADST-47 (#324) * fixed crash * optimize error handling * add more sceanrio to error handling * linked search screen * added folder search screen * get result from folder search --- .../actions/sheet/ProcessDefinitionsSheet.kt | 3 +- app/build.gradle | 3 +- app/src/main/AndroidManifest.xml | 14 ++- .../content/app/activity/ProcessActivity.kt | 40 +++++++ app/src/main/res/layout/activity_process.xml | 25 +++++ .../browse/preview/LocalPreviewActivity.kt | 2 +- .../browse/tasks/BaseDetailFragment.kt | 2 +- .../attachments/AttachedFilesFragment.kt | 2 +- .../main/res/navigation/nav_task_paths.xml | 4 +- .../com/alfresco/content/NavControllerExt.kt | 7 ++ .../alfresco/content/common/EntryListener.kt | 2 + .../content/component/DatePickerBuilder.kt | 1 - .../content/data/AttachFolderSearchData.kt | 3 + .../content/data/payloads/FieldsData.kt | 1 + gradle/libs.versions.toml | 6 + .../com/alfresco/content/move/MoveFragment.kt | 8 -- process-app/build.gradle | 1 + .../content/process/ui/ProcessFormActivity.kt | 37 ------- .../process/ui/components/AmountInputField.kt | 2 +- .../process/ui/components/AttachFilesField.kt | 7 +- .../ui/components/AttachFolderField.kt | 102 +++++++++++++++++ .../process/ui/components/DateTimeField.kt | 2 +- .../process/ui/components/DropdownField.kt | 2 +- .../process/ui/components/HyperLinkField.kt | 3 +- .../ui/components/IntegerInputField.kt | 2 +- .../ui/components/MultiLineInputField.kt | 2 +- .../process/ui/components/ReadOnlyField.kt | 1 + .../process/ui/components/SearchBar.kt | 104 ++++++++++++++++++ .../ui/components/SingleLineInputField.kt | 2 +- .../ui/components/TrailingInputField.kt | 1 + .../process/ui/composeviews/FormScreen.kt | 19 +--- .../ui/composeviews/FormScrollContent.kt | 29 +++-- .../ui/composeviews/NavigationComponent.kt | 77 ------------- .../ui/composeviews/ProcessAttachedFiles.kt | 2 +- .../process/ui/fragments/FormViewModel.kt | 16 ++- ...gment.kt => ProcessAttachFilesFragment.kt} | 17 +-- ...tailFragment.kt => ProcessBaseFragment.kt} | 5 +- .../process/ui/fragments/ProcessFragment.kt | 78 +++++++++++++ .../content/process/ui/theme/Theme.kt | 23 ---- .../process/ui/{components => utils}/Utils.kt | 4 +- ...ed_files.xml => fragment_attach_files.xml} | 9 -- .../res/layout/fragment_container_view.xml | 8 -- .../src/main/res/layout/fragment_process.xml | 30 +++++ .../main/res/navigation/nav_process_paths.xml | 51 +++++++++ process-app/src/main/res/values/strings.xml | 4 + .../alfresco/content/search/SearchFragment.kt | 34 ++++-- .../content/search/SearchResultsFragment.kt | 32 ++++-- .../content/search/SearchResultsState.kt | 9 +- .../content/search/SearchViewModel.kt | 10 ++ settings.gradle | 1 - 50 files changed, 593 insertions(+), 256 deletions(-) create mode 100644 app/src/main/java/com/alfresco/content/app/activity/ProcessActivity.kt create mode 100644 app/src/main/res/layout/activity_process.xml create mode 100644 data/src/main/kotlin/com/alfresco/content/data/AttachFolderSearchData.kt delete mode 100644 process-app/src/main/kotlin/com/alfresco/content/process/ui/ProcessFormActivity.kt create mode 100644 process-app/src/main/kotlin/com/alfresco/content/process/ui/components/AttachFolderField.kt create mode 100644 process-app/src/main/kotlin/com/alfresco/content/process/ui/components/SearchBar.kt delete mode 100644 process-app/src/main/kotlin/com/alfresco/content/process/ui/composeviews/NavigationComponent.kt rename process-app/src/main/kotlin/com/alfresco/content/process/ui/fragments/{ProcessAttachedFilesFragment.kt => ProcessAttachFilesFragment.kt} (84%) rename process-app/src/main/kotlin/com/alfresco/content/process/ui/fragments/{BaseDetailFragment.kt => ProcessBaseFragment.kt} (91%) create mode 100644 process-app/src/main/kotlin/com/alfresco/content/process/ui/fragments/ProcessFragment.kt rename process-app/src/main/kotlin/com/alfresco/content/process/ui/{components => utils}/Utils.kt (97%) rename process-app/src/main/res/layout/{fragment_attached_files.xml => fragment_attach_files.xml} (92%) delete mode 100644 process-app/src/main/res/layout/fragment_container_view.xml create mode 100644 process-app/src/main/res/layout/fragment_process.xml create mode 100644 process-app/src/main/res/navigation/nav_process_paths.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 5f37bf4e9..cfe5b91ca 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,8 @@ class ProcessDefinitionsSheet : BottomSheetDialogFragment(), MavericksView { val intent = Intent( requireActivity(), - Class.forName("com.alfresco.content.process.ui.ProcessFormActivity"), + Class.forName("com.alfresco.content.app.activity.ProcessActivity"), +// Class.forName("com.alfresco.content.process.ui.ProcessFormActivity"), ) intent.putExtra(Mavericks.KEY_ARG, processEntry) startActivity(intent) diff --git a/app/build.gradle b/app/build.gradle index 171cd4a20..6a2e50329 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -100,7 +100,7 @@ dependencies { implementation project(':viewer') implementation project(':shareextension') implementation project(':move') - + implementation project(':process-app') implementation project(':data') implementation libs.alfresco.content @@ -122,6 +122,7 @@ dependencies { implementation libs.coil.core implementation libs.gson implementation libs.compose.runtime + implementation libs.constraintlayout coreLibraryDesugaring libs.android.desugar diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e2416c846..480103c9c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -4,7 +4,8 @@ - + android:theme="@style/Theme.Alfresco" + android:useEmbeddedDex="true"> + - - diff --git a/app/src/main/java/com/alfresco/content/app/activity/ProcessActivity.kt b/app/src/main/java/com/alfresco/content/app/activity/ProcessActivity.kt new file mode 100644 index 000000000..252384cb8 --- /dev/null +++ b/app/src/main/java/com/alfresco/content/app/activity/ProcessActivity.kt @@ -0,0 +1,40 @@ +package com.alfresco.content.app.activity + +import android.os.Bundle +import androidx.navigation.fragment.NavHostFragment +import com.airbnb.mvrx.MavericksView +import com.alfresco.content.app.R +import com.alfresco.content.app.databinding.ActivityProcessBinding +import com.alfresco.content.app.widget.ActionBarController +import com.alfresco.content.app.widget.ActionBarLayout +import com.alfresco.content.common.BaseActivity + +class ProcessActivity : BaseActivity(), MavericksView { + + private lateinit var binding: ActivityProcessBinding + private lateinit var actionBarController: ActionBarController + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = ActivityProcessBinding.inflate(layoutInflater) + setContentView(binding.root) + configureNav() + } + + private fun configureNav() { + val navHostFragment = + supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment + val navController = navHostFragment.navController + val inflater = navController.navInflater + val graph = inflater.inflate(R.navigation.nav_process_paths) + navController.setGraph(graph, intent.extras) + val actionBarLayout = findViewById(R.id.toolbar) + actionBarController = ActionBarController(actionBarLayout) + actionBarController.setupActionBar(this, navController) + + actionBarLayout.toolbar.setNavigationOnClickListener { onBackPressed() } + } + + override fun invalidate() { + } +} diff --git a/app/src/main/res/layout/activity_process.xml b/app/src/main/res/layout/activity_process.xml new file mode 100644 index 000000000..0baf75cb5 --- /dev/null +++ b/app/src/main/res/layout/activity_process.xml @@ -0,0 +1,25 @@ + + + + + + + + + + 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 28f4a73ca..9140abe80 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,7 +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 +import com.alfresco.content.process.ui.fragments.ProcessBaseFragment.Companion.KEY_ENTRY_OBJ /** * Mark as Preview Activity 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 eca91e07c..67782d14a 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,7 +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.process.ui.fragments.ProcessBaseFragment.Companion.KEY_ENTRY_OBJ import com.alfresco.content.viewer.ViewerActivity import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.snackbar.Snackbar 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 a7174d323..4eab3ea9d 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,7 +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.process.ui.fragments.ProcessBaseFragment.Companion.KEY_ENTRY_OBJ import com.alfresco.content.simpleController import com.alfresco.ui.getDrawableForAttribute diff --git a/browse/src/main/res/navigation/nav_task_paths.xml b/browse/src/main/res/navigation/nav_task_paths.xml index 6c0f05e99..d26488255 100644 --- a/browse/src/main/res/navigation/nav_task_paths.xml +++ b/browse/src/main/res/navigation/nav_task_paths.xml @@ -30,12 +30,12 @@ + tools:layout="@layout/fragment_attach_files" /> + tools:layout="@layout/fragment_attach_files" /> ) {} + + fun onAttachFolder(entry: ParentEntry) {} } diff --git a/component/src/main/java/com/alfresco/content/component/DatePickerBuilder.kt b/component/src/main/java/com/alfresco/content/component/DatePickerBuilder.kt index 01f6642c7..753a81ee1 100644 --- a/component/src/main/java/com/alfresco/content/component/DatePickerBuilder.kt +++ b/component/src/main/java/com/alfresco/content/component/DatePickerBuilder.kt @@ -108,7 +108,6 @@ data class DatePickerBuilder( timePicker.addOnPositiveButtonClickListener { val hour = timePicker.hour val minute = timePicker.minute - println("string date $stringDateTime || $hour || $minute") val combinedDateTime = "$stringDateTime $hour:$minute" onSuccess?.invoke(combinedDateTime) } diff --git a/data/src/main/kotlin/com/alfresco/content/data/AttachFolderSearchData.kt b/data/src/main/kotlin/com/alfresco/content/data/AttachFolderSearchData.kt new file mode 100644 index 000000000..873f05549 --- /dev/null +++ b/data/src/main/kotlin/com/alfresco/content/data/AttachFolderSearchData.kt @@ -0,0 +1,3 @@ +package com.alfresco.content.data + +data class AttachFolderSearchData(val entry: Entry? = null) 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 131e02297..cf1c43193 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 @@ -123,6 +123,7 @@ enum class FieldType { FUNCTIONAL_GROUP, HYPERLINK, UPLOAD, + SELECT_FOLDER, ; fun value() = name.lowercase() diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 066fff2df..3ccaa59e5 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -12,6 +12,9 @@ test = "1.5.0" activity-compose = "1.7.0" compose-bom = "2023.10.01" ui-tooling = "1.5.4" +appcompat = "1.6.1" +material = "1.11.0" +constraintlayout = "2.1.4" [libraries] alfresco-auth = "com.alfresco.android:auth:0.8.1-SNAPSHOT" @@ -133,4 +136,7 @@ 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" androidx-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling", version.ref = "ui-tooling" } +appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" } +material = { group = "com.google.android.material", name = "material", version.ref = "material" } +constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" } diff --git a/move/src/main/java/com/alfresco/content/move/MoveFragment.kt b/move/src/main/java/com/alfresco/content/move/MoveFragment.kt index db8861973..299d4f979 100644 --- a/move/src/main/java/com/alfresco/content/move/MoveFragment.kt +++ b/move/src/main/java/com/alfresco/content/move/MoveFragment.kt @@ -1,6 +1,5 @@ package com.alfresco.content.move -import android.content.Context import android.os.Bundle import android.os.Parcelable import androidx.fragment.app.Fragment @@ -46,14 +45,8 @@ class MoveFragment : Fragment(), MavericksView { @OptIn(InternalMavericksApi::class) val viewModel: MoveViewModel by fragmentViewModelWithArgs { args } - override fun onAttach(context: Context) { - super.onAttach(context) - println("MoveFragment.onAttach") - } - override fun onStart() { super.onStart() - println("MoveFragment.onStart") val nodeId = viewModel.getMyFilesNodeId() args.entryObj?.let { findNavController().navigateToMoveParent(nodeId, it.id, getString(R.string.browse_menu_personal)) @@ -62,7 +55,6 @@ class MoveFragment : Fragment(), MavericksView { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - println("MoveFragment.onCreate") args = MoveArgs.with(requireArguments()) } diff --git a/process-app/build.gradle b/process-app/build.gradle index ea1707bfa..af0e75e89 100644 --- a/process-app/build.gradle +++ b/process-app/build.gradle @@ -59,6 +59,7 @@ dependencies { implementation project(':viewer-text') implementation project(':viewer') implementation project(':mimetype') + implementation project(':search') implementation libs.androidx.core implementation libs.androidx.appcompat 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 deleted file mode 100644 index d0049972b..000000000 --- a/process-app/src/main/kotlin/com/alfresco/content/process/ui/ProcessFormActivity.kt +++ /dev/null @@ -1,37 +0,0 @@ -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/components/AmountInputField.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/AmountInputField.kt index 51eff7634..be71fda23 100644 --- a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/AmountInputField.kt +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/AmountInputField.kt @@ -3,12 +3,12 @@ package com.alfresco.content.process.ui.components import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.tooling.preview.Preview import com.alfresco.content.data.payloads.FieldsData +import com.alfresco.content.process.ui.utils.inputField @Composable fun AmountInputField( 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 26285c200..d30620da3 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 @@ -25,10 +25,10 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.navigation.NavController +import androidx.navigation.compose.rememberNavController import com.alfresco.content.data.Entry 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 @@ -37,6 +37,7 @@ fun AttachFilesField( contents: List = emptyList(), fieldsData: FieldsData = FieldsData(), navController: NavController, + errorData: Pair = Pair(false, ""), ) { val labelWithAsterisk = buildAnnotatedString { append(fieldsData.name) @@ -72,7 +73,7 @@ fun AttachFilesField( IconButton(onClick = { navController.navigate( - NavigationScreen.ATTACHED_FILES_SCREEN.value(), + R.id.action_nav_process_form_to_nav_attach_files, ) }) { Icon( @@ -98,5 +99,5 @@ fun AttachFilesField( @Preview @Composable fun AttachFilesFieldPreview() { -// AttachFilesField() + AttachFilesField(navController = rememberNavController()) } diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/AttachFolderField.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/AttachFolderField.kt new file mode 100644 index 000000000..161b23b96 --- /dev/null +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/AttachFolderField.kt @@ -0,0 +1,102 @@ +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 androidx.navigation.NavController +import androidx.navigation.compose.rememberNavController +import com.alfresco.content.data.payloads.FieldsData +import com.alfresco.content.navigateToContextualSearch +import com.alfresco.content.process.R +import com.alfresco.content.process.ui.theme.AlfrescoBlue300 +import com.alfresco.content.process.ui.theme.AlfrescoError + +@Composable +fun AttachFolderField( + fieldsData: FieldsData = FieldsData(), + onUserTap: (Boolean) -> Unit = { }, + navController: NavController, + errorData: Pair = Pair(false, ""), +) { + 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 (fieldsData.value == null) { + stringResource(id = R.string.no_attached_folder) + } else { + stringResource(id = R.string.text_attached_folder, 1) + } + + 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 = { + onUserTap(true) + navController.navigateToContextualSearch("Search Folder", true) + }) { + Icon( + imageVector = Icons.Default.Attachment, + tint = AlfrescoBlue300, + contentDescription = "", + ) + } + } + Text( + text = contentValue, + style = TextStyle( + color = MaterialTheme.colorScheme.onSurfaceVariant, + fontSize = 12.sp, + ), + modifier = Modifier + .padding(start = 4.dp, top = 0.dp) + .align(alignment = Alignment.Start), + ) + } +} + +@Preview +@Composable +fun AttachFolderFieldPreview() { + AttachFolderField(navController = rememberNavController()) +} diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/DateTimeField.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/DateTimeField.kt index c0f781998..23e604178 100644 --- a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/DateTimeField.kt +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/DateTimeField.kt @@ -5,7 +5,6 @@ import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextFieldDefaults import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.input.ImeAction @@ -14,6 +13,7 @@ import androidx.compose.ui.tooling.preview.Preview import com.alfresco.content.DATE_FORMAT_4 import com.alfresco.content.component.DatePickerBuilder import com.alfresco.content.data.payloads.FieldsData +import com.alfresco.content.process.ui.utils.inputField @Composable fun DateTimeField( diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/DropdownField.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/DropdownField.kt index 336d86de1..749d7f95f 100644 --- a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/DropdownField.kt +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/DropdownField.kt @@ -5,7 +5,6 @@ import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextFieldDefaults import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.input.ImeAction @@ -14,6 +13,7 @@ import androidx.compose.ui.tooling.preview.Preview import com.alfresco.content.component.ComponentBuilder import com.alfresco.content.component.ComponentData import com.alfresco.content.data.payloads.FieldsData +import com.alfresco.content.process.ui.utils.inputField @Composable fun DropdownField( diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/HyperLinkField.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/HyperLinkField.kt index 0a2c1db72..4f9ef9fff 100644 --- a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/HyperLinkField.kt +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/HyperLinkField.kt @@ -17,12 +17,13 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.tooling.preview.Preview -import androidx.core.content.ContextCompat.startActivity import com.alfresco.content.common.SharedURLParser import com.alfresco.content.common.SharedURLParser.Companion.ID_KEY import com.alfresco.content.common.SharedURLParser.Companion.MODE_KEY import com.alfresco.content.data.payloads.FieldsData import com.alfresco.content.process.R +import com.alfresco.content.process.ui.utils.inputField +import com.alfresco.content.process.ui.utils.trailingIconColor import com.alfresco.content.viewer.ViewerActivity @Composable diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/IntegerInputField.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/IntegerInputField.kt index ad1555100..5e6fb94c2 100644 --- a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/IntegerInputField.kt +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/IntegerInputField.kt @@ -2,12 +2,12 @@ package com.alfresco.content.process.ui.components import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.tooling.preview.Preview import com.alfresco.content.data.payloads.FieldsData +import com.alfresco.content.process.ui.utils.inputField @Composable fun IntegerInputField( diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/MultiLineInputField.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/MultiLineInputField.kt index a9b496e6a..214082018 100644 --- a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/MultiLineInputField.kt +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/MultiLineInputField.kt @@ -2,11 +2,11 @@ package com.alfresco.content.process.ui.components import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.tooling.preview.Preview import com.alfresco.content.data.payloads.FieldsData +import com.alfresco.content.process.ui.utils.inputField @Composable fun MultiLineInputField( diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/ReadOnlyField.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/ReadOnlyField.kt index 97b142e36..8fc536d37 100644 --- a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/ReadOnlyField.kt +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/ReadOnlyField.kt @@ -9,6 +9,7 @@ import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.tooling.preview.Preview import com.alfresco.content.data.payloads.FieldsData +import com.alfresco.content.process.ui.utils.inputField @Composable fun ReadOnlyField( diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/SearchBar.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/SearchBar.kt new file mode 100644 index 000000000..109be72ec --- /dev/null +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/SearchBar.kt @@ -0,0 +1,104 @@ +package com.alfresco.content.process.ui.components + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.ExperimentalAnimationApi +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.text.KeyboardActions +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material.icons.filled.Close +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.Text +import androidx.compose.material3.TextFieldDefaults +import androidx.compose.material3.TopAppBar +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +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.Modifier +import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.focus.focusRequester +import androidx.compose.ui.focus.onFocusChanged +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalSoftwareKeyboardController +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.unit.dp + +@OptIn(ExperimentalMaterial3Api::class) +@ExperimentalAnimationApi +@ExperimentalComposeUiApi +@Composable +fun SearchBar( + searchText: String, + placeholderText: String = "", + onSearchTextChanged: (String) -> Unit = {}, + onClearClick: () -> Unit = {}, + onNavigateBack: () -> Unit = {}, +) { + var showClearButton by remember { mutableStateOf(false) } + val keyboardController = LocalSoftwareKeyboardController.current + val focusRequester = remember { FocusRequester() } + + TopAppBar(title = { Text("") }, navigationIcon = { + IconButton(onClick = { onNavigateBack() }) { + Icon( + imageVector = Icons.Filled.ArrowBack, + modifier = Modifier, + contentDescription = "", + ) + } + }, actions = { + OutlinedTextField( + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 2.dp) + .onFocusChanged { focusState -> + showClearButton = (focusState.isFocused) + } + .focusRequester(focusRequester), + value = searchText, + onValueChange = onSearchTextChanged, + placeholder = { + Text(text = placeholderText) + }, + colors = TextFieldDefaults.textFieldColors( + focusedIndicatorColor = Color.Transparent, + unfocusedIndicatorColor = Color.Transparent, + ), + trailingIcon = { + AnimatedVisibility( + visible = showClearButton, + enter = fadeIn(), + exit = fadeOut(), + ) { + IconButton(onClick = { onClearClick() }) { + Icon( + imageVector = Icons.Filled.Close, + contentDescription = "", + ) + } + } + }, + maxLines = 1, + singleLine = true, + keyboardOptions = KeyboardOptions.Default.copy(imeAction = ImeAction.Done), + keyboardActions = KeyboardActions(onDone = { + keyboardController?.hide() + }), + ) + }) + + LaunchedEffect(Unit) { + focusRequester.requestFocus() + } +} diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/SingleLineInputField.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/SingleLineInputField.kt index 4e7c20423..07ce761be 100644 --- a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/SingleLineInputField.kt +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/SingleLineInputField.kt @@ -2,13 +2,13 @@ package com.alfresco.content.process.ui.components import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.tooling.preview.Preview import com.alfresco.content.data.payloads.FieldsData +import com.alfresco.content.process.ui.utils.inputField @Composable fun SingleLineInputField( diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/TrailingInputField.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/TrailingInputField.kt index 869c6bbd4..b64d9acb9 100644 --- a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/TrailingInputField.kt +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/TrailingInputField.kt @@ -13,6 +13,7 @@ import androidx.compose.ui.res.stringResource import com.alfresco.content.data.payloads.FieldType import com.alfresco.content.data.payloads.FieldsData import com.alfresco.content.process.R +import com.alfresco.content.process.ui.utils.trailingIconColor @Composable fun TrailingInputField( diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/composeviews/FormScreen.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/composeviews/FormScreen.kt index e70223dd9..6284d461d 100644 --- a/process-app/src/main/kotlin/com/alfresco/content/process/ui/composeviews/FormScreen.kt +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/composeviews/FormScreen.kt @@ -1,6 +1,5 @@ package com.alfresco.content.process.ui.composeviews -import ComposeTopBar import android.app.Activity import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.statusBarsPadding @@ -13,21 +12,16 @@ 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 import com.alfresco.content.process.R -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) { - // This will get or create a ViewModel scoped to the Activity. - val viewModel: FormViewModel = mavericksActivityViewModel() +fun FormScreen(navController: NavController, viewModel: FormViewModel) { val state by viewModel.collectAsState() val context = LocalContext.current @@ -50,9 +44,7 @@ fun FormScreen(navController: NavController) { when { customOutcomes.size < 3 -> { - Scaffold( - topBar = { ComposeTopBar() }, - ) { padding -> + Scaffold() { padding -> val colorScheme = MaterialTheme.colorScheme // Wrap the content in a Column with verticalScroll Surface( @@ -62,9 +54,6 @@ fun FormScreen(navController: NavController) { color = colorScheme.background, contentColor = colorScheme.onBackground, ) { - if (state.requestStartForm is Loading) { - CustomLinearProgressIndicator(padding) - } FormDetailScreen(state, viewModel, customOutcomes, navController) } } @@ -72,7 +61,6 @@ fun FormScreen(navController: NavController) { else -> { Scaffold( - topBar = { ComposeTopBar() }, floatingActionButton = { FloatingActionButton(customOutcomes, state.enabledOutcomes, viewModel) }, floatingActionButtonPosition = FabPosition.End, ) { padding -> @@ -85,9 +73,6 @@ fun FormScreen(navController: NavController) { color = colorScheme.background, contentColor = colorScheme.onBackground, ) { - if (state.requestStartForm is Loading || state.requestStartWorkflow is Loading) { - CustomLinearProgressIndicator(padding) - } FormDetailScreen(state, viewModel, emptyList(), navController) } } 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 5a745f367..140ab9937 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 @@ -15,6 +15,7 @@ import com.alfresco.content.data.payloads.FieldsData 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.AttachFolderField import com.alfresco.content.process.ui.components.CheckBoxField import com.alfresco.content.process.ui.components.DateTimeField import com.alfresco.content.process.ui.components.DropdownField @@ -24,16 +25,16 @@ 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.components.amountInputError -import com.alfresco.content.process.ui.components.booleanInputError -import com.alfresco.content.process.ui.components.dateTimeInputError -import com.alfresco.content.process.ui.components.dropDownRadioInputError -import com.alfresco.content.process.ui.components.integerInputError -import com.alfresco.content.process.ui.components.multiLineInputError -import com.alfresco.content.process.ui.components.singleLineInputError -import com.alfresco.content.process.ui.components.userGroupInputError import com.alfresco.content.process.ui.fragments.FormViewModel import com.alfresco.content.process.ui.fragments.FormViewState +import com.alfresco.content.process.ui.utils.amountInputError +import com.alfresco.content.process.ui.utils.booleanInputError +import com.alfresco.content.process.ui.utils.dateTimeInputError +import com.alfresco.content.process.ui.utils.dropDownRadioInputError +import com.alfresco.content.process.ui.utils.integerInputError +import com.alfresco.content.process.ui.utils.multiLineInputError +import com.alfresco.content.process.ui.utils.singleLineInputError +import com.alfresco.content.process.ui.utils.userGroupInputError @Composable fun FormScrollContent(field: FieldsData, viewModel: FormViewModel, state: FormViewState, navController: NavController) { @@ -194,5 +195,17 @@ fun FormScrollContent(field: FieldsData, viewModel: FormViewModel, state: FormVi navController = navController, ) } + + FieldType.SELECT_FOLDER.value() -> { + AttachFolderField( + fieldsData = field, + navController = navController, + onUserTap = { + if (it) { + viewModel.folderFieldId = field.id + } + }, + ) + } } } 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 deleted file mode 100644 index 66c70d778..000000000 --- a/process-app/src/main/kotlin/com/alfresco/content/process/ui/composeviews/NavigationComponent.kt +++ /dev/null @@ -1,77 +0,0 @@ -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), - ) - - 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 index 51b618076..4e6e7f202 100644 --- 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 @@ -17,7 +17,7 @@ fun ProcessAttachedFiles() { modifier = Modifier.fillMaxSize(), factory = { context -> // Inflate your XML layout here - LayoutInflater.from(context).inflate(R.layout.fragment_attached_files, null) + LayoutInflater.from(context).inflate(R.layout.fragment_attach_files, null) }, ) } 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 9e3df4952..07050a3da 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 @@ -10,6 +10,7 @@ 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.AttachFolderSearchData import com.alfresco.content.data.OfflineRepository import com.alfresco.content.data.OptionsModel import com.alfresco.content.data.ProcessEntry @@ -20,6 +21,7 @@ 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 com.alfresco.events.on import kotlinx.coroutines.Job import kotlinx.coroutines.launch import java.util.UUID @@ -31,13 +33,19 @@ class FormViewModel( ) : MavericksViewModel(state) { private var observeUploadsJob: Job? = null - var entryListener: EntryListener? = null var observerID: String = "" - private var isExecuted = false + var folderFieldId = "" + private var entryListener: EntryListener? = null init { observerID = UUID.randomUUID().toString() singleProcessDefinition(state.parent.id) + + viewModelScope.on { + it.entry?.let { entry -> + entryListener?.onAttachFolder(entry) + } + } } /** @@ -225,6 +233,10 @@ class FormViewModel( return (hasValidDataInRequiredFields && hasValidDataInOtherFields) } + fun setListener(listener: EntryListener) { + entryListener = listener + } + companion object : MavericksViewModelFactory { override fun create( 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/ProcessAttachFilesFragment.kt similarity index 84% rename from process-app/src/main/kotlin/com/alfresco/content/process/ui/fragments/ProcessAttachedFilesFragment.kt rename to process-app/src/main/kotlin/com/alfresco/content/process/ui/fragments/ProcessAttachFilesFragment.kt index a7dceb390..a166db67c 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/ProcessAttachFilesFragment.kt @@ -21,18 +21,17 @@ 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 +import com.alfresco.content.process.databinding.FragmentAttachFilesBinding import com.alfresco.content.process.ui.epoxy.listViewAttachmentRow import com.alfresco.content.simpleController -import com.alfresco.ui.getDrawableForAttribute /** - * Marked as ProcessAttachedFilesFragment class + * Marked as ProcessAttachFilesFragment class */ -class ProcessAttachedFilesFragment : BaseDetailFragment(), MavericksView, EntryListener { +class ProcessAttachFilesFragment : ProcessBaseFragment(), MavericksView, EntryListener { val viewModel: FormViewModel by activityViewModel() - private lateinit var binding: FragmentAttachedFilesBinding + private lateinit var binding: FragmentAttachFilesBinding private val epoxyController: AsyncEpoxyController by lazy { epoxyController() } override fun onCreateView( @@ -40,7 +39,7 @@ class ProcessAttachedFilesFragment : BaseDetailFragment(), MavericksView, EntryL container: ViewGroup?, savedInstanceState: Bundle?, ): View { - binding = FragmentAttachedFilesBinding.inflate(inflater, container, false) + binding = FragmentAttachFilesBinding.inflate(inflater, container, false) return binding.root } @@ -49,12 +48,6 @@ class ProcessAttachedFilesFragment : BaseDetailFragment(), MavericksView, EntryL 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) 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/ProcessBaseFragment.kt similarity index 91% rename from process-app/src/main/kotlin/com/alfresco/content/process/ui/fragments/BaseDetailFragment.kt rename to process-app/src/main/kotlin/com/alfresco/content/process/ui/fragments/ProcessBaseFragment.kt index 1905df134..7a680cbde 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/ProcessBaseFragment.kt @@ -3,7 +3,6 @@ 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 @@ -12,14 +11,12 @@ 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 { +abstract class ProcessBaseFragment : Fragment(), DeleteContentListener { - private var deleteContentDialog = WeakReference(null) lateinit var listener: DeleteContentListener override fun onCreate(savedInstanceState: Bundle?) { diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/fragments/ProcessFragment.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/fragments/ProcessFragment.kt new file mode 100644 index 000000000..501ed86cf --- /dev/null +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/fragments/ProcessFragment.kt @@ -0,0 +1,78 @@ +package com.alfresco.content.process.ui.fragments + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.appcompat.app.AppCompatActivity +import androidx.compose.ui.platform.ViewCompositionStrategy +import androidx.core.view.isVisible +import androidx.fragment.app.Fragment +import androidx.navigation.findNavController +import com.airbnb.mvrx.Loading +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.Entry +import com.alfresco.content.data.ParentEntry +import com.alfresco.content.process.R +import com.alfresco.content.process.databinding.FragmentProcessBinding +import com.alfresco.content.process.ui.composeviews.FormScreen +import com.alfresco.content.process.ui.theme.AlfrescoBaseTheme + +class ProcessFragment : Fragment(), MavericksView, EntryListener { + + val viewModel: FormViewModel by activityViewModel() + lateinit var binding: FragmentProcessBinding + private var viewLayout: View? = null + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle?, + ): View { + binding = FragmentProcessBinding.inflate(inflater, container, false) + viewLayout = binding.root + return viewLayout as View + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + viewModel.setListener(this) + + val supportActionBar = (requireActivity() as AppCompatActivity).supportActionBar + supportActionBar?.setDisplayShowHomeEnabled(true) + supportActionBar?.setDisplayHomeAsUpEnabled(true) + supportActionBar?.setHomeActionContentDescription(getString(R.string.label_navigation_back)) + + binding.composeView.apply { + setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) + setContent { + AlfrescoBaseTheme { + FormScreen( + navController = findNavController(), + viewModel = viewModel, + ) + } + } + } + } + + override fun invalidate() = withState(viewModel) { state -> + binding.loading.isVisible = state.requestStartForm is Loading || state.requestStartWorkflow is Loading + } + + override fun onAttachFolder(entry: ParentEntry) = withState(viewModel) { + if (isAdded) { + viewModel.updateFieldValue( + viewModel.folderFieldId, + (entry as Entry).id, + it, + Pair(false, ""), + ) + viewModel.folderFieldId = "" + } + } +} diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/theme/Theme.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/theme/Theme.kt index eadba3d1d..fe1555442 100644 --- a/process-app/src/main/kotlin/com/alfresco/content/process/ui/theme/Theme.kt +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/theme/Theme.kt @@ -1,17 +1,12 @@ package com.alfresco.content.process.ui.theme -import android.app.Activity import androidx.appcompat.app.AppCompatDelegate import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.material3.MaterialTheme import androidx.compose.material3.darkColorScheme import androidx.compose.material3.lightColorScheme import androidx.compose.runtime.Composable -import androidx.compose.runtime.SideEffect import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.toArgb -import androidx.compose.ui.platform.LocalView -import androidx.core.view.WindowCompat private val DarkColorScheme = darkColorScheme( primary = AlfrescoBlue700, @@ -36,14 +31,6 @@ fun AlfrescoBaseTheme( dynamicColor: Boolean = true, content: @Composable () -> Unit, ) { - val statusBarColor = if (darkTheme) { - // Set status bar color for dark theme - designDefaultDarkBackgroundColor - } else { - // Set status bar color for light theme - AlfrescoGray900 // Replace with your desired light theme status bar color - } - val colorScheme = when { darkTheme -> DarkColorScheme.copy( secondary = MaterialTheme.colorScheme.primary, // @@ -53,16 +40,6 @@ fun AlfrescoBaseTheme( secondary = MaterialTheme.colorScheme.primary, // ) } - val view = LocalView.current - if (!view.isInEditMode) { - SideEffect { - val window = (view.context as Activity).window - WindowCompat.setDecorFitsSystemWindows(window, false) - window.statusBarColor = statusBarColor.toArgb() - window.navigationBarColor = AlfrescoGray900.toArgb() - WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = darkTheme - } - } MaterialTheme( colorScheme = colorScheme, diff --git a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/Utils.kt b/process-app/src/main/kotlin/com/alfresco/content/process/ui/utils/Utils.kt similarity index 97% rename from process-app/src/main/kotlin/com/alfresco/content/process/ui/components/Utils.kt rename to process-app/src/main/kotlin/com/alfresco/content/process/ui/utils/Utils.kt index f86940861..6d9b51c84 100644 --- a/process-app/src/main/kotlin/com/alfresco/content/process/ui/components/Utils.kt +++ b/process-app/src/main/kotlin/com/alfresco/content/process/ui/utils/Utils.kt @@ -1,4 +1,4 @@ -package com.alfresco.content.process.ui.components +package com.alfresco.content.process.ui.utils import android.annotation.SuppressLint import android.content.Context @@ -36,8 +36,6 @@ fun integerInputError(value: String?, fieldsData: FieldsData, context: Context): } } - println("IntegerInputField 3 == $errorData") - return errorData } diff --git a/process-app/src/main/res/layout/fragment_attached_files.xml b/process-app/src/main/res/layout/fragment_attach_files.xml similarity index 92% rename from process-app/src/main/res/layout/fragment_attached_files.xml rename to process-app/src/main/res/layout/fragment_attach_files.xml index 4597c4127..4388c00a9 100644 --- a/process-app/src/main/res/layout/fragment_attached_files.xml +++ b/process-app/src/main/res/layout/fragment_attach_files.xml @@ -5,13 +5,6 @@ android:layout_height="match_parent" android:orientation="vertical"> - - - - diff --git a/process-app/src/main/res/layout/fragment_container_view.xml b/process-app/src/main/res/layout/fragment_container_view.xml deleted file mode 100644 index 63cd22aa1..000000000 --- a/process-app/src/main/res/layout/fragment_container_view.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - diff --git a/process-app/src/main/res/layout/fragment_process.xml b/process-app/src/main/res/layout/fragment_process.xml new file mode 100644 index 000000000..d9676c051 --- /dev/null +++ b/process-app/src/main/res/layout/fragment_process.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + diff --git a/process-app/src/main/res/navigation/nav_process_paths.xml b/process-app/src/main/res/navigation/nav_process_paths.xml new file mode 100644 index 000000000..4f60957a3 --- /dev/null +++ b/process-app/src/main/res/navigation/nav_process_paths.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/process-app/src/main/res/values/strings.xml b/process-app/src/main/res/values/strings.xml index 38c7c3e99..83973e205 100644 --- a/process-app/src/main/res/values/strings.xml +++ b/process-app/src/main/res/values/strings.xml @@ -10,4 +10,8 @@ Actions Process Actions Button No Attachments + No Folder Attached + %d folders + + Hello blank fragment diff --git a/search/src/main/kotlin/com/alfresco/content/search/SearchFragment.kt b/search/src/main/kotlin/com/alfresco/content/search/SearchFragment.kt index 626b6a83f..ad99093c5 100644 --- a/search/src/main/kotlin/com/alfresco/content/search/SearchFragment.kt +++ b/search/src/main/kotlin/com/alfresco/content/search/SearchFragment.kt @@ -60,12 +60,14 @@ data class ContextualSearchArgs( val title: String?, val moveId: String, val isExtension: Boolean, + val isProcess: Boolean? = null, ) : Parcelable { companion object { private const val ID_KEY = "id" private const val TITLE_KEY = "title" private const val EXTENSION_KEY = "extension" private const val MOVE_ID_KEY = "moveId" + private const val PROCESS_KEY = "process" fun with(args: Bundle?): ContextualSearchArgs? { if (args == null) return null @@ -74,6 +76,7 @@ data class ContextualSearchArgs( args.getString(TITLE_KEY, null), args.getString(MOVE_ID_KEY, ""), args.getBoolean(EXTENSION_KEY, false), + args.getBoolean(PROCESS_KEY, false), ) } } @@ -134,10 +137,15 @@ class SearchFragment : Fragment(), MavericksView { binding.recyclerViewChips.setController(epoxyController) withState(viewModel) { state -> - if (!state.isExtension) { - setAdvanceSearchFiltersData() - } else { + + if (state.isProcess == true) { binding.parentAdvanceSearch.visibility = View.GONE + } else { + if (!state.isExtension) { + setAdvanceSearchFiltersData() + } else { + binding.parentAdvanceSearch.visibility = View.GONE + } } } @@ -147,14 +155,16 @@ class SearchFragment : Fragment(), MavericksView { private fun setAdvanceSearchFiltersData() { withState(viewModel) { - if (viewModel.isShowAdvanceFilterView(it.listSearchFilters)) { - binding.parentAdvanceSearch.visibility = View.VISIBLE - binding.chipGroup.visibility = View.GONE - setupDropDown() - } else { - binding.parentAdvanceSearch.visibility = View.GONE - binding.chipGroup.visibility = View.VISIBLE - setupChips() + if (it.isProcess == null) { + if (viewModel.isShowAdvanceFilterView(it.listSearchFilters)) { + binding.parentAdvanceSearch.visibility = View.VISIBLE + binding.chipGroup.visibility = View.GONE + setupDropDown() + } else { + binding.parentAdvanceSearch.visibility = View.GONE + binding.chipGroup.visibility = View.VISIBLE + setupChips() + } } } } @@ -528,7 +538,7 @@ class SearchFragment : Fragment(), MavericksView { resultsFragment.setFilters(advanceSearchFilter, facetData) } - fun clearMultiSelection() { + private fun clearMultiSelection() { resultsFragment.clearMultiSelection() } } diff --git a/search/src/main/kotlin/com/alfresco/content/search/SearchResultsFragment.kt b/search/src/main/kotlin/com/alfresco/content/search/SearchResultsFragment.kt index 8c2b22d75..4f9c5ca7e 100644 --- a/search/src/main/kotlin/com/alfresco/content/search/SearchResultsFragment.kt +++ b/search/src/main/kotlin/com/alfresco/content/search/SearchResultsFragment.kt @@ -82,15 +82,29 @@ class SearchResultsFragment : ListFragment( override fun onItemClicked(entry: Entry) { viewModel.saveSearch() withState(viewModel) { state -> - if (!state.isExtension) { - findNavController().navigateTo(entry) - } else if (entry.isFolder) { - if (state.moveId.isNotEmpty()) { - val parentId = entry.parentPaths.find { it == state.moveId } - if (parentId.isNullOrEmpty()) { - findNavController().navigateToFolder(entry, state.moveId) - } else Toast.makeText(requireContext(), getString(R.string.search_move_warning), Toast.LENGTH_SHORT).show() - } else findNavController().navigateToExtensionFolder(entry) + when { + state.isProcess != null -> { + if (entry.isFolder) { + viewModel.setSearchResult(entry) + requireActivity().onBackPressed() + } + } + else -> { + if (!state.isExtension) { + findNavController().navigateTo(entry) + } else if (entry.isFolder) { + when { + state.moveId.isNotEmpty() -> { + val parentId = entry.parentPaths.find { it == state.moveId } + if (parentId.isNullOrEmpty()) { + findNavController().navigateToFolder(entry, state.moveId) + } else Toast.makeText(requireContext(), getString(R.string.search_move_warning), Toast.LENGTH_SHORT).show() + } + + else -> findNavController().navigateToExtensionFolder(entry) + } + } + } } } } diff --git a/search/src/main/kotlin/com/alfresco/content/search/SearchResultsState.kt b/search/src/main/kotlin/com/alfresco/content/search/SearchResultsState.kt index 9c0e07ebf..7e2a1fee0 100644 --- a/search/src/main/kotlin/com/alfresco/content/search/SearchResultsState.kt +++ b/search/src/main/kotlin/com/alfresco/content/search/SearchResultsState.kt @@ -39,10 +39,17 @@ data class SearchResultsState( val contextId: String? = null, val contextTitle: String? = null, val isExtension: Boolean = false, + val isProcess: Boolean? = null, val moveId: String = "", ) : ListViewState { - constructor(args: ContextualSearchArgs) : this(contextId = args.id, contextTitle = args.title, isExtension = args.isExtension, moveId = args.moveId) + constructor(args: ContextualSearchArgs) : this( + contextId = args.id, + contextTitle = args.title, + isExtension = args.isExtension, + moveId = args.moveId, + isProcess = args.isProcess, + ) val isContextual: Boolean get() { diff --git a/search/src/main/kotlin/com/alfresco/content/search/SearchViewModel.kt b/search/src/main/kotlin/com/alfresco/content/search/SearchViewModel.kt index 37fafb2d5..0c0d6e9a6 100644 --- a/search/src/main/kotlin/com/alfresco/content/search/SearchViewModel.kt +++ b/search/src/main/kotlin/com/alfresco/content/search/SearchViewModel.kt @@ -11,6 +11,7 @@ import com.alfresco.content.component.ComponentMetaData import com.alfresco.content.component.models.SearchChipCategory import com.alfresco.content.data.AdvanceSearchFilter import com.alfresco.content.data.AdvanceSearchFilters +import com.alfresco.content.data.AttachFolderSearchData import com.alfresco.content.data.Entry import com.alfresco.content.data.SearchFacetData import com.alfresco.content.data.SearchFacetFields @@ -28,6 +29,9 @@ import com.alfresco.content.listview.ListViewState import com.alfresco.content.models.AppConfigModel import com.alfresco.content.models.SearchItem import com.alfresco.content.network.ConnectivityTracker +import com.alfresco.events.EventBus +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.collectLatest @@ -468,6 +472,7 @@ class SearchViewModel( maxLimitReachedForMultiSelection = false, ) } + override fun resetMaxLimitError() = setState { copy(maxLimitReachedForMultiSelection = false) } /** @@ -476,6 +481,11 @@ class SearchViewModel( fun canSearchOverCurrentNetwork() = ConnectivityTracker.isActiveNetwork(context) override fun emptyMessageArgs(state: ListViewState) = Triple(R.drawable.ic_empty_search, R.string.search_empty_title, R.string.search_empty_message) + fun setSearchResult(entry: Entry) { + CoroutineScope(Dispatchers.Main).launch { + EventBus.default.send(AttachFolderSearchData(entry)) + } + } companion object : MavericksViewModelFactory { const val MIN_QUERY_LENGTH = 3 diff --git a/settings.gradle b/settings.gradle index 0357d1c6d..365e7ab1d 100644 --- a/settings.gradle +++ b/settings.gradle @@ -23,7 +23,6 @@ include ':shareextension' include ':move' include ':component' include ':app' -//include ':process' include ':process-app' //include ':content' //include ':content-ktx'