Repository: Automattic/Gravatar-SDK-Android
Pull request #631: Only display the input fields that are configured in the scope
Author: login: AdamGrzybkowski
Labels: name: [Feature] Gravatar-Quickeditor
description: Gravatar Quick Editor module
Created: 2025-05-16T08:20:07Z | Merged: 2025-05-19T14:01:03Z



### Description

This PR allows displaying only certain AboutInputFields in the editors per the scope config. 

The public API was already done. The changes made are:
- Introduce the option to pick specific fields within the Demo App. 
- Pass the `aboutFields` from the scope config to the `AboutEditorViewModel` and set the visibility in the state.
- Adjust the UI component to respect the visibility flags.


https://github.com/user-attachments/assets/a02ba894-cd83-4f5b-be31-666588ef8715



### Testing Steps

1. Launch the demo app
2. Select the `About` or `AvatarAndAbout` scope
3. Tap on the `About fields`
4. Select the ones you want
5. Close the sheet
6. Open the QE
7. Verify the selected fields are visible



Diff:
diff --git a/demo-app/build.gradle.kts b/demo-app/build.gradle.kts
index ebd9fc993..d89c77e15 100644
--- a/demo-app/build.gradle.kts
+++ b/demo-app/build.gradle.kts
@@ -118,6 +118,7 @@ dependencies {
     implementation(libs.androidx.activity)
     implementation(libs.androidx.constraintlayout)
     implementation(libs.ucrop)
+    implementation(libs.composables.core)
     implementation(project(":gravatar"))
     implementation(project(":gravatar-ui"))
     implementation(project(":gravatar-quickeditor"))
diff --git a/demo-app/src/main/java/com/gravatar/demoapp/ui/AvatarUpdateTab.kt b/demo-app/src/main/java/com/gravatar/demoapp/ui/AvatarUpdateTab.kt
index 8ac6dc05c..8fc44ad92 100644
--- a/demo-app/src/main/java/com/gravatar/demoapp/ui/AvatarUpdateTab.kt
+++ b/demo-app/src/main/java/com/gravatar/demoapp/ui/AvatarUpdateTab.kt
@@ -5,6 +5,7 @@ import android.widget.Toast
 import androidx.compose.animation.AnimatedVisibility
 import androidx.compose.foundation.ScrollState
 import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
 import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
@@ -24,6 +25,7 @@ import androidx.compose.material3.ExposedDropdownMenuDefaults
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.Text
 import androidx.compose.material3.TextField
+import androidx.compose.material3.TextFieldDefaults
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.CompositionLocalProvider
 import androidx.compose.runtime.LaunchedEffect
@@ -46,8 +48,10 @@ import androidx.compose.ui.unit.dp
 import com.gravatar.demoapp.BuildConfig
 import com.gravatar.demoapp.R
 import com.gravatar.demoapp.ui.activity.QuickEditorTestActivity
+import com.gravatar.demoapp.ui.components.AboutFieldsBottomSheet
 import com.gravatar.demoapp.ui.components.GravatarEmailInput
 import com.gravatar.demoapp.ui.components.GravatarPasswordInput
+import com.gravatar.demoapp.ui.components.translatedValue
 import com.gravatar.quickeditor.GravatarQuickEditor
 import com.gravatar.quickeditor.ui.editor.AboutEditorConfiguration
 import com.gravatar.quickeditor.ui.editor.AboutEditorResult
@@ -81,9 +85,13 @@ fun AvatarUpdateTab(modifier: Modifier = Modifier) {
     var tokenVisible by remember { mutableStateOf(false) }
     val context = LocalContext.current
     var showBottomSheet by rememberSaveable { mutableStateOf(false) }
+    var showAboutFieldsPicker by rememberSaveable { mutableStateOf(false) }
     val coroutineScope = rememberCoroutineScope()
     var cacheBuster: String? by remember { mutableStateOf(null) }
     val scrollState: ScrollState = rememberScrollState()
+    var aboutFields: Set<AboutInputField> by rememberSaveable(stateSaver = AboutInputFieldSetSaver) {
+        mutableStateOf(AboutInputField.all)
+    }
     var pickerContentLayout: AvatarPickerContentLayout by rememberSaveable(
         stateSaver = AvatarPickerContentLayoutSaver,
     ) {
@@ -184,6 +192,27 @@ fun AvatarUpdateTab(modifier: Modifier = Modifier) {
                     modifier = Modifier.fillMaxWidth(),
                 )
             }
+            AnimatedVisibility(
+                visible = editorScope == QuickEditorScope.AvatarAndAbout || editorScope == QuickEditorScope.About,
+            ) {
+                TextField(
+                    enabled = false,
+                    value = aboutFields.joinToString(", ") { it.translatedValue(context) },
+                    maxLines = 1,
+                    singleLine = true,
+                    onValueChange = { },
+                    colors = TextFieldDefaults.colors(
+                        disabledTextColor = MaterialTheme.colorScheme.onSurface,
+                        disabledLabelColor = MaterialTheme.colorScheme.onSurface,
+                    ),
+                    label = { Text("About fields") },
+                    modifier = Modifier
+                        .clickable {
+                            showAboutFieldsPicker = true
+                        }
+                        .fillMaxWidth(),
+                )
+            }
             Button(
                 onClick = {
                     keyboardController?.hide()
@@ -222,6 +251,15 @@ fun AvatarUpdateTab(modifier: Modifier = Modifier) {
             }
         }
     }
+    if (showAboutFieldsPicker) {
+        AboutFieldsBottomSheet(
+            aboutFields = aboutFields,
+            onDismiss = { showAboutFieldsPicker = false },
+            onFieldsChanged = { fields ->
+                aboutFields = fields
+            },
+        )
+    }
     if (showBottomSheet) {
         val authenticationMethod = if (useToken) {
             AuthenticationMethod.Bearer(userToken)
@@ -256,7 +294,7 @@ fun AvatarUpdateTab(modifier: Modifier = Modifier) {
 
                         QuickEditorScope.About -> QuickEditorScopeOption.aboutEditor(
                             config = AboutEditorConfiguration(
-                                fields = AboutInputField.all,
+                                fields = aboutFields,
                             ),
                         )
 
@@ -264,7 +302,7 @@ fun AvatarUpdateTab(modifier: Modifier = Modifier) {
                             config = AvatarPickerAndAboutEditorConfiguration(
                                 contentLayout = pickerContentLayout,
                                 initialPage = editorInitialPage,
-                                fields = AboutInputField.all,
+                                fields = aboutFields,
                             ),
                         )
                     }
@@ -466,6 +504,11 @@ private fun InitialPageDropdown(
     }
 }
 
+private val AboutInputFieldSetSaver = Saver<Set<AboutInputField>, List<AboutInputField>>(
+    save = { it.toList() },
+    restore = { it.toSet() },
+)
+
 private val AvatarPickerContentLayoutSaver: Saver<AvatarPickerContentLayout, String> = run {
     val horizontalKey = "horizontal"
     val verticalKey = "vertical"
diff --git a/demo-app/src/main/java/com/gravatar/demoapp/ui/components/AboutFieldsBottomSheet.kt b/demo-app/src/main/java/com/gravatar/demoapp/ui/components/AboutFieldsBottomSheet.kt
new file mode 100644
index 000000000..2398772d9
--- /dev/null
+++ b/demo-app/src/main/java/com/gravatar/demoapp/ui/components/AboutFieldsBottomSheet.kt
@@ -0,0 +1,160 @@
+package com.gravatar.demoapp.ui.components
+
+import android.content.Context
+import androidx.compose.animation.animateColorAsState
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.foundation.layout.WindowInsetsSides
+import androidx.compose.foundation.layout.asPaddingValues
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.imePadding
+import androidx.compose.foundation.layout.navigationBars
+import androidx.compose.foundation.layout.only
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.widthIn
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Surface
+import androidx.compose.material3.Text
+import androidx.compose.material3.surfaceColorAtElevation
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.draw.shadow
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import com.composables.core.ModalBottomSheet
+import com.composables.core.ModalSheetProperties
+import com.composables.core.Scrim
+import com.composables.core.Sheet
+import com.composables.core.SheetDetent
+import com.composables.core.rememberModalBottomSheetState
+import com.composeunstyled.Thumb
+import com.composeunstyled.ToggleSwitch
+import com.gravatar.quickeditor.ui.editor.AboutInputField
+
+@Composable
+internal fun AboutFieldsBottomSheet(
+    aboutFields: Set<AboutInputField>,
+    onFieldsChanged: (Set<AboutInputField>) -> Unit,
+    onDismiss: () -> Unit = {},
+) {
+    ModalBottomSheet(
+        state = rememberModalBottomSheetState(
+            initialDetent = SheetDetent.FullyExpanded,
+        ),
+        onDismiss = onDismiss,
+        properties = ModalSheetProperties(
+            dismissOnBackPress = true,
+            dismissOnClickOutside = true,
+        ),
+    ) {
+        Scrim(
+            scrimColor = MaterialTheme.colorScheme.scrim.copy(alpha = 0.32f),
+        )
+        Sheet(
+            modifier = Modifier
+                .imePadding()
+                .clip(RoundedCornerShape(topStart = 28.dp, topEnd = 28.dp))
+                .background(MaterialTheme.colorScheme.surfaceColorAtElevation(1.dp))
+                .widthIn(max = 640.dp)
+                .fillMaxWidth()
+                .padding(
+                    WindowInsets.navigationBars
+                        .only(WindowInsetsSides.Vertical)
+                        .asPaddingValues(),
+                ),
+        ) {
+            Surface(
+                modifier = Modifier
+                    .padding(24.dp)
+                    .fillMaxWidth(),
+                tonalElevation = 1.dp,
+            ) {
+                Column(
+                    horizontalAlignment = Alignment.CenterHorizontally,
+                ) {
+                    AboutInputField.all.forEach { field ->
+                        Row(
+                            modifier = Modifier
+                                .padding(4.dp)
+                                .fillMaxWidth(),
+                        ) {
+                            val fieldsChecked = aboutFields.contains(field)
+
+                            val animatedColor by animateColorAsState(
+                                if (fieldsChecked) {
+                                    MaterialTheme.colorScheme.primary
+                                } else {
+                                    MaterialTheme.colorScheme.inversePrimary
+                                },
+                            )
+                            Text(
+                                text = field.translatedValue(LocalContext.current),
+                                modifier = Modifier
+                                    .weight(1f),
+                            )
+                            ToggleSwitch(
+                                toggled = fieldsChecked,
+                                backgroundColor = MaterialTheme.colorScheme.surfaceContainerHigh,
+                                shape = RoundedCornerShape(100),
+                                contentPadding = PaddingValues(2.dp),
+                                onToggled = { toggled ->
+                                    if (toggled) {
+                                        onFieldsChanged(aboutFields + field)
+                                    } else {
+                                        onFieldsChanged(aboutFields - field)
+                                    }
+                                },
+                                thumb = {
+                                    Thumb(
+                                        shape = CircleShape,
+                                        color = animatedColor,
+                                        modifier = Modifier.shadow(elevation = 4.dp, CircleShape),
+                                    )
+                                },
+                            )
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
+internal fun AboutInputField.translatedValue(context: Context): String {
+    return when (this) {
+        AboutInputField.DisplayName -> com.gravatar.quickeditor.R.string.gravatar_qe_about_field_label_display_name
+        AboutInputField.AboutMe -> com.gravatar.quickeditor.R.string.gravatar_qe_about_field_label_about_me
+        AboutInputField.Pronouns -> com.gravatar.quickeditor.R.string.gravatar_qe_about_field_label_pronouns
+        AboutInputField.Pronunciation -> com.gravatar.quickeditor.R.string.gravatar_qe_about_field_label_pronunciation
+        AboutInputField.Location -> com.gravatar.quickeditor.R.string.gravatar_qe_about_field_label_location
+        AboutInputField.JobTitle -> com.gravatar.quickeditor.R.string.gravatar_qe_about_field_label_job_title
+        AboutInputField.Company -> com.gravatar.quickeditor.R.string.gravatar_qe_about_field_label_company
+        else -> com.gravatar.quickeditor.R.string.gravatar_qe_about_field_label_display_name
+    }.let { context.getString(it) }
+}
+
+@Preview
+@Composable
+private fun AboutFieldsBottomSheetPreview() {
+    AboutFieldsBottomSheet(
+        aboutFields = setOf(
+            AboutInputField.DisplayName,
+            AboutInputField.AboutMe,
+            AboutInputField.Pronouns,
+            AboutInputField.Pronunciation,
+            AboutInputField.Location,
+            AboutInputField.JobTitle,
+            AboutInputField.Company,
+        ),
+        onFieldsChanged = {},
+    )
+}
diff --git a/gravatar-quickeditor/api/gravatar-quickeditor.api b/gravatar-quickeditor/api/gravatar-quickeditor.api
index 940b42936..5bcbca7c7 100644
--- a/gravatar-quickeditor/api/gravatar-quickeditor.api
+++ b/gravatar-quickeditor/api/gravatar-quickeditor.api
@@ -84,8 +84,10 @@ public final class com/gravatar/quickeditor/ui/abouteditor/components/Composable
 public final class com/gravatar/quickeditor/ui/abouteditor/components/ComposableSingletons$AboutSectionKt {
 	public static final field INSTANCE Lcom/gravatar/quickeditor/ui/abouteditor/components/ComposableSingletons$AboutSectionKt;
 	public static field lambda-1 Lkotlin/jvm/functions/Function2;
+	public static field lambda-2 Lkotlin/jvm/functions/Function2;
 	public fun <init> ()V
 	public final fun getLambda-1$gravatar_quickeditor_release ()Lkotlin/jvm/functions/Function2;
+	public final fun getLambda-2$gravatar_quickeditor_release ()Lkotlin/jvm/functions/Function2;
 }
 
 public final class com/gravatar/quickeditor/ui/abouteditor/components/ComposableSingletons$DiscardChangesAlertDialogKt {
diff --git a/gravatar-quickeditor/screenshotTests/roborazzi/com.gravatar.quickeditor.ui.abouteditor.AboutEditorTest.aboutEditorLoaded.png b/gravatar-quickeditor/screenshotTests/roborazzi/com.gravatar.quickeditor.ui.abouteditor.AboutEditorTest.aboutEditorLoaded.png
index 3aebcf3c2..98ddba525 100644
Binary files a/gravatar-quickeditor/screenshotTests/roborazzi/com.gravatar.quickeditor.ui.abouteditor.AboutEditorTest.aboutEditorLoaded.png and b/gravatar-quickeditor/screenshotTests/roborazzi/com.gravatar.quickeditor.ui.abouteditor.AboutEditorTest.aboutEditorLoaded.png differ
diff --git a/gravatar-quickeditor/screenshotTests/roborazzi/com.gravatar.quickeditor.ui.abouteditor.AboutEditorTest.aboutEditorLoadedDark.png b/gravatar-quickeditor/screenshotTests/roborazzi/com.gravatar.quickeditor.ui.abouteditor.AboutEditorTest.aboutEditorLoadedDark.png
index 681216f0b..0975c1f17 100644
Binary files a/gravatar-quickeditor/screenshotTests/roborazzi/com.gravatar.quickeditor.ui.abouteditor.AboutEditorTest.aboutEditorLoadedDark.png and b/gravatar-quickeditor/screenshotTests/roborazzi/com.gravatar.quickeditor.ui.abouteditor.AboutEditorTest.aboutEditorLoadedDark.png differ
diff --git a/gravatar-quickeditor/screenshotTests/roborazzi/com.gravatar.quickeditor.ui.abouteditor.AboutEditorTest.aboutEditorPersonalLoaded.png b/gravatar-quickeditor/screenshotTests/roborazzi/com.gravatar.quickeditor.ui.abouteditor.AboutEditorTest.aboutEditorPersonalLoaded.png
new file mode 100644
index 000000000..235d733d4
Binary files /dev/null and b/gravatar-quickeditor/screenshotTests/roborazzi/com.gravatar.quickeditor.ui.abouteditor.AboutEditorTest.aboutEditorPersonalLoaded.png differ
diff --git a/gravatar-quickeditor/screenshotTests/roborazzi/com.gravatar.quickeditor.ui.abouteditor.AboutEditorTest.aboutEditorSaving.png b/gravatar-quickeditor/screenshotTests/roborazzi/com.gravatar.quickeditor.ui.abouteditor.AboutEditorTest.aboutEditorSaving.png
index 834b6bb77..be2fe044a 100644
Binary files a/gravatar-quickeditor/screenshotTests/roborazzi/com.gravatar.quickeditor.ui.abouteditor.AboutEditorTest.aboutEditorSaving.png and b/gravatar-quickeditor/screenshotTests/roborazzi/com.gravatar.quickeditor.ui.abouteditor.AboutEditorTest.aboutEditorSaving.png differ
diff --git a/gravatar-quickeditor/screenshotTests/roborazzi/com.gravatar.quickeditor.ui.abouteditor.AboutEditorTest.heightRestrictedAboutEditorLoaded.png b/gravatar-quickeditor/screenshotTests/roborazzi/com.gravatar.quickeditor.ui.abouteditor.AboutEditorTest.heightRestrictedAboutEditorLoaded.png
index 7a5bd9e0a..d5442ab0d 100644
Binary files a/gravatar-quickeditor/screenshotTests/roborazzi/com.gravatar.quickeditor.ui.abouteditor.AboutEditorTest.heightRestrictedAboutEditorLoaded.png and b/gravatar-quickeditor/screenshotTests/roborazzi/com.gravatar.quickeditor.ui.abouteditor.AboutEditorTest.heightRestrictedAboutEditorLoaded.png differ
diff --git a/gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/abouteditor/AboutEditor.kt b/gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/abouteditor/AboutEditor.kt
index f7ff685d5..c8e722698 100644
--- a/gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/abouteditor/AboutEditor.kt
+++ b/gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/abouteditor/AboutEditor.kt
@@ -34,6 +34,7 @@ import com.gravatar.quickeditor.R
 import com.gravatar.quickeditor.ui.abouteditor.components.AboutSection
 import com.gravatar.quickeditor.ui.abouteditor.components.DiscardChangesAlertDialog
 import com.gravatar.quickeditor.ui.components.QEButton
+import com.gravatar.quickeditor.ui.editor.AboutInputField
 import com.gravatar.quickeditor.ui.editor.GravatarQuickEditorParams
 import com.gravatar.quickeditor.ui.extensions.QESnackbarHost
 import com.gravatar.quickeditor.ui.extensions.SnackbarType
@@ -130,7 +131,7 @@ internal fun AboutEditor(
 @Composable
 internal fun AboutEditor(
     uiState: AboutEditorUiState,
-    onValueChange: (AboutInputField) -> Unit,
+    onValueChange: (AboutEditorField) -> Unit,
     onSaveClick: () -> Unit,
 ) {
     Surface {
@@ -163,7 +164,7 @@ internal fun AboutEditor(
                             formEnabled = uiState.formEnabled,
                             modifier = Modifier
                                 .fillMaxWidth()
-                                .padding(horizontal = 16.dp),
+                                .padding(16.dp),
                             onValueChange = onValueChange,
                         )
                     }
@@ -189,17 +190,36 @@ internal fun AboutEditorLoadedPreview() {
         Box(modifier = Modifier.padding(10.dp)) {
             AboutEditor(
                 uiState = AboutEditorUiState(
-                    aboutFields = AboutFields(
-                        personal = PersonalFields(
-                            aboutMe = AboutInputField.Personal.AboutMe(value = "My description"),
-                            displayName = AboutInputField.Personal.DisplayName(value = "John Doe"),
-                            location = AboutInputField.Personal.Location(value = "San Francisco, CA"),
-                            pronunciation = AboutInputField.Personal.Pronunciation(value = "John Doe"),
-                            pronouns = AboutInputField.Personal.Pronouns(value = "he/him"),
+                    aboutFields = setOf(
+                        AboutEditorField(
+                            type = AboutInputField.DisplayName,
+                            value = "John Doe",
+                            maxLines = 1,
                         ),
-                        professional = ProfessionalFields(
-                            company = AboutInputField.Professional.Company(value = "Automattic"),
-                            jobTitle = AboutInputField.Professional.JobTitle(value = "Software Engineer"),
+                        AboutEditorField(
+                            type = AboutInputField.AboutMe,
+                            value = "My description",
+                            maxLines = 3,
+                        ),
+                        AboutEditorField(
+                            type = AboutInputField.Pronunciation,
+                            value = "John Doe",
+                        ),
+                        AboutEditorField(
+                            type = AboutInputField.Pronouns,
+                            value = "he/him",
+                        ),
+                        AboutEditorField(
+                            type = AboutInputField.Location,
+                            value = "San Francisco, CA",
+                        ),
+                        AboutEditorField(
+                            type = AboutInputField.Company,
+                            value = "Automattic",
+                        ),
+                        AboutEditorField(
+                            type = AboutInputField.JobTitle,
+                            value = "Software Engineer",
                         ),
                     ),
                 ),
@@ -217,7 +237,7 @@ internal fun AboutEditorLoadingPreview() {
         Box(modifier = Modifier.padding(10.dp)) {
             AboutEditor(
                 uiState = AboutEditorUiState(
-                    aboutFields = AboutFields.EMPTY,
+                    aboutFields = emptySet(),
                     isLoading = true,
                 ),
                 onValueChange = { },
diff --git a/gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/abouteditor/AboutEditorEvent.kt b/gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/abouteditor/AboutEditorEvent.kt
index 7eb590b56..581f41f37 100644
--- a/gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/abouteditor/AboutEditorEvent.kt
+++ b/gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/abouteditor/AboutEditorEvent.kt
@@ -2,7 +2,7 @@ package com.gravatar.quickeditor.ui.abouteditor
 
 internal sealed class AboutEditorEvent {
     data class OnAboutFieldUpdated(
-        val aboutField: AboutInputField,
+        val aboutField: AboutEditorField,
     ) : AboutEditorEvent()
 
     data object OnSaveClicked : AboutEditorEvent()
diff --git a/gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/abouteditor/AboutEditorField.kt b/gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/abouteditor/AboutEditorField.kt
new file mode 100644
index 000000000..786b13e9d
--- /dev/null
+++ b/gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/abouteditor/AboutEditorField.kt
@@ -0,0 +1,9 @@
+package com.gravatar.quickeditor.ui.abouteditor
+
+import com.gravatar.quickeditor.ui.editor.AboutInputField
+
+internal data class AboutEditorField(
+    val type: AboutInputField,
+    val value: String,
+    val maxLines: Int = 1,
+)
diff --git a/gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/abouteditor/AboutEditorUiState.kt b/gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/abouteditor/AboutEditorUiState.kt
index 384fb4a04..d1123113d 100644
--- a/gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/abouteditor/AboutEditorUiState.kt
+++ b/gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/abouteditor/AboutEditorUiState.kt
@@ -1,7 +1,7 @@
 package com.gravatar.quickeditor.ui.abouteditor
 
 internal data class AboutEditorUiState(
-    val aboutFields: AboutFields = AboutFields.EMPTY,
+    val aboutFields: Set<AboutEditorField> = emptySet(),
     val isLoading: Boolean = false,
     val savingProfile: Boolean = false,
     val discardChangesDialogVisible: Boolean = false,
diff --git a/gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/abouteditor/AboutEditorViewModel.kt b/gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/abouteditor/AboutEditorViewModel.kt
index 163961b3f..464028452 100644
--- a/gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/abouteditor/AboutEditorViewModel.kt
+++ b/gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/abouteditor/AboutEditorViewModel.kt
@@ -6,6 +6,7 @@ import androidx.lifecycle.viewModelScope
 import androidx.lifecycle.viewmodel.CreationExtras
 import com.gravatar.quickeditor.QuickEditorContainer
 import com.gravatar.quickeditor.data.repository.ProfileRepository
+import com.gravatar.quickeditor.ui.editor.AboutInputField
 import com.gravatar.quickeditor.ui.editor.GravatarQuickEditorParams
 import com.gravatar.restapi.models.Profile
 import com.gravatar.restapi.models.UpdateProfileRequest
@@ -21,6 +22,7 @@ import kotlinx.coroutines.launch
 
 internal class AboutEditorViewModel(
     private val email: Email,
+    private val visibleAboutFields: Set<AboutInputField>,
     private val profileRepository: ProfileRepository,
 ) : ViewModel() {
     private val _uiState = MutableStateFlow(AboutEditorUiState())
@@ -66,10 +68,10 @@ internal class AboutEditorViewModel(
     private fun checkForUnsavedChanges() {
         viewModelScope.launch {
             val currentProfile = uiState.value.aboutFields
-            val savedProfile = savedProfile?.aboutFields
+            val savedProfile = savedProfile?.aboutFields(visibleAboutFields)
             if (savedProfile != null && currentProfile != savedProfile) {
-                _uiState.update { currentProfile ->
-                    currentProfile.copy(
+                _uiState.update { currentState ->
+                    currentState.copy(
                         discardChangesDialogVisible = true,
                     )
                 }
@@ -92,7 +94,7 @@ internal class AboutEditorViewModel(
                     _uiState.update { currentState ->
                         currentState.copy(
                             savingProfile = false,
-                            aboutFields = profile.aboutFields,
+                            aboutFields = profile.aboutFields(visibleAboutFields),
                         )
                     }
                     _actions.send(
@@ -112,11 +114,17 @@ internal class AboutEditorViewModel(
         }
     }
 
-    private fun updateAboutField(aboutField: AboutInputField) {
+    private fun updateAboutField(aboutField: AboutEditorField) {
         viewModelScope.launch {
             _uiState.update { currentState ->
                 currentState.copy(
-                    aboutFields = currentState.aboutFields.update(aboutField),
+                    aboutFields = currentState.aboutFields.map {
+                        if (it.type == aboutField.type) {
+                            it.copy(value = aboutField.value)
+                        } else {
+                            it
+                        }
+                    }.toSet(),
                 )
             }
         }
@@ -136,7 +144,7 @@ internal class AboutEditorViewModel(
                         savedProfile = profile
                         it.copy(
                             isLoading = false,
-                            aboutFields = profile.aboutFields,
+                            aboutFields = profile.aboutFields(visibleAboutFields),
                         )
                     }
                 }
@@ -153,33 +161,41 @@ internal class AboutEditorViewModel(
     }
 }
 
-internal val Profile.aboutFields: AboutFields
-    get() {
-        return AboutFields(
-            personal = PersonalFields(
-                displayName = AboutInputField.Personal.DisplayName(value = displayName),
-                aboutMe = AboutInputField.Personal.AboutMe(value = description),
-                location = AboutInputField.Personal.Location(value = location),
-                pronouns = AboutInputField.Personal.Pronouns(value = pronouns),
-                pronunciation = AboutInputField.Personal.Pronunciation(value = pronunciation),
-            ),
-            professional = ProfessionalFields(
-                company = AboutInputField.Professional.Company(value = company),
-                jobTitle = AboutInputField.Professional.JobTitle(value = jobTitle),
-            ),
-        )
-    }
+internal fun Profile.aboutFields(visibleAboutFields: Set<AboutInputField>): Set<AboutEditorField> {
+    return visibleAboutFields
+        .map {
+            AboutEditorField(
+                type = it,
+                value = when (it) {
+                    AboutInputField.DisplayName -> displayName
+                    AboutInputField.AboutMe -> description
+                    AboutInputField.Pronouns -> pronouns
+                    AboutInputField.Pronunciation -> pronunciation
+                    AboutInputField.Location -> location
+                    AboutInputField.JobTitle -> jobTitle
+                    AboutInputField.Company -> company
+                    else -> ""
+                },
+                maxLines = when (it) {
+                    AboutInputField.AboutMe -> 3
+                    else -> 1
+                },
+            )
+        }
+        .sortedBy { it.type.order }
+        .toSet()
+}
 
-private val AboutFields.updateProfileRequest: UpdateProfileRequest
+private val Set<AboutEditorField>.updateProfileRequest: UpdateProfileRequest
     get() {
         return UpdateProfileRequest {
-            displayName = personal.displayName.value
-            description = personal.aboutMe.value
-            pronouns = personal.pronouns.value
-            pronunciation = personal.pronunciation.value
-            location = personal.location.value
-            jobTitle = professional.jobTitle.value
-            company = professional.company.value
+            displayName = this@updateProfileRequest.find { it.type == AboutInputField.DisplayName }?.value
+            description = this@updateProfileRequest.find { it.type == AboutInputField.AboutMe }?.value
+            pronouns = this@updateProfileRequest.find { it.type == AboutInputField.Pronouns }?.value
+            pronunciation = this@updateProfileRequest.find { it.type == AboutInputField.Pronunciation }?.value
+            location = this@updateProfileRequest.find { it.type == AboutInputField.Location }?.value
+            jobTitle = this@updateProfileRequest.find { it.type == AboutInputField.JobTitle }?.value
+            company = this@updateProfileRequest.find { it.type == AboutInputField.Company }?.value
         }
     }
 
@@ -191,6 +207,7 @@ internal class AboutEditorViewModelFactory(
         return AboutEditorViewModel(
             email = gravatarQuickEditorParams.email,
             profileRepository = QuickEditorContainer.getInstance().profileRepository,
+            visibleAboutFields = gravatarQuickEditorParams.scopeOption.aboutFields,
         ) as T
     }
 }
diff --git a/gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/abouteditor/AboutFields.kt b/gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/abouteditor/AboutFields.kt
deleted file mode 100644
index bea7447dd..000000000
--- a/gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/abouteditor/AboutFields.kt
+++ /dev/null
@@ -1,113 +0,0 @@
-package com.gravatar.quickeditor.ui.abouteditor
-
-internal data class AboutFields(
-    val personal: PersonalFields,
-    val professional: ProfessionalFields,
-) {
-    companion object {
-        val EMPTY: AboutFields = AboutFields(
-            personal = PersonalFields(
-                displayName = AboutInputField.Personal.DisplayName(value = ""),
-                aboutMe = AboutInputField.Personal.AboutMe(value = ""),
-                pronunciation = AboutInputField.Personal.Pronunciation(value = ""),
-                pronouns = AboutInputField.Personal.Pronouns(value = ""),
-                location = AboutInputField.Personal.Location(value = ""),
-            ),
-            professional = ProfessionalFields(
-                jobTitle = AboutInputField.Professional.JobTitle(value = ""),
-                company = AboutInputField.Professional.Company(value = ""),
-            ),
-        )
-    }
-
-    fun update(field: AboutInputField): AboutFields {
-        return when (field) {
-            is AboutInputField.Personal.DisplayName ->
-                copy(personal = personal.copy(displayName = field))
-
-            is AboutInputField.Personal.AboutMe ->
-                copy(personal = personal.copy(aboutMe = field))
-
-            is AboutInputField.Personal.Pronunciation ->
-                copy(personal = personal.copy(pronunciation = field))
-
-            is AboutInputField.Personal.Pronouns ->
-                copy(personal = personal.copy(pronouns = field))
-
-            is AboutInputField.Personal.Location ->
-                copy(personal = personal.copy(location = field))
-
-            is AboutInputField.Professional.JobTitle ->
-                copy(professional = professional.copy(jobTitle = field))
-
-            is AboutInputField.Professional.Company ->
-                copy(professional = professional.copy(company = field))
-        }
-    }
-}
-
-internal data class PersonalFields(
-    val displayName: AboutInputField.Personal.DisplayName,
-    val aboutMe: AboutInputField.Personal.AboutMe,
-    val pronunciation: AboutInputField.Personal.Pronunciation,
-    val pronouns: AboutInputField.Personal.Pronouns,
-    val location: AboutInputField.Personal.Location,
-)
-
-internal data class ProfessionalFields(
-    val jobTitle: AboutInputField.Professional.JobTitle,
-    val company: AboutInputField.Professional.Company,
-)
-
-internal sealed class AboutInputField {
-    abstract val value: String
-    open val maxLines: Int = 1
-    abstract val order: Int
-
-    sealed class Personal : AboutInputField() {
-        data class DisplayName(
-            override val value: String,
-        ) : Personal() {
-            override val order: Int = 0
-        }
-
-        data class AboutMe(
-            override val value: String,
-        ) : Personal() {
-            override val order: Int = 1
-            override val maxLines: Int = 4
-        }
-
-        data class Pronunciation(
-            override val value: String,
-        ) : Personal() {
-            override val order: Int = 2
-        }
-
-        data class Pronouns(
-            override val value: String,
-        ) : Personal() {
-            override val order: Int = 3
-        }
-
-        data class Location(
-            override val value: String,
-        ) : Personal() {
-            override val order: Int = 4
-        }
-    }
-
-    sealed class Professional : AboutInputField() {
-        data class JobTitle(
-            override val value: String,
-        ) : Professional() {
-            override val order: Int = 0
-        }
-
-        data class Company(
-            override val value: String,
-        ) : Professional() {
-            override val order: Int = 1
-        }
-    }
-}
diff --git a/gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/abouteditor/components/AboutEditField.kt b/gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/abouteditor/components/AboutEditField.kt
index deb1b0dd0..430cbd912 100644
--- a/gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/abouteditor/components/AboutEditField.kt
+++ b/gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/abouteditor/components/AboutEditField.kt
@@ -30,8 +30,7 @@ internal fun AboutEditField(
 ) {
     Column(
         modifier = modifier
-            .fillMaxWidth()
-            .padding(vertical = 8.dp),
+            .fillMaxWidth(),
     ) {
         Text(
             text = label,
@@ -62,11 +61,11 @@ internal fun AboutEditField(
             },
         )
         if (!description.isNullOrEmpty()) {
-            Spacer(modifier = Modifier.height(8.dp))
             Text(
                 text = description,
                 style = MaterialTheme.typography.bodySmall,
                 color = MaterialTheme.colorScheme.onSurfaceVariant,
+                modifier = Modifier.padding(vertical = 8.dp),
             )
         }
     }
diff --git a/gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/abouteditor/components/AboutFieldsSection.kt b/gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/abouteditor/components/AboutFieldsSection.kt
new file mode 100644
index 000000000..9a67f30fa
--- /dev/null
+++ b/gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/abouteditor/components/AboutFieldsSection.kt
@@ -0,0 +1,41 @@
+package com.gravatar.quickeditor.ui.abouteditor.components
+
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.unit.dp
+import com.gravatar.quickeditor.ui.abouteditor.AboutEditorField
+
+@Composable
+internal fun AboutFieldsSection(
+    label: String?,
+    fields: Set<AboutEditorField>,
+    formEnabled: Boolean,
+    onValueChange: (AboutEditorField) -> Unit,
+    modifier: Modifier = Modifier,
+) {
+    Column(
+        modifier = modifier,
+        verticalArrangement = Arrangement.spacedBy(16.dp),
+    ) {
+        label?.let {
+            AboutEditSectionLabel(
+                title = it,
+            )
+        }
+        fields.forEach { editorField ->
+            AboutEditField(
+                label = stringResource(editorField.labelRes),
+                value = editorField.value,
+                enabled = formEnabled,
+                maxLines = editorField.maxLines,
+                description = editorField.descriptionRes?.let { stringResource(it) },
+                onValueChange = {
+                    onValueChange(editorField.copy(value = it))
+                },
+            )
+        }
+    }
+}
diff --git a/gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/abouteditor/components/AboutSection.kt b/gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/abouteditor/components/AboutSection.kt
index f60b54d79..7d65d4766 100644
--- a/gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/abouteditor/components/AboutSection.kt
+++ b/gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/abouteditor/components/AboutSection.kt
@@ -1,104 +1,162 @@
 package com.gravatar.quickeditor.ui.abouteditor.components
 
 import androidx.annotation.StringRes
-import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.Spacer
 import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.layout.padding
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.tooling.preview.Preview
 import androidx.compose.ui.unit.dp
 import com.gravatar.quickeditor.R
-import com.gravatar.quickeditor.ui.abouteditor.AboutFields
-import com.gravatar.quickeditor.ui.abouteditor.AboutInputField
-import com.gravatar.quickeditor.ui.abouteditor.PersonalFields
-import com.gravatar.quickeditor.ui.abouteditor.ProfessionalFields
+import com.gravatar.quickeditor.ui.abouteditor.AboutEditorField
+import com.gravatar.quickeditor.ui.editor.AboutInputField
 import com.gravatar.ui.GravatarTheme
 
 @Composable
 internal fun AboutSection(
-    aboutFields: AboutFields,
+    aboutFields: Set<AboutEditorField>,
     formEnabled: Boolean,
-    onValueChange: (AboutInputField) -> Unit,
+    onValueChange: (AboutEditorField) -> Unit,
     modifier: Modifier = Modifier,
 ) {
-    Column(modifier = modifier) {
-        PersonalSection(
-            personalFields = aboutFields.personal,
-            formEnabled = formEnabled,
-            onValueChange = onValueChange,
-        )
-        Spacer(modifier = Modifier.height(16.dp))
-        ProfessionalSection(
-            professionalFields = aboutFields.professional,
-            formEnabled = formEnabled,
-            onValueChange = onValueChange,
-        )
-        Spacer(modifier = Modifier.height(8.dp))
+    Column(
+        modifier = modifier,
+        verticalArrangement = Arrangement.spacedBy(32.dp),
+    ) {
+        if (aboutFields.any { it.type.isPersonal }) {
+            AboutFieldsSection(
+                label = aboutFields.personalLabelRes?.let { stringResource(it) },
+                fields = aboutFields.filter { it.type.isPersonal }.toSet(),
+                formEnabled = formEnabled,
+                onValueChange = onValueChange,
+                modifier = Modifier,
+            )
+        }
+        if (aboutFields.any { it.type.isProfessional }) {
+            AboutFieldsSection(
+                label = aboutFields.professionalLabelRes?.let { stringResource(it) },
+                fields = aboutFields.filter { it.type.isProfessional }.toSet(),
+                formEnabled = formEnabled,
+                onValueChange = onValueChange,
+            )
+        }
     }
 }
 
-internal val AboutInputField.labelRes: Int
-    @StringRes get() = when (this) {
-        is AboutInputField.Personal.AboutMe -> R.string.gravatar_qe_about_field_label_about_me
-        is AboutInputField.Personal.DisplayName -> R.string.gravatar_qe_about_field_label_display_name
-        is AboutInputField.Personal.Location -> R.string.gravatar_qe_about_field_label_location
-        is AboutInputField.Personal.Pronouns -> R.string.gravatar_qe_about_field_label_pronouns
-        is AboutInputField.Personal.Pronunciation -> R.string.gravatar_qe_about_field_label_pronunciation
-        is AboutInputField.Professional.Company -> R.string.gravatar_qe_about_field_label_company
-        is AboutInputField.Professional.JobTitle -> R.string.gravatar_qe_about_field_label_job_title
+private val Set<AboutEditorField>.personalLabelRes: Int?
+    @StringRes get() = if (hasPersonalAndProfessional) {
+        R.string.gravatar_qe_about_field_section_label_personal
+    } else {
+        null
     }
 
-internal val AboutInputField.descriptionRes: Int?
-    @StringRes get() = when (this) {
-        is AboutInputField.Personal.AboutMe -> R.string.gravatar_qe_about_field_description_about_me
-        is AboutInputField.Personal.Pronunciation -> R.string.gravatar_qe_about_field_description_pronunciation
-        is AboutInputField.Personal.DisplayName,
-        is AboutInputField.Personal.Location,
-        is AboutInputField.Personal.Pronouns,
-        is AboutInputField.Professional.Company,
-        is AboutInputField.Professional.JobTitle,
-        -> null
+private val Set<AboutEditorField>.professionalLabelRes: Int?
+    @StringRes get() = if (hasPersonalAndProfessional) {
+        R.string.gravatar_qe_about_field_section_label_professional
+    } else {
+        null
     }
 
-internal fun AboutInputField.copy(value: String): AboutInputField {
-    return when (this) {
-        is AboutInputField.Personal.AboutMe -> AboutInputField.Personal.AboutMe(value)
-        is AboutInputField.Personal.DisplayName -> AboutInputField.Personal.DisplayName(value)
-        is AboutInputField.Personal.Location -> AboutInputField.Personal.Location(value)
-        is AboutInputField.Personal.Pronouns -> AboutInputField.Personal.Pronouns(value)
-        is AboutInputField.Personal.Pronunciation -> AboutInputField.Personal.Pronunciation(value)
-        is AboutInputField.Professional.Company -> AboutInputField.Professional.Company(value)
-        is AboutInputField.Professional.JobTitle -> AboutInputField.Professional.JobTitle(value)
+private val Set<AboutEditorField>.hasPersonalAndProfessional: Boolean
+    get() = any { it.type.isPersonal } && any { it.type.isProfessional }
+
+internal val AboutEditorField.labelRes: Int
+    @StringRes get() = when (this.type) {
+        AboutInputField.AboutMe -> R.string.gravatar_qe_about_field_label_about_me
+        AboutInputField.DisplayName -> R.string.gravatar_qe_about_field_label_display_name
+        AboutInputField.Location -> R.string.gravatar_qe_about_field_label_location
+        AboutInputField.Pronouns -> R.string.gravatar_qe_about_field_label_pronouns
+        AboutInputField.Pronunciation -> R.string.gravatar_qe_about_field_label_pronunciation
+        AboutInputField.Company -> R.string.gravatar_qe_about_field_label_company
+        AboutInputField.JobTitle -> R.string.gravatar_qe_about_field_label_job_title
+        else -> R.string.gravatar_qe_about_field_label_display_name
+    }
+
+internal val AboutEditorField.descriptionRes: Int?
+    @StringRes get() = when (this.type) {
+        AboutInputField.AboutMe -> R.string.gravatar_qe_about_field_description_about_me
+        AboutInputField.Pronunciation -> R.string.gravatar_qe_about_field_description_pronunciation
+        else -> null
     }
-}
 
 @Preview(showBackground = true)
 @Composable
 internal fun AboutSectionPreview() {
     GravatarTheme {
-        Box(modifier = Modifier.padding(10.dp)) {
-            AboutSection(
-                aboutFields = AboutFields(
-                    personal = PersonalFields(
-                        aboutMe = AboutInputField.Personal.AboutMe(value = "My description"),
-                        displayName = AboutInputField.Personal.DisplayName(value = "John Doe"),
-                        pronunciation = AboutInputField.Personal.Pronunciation(value = "John Doe"),
-                        pronouns = AboutInputField.Personal.Pronouns(value = "he/him"),
-                        location = AboutInputField.Personal.Location(value = "San Francisco, CA"),
-                    ),
-                    professional = ProfessionalFields(
-                        company = AboutInputField.Professional.Company(value = "Automattic"),
-                        jobTitle = AboutInputField.Professional.JobTitle(value = "Software Engineer"),
-                    ),
+        AboutSection(
+            aboutFields = setOf(
+                AboutEditorField(
+                    type = AboutInputField.DisplayName,
+                    value = "John Doe",
+                    maxLines = 1,
                 ),
-                formEnabled = true,
-                onValueChange = { },
-                modifier = Modifier.fillMaxWidth(),
-            )
-        }
+                AboutEditorField(
+                    type = AboutInputField.AboutMe,
+                    value = "My description",
+                    maxLines = 3,
+                ),
+                AboutEditorField(
+                    type = AboutInputField.Pronunciation,
+                    value = "John Doe",
+                ),
+                AboutEditorField(
+                    type = AboutInputField.Pronouns,
+                    value = "he/him",
+                ),
+                AboutEditorField(
+                    type = AboutInputField.Location,
+                    value = "San Francisco, CA",
+                ),
+                AboutEditorField(
+                    type = AboutInputField.Company,
+                    value = "Automattic",
+                ),
+                AboutEditorField(
+                    type = AboutInputField.JobTitle,
+                    value = "Software Engineer",
+                ),
+            ),
+            formEnabled = true,
+            onValueChange = { },
+            modifier = Modifier.fillMaxWidth(),
+        )
+    }
+}
+
+@Preview(showBackground = true)
+@Composable
+internal fun AboutSectionPersonalOnlyPreview() {
+    GravatarTheme {
+        AboutSection(
+            aboutFields = setOf(
+                AboutEditorField(
+                    type = AboutInputField.DisplayName,
+                    value = "John Doe",
+                    maxLines = 1,
+                ),
+                AboutEditorField(
+                    type = AboutInputField.AboutMe,
+                    value = "My description",
+                    maxLines = 3,
+                ),
+                AboutEditorField(
+                    type = AboutInputField.Pronunciation,
+                    value = "John Doe",
+                ),
+                AboutEditorField(
+                    type = AboutInputField.Pronouns,
+                    value = "he/him",
+                ),
+                AboutEditorField(
+                    type = AboutInputField.Location,
+                    value = "San Francisco, CA",
+                ),
+            ),
+            formEnabled = true,
+            onValueChange = { },
+            modifier = Modifier.fillMaxWidth(),
+        )
     }
 }
diff --git a/gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/abouteditor/components/PersonalSection.kt b/gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/abouteditor/components/PersonalSection.kt
deleted file mode 100644
index e77e76ba2..000000000
--- a/gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/abouteditor/components/PersonalSection.kt
+++ /dev/null
@@ -1,75 +0,0 @@
-package com.gravatar.quickeditor.ui.abouteditor.components
-
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.padding
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.res.stringResource
-import androidx.compose.ui.unit.dp
-import com.gravatar.quickeditor.R
-import com.gravatar.quickeditor.ui.abouteditor.AboutInputField
-import com.gravatar.quickeditor.ui.abouteditor.PersonalFields
-
-@Composable
-internal fun PersonalSection(
-    personalFields: PersonalFields,
-    formEnabled: Boolean,
-    onValueChange: (AboutInputField) -> Unit,
-) {
-    Column {
-        AboutEditSectionLabel(
-            title = stringResource(R.string.gravatar_qe_about_field_section_label_personal),
-            modifier = Modifier.padding(bottom = 8.dp, top = 16.dp),
-        )
-        AboutEditField(
-            label = stringResource(personalFields.displayName.labelRes),
-            value = personalFields.displayName.value,
-            enabled = formEnabled,
-            maxLines = personalFields.displayName.maxLines,
-            description = personalFields.displayName.descriptionRes?.let { stringResource(it) },
-            onValueChange = {
-                onValueChange(personalFields.displayName.copy(value = it))
-            },
-        )
-        AboutEditField(
-            label = stringResource(personalFields.aboutMe.labelRes),
-            value = personalFields.aboutMe.value,
-            enabled = formEnabled,
-            maxLines = personalFields.aboutMe.maxLines,
-            description = personalFields.aboutMe.descriptionRes?.let { stringResource(it) },
-            onValueChange = {
-                onValueChange(personalFields.aboutMe.copy(value = it))
-            },
-        )
-        AboutEditField(
-            label = stringResource(personalFields.pronunciation.labelRes),
-            value = personalFields.pronunciation.value,
-            enabled = formEnabled,
-            maxLines = personalFields.pronunciation.maxLines,
-            description = personalFields.pronunciation.descriptionRes?.let { stringResource(it) },
-            onValueChange = {
-                onValueChange(personalFields.pronunciation.copy(value = it))
-            },
-        )
-        AboutEditField(
-            label = stringResource(personalFields.pronouns.labelRes),
-            value = personalFields.pronouns.value,
-            enabled = formEnabled,
-            maxLines = personalFields.pronouns.maxLines,
-            description = personalFields.pronouns.descriptionRes?.let { stringResource(it) },
-            onValueChange = {
-                onValueChange(personalFields.pronouns.copy(value = it))
-            },
-        )
-        AboutEditField(
-            label = stringResource(personalFields.location.labelRes),
-            value = personalFields.location.value,
-            enabled = formEnabled,
-            maxLines = personalFields.location.maxLines,
-            description = personalFields.location.descriptionRes?.let { stringResource(it) },
-            onValueChange = {
-                onValueChange(personalFields.location.copy(value = it))
-            },
-        )
-    }
-}
diff --git a/gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/abouteditor/components/ProfessionalSection.kt b/gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/abouteditor/components/ProfessionalSection.kt
deleted file mode 100644
index e81e06b3a..000000000
--- a/gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/abouteditor/components/ProfessionalSection.kt
+++ /dev/null
@@ -1,45 +0,0 @@
-package com.gravatar.quickeditor.ui.abouteditor.components
-
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.padding
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.res.stringResource
-import androidx.compose.ui.unit.dp
-import com.gravatar.quickeditor.R
-import com.gravatar.quickeditor.ui.abouteditor.AboutInputField
-import com.gravatar.quickeditor.ui.abouteditor.ProfessionalFields
-
-@Composable
-internal fun ProfessionalSection(
-    professionalFields: ProfessionalFields,
-    formEnabled: Boolean,
-    onValueChange: (AboutInputField) -> Unit,
-) {
-    Column {
-        AboutEditSectionLabel(
-            title = stringResource(R.string.gravatar_qe_about_field_section_label_professional),
-            modifier = Modifier.padding(bottom = 8.dp),
-        )
-        AboutEditField(
-            label = stringResource(professionalFields.jobTitle.labelRes),
-            value = professionalFields.jobTitle.value,
-            enabled = formEnabled,
-            maxLines = professionalFields.jobTitle.maxLines,
-            description = professionalFields.jobTitle.descriptionRes?.let { stringResource(it) },
-            onValueChange = {
-                onValueChange(professionalFields.jobTitle.copy(value = it))
-            },
-        )
-        AboutEditField(
-            label = stringResource(professionalFields.company.labelRes),
-            value = professionalFields.company.value,
-            enabled = formEnabled,
-            maxLines = professionalFields.company.maxLines,
-            description = professionalFields.company.descriptionRes?.let { stringResource(it) },
-            onValueChange = {
-                onValueChange(professionalFields.company.copy(value = it))
-            },
-        )
-    }
-}
diff --git a/gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/editor/AboutInputField.kt b/gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/editor/AboutInputField.kt
index ff48cbe49..d75dc319b 100644
--- a/gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/editor/AboutInputField.kt
+++ b/gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/editor/AboutInputField.kt
@@ -91,4 +91,22 @@ public value class AboutInputField(
             Company,
         )
     }
+
+    internal val isPersonal: Boolean
+        get() = personal.contains(this)
+
+    internal val isProfessional: Boolean
+        get() = professional.contains(this)
+
+    internal val order: Int
+        get() = when (this) {
+            DisplayName -> 0
+            AboutMe -> 1
+            Pronunciation -> 2
+            Pronouns -> 3
+            Location -> 4
+            JobTitle -> 100
+            Company -> 101
+            else -> -1
+        }
 }
diff --git a/gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/editor/QuickEditorScopeOption.kt b/gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/editor/QuickEditorScopeOption.kt
index cee586420..e1ed075de 100644
--- a/gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/editor/QuickEditorScopeOption.kt
+++ b/gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/editor/QuickEditorScopeOption.kt
@@ -40,6 +40,13 @@ public class QuickEditorScopeOption private constructor(
             is Scope.AboutEditor -> AvatarPickerContentLayout.Horizontal
         }
 
+    internal val aboutFields: Set<AboutInputField>
+        get() = when (scope) {
+            is Scope.AboutEditor -> scope.config.fields
+            is Scope.AvatarPickerAndAboutEditor -> scope.config.fields
+            is Scope.AvatarPicker -> AboutInputField.all
+        }
+
     public companion object {
         internal val default = QuickEditorScopeOption(
             scope = Scope.AvatarPicker(AvatarPickerConfiguration.default),
diff --git a/gravatar-quickeditor/src/test/java/com/gravatar/quickeditor/ui/abouteditor/AboutEditorTest.kt b/gravatar-quickeditor/src/test/java/com/gravatar/quickeditor/ui/abouteditor/AboutEditorTest.kt
index e66763a72..3990c977c 100644
--- a/gravatar-quickeditor/src/test/java/com/gravatar/quickeditor/ui/abouteditor/AboutEditorTest.kt
+++ b/gravatar-quickeditor/src/test/java/com/gravatar/quickeditor/ui/abouteditor/AboutEditorTest.kt
@@ -4,23 +4,43 @@ import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.height
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.unit.dp
+import com.gravatar.quickeditor.ui.editor.AboutInputField
 import com.gravatar.quickeditor.ui.gravatarScreenshotTest
 import com.gravatar.uitestutils.RoborazziTest
 import org.junit.Test
 import org.robolectric.annotation.Config
 
 class AboutEditorTest : RoborazziTest() {
-    private val aboutFields = AboutFields(
-        personal = PersonalFields(
-            aboutMe = AboutInputField.Personal.AboutMe(value = "My description"),
-            displayName = AboutInputField.Personal.DisplayName(value = "John Doe"),
-            location = AboutInputField.Personal.Location(value = "San Francisco, CA"),
-            pronunciation = AboutInputField.Personal.Pronunciation(value = "John Doe"),
-            pronouns = AboutInputField.Personal.Pronouns(value = "he/him"),
+    private val aboutFields = setOf(
+        AboutEditorField(
+            type = AboutInputField.DisplayName,
+            value = "John Doe",
+            maxLines = 1,
         ),
-        professional = ProfessionalFields(
-            company = AboutInputField.Professional.Company(value = "Automattic"),
-            jobTitle = AboutInputField.Professional.JobTitle(value = "Software Engineer"),
+        AboutEditorField(
+            type = AboutInputField.AboutMe,
+            value = "My description",
+            maxLines = 3,
+        ),
+        AboutEditorField(
+            type = AboutInputField.Pronunciation,
+            value = "John Doe",
+        ),
+        AboutEditorField(
+            type = AboutInputField.Pronouns,
+            value = "he/him",
+        ),
+        AboutEditorField(
+            type = AboutInputField.Location,
+            value = "San Francisco, CA",
+        ),
+        AboutEditorField(
+            type = AboutInputField.JobTitle,
+            value = "Software Engineer",
+        ),
+        AboutEditorField(
+            type = AboutInputField.Company,
+            value = "Automattic",
         ),
     )
 
@@ -36,6 +56,18 @@ class AboutEditorTest : RoborazziTest() {
         )
     }
 
+    @Test
+    fun aboutEditorPersonalLoaded() = gravatarScreenshotTest {
+        AboutEditor(
+            uiState = AboutEditorUiState(
+                aboutFields = aboutFields.filter { it.type.isPersonal }.toSet(),
+                isLoading = false,
+            ),
+            onSaveClick = { },
+            onValueChange = { },
+        )
+    }
+
     @Config(qualifiers = "+night")
     @Test
     fun aboutEditorLoadedDark() = gravatarScreenshotTest {
diff --git a/gravatar-quickeditor/src/test/java/com/gravatar/quickeditor/ui/abouteditor/AboutEditorViewModelTest.kt b/gravatar-quickeditor/src/test/java/com/gravatar/quickeditor/ui/abouteditor/AboutEditorViewModelTest.kt
index fa9a71537..9e2e7582c 100644
--- a/gravatar-quickeditor/src/test/java/com/gravatar/quickeditor/ui/abouteditor/AboutEditorViewModelTest.kt
+++ b/gravatar-quickeditor/src/test/java/com/gravatar/quickeditor/ui/abouteditor/AboutEditorViewModelTest.kt
@@ -5,6 +5,7 @@ import com.gravatar.extensions.defaultProfile
 import com.gravatar.quickeditor.data.models.QuickEditorError
 import com.gravatar.quickeditor.data.repository.ProfileRepository
 import com.gravatar.quickeditor.ui.CoroutineTestRule
+import com.gravatar.quickeditor.ui.editor.AboutInputField
 import com.gravatar.restapi.models.UpdateProfileRequest
 import com.gravatar.services.GravatarResult
 import com.gravatar.types.Email
@@ -41,6 +42,7 @@ class AboutEditorViewModelTest {
         pronunciation = ""
         pronouns = ""
     }
+    private val visibleAboutFields = AboutInputField.all
 
     @Before
     fun setup() {
@@ -57,7 +59,7 @@ class AboutEditorViewModelTest {
             assertEquals(
                 AboutEditorUiState(
                     isLoading = false,
-                    aboutFields = profile.aboutFields,
+                    aboutFields = profile.aboutFields(visibleAboutFields),
                 ),
                 awaitItem(),
             )
@@ -88,8 +90,9 @@ class AboutEditorViewModelTest {
         viewModel = initViewModel()
         viewModel.onEvent(
             AboutEditorEvent.OnAboutFieldUpdated(
-                AboutInputField.Personal.DisplayName(
-                    "Updated Name",
+                AboutEditorField(
+                    type = AboutInputField.DisplayName,
+                    value = "Updated Name",
                 ),
             ),
         )
@@ -103,14 +106,14 @@ class AboutEditorViewModelTest {
             assertEquals(
                 AboutEditorUiState(
                     savingProfile = true,
-                    aboutFields = updatedProfile.aboutFields,
+                    aboutFields = updatedProfile.aboutFields(visibleAboutFields),
                 ),
                 awaitItem(),
             )
             assertEquals(
                 AboutEditorUiState(
                     savingProfile = false,
-                    aboutFields = updatedProfile.aboutFields,
+                    aboutFields = updatedProfile.aboutFields(visibleAboutFields),
                 ),
                 awaitItem(),
             )
@@ -129,8 +132,9 @@ class AboutEditorViewModelTest {
         viewModel = initViewModel()
         viewModel.onEvent(
             AboutEditorEvent.OnAboutFieldUpdated(
-                AboutInputField.Personal.DisplayName(
-                    "Updated Name",
+                AboutEditorField(
+                    type = AboutInputField.DisplayName,
+                    value = "Updated Name",
                 ),
             ),
         )
@@ -144,14 +148,14 @@ class AboutEditorViewModelTest {
             assertEquals(
                 AboutEditorUiState(
                     savingProfile = true,
-                    aboutFields = updatedProfile.aboutFields,
+                    aboutFields = updatedProfile.aboutFields(visibleAboutFields),
                 ),
                 awaitItem(),
             )
             assertEquals(
                 AboutEditorUiState(
                     savingProfile = false,
-                    aboutFields = updatedProfile.aboutFields,
+                    aboutFields = updatedProfile.aboutFields(visibleAboutFields),
                 ),
                 awaitItem(),
             )
@@ -180,8 +184,9 @@ class AboutEditorViewModelTest {
 
         viewModel.onEvent(
             AboutEditorEvent.OnAboutFieldUpdated(
-                AboutInputField.Personal.DisplayName(
-                    "Updated Name",
+                AboutEditorField(
+                    type = AboutInputField.DisplayName,
+                    value = "Updated Name",
                 ),
             ),
         )
@@ -200,8 +205,9 @@ class AboutEditorViewModelTest {
 
         viewModel.onEvent(
             AboutEditorEvent.OnAboutFieldUpdated(
-                AboutInputField.Personal.DisplayName(
-                    "Updated Name",
+                AboutEditorField(
+                    type = AboutInputField.DisplayName,
+                    value = "Updated Name",
                 ),
             ),
         )
@@ -227,8 +233,9 @@ class AboutEditorViewModelTest {
 
         viewModel.onEvent(
             AboutEditorEvent.OnAboutFieldUpdated(
-                AboutInputField.Personal.DisplayName(
-                    "Updated Name",
+                AboutEditorField(
+                    type = AboutInputField.DisplayName,
+                    value = "Updated Name",
                 ),
             ),
         )
@@ -247,8 +254,46 @@ class AboutEditorViewModelTest {
         }
     }
 
-    private fun initViewModel() = AboutEditorViewModel(
+    @Test
+    fun `given only personal about section visible when profile fetched then uiState is updated`() = runTest {
+        viewModel = initViewModel(aboutFields = AboutInputField.personal)
+
+        viewModel.uiState.test {
+            assertEquals(AboutEditorUiState(isLoading = false), awaitItem())
+            assertEquals(AboutEditorUiState(isLoading = true), awaitItem())
+            assertEquals(
+                setOf(
+                    AboutEditorField(
+                        type = AboutInputField.DisplayName,
+                        value = profile.displayName,
+                        maxLines = 1,
+                    ),
+                    AboutEditorField(
+                        type = AboutInputField.AboutMe,
+                        value = profile.description,
+                        maxLines = 3,
+                    ),
+                    AboutEditorField(
+                        type = AboutInputField.Pronunciation,
+                        value = profile.pronunciation,
+                    ),
+                    AboutEditorField(
+                        type = AboutInputField.Pronouns,
+                        value = profile.pronouns,
+                    ),
+                    AboutEditorField(
+                        type = AboutInputField.Location,
+                        value = profile.location,
+                    ),
+                ),
+                awaitItem().aboutFields,
+            )
+        }
+    }
+
+    private fun initViewModel(aboutFields: Set<AboutInputField> = visibleAboutFields) = AboutEditorViewModel(
         email = email,
         profileRepository = profileRepository,
+        visibleAboutFields = aboutFields,
     )
 }


Reviews:
user: login: copilot-pull-request-reviewer[bot]
body: ## Pull Request Overview

This PR implements a configuration option that restricts the display of About input fields in the editors by passing a set of visible fields down through the view model and UI components. Key changes include:
- Replacing usages of AboutInputField with AboutEditorField in the editor components and tests.
- Updating the view model and profile mapping to respect the configured visibility flags.
- Adding a new about fields picker in the demo app to allow dynamic field configuration.

### Reviewed Changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 1 comment.

<details>
<summary>Show a summary per file</summary>

| File | Description |
| ---- | ----------- |
| AboutEditorViewModelTest.kt | Updated tests to use the new visibility configuration and field type. |
| AboutEditorTest.kt | Modified tests to verify the UI state correctly reflects visible fields. |
| QuickEditorScopeOption.kt | Added a getter to expose aboutFields based on the scope configuration. |
| ProfessionalSection.kt, PersonalSection.kt, AboutSection.kt | Wrapped field rendering with conditional visibility checks and updated field types. |
| AboutFields.kt | Modified data classes and update functions to use AboutEditorField with a new visible flag. |
| AboutEditorViewModel.kt | Changed the view model to map the profile using configured visible fields and updated API types. |
| AboutEditorEvent.kt, AboutEditor.kt | Adjusted event and editor definitions to use AboutEditorField. |
| AboutFieldsBottomSheet.kt | Adapted the bottom sheet component to work with the field configuration. |
| AvatarUpdateTab.kt | Integrated an about fields picker and updated scope configuration to use the chosen fields. |
| demo-app/build.gradle.kts | Added a dependency on composable core components. |
</details>





state: COMMENTED
author_association: NONE
submitted_at: 2025-05-16T08:20:36Z
user: login: copilot-pull-request-reviewer[bot]
body: ## Pull Request Overview

This PR adds support for displaying only configured About input fields in the editor based on scope settings.  
- Passes `aboutFields` from scope config into `AboutEditorViewModel` to control visibility.  
- Refactors state and UI to use `AboutEditorField` sets instead of fixed `AboutFields` classes.  
- Introduces a bottom sheet in the demo app for selecting visible About input fields.

### Reviewed Changes

Copilot reviewed 19 out of 19 changed files in this pull request and generated 3 comments.

<details>
<summary>Show a summary per file</summary>

| File                                           | Description                                                             |
| ---------------------------------------------- | ----------------------------------------------------------------------- |
| AboutEditorViewModelTest.kt                    | Updated tests to use new `AboutEditorField` API                         |
| AboutEditorViewModel.kt                        | Accepts `visibleAboutFields` and maps profile fields accordingly        |
| AboutSection.kt                                | Refactored UI to render dynamic field sets                              |
| AboutInputField.kt                             | Added ordering and category helpers for fields                          |
| AboutFieldsBottomSheet.kt                      | New UI for picking visible About fields in demo app                    |
| AvatarUpdateTab.kt                             | Integrated bottom sheet and bound selected fields in demo app          |
</details>



<details>
<summary>Comments suppressed due to low confidence (3)</summary>

**gravatar-quickeditor/src/test/java/com/gravatar/quickeditor/ui/abouteditor/AboutEditorViewModelTest.kt:258**
* You’ve added a test for personal-only visibility—consider adding a complementary test for the professional-only case to ensure that section toggling works as expected.
```
fun `given only personal about section visible when profile fetched then uiState is updated`() = runTest {
```
**demo-app/src/main/java/com/gravatar/demoapp/ui/components/AboutFieldsBottomSheet.kt:44**
* [nitpick] The parameter name `aboutFields` in this sheet conflicts with the editor’s `aboutFields` type (`AboutEditorField`). Consider renaming to `selectedFields` or similar for clarity.
```
internal fun AboutFieldsBottomSheet( aboutFields: Set<AboutInputField>,
```
**gravatar-quickeditor/src/test/java/com/gravatar/quickeditor/ui/abouteditor/AboutEditorViewModelTest.kt:8**
* Tests reference `AboutEditorField`, but there's no import; add `import com.gravatar.quickeditor.ui.abouteditor.AboutEditorField` to avoid compilation errors.
```
import com.gravatar.quickeditor.ui.editor.AboutInputField
```
</details>


state: COMMENTED
author_association: NONE
submitted_at: 2025-05-16T12:40:00Z
user: login: etoledom
body: Looking great 🎉 

One small detail comparing with Figma:
It seems that when there's only one section present, the section title is not being shown:

| Figma | Implemented |
| ------ | ----- |
| ![CleanShot 2025-05-19 at 08 27 08@2x](https://github.com/user-attachments/assets/ca557b85-1fe2-4df5-8699-5fd3d754a633) | ![CleanShot 2025-05-19 at 08 40 10@2x](https://github.com/user-attachments/assets/54fdb92a-29dd-43c7-ae17-6367fb1b18eb) |

This is how it was implemented on iOS also.

If there are fields from only one section, there's no section title. But when there are at least 1 field from each section, the section titles are being shown.

| Same section | Different sections |
| ------ | ----- |
| ![CleanShot 2025-05-19 at 08 45 53@2x](https://github.com/user-attachments/assets/07374b78-386f-4cf4-a761-df94cb2df549) | ![CleanShot 2025-05-19 at 08 46 06@2x](https://github.com/user-attachments/assets/5e9b52b3-3caf-4380-8dd2-65313c1052d6) |


state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-19T06:47:41Z
user: login: etoledom
body: Looking great! Thank you for the update 🙏 
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-19T12:56:45Z

Review comments:
diff_hunk: @@ -153,22 +155,42 @@ internal class AboutEditorViewModel(
     }
 }
 
-internal val Profile.aboutFields: AboutFields
-    get() {
-        return AboutFields(
-            personal = PersonalFields(
-                displayName = AboutInputField.Personal.DisplayName(value = displayName),
-                aboutMe = AboutInputField.Personal.AboutMe(value = description),
-                location = AboutInputField.Personal.Location(value = location),
-                pronouns = AboutInputField.Personal.Pronouns(value = pronouns),
-                pronunciation = AboutInputField.Personal.Pronunciation(value = pronunciation),
+internal fun Profile.aboutFields(visibleAboutFields: Set<AboutInputField>): AboutFields {
path: gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/abouteditor/AboutEditorViewModel.kt
user: login: Copilot
body: The configuration set is of type AboutInputField while the constructed fields are based on AboutEditorField. Consider ensuring a consistent type or a proper mapping between the two to avoid potential equality mismatches.
created_at: 2025-05-16T08:20:36Z
author_association: NONE
diff_hunk: @@ -9,90 +9,137 @@ import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.layout.padding
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.tooling.preview.Preview
 import androidx.compose.ui.unit.dp
 import com.gravatar.quickeditor.R
-import com.gravatar.quickeditor.ui.abouteditor.AboutFields
-import com.gravatar.quickeditor.ui.abouteditor.AboutInputField
-import com.gravatar.quickeditor.ui.abouteditor.PersonalFields
-import com.gravatar.quickeditor.ui.abouteditor.ProfessionalFields
+import com.gravatar.quickeditor.ui.abouteditor.AboutEditorField
+import com.gravatar.quickeditor.ui.editor.AboutInputField
 import com.gravatar.ui.GravatarTheme
 
 @Composable
 internal fun AboutSection(
-    aboutFields: AboutFields,
+    aboutFields: Set<AboutEditorField>,
     formEnabled: Boolean,
-    onValueChange: (AboutInputField) -> Unit,
+    onValueChange: (AboutEditorField) -> Unit,
     modifier: Modifier = Modifier,
 ) {
     Column(modifier = modifier) {
-        PersonalSection(
-            personalFields = aboutFields.personal,
-            formEnabled = formEnabled,
-            onValueChange = onValueChange,
-        )
-        Spacer(modifier = Modifier.height(16.dp))
-        ProfessionalSection(
-            professionalFields = aboutFields.professional,
-            formEnabled = formEnabled,
-            onValueChange = onValueChange,
-        )
+        if (aboutFields.any { it.type.isPersonal }) {
+            AboutFieldsSection(
+                label = stringResource(R.string.gravatar_qe_about_field_section_label_personal),
+                fields = aboutFields.filter { it.type.isPersonal }.toSet(),
+                formEnabled = formEnabled,
+                onValueChange = onValueChange,
+                modifier = Modifier.padding(top = 16.dp),
+            )
+        }
+        if (aboutFields.any { it.type.isProfessional }) {
+            Spacer(modifier = Modifier.height(16.dp))
+            AboutFieldsSection(
+                label = stringResource(R.string.gravatar_qe_about_field_section_label_professional),
+                fields = aboutFields.filter { it.type.isProfessional }.toSet(),
+                formEnabled = formEnabled,
+                onValueChange = onValueChange,
+            )
+        }
         Spacer(modifier = Modifier.height(8.dp))
     }
 }
 
-internal val AboutInputField.labelRes: Int
-    @StringRes get() = when (this) {
-        is AboutInputField.Personal.AboutMe -> R.string.gravatar_qe_about_field_label_about_me
-        is AboutInputField.Personal.DisplayName -> R.string.gravatar_qe_about_field_label_display_name
-        is AboutInputField.Personal.Location -> R.string.gravatar_qe_about_field_label_location
-        is AboutInputField.Personal.Pronouns -> R.string.gravatar_qe_about_field_label_pronouns
-        is AboutInputField.Personal.Pronunciation -> R.string.gravatar_qe_about_field_label_pronunciation
-        is AboutInputField.Professional.Company -> R.string.gravatar_qe_about_field_label_company
-        is AboutInputField.Professional.JobTitle -> R.string.gravatar_qe_about_field_label_job_title
+internal val AboutEditorField.labelRes: Int
+    @StringRes get() = when (this.type) {
+        AboutInputField.AboutMe -> R.string.gravatar_qe_about_field_label_about_me
+        AboutInputField.DisplayName -> R.string.gravatar_qe_about_field_label_display_name
+        AboutInputField.Location -> R.string.gravatar_qe_about_field_label_location
+        AboutInputField.Pronouns -> R.string.gravatar_qe_about_field_label_pronouns
+        AboutInputField.Pronunciation -> R.string.gravatar_qe_about_field_label_pronunciation
+        AboutInputField.Company -> R.string.gravatar_qe_about_field_label_company
+        AboutInputField.JobTitle -> R.string.gravatar_qe_about_field_label_job_title
+        else -> R.string.gravatar_qe_about_field_label_display_name
path: gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/abouteditor/components/AboutSection.kt
user: login: Copilot
body: [nitpick] Mapping all unspecified types to the DisplayName label can mask missing cases. Consider handling each `AboutInputField` explicitly or throwing an exception for unknown types to surface omissions.
```suggestion
        else -> throw IllegalArgumentException("Unknown AboutInputField type: $type")
```
created_at: 2025-05-16T12:39:59Z
author_association: NONE
diff_hunk: @@ -153,33 +161,41 @@ internal class AboutEditorViewModel(
     }
 }
 
-internal val Profile.aboutFields: AboutFields
-    get() {
-        return AboutFields(
-            personal = PersonalFields(
-                displayName = AboutInputField.Personal.DisplayName(value = displayName),
-                aboutMe = AboutInputField.Personal.AboutMe(value = description),
-                location = AboutInputField.Personal.Location(value = location),
-                pronouns = AboutInputField.Personal.Pronouns(value = pronouns),
-                pronunciation = AboutInputField.Personal.Pronunciation(value = pronunciation),
-            ),
-            professional = ProfessionalFields(
-                company = AboutInputField.Professional.Company(value = company),
-                jobTitle = AboutInputField.Professional.JobTitle(value = jobTitle),
-            ),
-        )
-    }
+internal fun Profile.aboutFields(visibleAboutFields: Set<AboutInputField>): Set<AboutEditorField> {
+    return visibleAboutFields
+        .map {
+            AboutEditorField(
+                type = it,
+                value = when (it) {
+                    AboutInputField.DisplayName -> displayName
+                    AboutInputField.AboutMe -> description
+                    AboutInputField.Pronouns -> pronouns
+                    AboutInputField.Pronunciation -> pronunciation
+                    AboutInputField.Location -> location
+                    AboutInputField.JobTitle -> jobTitle
+                    AboutInputField.Company -> company
+                    else -> ""
path: gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/abouteditor/AboutEditorViewModel.kt
user: login: Copilot
body: [nitpick] Using an empty string fallback for unexpected `AboutInputField` types may hide errors. It’s safer to explicitly handle each case or log a warning when an unmapped type appears.
```suggestion
                    else -> {
                        Log.w("AboutEditorViewModel", "Unhandled AboutInputField type: $it")
                        ""
                    }
```
created_at: 2025-05-16T12:40:00Z
author_association: NONE
diff_hunk: @@ -91,4 +91,22 @@ public value class AboutInputField(
             Company,
         )
     }
+
+    internal val isPersonal: Boolean
+        get() = personal.contains(this)
+
+    internal val isProfessional: Boolean
+        get() = professional.contains(this)
+
+    internal val order: Int
+        get() = when (this) {
+            DisplayName -> 0
+            AboutMe -> 1
+            Pronunciation -> 2
+            Pronouns -> 3
+            Location -> 4
+            JobTitle -> 100
+            Company -> 101
path: gravatar-quickeditor/src/main/java/com/gravatar/quickeditor/ui/editor/AboutInputField.kt
user: login: Copilot
body: [nitpick] Using large, non-contiguous magic numbers for ordering (e.g., 100, 101) can be confusing. Consider using a small contiguous range or named constants with comments explaining the gaps.
```suggestion
            JobTitle -> PROFESSIONAL_START_ORDER
            Company -> PROFESSIONAL_START_ORDER + 1
```
created_at: 2025-05-16T12:40:00Z
author_association: NONE

PR comments:
user: login: wpmobilebot
created_at: 2025-05-16T08:25:05Z
body: <!-- REUSE_ID: app-prototype-build-link -->

<details><summary>📲 You can test the changes from this Pull Request in <b>Gravatar Demo</b> by scanning the QR code below to install the corresponding build.</summary>
<table>
<tr>
  <td rowspan='3' width='260px'><img src='https://api.qrserver.com/v1/create-qr-code/?size=500x500&qzone=4&data=https%3A%2F%2Fcdn.a8c-ci.services%2F428e0f921ef77474515d6e3cdb7d3e0a4f1f62c9%2Fgravatar-demo-prototype-build-pr631-4179c74.apk' width='250' height='250' /></td>
  <td><b>App Name</b></td><td>Gravatar Demo</td>
</tr>
<tr><td><b>Commit</b></td><td>4179c74e68002155958337d7c0406573d8262518</td></tr>
<tr><td><b>Direct Download</b></td><td><a href='https://cdn.a8c-ci.services/428e0f921ef77474515d6e3cdb7d3e0a4f1f62c9/gravatar-demo-prototype-build-pr631-4179c74.apk'><code>gravatar-demo-prototype-build-pr631-4179c74.apk</code></a></td></tr>
</table>
</details>

author_association: COLLABORATOR
user: login: AdamGrzybkowski
created_at: 2025-05-16T10:31:49Z
body: @etoledom I've marked this as a Draft. I'm not 100% happy with how the state is modeled in the `AboutEditorViewModel` and I want to change that.
author_association: CONTRIBUTOR
user: login: AdamGrzybkowski
created_at: 2025-05-16T11:51:17Z
body: @etoledom This is now ready to review. I did modify the model for the AboutEditor state in https://github.com/Automattic/Gravatar-SDK-Android/pull/631/commits/94bcfd74cb260efba97aa9d69682ddade7e4c2f6. Mainly, I've decided to keep about fields as a `Set` rather than having them all defined with a visibility flag set. Now we simply hold only those that should be visible. This significantly reduced the complexity of the UI components and even reduced the number of them as they are now more generic. 
author_association: CONTRIBUTOR
user: login: AdamGrzybkowski
created_at: 2025-05-19T07:41:48Z
body: Ohh I missed that detail, thanks. 
author_association: CONTRIBUTOR
user: login: AdamGrzybkowski
created_at: 2025-05-19T08:04:50Z
body: @etoledom Fixed!
author_association: CONTRIBUTOR