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
1 change: 1 addition & 0 deletions composeApp/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ kotlin {

implementation(libs.coil.network)
implementation(libs.coil.compose)
implementation(libs.coil.svg)

}
appleMain.dependencies {
Expand Down
6 changes: 6 additions & 0 deletions composeApp/src/commonMain/composeResources/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,11 @@
<string name="detailEvent_toast_success">Evento registrado con éxito</string>
<string name="detailEvent_toast_failure">Ocurrió un error al registrar el evento</string>
<string name="detailEvent_add_to_calendar_button">Añadir al calendario</string>
<!-- endregion -->

<!-- region Screen Community Detail -->
<string name="communityTitle_organizer">Organizers</string>
<string name="communityTitle_ex_organizer">Ex Organizers</string>
<!-- endregion -->

</resources>
10 changes: 5 additions & 5 deletions composeApp/src/commonMain/kotlin/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import androidx.navigation.navArgument
import core.ui.AdpDestination
import core.ui.AdpTheme
import core.ui.components.AdpBottomNavigationBar
import features.community.CommunityDetailScreen
import features.eventDetail.EventDetailScreen
import features.main.HomeRoute

Expand All @@ -32,9 +33,9 @@ fun App() {
}
},
onLiveEventTap = {
navController.navigate(AdpDestination.LiveEvent.route) {
/*navController.navigate(AdpDestination.LiveEvent.route) {
this.launchSingleTop = true
}
}*/
},
onInfoTap = {
navController.navigate(AdpDestination.CommunityDetails.route) {
Expand Down Expand Up @@ -67,10 +68,9 @@ fun App() {
EventDetailScreen()
}
composable(
route = AdpDestination.CommunityDetails.route,
arguments = listOf(navArgument("eventId", builder = { type = StringType }))
route = AdpDestination.CommunityDetails.route
) {
// CommunityDetailScreen()
CommunityDetailScreen()
}
composable(
route = AdpDestination.LiveEvent.route,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class MockCommunityRepository(
url = "https://www.instagram.com/androiddevperu/"
),
SocialMedia(
icon = "https://cdn.simpleicons.org/linkedin",
icon = "https://cdn-icons-png.flaticon.com/512/174/174857.png",
url = "https://www.linkedin.com/company/android-dev-peru"
),
SocialMedia(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,225 @@
package features.community

import adpmeetups.composeapp.generated.resources.Res
import adpmeetups.composeapp.generated.resources.communityTitle_ex_organizer
import adpmeetups.composeapp.generated.resources.communityTitle_organizer
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
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.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
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.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.platform.UriHandler
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import coil3.compose.AsyncImage
import coil3.compose.LocalPlatformContext
import coil3.request.ImageRequest
import coil3.svg.SvgDecoder
import core.DomainInjector
import domain.models.Community
import domain.models.Organizer
import domain.models.SocialMedia
import org.jetbrains.compose.resources.stringResource

@Composable
fun CommunityDetailScreen(
vm: CommunityDetailViewModel = viewModel {
CommunityDetailViewModel(
DomainInjector.getCommunityInfo
)
}
) {

val uiState by vm.uiState.collectAsState()
val uriHandler = LocalUriHandler.current

uiState.community?.let {
CommunityDetailLayout(
modifier = Modifier.background(MaterialTheme.colors.background),
community = it,
organizers = it.organizers,
exOrganizers = it.exOrganizers,
socialMedia = it.socialMedia,
uriHandler = uriHandler
)
}
}

@Composable
private fun CommunityDetailLayout(
modifier: Modifier = Modifier,
community: Community?,
organizers: List<Organizer>,
exOrganizers: List<Organizer>,
socialMedia: List<SocialMedia>,
uriHandler: UriHandler
) {
LazyColumn (
modifier = modifier.fillMaxSize()
) {
item {
AsyncImage(
modifier = Modifier
.fillMaxWidth(),
contentScale = ContentScale.FillWidth,
model= community?.topBanner,
contentDescription = community?.name,
)

Column(
modifier = Modifier.padding(16.dp)
) {
Text(
text = community?.name.orEmpty(),
style = MaterialTheme.typography.h5
)

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

Text(text = community?.description.orEmpty())
}

Spacer(modifier = Modifier.size(8.dp))
}

item {
Text(
modifier = Modifier.padding(16.dp),
text = stringResource(Res.string.communityTitle_organizer)
)
}

organizers.forEach { organizer ->
item {
OrganizerItem(organizer = organizer)
Spacer(modifier = Modifier.height(16.dp))
}
}

item {
Text(
modifier = Modifier.padding(16.dp),
text = stringResource(Res.string.communityTitle_ex_organizer)
)
}

exOrganizers.forEach { exOrganizer ->
item {
OrganizerItem(organizer = exOrganizer)
Spacer(modifier = Modifier.height(16.dp))
}
}

item {
SocialMediaBar(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 12.dp),
socialMedia = socialMedia,
uriHandler = uriHandler
)
}
}
}

@Composable
fun OrganizerItem(modifier: Modifier = Modifier, organizer: Organizer?) {
Row(
modifier = modifier
.fillMaxWidth()
.padding(16.dp),
verticalAlignment = Alignment.CenterVertically
) {
AsyncImage(
modifier = Modifier
.clip(androidx.compose.foundation.shape.CircleShape)
.size(80.dp),
contentScale = ContentScale.Crop,
model = organizer?.photo,
contentDescription = organizer?.name,
)

Text(
modifier = Modifier.padding(start = 16.dp),
text = organizer?.name.orEmpty(),
style = MaterialTheme.typography.subtitle1
)
}
}

@Composable
fun SocialMediaBar(
modifier: Modifier = Modifier,
socialMedia: List<SocialMedia>,
uriHandler: UriHandler
) {
LazyRow(
modifier = modifier.fillMaxWidth().padding(top = 16.dp),
horizontalArrangement = Arrangement.SpaceEvenly,
contentPadding = PaddingValues(horizontal = 16.dp)
) {
items(socialMedia.size) { social ->
SocialMediaItem(
socialMedia = socialMedia[social],
uriHandler = uriHandler
)
}
}
}

@Composable
fun SocialMediaItem(
modifier: Modifier = Modifier,
socialMedia: SocialMedia,
uriHandler: UriHandler
) {
Box(
modifier = modifier
.fillMaxWidth()
.padding(vertical = 4.dp),
contentAlignment = Alignment.Center
) {
AsyncImage(
modifier = Modifier
.clip(RoundedCornerShape(8.dp))
.size(24.dp)
.clickable {
uriHandler.openUri(socialMedia.url)
},
contentScale = ContentScale.Fit,
model = ImageRequest
.Builder(LocalPlatformContext.current)
.data(socialMedia.icon)
.decoderFactory(SvgDecoder.Factory())
.build(),
contentDescription = socialMedia.icon,
colorFilter = ColorFilter.tint(
if(isSystemInDarkTheme()) Color.White else Color.Black
)
)
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,48 @@
package features.community

class CommunityDetailViewModel {
}
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import domain.AdpError
import domain.models.Community
import domain.usecase.GetCommunityInfo
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch

class CommunityDetailViewModel(
private val getCommunityInfo: GetCommunityInfo
): ViewModel() {

private val _uiState = MutableStateFlow(CommunityDetailUiState())
val uiState: StateFlow<CommunityDetailUiState> = _uiState
.onStart {
getCommunityDetails()
}.stateIn(
viewModelScope,
SharingStarted.WhileSubscribed(),
CommunityDetailUiState()
)

private fun getCommunityDetails() {
// TODO add kotlinx-coroutines-swing to make viewModelScope
// available in desktop
viewModelScope.launch {
_uiState.update { it.copy(loading = true, error = null) }
getCommunityInfo.invoke().onSuccess { community ->
_uiState.update { it.copy(loading = false, community = community, error = null) }
}.onFailure {
_uiState.update { it.copy(loading = false, error = null) }
}
}
}
}

data class CommunityDetailUiState(
val loading: Boolean = true,
val community: Community? = null,
val error: AdpError? = null
)
1 change: 1 addition & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ koin-core = { module = "io.insert-koin:koin-core", version.ref = "koin" }
androidx-viewmodel = { group = "org.jetbrains.androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "jetbrains-viewModel" }
coil-compose = { module = "io.coil-kt.coil3:coil-compose", version.ref = "coil" }
coil-network = { module = "io.coil-kt.coil3:coil-network-ktor3", version.ref = "coil" }
coil-svg = { module = "io.coil-kt.coil3:coil-svg", version.ref = "coil" }

kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "kotlinxDatetime" }

Expand Down