Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6d49f7b6 authored by Ioana Alexandru's avatar Ioana Alexandru
Browse files

[Compose Notifs] Support large icon

Add the large icon to the compose layout. Also include a dummy top line
for now so we have the correct alignment.

Bug: 431222735
Test: manual in the Gallery app
Flag: EXEMPT code not in production yet
Change-Id: I18182c03de7d639a8759821b67016b6aaae549d7
parent 2f6de35b
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
@@ -42,3 +43,14 @@ internal fun AppIcon(drawable: Drawable, modifier: Modifier = Modifier) {
        )
    }
}

@Composable
internal fun LargeIcon(drawable: Drawable, modifier: Modifier = Modifier) {
    Image(
        painter = rememberDrawablePainter(drawable),
        contentDescription = null,
        // TODO: b/431222735 - Add support for different aspect ratio large icons.
        modifier = modifier.size(48.dp).clip(RoundedCornerShape(5.dp)),
        contentScale = ContentScale.Crop,
    )
}
+12 −1
Original line number Diff line number Diff line
@@ -27,7 +27,13 @@ import androidx.compose.ui.text.style.TextOverflow.Companion.Ellipsis

@Composable
internal fun Title(title: String, modifier: Modifier = Modifier) {
    Text(title, modifier, style = MaterialTheme.typography.titleSmallEmphasized)
    Text(
        title,
        modifier,
        style = MaterialTheme.typography.titleSmallEmphasized,
        maxLines = 1,
        overflow = Ellipsis,
    )
}

@Composable
@@ -51,3 +57,8 @@ internal fun ExpandedText(content: String, maxLines: Int, modifier: Modifier = M
        overflow = Ellipsis,
    )
}

@Composable
internal fun TopLineText(text: String, modifier: Modifier = Modifier) {
    Text(text, modifier, style = MaterialTheme.typography.bodySmallEmphasized, maxLines = 1)
}
+86 −15
Original line number Diff line number Diff line
@@ -17,13 +17,12 @@
package com.android.systemui.notifications.ui.composable.content

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@@ -32,33 +31,105 @@ import com.android.systemui.notifications.ui.composable.component.AppIcon
import com.android.systemui.notifications.ui.composable.component.CollapsedText
import com.android.systemui.notifications.ui.composable.component.ExpandedText
import com.android.systemui.notifications.ui.composable.component.Expander
import com.android.systemui.notifications.ui.composable.component.LargeIcon
import com.android.systemui.notifications.ui.composable.component.Title
import com.android.systemui.notifications.ui.composable.component.TopLineText
import com.android.systemui.notifications.ui.viewmodel.NotificationViewModel

@Composable
public fun NotificationContent(viewModel: NotificationViewModel, modifier: Modifier = Modifier) {
    // TODO: b/431222735 - Handle transitions using STL.
    // TODO: b/431222735 - Handle empty text edge cases.
    if (!viewModel.isExpanded) {
        NotificationRow(
            viewModel,
            firstLine = { Title(viewModel.title) },
            secondLine = { CollapsedText(viewModel.text) },
            modifier,
        )
    } else {
        NotificationRow(
            viewModel,
            firstLine = {
                // TODO: b/431222735 - Implement the top line properly.
                TopLineText("Placeholder • Top Line Text", Modifier.padding(vertical = 2.dp))
            },
            secondLine = { Title(viewModel.title) },
            modifier,
        ) {
            ExpandedText(viewModel.text, maxLines = viewModel.maxLinesWhenExpanded)
        }
    }
}

@Composable
private fun NotificationRow(
    viewModel: NotificationViewModel,
    firstLine: @Composable () -> Unit,
    secondLine: @Composable () -> Unit,
    modifier: Modifier = Modifier,
    content: (@Composable () -> Unit)? = null,
) {
    Row(
        modifier.padding(16.dp).heightIn(max = viewModel.maxHeightDp.dp),
        modifier
            .heightIn(max = viewModel.maxHeightDp.dp)
            .padding(vertical = 12.dp, horizontal = 16.dp),
        verticalAlignment = Alignment.Top,
    ) {
        AppIcon(viewModel.appIcon)
        Spacer(Modifier.width(16.dp))
        AppIcon(viewModel.appIcon, Modifier.padding(top = 4.dp, bottom = 4.dp, end = 16.dp))
        Column(Modifier.weight(1f)) {
            Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
                Title(viewModel.title)
                Expander(expanded = viewModel.isExpanded)
            if (viewModel.largeIcon != null) {
                HeaderWithLargeIcon(viewModel, firstLine, secondLine)
            } else {
                HeaderWithoutLargeIcon(viewModel, firstLine, secondLine)
            }
            if (content != null) {
                Box(Modifier.padding(top = 4.dp)) { content() }
            }
        }
            MainContent(viewModel)
    }
}

/**
 * When the large icon is present, show the two lines of text, then the icon to the right of them,
 * then the expander.
 */
@Composable
private fun HeaderWithLargeIcon(
    viewModel: NotificationViewModel,
    firstLine: @Composable () -> Unit,
    secondLine: @Composable () -> Unit,
    modifier: Modifier = Modifier,
) {
    Row(modifier.fillMaxWidth()) {
        Column(
            modifier = Modifier.weight(1f).padding(top = 4.dp),
            verticalArrangement = Arrangement.Center,
        ) {
            firstLine()
            secondLine()
        }
        viewModel.largeIcon?.let { LargeIcon(it, Modifier.padding(start = 16.dp, end = 8.dp)) }
        Expander(expanded = viewModel.isExpanded, modifier = Modifier.padding(top = 4.dp))
    }
}

// TODO: b/431222735 - Consider making the various types of content subtypes of a sealed class.
/**
 * When the large icon is not present, the second line of text takes up all the available space
 * under the expander.
 */
@Composable
private fun MainContent(viewModel: NotificationViewModel) {
    return if (viewModel.isExpanded) {
        ExpandedText(viewModel.text, maxLines = viewModel.maxLinesWhenExpanded)
    } else {
        CollapsedText(viewModel.text)
private fun HeaderWithoutLargeIcon(
    viewModel: NotificationViewModel,
    firstLine: @Composable () -> Unit,
    secondLine: @Composable () -> Unit,
    modifier: Modifier = Modifier,
) {
    Column(modifier.padding(top = 4.dp).fillMaxWidth()) {
        Row(verticalAlignment = Alignment.CenterVertically) {
            Box(Modifier.weight(1f)) { firstLine() }
            Expander(expanded = viewModel.isExpanded)
        }
        secondLine()
    }
}
+2 −0
Original line number Diff line number Diff line
@@ -28,6 +28,8 @@ public interface NotificationViewModel {
     * of the content.
     */
    public val appIcon: Drawable
    /** The "large icon" shown on the top end of the notification beside the expander. */
    public val largeIcon: Drawable?

    /** The title of the notification, emphasized in the content. */
    public val title: String