Skip to content

Feat: Migrate About screen to Jetpack Compose with Material 3#6791

Draft
Kota-Jagadeesh wants to merge 13 commits into
commons-app:mainfrom
Kota-Jagadeesh:feat/migrate-about-to-compose
Draft

Feat: Migrate About screen to Jetpack Compose with Material 3#6791
Kota-Jagadeesh wants to merge 13 commits into
commons-app:mainfrom
Kota-Jagadeesh:feat/migrate-about-to-compose

Conversation

@Kota-Jagadeesh
Copy link
Copy Markdown
Collaborator

@Kota-Jagadeesh Kota-Jagadeesh commented Mar 24, 2026

Description (required)

Part of #6626

Changes:

  • Migrated the AboutActivity to a modern, declarative Jetpack Compose architecture.
  • implemented Material 3 components, including CenterAlignedTopAppBar, Card, and AssistChip.
  • Centralized the color management using a custom CommonsTheme to ensure perfect support for both Light and Dark modes.
  • and grouped the UI actions into an AboutActions data class for better scalability and cleaner code structure.
  • then refactored the layout to use a modern card-based design with interactive social icons and link rows.

Tests performed (required)

Tested ProdDebug on Redmi Note 13 Pro with API level 35.

Screenshots (for UI changes only)

Before (XML) After (Compose)

Copy link
Copy Markdown
Collaborator

@RitikaPahwa4444 RitikaPahwa4444 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @Kota-Jagadeesh. I would have tried to loop in the WMF design team for a review on design but since this is a very basic one, we're good to migrate it at this point.

Do we still need the corresponding XML file? If not, please remove it.

Card(
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(16.dp),
colors = CardDefaults.cardColors(containerColor = if (isSystemInDarkTheme()) Color(0xFF1E1E1E) else Color.White),
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about maintaining colors in one file? Those could be reused later in other activities according to the theme. Same goes for other primary design tokens.

@Kota-Jagadeesh
Copy link
Copy Markdown
Collaborator Author

@RitikaPahwa4444 moved all colors into thee new, reusable CommonsTheme file to allow for consistent styling across the app. and, removed activity_about.xml file as it is no longer needed 🙂

@Composable
fun EnhancedLinkRow(text: String, onClick: () -> Unit) {
Row(modifier = Modifier.fillMaxWidth().clickable { onClick() }.padding(16.dp), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.SpaceBetween) {
Text(text = text, style = MaterialTheme.typography.bodyLarge, color = MaterialTheme.colorScheme.onSurface)
Copy link
Copy Markdown
Collaborator

@neeldoshii neeldoshii Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we create a reusable component for TextView this will be helpful in reusing for other screens?

fun CommonsText(
    text: AnnotatedString,
    preset: CommonsTextPreset,
    modifier: Modifier = Modifier,
    color: Color = Color.Unspecified,
    textAlign: TextAlign? = null,
    maxLines: Int = Int.MAX_VALUE,
    overflow: TextOverflow = TextOverflow.Clip,
    softWrap: Boolean = true,
)

@RitikaPahwa4444 for future component should we have a predefined text style format which can be used like below? Should we get this from Wikimedia designer?

Edit : Android Doc Suggest Something like this https://developer.android.com/codelabs/jetpack-compose-theming#5

enum class CommonsTextPreset {
    Body,
    BodySmall,
    Title,
    TitleSmall,
    Label,
}

@Composable
private fun CommonsTextPreset.toTextStyle(): TextStyle =
    when (this) {
        CommonsTextPreset.Body -> MaterialTheme.typography.bodyLarge
        CommonsTextPreset.BodySmall -> MaterialTheme.typography.bodySmall
        CommonsTextPreset.Title -> MaterialTheme.typography.titleLarge
        CommonsTextPreset.TitleSmall -> MaterialTheme.typography.titleSmall
        CommonsTextPreset.Label -> MaterialTheme.typography.labelLarge
    }

or

pass it like this

@Immutable
data class TextPreset(
    val fontFamily: FontFamily,
    val fontWeight: FontWeight,
    val fontSize: TextUnit,
    val lineHeight: TextUnit,
) {
    internal fun toTextStyle(): TextStyle = TextStyle(
        fontFamily = fontFamily,
        fontWeight = fontWeight,
        fontSize = fontSize,
        lineHeight = lineHeight,
    )
}
object Roboto {
    private val family: FontFamily = FontFamily.Default
    object Medium {
        val sp14 = TextPreset(family, FontWeight.Medium, 14.sp, 20.sp)
        val sp16 = TextPreset(family, FontWeight.Medium, 16.sp, 24.sp)
        val sp18 = TextPreset(family, FontWeight.Medium, 18.sp, 26.sp)
    }
    // Regular, Bold, ...
}
object AppTypographyTokens {
    val Medium = Roboto.Medium
    val Regular = Roboto.Regular
    val Bold = Roboto.Bold
}


Call it like this

CommonsText(
    text = "Caption",
    color = Color.Black,
    preset = Roboto.Medium.sp16,
)

Note : Used LLM to generate, also I plan that this CommonsText supports HtmlText bydefault if received. That's why I have given annotatedString as the data type for text.

Both have pros and cons I really like and have used 2nd option as it is readable and debugable, but first one is configurable i.e font family, size one change can make the changes throughout the app.

Can you @ALL suggest what approach should we go also feel free to suggest if you have some other way in mind.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I had a different approach in mind, but that's too much for this PR. I'd suggested to do it for all the design tokens in my earlier comment, but my bad, I need to explain what that is, why we're adopting that style, etc. since not everyone is aware about the design system issue.

I would accept this PR as is, but for any subsequent work on this, I'll create tasks with clear instructions and not accept PRs without any assignees.

Copy link
Copy Markdown
Collaborator

@RitikaPahwa4444 RitikaPahwa4444 Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#6791 (comment)

Not just colors, by primary design tokens I meant everything including typography, sizes, styles, etc. All of them need to be created as separate files with a style similar to the Wikipedia app so that we could generate code leveraging Codex as well.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we create a reusable component for TextView this will be helpful in reusing for other screens?

yes, i will implement that :)

All of them need to be created as separate files

makes sense @RitikaPahwa4444, i will extract all design tokens into separate files :)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want @Kota-Jagadeesh, you can take reference from my PR #5964 or just copy paste the ui/theme folder. That looks good for Custom Selector but please feel free to make any changes as suggested by @RitikaPahwa4444 and @neeldoshii :)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would accept this PR as is, but for any subsequent work on this, I'll create tasks with clear instructions and not accept PRs without any assignees.

I would agree with @RitikaPahwa4444 over here.

Not just colors, by primary design tokens I meant everything including typography, sizes, styles, etc. All of them need to be created as separate files with a style similar to the Wikipedia app so that we could generate code leveraging Codex as well.

Let's not focus on this over here and focus on it properly in a separate PR. Can you revert those changes? @Kota-Jagadeesh. Rest LGTM after that.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the changes have been done already and they look good, let's not revert. Apologies @Kota-Jagadeesh for the conflicting suggestions here.

elevation = CardDefaults.cardElevation(defaultElevation = 2.dp)
) {
Column {
EnhancedLinkRow(stringResource(R.string.about_rate_us), actions.onRateUs)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about we use LazyColumn here, somewhat like the below? WDYT? @Kota-Jagadeesh
pass this as an Item to LazyColumn

data class AboutLinkItem(
    val text: String,
    val onClick: () -> Unit,
)
val aboutLinks = listOf(
    AboutLinkItem(getString(R.string.about_rate_us)) { launchRatings() },
    AboutLinkItem(getString(R.string.user_guide)) { launchUserGuide() },
    AboutLinkItem(getString(R.string.about_privacy_policy)) { launchPrivacyPolicy() },
    AboutLinkItem(getString(R.string.about_translate)) { launchTranslate() },
    AboutLinkItem(getString(R.string.about_credits)) { launchCredits() },
    AboutLinkItem(getString(R.string.about_faq)) { launchFrequentlyAskedQuestions() },
)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for me it feels like a great idea. refactooring the links into a LazyColumn using a data class model, makes the list more scalable and easier to manage. i'll do that, thanks for the review :)

fun CommonsTheme(content: @Composable () -> Unit) {
val isDarkTheme = isSystemInDarkTheme()
val background = if (isDarkTheme)
colorResource(R.color.main_background_dark)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we setup color scheme in the compose way rather than getting it from xml file?

See Doc : https://developer.android.com/codelabs/jetpack-compose-theming#3

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we setup color scheme in the compose way rather than getting it from xml file?

Sure @neeldoshii. i will move the hex values into a Color.kt file and define full lightColorScheme and darkColorScheme objects to remove all dependencies on theXML file.

@Kota-Jagadeesh
Copy link
Copy Markdown
Collaborator Author

by primary design tokens I meant everything including typography, sizes, styles

@neeldoshii @RitikaPahwa4444, i have refactored the implementation to fully align with a token-based design system.

  • extracted the all colors, typography, and spacing/dimensions into seperate files (Color.kt, Type.kt, Spacing.kt)
  • implemented the CommonsText component with a CommonsTextPreset system for the consistent typography.
  • updated the CommonsTheme to use pure Compose color schemes, removing the dependenciees onthe XML color resources.
  • refactored the links section into a LazyColumn using a data model for the better scalability.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 9, 2026

✅ Generated APK variants!

overflow: TextOverflow = TextOverflow.Clip,
fontWeight: FontWeight? = null
) {
CommonsText(AnnotatedString(text), preset, modifier, color, textAlign, maxLines, overflow, fontWeight)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a recursion function call. Why can't we pass AnnotatedString as a type parameter so it will support html.

But for now I would recommned let's use the Text directly and have a separate PR that focuses on design tokens and Codex colour, as said by @RitikaPahwa4444, #6791 (comment).

Feel free to have a ToDo that says that once the component is made, it takes it from there something.

val gigantic = 48.dp
}

object Dimensions {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unsure what's the use of this? I am not sure this is gonna be reused somewhere?

The below makes sense, but having an object for this, I am not sure it's needed. Open for suggestions over here :-)

val cardCorner = 16.dp
val cardElevation = 2.dp

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://developer.android.com/develop/ui/compose/designsystems

The documentation is really good for anyone who wants to dive deeper 🙂

handleWebUrl(this, BuildConfig.PRIVACY_POLICY_URL.toUri())
internal fun launchTranslate() {
val instance = CommonsApplication.instance
val sortedNames = instance.languageLookUpTable!!.getCanonicalNames().toMutableList().apply { Collections.sort(this) }
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make it nullable

showAlertDialog(this, getString(R.string.about_translate_title), getString(R.string.about_translate_message),
getString(R.string.about_translate_proceed), getString(R.string.about_translate_cancel),
{
val langCode = instance.languageLookUpTable!!.getCodes()[spinner.selectedItemPosition]
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same.

elevation = CardDefaults.cardElevation(defaultElevation = Dimensions.cardElevation)
) {
Column {
aboutLinks.forEachIndexed { index, item ->
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of for loop can you pass the aboutLinks list in itemIndexed and utlizie LazyColumn here?

val inflater = menuInflater
inflater.inflate(R.menu.menu_about, menu)
return super.onCreateOptionsMenu(menu)
val aboutLinks = remember {
Copy link
Copy Markdown
Collaborator

@neeldoshii neeldoshii Apr 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you give a good naming convention here, like aboutLinkItemsList? Have you checked does it survives configuration changes?

The above #6791 (comment) was just for reference

@Kota-Jagadeesh
Copy link
Copy Markdown
Collaborator Author

@neeldoshii @RitikaPahwa4444 thanks for the review. i have a tight schedule for the next few days, so i'll get back to this issue after a few days. until then, i'll mark this as a draft

@Kota-Jagadeesh Kota-Jagadeesh reopened this May 5, 2026
@Kota-Jagadeesh Kota-Jagadeesh marked this pull request as draft May 5, 2026 16:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants