Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor: Sessions Screen Refactor #243

Merged
merged 2 commits into from
Oct 28, 2023
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
31 changes: 29 additions & 2 deletions data/src/main/java/com/android254/data/repos/SessionsManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ package com.android254.data.repos
import com.android254.data.repos.mappers.toDomainModel
import com.android254.data.repos.mappers.toEntity
import com.android254.domain.models.Session
import com.android254.domain.models.SessionsInformationDomainModel
import com.android254.domain.repos.SessionsRepo
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import javax.inject.Inject
import ke.droidcon.kotlin.datasource.local.dao.BookmarkDao
import ke.droidcon.kotlin.datasource.local.model.BookmarkEntity
Expand Down Expand Up @@ -51,6 +55,24 @@ class SessionsManager @Inject constructor(
}
}.flowOn(ioDispatcher)
}

override suspend fun fetchSessionsInformation(): Flow<SessionsInformationDomainModel> = combine(
localSessionsDataSource.getCachedSessions(),
bookmarkDao.getBookmarkIds()
) { sessions, bookmarks ->
val eventDays = sessions.groupBy { it.startTimestamp.toEventDay() }.keys.toList()
SessionsInformationDomainModel(
sessions = sessions.map { session -> session.toDomainModel().copy(isBookmarked = bookmarks.map { it.sessionId }.contains(session.id.toString())) },
eventDays = eventDays
)
}

private fun Long.toEventDay(): String {
val date = Date(this)
val sdf = SimpleDateFormat("dd", Locale.getDefault())
return sdf.format(date)
}

override fun fetchBookmarkedSessions(): Flow<List<Session>> {
val bookmarksFlow = bookmarkDao.getBookmarkIds()
val sessionsFlow = localSessionsDataSource.getCachedSessions()
Expand All @@ -74,9 +96,13 @@ class SessionsManager @Inject constructor(
}.flowOn(ioDispatcher)
}

override fun fetchSessionById(sessionId: String): Flow<Session?> {
override fun fetchFilteredSessions(vararg filters: List<String>) {
//
}

override fun fetchSessionById(id: String): Flow<Session?> {
val bookmarksFlow = bookmarkDao.getBookmarkIds()
val sessionFlow = localSessionsDataSource.getCachedSessionById(sessionId).map {
val sessionFlow = localSessionsDataSource.getCachedSessionById(id).map {
it?.toDomainModel()
}
return combine(sessionFlow, bookmarksFlow) { session, bookmarks ->
Expand Down Expand Up @@ -109,6 +135,7 @@ class SessionsManager @Inject constructor(
is DataResult.Error -> {
Timber.d("Sync sessions failed ${response.message}")
}

else -> {
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.android254.domain.models

data class SessionsInformationDomainModel(
val sessions: List<Session>,
val eventDays: List<String>
)
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,18 @@
package com.android254.domain.repos

import com.android254.domain.models.Session
import com.android254.domain.models.SessionsInformationDomainModel
import kotlinx.coroutines.flow.Flow

interface SessionsRepo {
fun fetchSessions(): Flow<List<Session>>

suspend fun fetchSessionsInformation(): Flow<SessionsInformationDomainModel>

fun fetchFilteredSessions(query: String): Flow<List<Session>>

fun fetchFilteredSessions(vararg filters: List<String>)

fun fetchBookmarkedSessions(): Flow<List<Session>>

fun fetchSessionById(id: String): Flow<Session?>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@
*/
package com.android254.presentation.models

import kotlinx.datetime.LocalDate

data class EventDate(
val value: LocalDate
val value: String,
val day: Int
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package com.android254.presentation.sessions.components

import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Star
import androidx.compose.material.icons.filled.StarOutline
import androidx.compose.material3.Icon
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.BiasAlignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.android254.presentation.utils.ChaiLightAndDarkComposePreview
import com.droidconke.chai.ChaiDCKE22Theme


@Composable
fun CustomSwitch(
width: Dp = 72.dp,
height: Dp = 40.dp,
checkedTrackColor: Color = Color(0xFF35898F),
uncheckedTrackColor: Color = Color(0xFFe0e0e0),
gapBetweenThumbAndTrackEdge: Dp = 8.dp,
borderWidth: Dp = 2.dp,
cornerSize: Int = 50,
iconInnerPadding: Dp = 4.dp,
thumbSize: Dp = 24.dp,
checked: Boolean,
onCheckedChange: (Boolean) -> Unit
) {
// this is to disable the ripple effect
val interactionSource = remember {
MutableInteractionSource()
}

// for moving the thumb
val alignment by animateAlignmentAsState(if (checked) 1f else -1f)

// outer rectangle with border
Box(
modifier = Modifier
.size(width = width, height = height)
.border(
width = borderWidth,
color = if (checked) checkedTrackColor else uncheckedTrackColor,
shape = RoundedCornerShape(percent = cornerSize)
)
.clickable(
indication = null,
interactionSource = interactionSource
) {
onCheckedChange(!checked)
},
contentAlignment = Alignment.Center
) {
// this is to add padding at the each horizontal side
Box(
modifier = Modifier
.padding(
start = gapBetweenThumbAndTrackEdge,
end = gapBetweenThumbAndTrackEdge
)
.fillMaxSize(),
contentAlignment = alignment
) {
// thumb with icon
Icon(
imageVector = if (checked) Icons.Filled.Star else Icons.Filled.StarOutline,
contentDescription = if (checked) "Enabled" else "Disabled",
modifier = Modifier
.size(size = thumbSize)
.background(
color = if (checked) checkedTrackColor else uncheckedTrackColor,
shape = CircleShape
)
.padding(all = iconInnerPadding),
tint = Color.White
)
}
}
}

@Composable
private fun animateAlignmentAsState(
targetBiasValue: Float
): State<BiasAlignment> {
val bias by animateFloatAsState(targetValue = targetBiasValue, label = "")

return remember {
derivedStateOf { BiasAlignment(horizontalBias = bias, verticalBias = 0f) }
}
}


@ChaiLightAndDarkComposePreview
@Composable
private fun CustomSwitchPreview() {
ChaiDCKE22Theme {
CustomSwitch(checked = false, onCheckedChange = {})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,22 @@
*/
package com.android254.presentation.sessions.components

import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.items
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.android254.presentation.models.EventDate
import kotlinx.datetime.LocalDate

/*
val droidconEventDays = listOf(
EventDate(LocalDate(2023, 11, 16)),
EventDate(LocalDate(2023, 11, 17)),
EventDate(LocalDate(2023, 11, 18))
EventDate(LocalDate(2023, 11, 16), 1),
EventDate(LocalDate(2023, 11, 17), 2),
EventDate(LocalDate(2023, 11, 18), 3)
)
*/

fun ordinal(i: Int): String {
val suffixes = arrayOf("th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th")
Expand All @@ -41,17 +43,17 @@ fun ordinal(i: Int): String {
@Composable
fun EventDaySelector(
selectedDate: EventDate,
updateSelectedDay: (EventDate) -> Unit
updateSelectedDay: (EventDate) -> Unit,
eventDates: List<EventDate>
) {
Row() {
droidconEventDays.forEachIndexed { index, eventDate ->
LazyRow {
items(eventDates) { eventDay ->
EventDaySelectorButton(
title = ordinal(eventDate.value.dayOfMonth),
subtitle = "Day ${index + 1}",
onClick = { updateSelectedDay(eventDate) },
selected = selectedDate == eventDate
) {
}
title = ordinal(eventDay.value.toInt()),
subtitle = "Day ${eventDay.day}",
onClick = { updateSelectedDay(eventDay) },
selected = selectedDate == eventDay
)
Spacer(Modifier.width(16.dp))
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.ButtonColors
Expand Down Expand Up @@ -66,20 +64,8 @@ fun EventDaySelectorButton(
} else {
MaterialTheme.colorScheme.onSecondaryContainer
}
),
contentPadding: PaddingValues = PaddingValues(
start = 0.dp,
top = 0.dp,
end = 0.dp,
bottom = 0.dp
),
content: @Composable RowScope.() -> Unit
)
) {
/*val containerColor = colors.containerColor(enabled).value
val contentColor = colors.contentColor(enabled).value
val shadowElevation = elevation?.shadowElevation(enabled, interactionSource)?.value ?: 0.dp
val tonalElevation = elevation?.tonalElevation(enabled, interactionSource)?.value ?: 0.dp
*/
val containerColor = Color.Black
val contentColor = Color.Red
val shadowElevation = 0.dp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,54 +58,48 @@ fun SessionsStateComponent(
isRefreshing: Boolean
) {
val swipeRefreshState = rememberSwipeRefreshState(isRefreshing = isRefreshing)
when (sessionsUiState) {
is SessionsUiState.Loading -> {
SessionLoadingComponent()
}

is SessionsUiState.Empty -> {
val message = sessionsUiState.message
Column(
modifier = Modifier
.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Icon(
modifier = Modifier.size(70.dp),
painter = painterResource(id = R.drawable.sessions_icon),
contentDescription = stringResource(id = R.string.sessions_icon_description),
tint = ChaiBlue
)
Spacer(modifier = Modifier.height(20.dp))
Text(
text = message,
style = TextStyle(
color = ChaiDarkGrey,
fontSize = 18.sp,
fontFamily = MontserratRegular,
textAlign = TextAlign.Center
)
)
}
}
if (sessionsUiState.isLoading){
SessionLoadingComponent()
}

is SessionsUiState.Data -> {
val sessionsList = sessionsUiState.data
SessionListComponent(
swipeRefreshState = swipeRefreshState,
sessions = sessionsList,
navigateToSessionDetails = navigateToSessionDetails,
refreshSessionsList = refreshSessionsList
if (sessionsUiState.isEmpty){
Column(
modifier = Modifier
.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Icon(
modifier = Modifier.size(70.dp),
painter = painterResource(id = R.drawable.sessions_icon),
contentDescription = stringResource(id = R.string.sessions_icon_description),
tint = ChaiBlue
)
Spacer(modifier = Modifier.height(20.dp))
Text(
text = sessionsUiState.isEmptyMessage,
style = TextStyle(
color = ChaiDarkGrey,
fontSize = 18.sp,
fontFamily = MontserratRegular,
textAlign = TextAlign.Center
)
)
}
}

is SessionsUiState.Error -> {
val message = sessionsUiState.message
SessionsErrorComponent(errorMessage = message, retry = retry)
}
if (sessionsUiState.isError){
SessionsErrorComponent(errorMessage = sessionsUiState.errorMessage, retry = retry)
}

is SessionsUiState.Idle -> {}
if (!sessionsUiState.isEmpty){
SessionListComponent(
swipeRefreshState = swipeRefreshState,
sessions = sessionsUiState.sessions,
navigateToSessionDetails = navigateToSessionDetails,
refreshSessionsList = refreshSessionsList
)
}
}

Expand Down
Loading
Loading