Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Jetchat/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ plugins {

android {
compileSdk = libs.versions.compileSdk.get().toInt()
compileSdkMinor = 1
namespace = "com.example.compose.jetchat"

defaultConfig {
Expand Down Expand Up @@ -88,6 +89,9 @@ android {
}

dependencies {

implementation("androidx.compose.ui:ui-graphics:1.13.0-alpha03")

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.

dont add new dependency, rather switch the sample to the Compose alpha BOM


val composeBom = platform(libs.androidx.compose.bom)
implementation(composeBom)
androidTestImplementation(composeBom)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,12 +114,12 @@ val colleagueProfile = ProfileScreenState(
*/
val meProfile = ProfileScreenState(
userId = "me",
photo = R.drawable.ali,
name = "Ali Conors",
photo = R.drawable.img,
name = "Taylor Brooks",
status = "Online",
displayName = "aliconors",
position = "Senior Android Dev at Yearin\nGoogle Developer Expert",
twitter = "twitter.com/aliconors",
displayName = "taylor",
position = "Senior Android Dev at Openlane",
twitter = "twitter.com/taylor",
timeZone = "In your timezone",
commonChannels = null,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,18 @@
package com.example.compose.jetchat.profile

import androidx.compose.foundation.Image
import androidx.compose.foundation.ScrollState
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.systemBarsPadding
import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.FloatingActionButton
Expand All @@ -41,26 +38,27 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.key
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.draw.BlurredEdgeTreatment
import androidx.compose.ui.draw.blur
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.blur.BlurRadiusSpec
import androidx.compose.ui.graphics.blur.BlurStop
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.rememberNestedScrollInteropConnection
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.example.compose.jetchat.FunctionalityNotAvailablePopup
import com.example.compose.jetchat.R
import com.example.compose.jetchat.components.AnimatingFabContent
Expand All @@ -71,10 +69,7 @@ import com.example.compose.jetchat.theme.JetchatTheme

@OptIn(ExperimentalMaterial3Api::class, ExperimentalComposeUiApi::class)
@Composable
fun ProfileScreen(
userData: ProfileScreenState,
nestedScrollInteropConnection: NestedScrollConnection = rememberNestedScrollInteropConnection(),
) {
fun ProfileScreen(userData: ProfileScreenState) {
var functionalityNotAvailablePopupShown by remember { mutableStateOf(false) }
if (functionalityNotAvailablePopupShown) {
FunctionalityNotAvailablePopup { functionalityNotAvailablePopupShown = false }
Expand All @@ -84,42 +79,26 @@ fun ProfileScreen(

BoxWithConstraints(
modifier = Modifier
.fillMaxSize()
.nestedScroll(nestedScrollInteropConnection)
.systemBarsPadding(),
.fillMaxSize(),
) {
Surface {
Column(
modifier = Modifier
.fillMaxSize()
.background(color = Color(0xFFEAE9FC))

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.

pull the background color from the theme

.verticalScroll(scrollState),
) {
ProfileHeader(
scrollState,
userData,
this@BoxWithConstraints.maxHeight,
)
ProfileHeader(userData)
UserInfoFields(userData, this@BoxWithConstraints.maxHeight)
}
}

val fabExtended by remember { derivedStateOf { scrollState.value == 0 } }
ProfileFab(
extended = fabExtended,
userIsMe = userData.isMe(),
modifier = Modifier
.align(Alignment.BottomEnd)
// Offsets the FAB to compensate for CoordinatorLayout collapsing behaviour
.offset(y = ((-100).dp)),
onFabClicked = { functionalityNotAvailablePopupShown = true },
)
}
}

@Composable
private fun UserInfoFields(userData: ProfileScreenState, containerHeight: Dp) {
Column {
Spacer(modifier = Modifier.height(8.dp))
Spacer(modifier = Modifier.height(40.dp))

NameAndPosition(userData)

Expand Down Expand Up @@ -160,7 +139,12 @@ private fun Name(userData: ProfileScreenState, modifier: Modifier = Modifier) {
Text(
text = userData.name,
modifier = modifier,
style = MaterialTheme.typography.headlineSmall,
style = TextStyle(
fontSize = 74.sp,
lineHeight = 70.82.sp,
fontWeight = FontWeight(800),
color = Color(0xFF1D1B1F),

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.

pull text style from theme

),
)
}

Expand All @@ -169,28 +153,33 @@ private fun Position(userData: ProfileScreenState, modifier: Modifier = Modifier
Text(
text = userData.position,
modifier = modifier,
style = MaterialTheme.typography.bodyLarge,
color = MaterialTheme.colorScheme.onSurfaceVariant,
style = TextStyle(

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.

pull text style from theme

fontSize = 16.sp,
lineHeight = 24.sp,
fontWeight = FontWeight(400),
color = Color(0xFF48454F),
),
)
}

@Composable
private fun ProfileHeader(scrollState: ScrollState, data: ProfileScreenState, containerHeight: Dp) {
val offset = (scrollState.value / 2)
val offsetDp = with(LocalDensity.current) { offset.toDp() }
private fun ProfileHeader(data: ProfileScreenState) {

data.photo?.let {
Image(
modifier = Modifier
.heightIn(max = containerHeight / 2)
.fillMaxWidth()
// TODO: Update to use offset to avoid recomposition
.padding(
start = 16.dp,
top = offsetDp,
end = 16.dp,
)
.clip(CircleShape),
.aspectRatio(0.96f)
.blur {
radius = BlurRadiusSpec.verticalGradient(
listOf(
BlurStop(0.0f, 0.dp),
BlurStop(0.5f, 0.dp),
BlurStop(1.0f, 32.dp),
),
)
edgeTreatment = BlurredEdgeTreatment.Unbounded
},
painter = painterResource(id = it),
contentScale = ContentScale.Crop,
contentDescription = null,
Expand All @@ -205,8 +194,13 @@ fun ProfileProperty(label: String, value: String, isLink: Boolean = false) {
Text(
text = label,
modifier = Modifier.baselineHeight(24.dp),
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant,
style = TextStyle(

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.

pull text style from theme

fontSize = 12.sp,
lineHeight = 16.sp,
fontWeight = FontWeight(700),
color = Color(0xFF48454F),
letterSpacing = 0.15.sp,
),
)
val style = if (isLink) {
MaterialTheme.typography.bodyLarge.copy(color = MaterialTheme.colorScheme.primary)
Expand All @@ -216,7 +210,12 @@ fun ProfileProperty(label: String, value: String, isLink: Boolean = false) {
Text(
text = value,
modifier = Modifier.baselineHeight(24.dp),
style = style,
style = TextStyle(

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.

pull text style from theme

fontSize = 16.sp,
lineHeight = 24.sp,
fontWeight = FontWeight(400),
color = Color(0xFF1D1B1F),
),
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,32 +21,15 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.rememberNestedScrollInteropConnection
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.fragment.app.viewModels
import com.example.compose.jetchat.FunctionalityNotAvailablePopup
import com.example.compose.jetchat.MainViewModel
import com.example.compose.jetchat.R
import com.example.compose.jetchat.components.JetchatAppBar
import com.example.compose.jetchat.theme.JetchatTheme

class ProfileFragment : Fragment() {
Expand All @@ -62,58 +45,25 @@ class ProfileFragment : Fragment() {
}

@OptIn(ExperimentalComposeUiApi::class, ExperimentalMaterial3Api::class)
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
val rootView: View = inflater.inflate(R.layout.fragment_profile, container, false)
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
ComposeView(inflater.context).apply {
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT,
)

rootView.findViewById<ComposeView>(R.id.toolbar_compose_view).apply {
setContent {
var functionalityNotAvailablePopupShown by remember { mutableStateOf(false) }
if (functionalityNotAvailablePopupShown) {
FunctionalityNotAvailablePopup { functionalityNotAvailablePopupShown = false }
}

JetchatTheme {
JetchatAppBar(
// Reset the minimum bounds that are passed to the root of a compose tree
modifier = Modifier.wrapContentSize(),
onNavIconPressed = { activityViewModel.openDrawer() },
title = { },
actions = {
// More icon
Icon(
painter = painterResource(id = R.drawable.ic_more_vert),
tint = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier
.clickable(onClick = {
functionalityNotAvailablePopupShown = true
})
.padding(horizontal = 12.dp, vertical = 16.dp)
.height(24.dp),
contentDescription = stringResource(id = R.string.more_options),
)
},
)
}
}
}

rootView.findViewById<ComposeView>(R.id.profile_compose_view).apply {
setContent {
val userData by viewModel.userData.observeAsState()
val nestedScrollInteropConnection = rememberNestedScrollInteropConnection()

JetchatTheme {
if (userData == null) {
ProfileError()
} else {
ProfileScreen(
userData = userData!!,
nestedScrollInteropConnection = nestedScrollInteropConnection,
)
}
}
}
}
return rootView
}
}
Binary file added Jetchat/app/src/main/res/drawable/img.png

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.

add it in drawable-nodpi, rename to android_profile_pic

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
42 changes: 0 additions & 42 deletions Jetchat/app/src/main/res/layout/fragment_profile.xml

This file was deleted.

2 changes: 1 addition & 1 deletion Jetchat/gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ maps-compose = "8.4.0"
media3Exoplayer = "1.11.0"
media3ExoplayerHls = "1.11.0"
media3UiCompose = "1.11.0"
minSdk = "23"
minSdk = "24"
okhttp = "5.4.0"
play-services-wearable = "20.0.1"
robolectric = "4.16.1"
Expand Down
Loading