|
| 1 | += Component Development |
| 2 | +:toc: left |
| 3 | + |
| 4 | +== Overview |
| 5 | + |
| 6 | +The following list contains a possible approach for implementing a new UI component: |
| 7 | + |
| 8 | +1. Create a new design or start with an existing design, see for example Figma |
| 9 | +2. Validate the use case and analyze the components that may be used for the implementation |
| 10 | +3. Create Composables that represent the UI component(s) and use placeholders for data population |
| 11 | +4. Create a component interface and implementation with the UI state and UI component interactions |
| 12 | +5. Create previews with preview component implementations to check the UI implementation |
| 13 | +6. Create a store and store provider for fetching resources and interacting with Solr backend |
| 14 | +7. Implement the client used by the store provider |
| 15 | +8. Write tests and test the new component |
| 16 | +9. If not already done, integrate the component in the existing application |
| 17 | +10. If not already done, extract resources like texts to allow internationalization and localization |
| 18 | + |
| 19 | +It is recommended to take a look at existing components, so that you get a better understanding |
| 20 | +of how things are implemented, what they have in common, and how each technology is utilized. |
| 21 | + |
| 22 | +== Component's Logic |
| 23 | + |
| 24 | +=== Components (Decompose) |
| 25 | + |
| 26 | +The component integration interacts with the UI composables and the state store. |
| 27 | + |
| 28 | +The implementation of the component interface "catches" user inputs like clicks and passes them |
| 29 | +to the store as ``Intent``s. The intents are then handled by the store implementation and |
| 30 | +may send a request to the backend and / or update the store state. The component is consuming |
| 31 | +and mapping the store state to the UI state. So once the store state is updated, it will |
| 32 | +reflect the changes in the UI. |
| 33 | + |
| 34 | +=== State Stores and Store Providers |
| 35 | + |
| 36 | +The state stores manage the state of the application, but independent of the state that is |
| 37 | +represented in the UI. Instances are created by store providers that hold the logic of the |
| 38 | +store. |
| 39 | + |
| 40 | +Store providers consist of three elements: |
| 41 | + |
| 42 | +- an executor implementation that consumes actions and intents and creates messages and labels |
| 43 | +- a reducer that updates the store state with the messages produced by the executor |
| 44 | +- a function for retrieving an instance of the store |
| 45 | + |
| 46 | +The store provider does also define the interface for the client that has to be provided in |
| 47 | +order for the executor to make API calls and interact with the Solr backend. |
| 48 | + |
| 49 | +== Component's Visuals |
| 50 | + |
| 51 | +=== Composables |
| 52 | + |
| 53 | +Composables are the UI elements that are defined and styled. They can be seen as boxes, rows and |
| 54 | +columns that are nested and change their style and structure based on conditions, state and input. |
| 55 | + |
| 56 | +There are many ways to get started, but the easiest way probably is to get familiar with the basics |
| 57 | +and try things out. The Figma designs make use of almost the same elements for designing, |
| 58 | +so the structure and configurations there may be mapped almost one-by-one in Compose code. |
| 59 | + |
| 60 | +=== Styling |
| 61 | + |
| 62 | +The styling in Compose is done via ``Modifier``s. Each composable should normally accept a modifier |
| 63 | +as a parameter, so that the user can customize specific visual parameters of the composable like |
| 64 | +width, height and alignment in the parent's composable. |
| 65 | + |
| 66 | +Since we are using Material 3, you do not have to care much about colors, typography and shapes. |
| 67 | +These are configured for the entire app, and you only have to make use of the right properties |
| 68 | +that are provided by the theme. |
| 69 | + |
| 70 | +=== Accessibility |
| 71 | + |
| 72 | +Compose comes with many accessibility features that can be used to improve the user experience. |
| 73 | + |
| 74 | +The simplest form of accessibility in a UI is probably the responsiveness of the UI. This is |
| 75 | +realized with `WindowSizeClass`. Some composables may use a wrapper (usually suffixed with |
| 76 | +`Content`) that checks the window size and loads different UI based on the dimensions of the |
| 77 | +current window. |
| 78 | + |
| 79 | +Another accessibility feature is the resource loading based on the system's locale or the user's |
| 80 | +preference. This allows the UI to be displayed in the user's native language. For that, you have |
| 81 | +to simply provide translations in the Compose resources. |
| 82 | + |
| 83 | +Another accessibility feature often underestimated is coloring. Some people with color vision |
| 84 | +deficiency may need a different theme, so that elements with problematic contrasts may be |
| 85 | +better visible again. |
| 86 | + |
| 87 | +Additional accessibility features like font scaling, semantics for screen readers may also |
| 88 | +be considered. Jetpack Compose provides a https://developer.android.com/develop/ui/compose/accessibility[simplified overview] |
| 89 | +and https://developer.android.com/codelabs/jetpack-compose-accessibility#0[Codelabs] for getting started. |
| 90 | + |
| 91 | +=== Navigation and Child Components |
| 92 | + |
| 93 | +Some components may have navigation elements and will load other components inside a frame layout. |
| 94 | +Since components hold a hierarchical context that needs to be managed somehow, child components |
| 95 | +(also used in navigation) are instantiated in a slightly different manner. |
| 96 | + |
| 97 | +Decompose provides https://arkivanov.github.io/Decompose/navigation/overview/[a few examples] |
| 98 | +and details of the process behind the navigation and child components. |
| 99 | + |
| 100 | +== Additional Notes |
| 101 | + |
| 102 | +=== Dependency Locking |
| 103 | + |
| 104 | +When adding or changing dependencies, you typically run `./gradlew resolveAndLockAll --write-locks`. |
| 105 | +Since we are building a web application from kotlin sources, we also have to update the JS lockfile |
| 106 | +with `./gradlew kotlinUpgradeYarnLock`. This will update the lockfile found at `kotlin-js-store/yarn.lock`. |
| 107 | + |
| 108 | +Some multiplatform libraries have platform-specific dependency resolution that will result in different |
| 109 | +lockfiles being generated, based on the environment the lock task is executed. It is important to exclude |
| 110 | +these platform-specific libraries from the lockfile to ensure a consistent lockfile generation across |
| 111 | +different operating systems. |
| 112 | + |
| 113 | +Platform-specific libraries come with a module name suffix that includes the platform name, like |
| 114 | +in `org.jetbrains.compose.desktop:desktop-jvm-windows-x64`. To identify those, look into the |
| 115 | +changes after updating the lockfile and add the necessary ignore-clause if such libraries |
| 116 | +exist. These ignore-clauses should be added in `gradle/validation/dependencies.gradle` inside the |
| 117 | +`allprojects.dependencyLocking` block. |
0 commit comments