Skip to content
Merged
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
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package friends.mobile.profile

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
Expand All @@ -9,30 +8,26 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.Person
import androidx.compose.material3.Button
import androidx.compose.material3.CenterAlignedTopAppBar
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
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.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import friends.mobile.designkit.DesignTheme
import friends.mobile.designkit.FormTextField
import friends.mobile.designkit.PrimaryButton
import friends.mobile.feature.profile.presentation.edit.EditProfileAction
import friends.mobile.feature.profile.presentation.edit.EditProfileEvent
import friends.mobile.feature.profile.presentation.edit.EditProfileViewModel
Expand Down Expand Up @@ -101,90 +96,84 @@ private fun EditContent(
state: EditProfileViewState.Content,
onEvent: (EditProfileEvent) -> Unit
) {
Column(
LazyColumn(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(16.dp)
.padding(DesignTheme.Spacing.lg),
verticalArrangement = Arrangement.spacedBy(DesignTheme.Spacing.lg)
) {
// Avatar Placeholder
Box(
modifier = Modifier
.size(100.dp)
.clip(CircleShape)
.background(MaterialTheme.colorScheme.surfaceVariant),
contentAlignment = Alignment.Center
) {
Icon(
imageVector = Icons.Default.Person,
contentDescription = null,
modifier = Modifier.size(64.dp),
tint = MaterialTheme.colorScheme.onSurfaceVariant
item {
FormTextField(
value = state.username,
onValueChange = { onEvent(EditProfileEvent.OnUsernameChanged(it)) },
placeholder = "Username",
modifier = Modifier
.fillMaxWidth()
.height(54.dp)
)
}

Spacer(modifier = Modifier.height(8.dp))

OutlinedTextField(
value = state.username,
onValueChange = { onEvent(EditProfileEvent.OnUsernameChanged(it)) },
label = { Text("Username") },
modifier = Modifier.fillMaxWidth(),
singleLine = true
)
item {
FormTextField(
value = state.bio,
onValueChange = { onEvent(EditProfileEvent.OnBioChanged(it)) },
placeholder = "Bio",
modifier = Modifier
.fillMaxWidth()
.height(54.dp)
)
}

OutlinedTextField(
value = state.avatarUrl,
onValueChange = { onEvent(EditProfileEvent.OnAvatarUrlChanged(it)) },
label = { Text("Avatar URL") },
modifier = Modifier.fillMaxWidth(),
singleLine = true
)
item {
FormTextField(
value = state.avatarUrl,
onValueChange = { onEvent(EditProfileEvent.OnAvatarUrlChanged(it)) },
placeholder = "Avatar URL",
modifier = Modifier
.fillMaxWidth()
.height(54.dp)
)
}

OutlinedTextField(
value = state.bio,
onValueChange = { onEvent(EditProfileEvent.OnBioChanged(it)) },
label = { Text("Bio") },
modifier = Modifier.fillMaxWidth(),
minLines = 3
)
item {
Spacer(modifier = Modifier.height(DesignTheme.Spacing.xxxl))
}

Spacer(modifier = Modifier.weight(1f))
item {
PrimaryButton(
text = if (state.isSaving) "Saving..." else "Save",
onClick = { onEvent(EditProfileEvent.OnSaveClick) },
modifier = Modifier.fillMaxWidth(),
isLoading = state.isSaving,
isEnabled = !state.isSaving
)
}

Button(
onClick = { onEvent(EditProfileEvent.OnSaveClick) },
modifier = Modifier.fillMaxWidth().height(50.dp),
enabled = !state.isSaving
) {
if (state.isSaving) {
CircularProgressIndicator(
modifier = Modifier.size(24.dp),
color = MaterialTheme.colorScheme.onPrimary,
strokeWidth = 2.dp
)
} else {
Text("Save Changes")
}
item {
Spacer(modifier = Modifier.height(DesignTheme.Spacing.lg))
}
}
}

@Composable
private fun ErrorState(message: String, onBack: () -> Unit) {
Column(
modifier = Modifier.fillMaxSize().padding(16.dp),
modifier = Modifier
.fillMaxSize()
.padding(DesignTheme.Spacing.lg),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text(
text = message,
color = MaterialTheme.colorScheme.error,
style = MaterialTheme.typography.bodyLarge
color = DesignTheme.Colors.error,
style = DesignTheme.Typography.body
)
Spacer(modifier = Modifier.height(DesignTheme.Spacing.lg))
PrimaryButton(
text = "Go Back",
onClick = onBack,
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(16.dp))
Button(onClick = onBack) {
Text("Go Back")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Refresh
import androidx.compose.material3.CenterAlignedTopAppBar
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
Expand All @@ -28,10 +29,11 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import friends.mobile.calendar.BusyDaysView
import friends.mobile.designkit.DesignTheme
import friends.mobile.designkit.PrimaryButton
import friends.mobile.feature.profile.domain.model.Profile
import friends.mobile.feature.profile.presentation.profile.ProfileAction
import friends.mobile.feature.profile.presentation.profile.ProfileEvent
Expand Down Expand Up @@ -162,8 +164,8 @@ private fun ProfileContent(

LazyColumn(
modifier = Modifier.fillMaxSize(),
contentPadding = PaddingValues(16.dp),
verticalArrangement = Arrangement.spacedBy(24.dp)
contentPadding = PaddingValues(DesignTheme.Spacing.lg),
verticalArrangement = Arrangement.spacedBy(DesignTheme.Spacing.xxl)
) {

item {
Expand All @@ -177,18 +179,35 @@ private fun ProfileContent(
}

item {
Column(
modifier = Modifier.fillMaxWidth(),
verticalArrangement = Arrangement.spacedBy(DesignTheme.Spacing.md)
) {
PrimaryButton(
text = "Refresh Activity",
onClick = { },
modifier = Modifier.fillMaxWidth(),
icon = {
Icon(
imageVector = Icons.Default.Refresh,
contentDescription = "Refresh",
modifier = Modifier.size(20.dp)
)
}
)

BusyDaysView(
userId = profile.id,
modifier = Modifier.fillMaxWidth()
)
BusyDaysView(
userId = profile.id,
modifier = Modifier.fillMaxWidth()
)
}
}

item {

Text(
text = "My Wish Places",
style = MaterialTheme.typography.titleLarge
style = DesignTheme.Typography.heading
)
}

Expand All @@ -202,7 +221,7 @@ private fun ProfileContent(
}

item {
Spacer(modifier = Modifier.height(32.dp))
Spacer(modifier = Modifier.height(DesignTheme.Spacing.xxxl))
}
}
}
Expand All @@ -218,58 +237,41 @@ private fun ProfileHeader(
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(12.dp)
verticalArrangement = Arrangement.spacedBy(DesignTheme.Spacing.md)
) {

Text(
text = profile.username,
style = MaterialTheme.typography.headlineMedium
style = DesignTheme.Typography.heading
)

profile.bio?.let { bio ->

Text(
text = bio,
style = MaterialTheme.typography.bodyLarge
style = DesignTheme.Typography.body
)
}

Row(
Column(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(12.dp)
verticalArrangement = Arrangement.spacedBy(DesignTheme.Spacing.md)
) {

Button(
PrimaryButton(
onClick = onEditClick,
modifier = Modifier.weight(1f),
enabled = !isLoggingOut
) {

Text("Edit Profile")
}
text = "Edit Profile",
modifier = Modifier.fillMaxWidth(),
isEnabled = !isLoggingOut
)

Button(
PrimaryButton(
onClick = onLogoutClick,
modifier = Modifier.weight(1f),
enabled = !isLoggingOut,

colors = ButtonDefaults.buttonColors(
containerColor = MaterialTheme.colorScheme.error
)
) {

if (isLoggingOut) {

CircularProgressIndicator(
modifier = Modifier.size(20.dp),
color = Color.White
)

} else {

Text("Logout")
}
}
text = if (isLoggingOut) "Logging out..." else "Log Out",
modifier = Modifier.fillMaxWidth(),
isLoading = isLoggingOut,
isEnabled = !isLoggingOut
)
}
}
}
Expand All @@ -281,23 +283,25 @@ private fun ErrorContent(
) {

Column(
modifier = Modifier.fillMaxSize(),
modifier = Modifier
.fillMaxSize()
.padding(DesignTheme.Spacing.lg),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {

Text(
text = message,
color = MaterialTheme.colorScheme.error
style = DesignTheme.Typography.body,
color = DesignTheme.Colors.error
)

Spacer(modifier = Modifier.height(12.dp))
Spacer(modifier = Modifier.height(DesignTheme.Spacing.lg))

Button(
onClick = onRetry
) {

Text("Retry")
}
PrimaryButton(
text = "Retry",
onClick = onRetry,
modifier = Modifier.fillMaxWidth()
)
}
}
4 changes: 4 additions & 0 deletions iosApp/iosApp/DesignKit/DesignTheme.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ import UIKit
enum DesignTheme {
static let accentColor = Color.blue
static let accentColorHex = Color(red: 0.0, green: 0.48, blue: 1.0)
static let error = Color(red: 1.0, green: 0.23, blue: 0.19)
static let errorLight = Color.red.opacity(0.08)
static let infoLight = Color.blue.opacity(0.06)
static let secondaryAccent = Color.green

enum Spacing {
static let xs: CGFloat = 4
Expand Down
Loading
Loading