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

Implement event map screen #105

Merged
merged 5 commits into from
Jul 10, 2024
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
Expand Up @@ -3,6 +3,7 @@ package io.github.droidkaigi.confsched.data.eventmap
import de.jensklingenberg.ktorfit.http.GET
import io.github.droidkaigi.confsched.data.eventmap.response.EventMapResponse
import io.github.droidkaigi.confsched.model.EventMapEvent
import io.github.droidkaigi.confsched.model.createSampleEventMapEvent
import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.toPersistentList

Expand All @@ -17,5 +18,5 @@ public interface EventMapApiClient {
}

public fun EventMapResponse.toEventMapList(): PersistentList<EventMapEvent> {
return listOf(EventMapEvent()).toPersistentList()
return listOf(createSampleEventMapEvent()).toPersistentList()
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,17 @@ package io.github.droidkaigi.confsched.data.eventmap

import io.github.droidkaigi.confsched.data.eventmap.response.EventMapResponse
import io.github.droidkaigi.confsched.model.EventMapEvent
import io.github.droidkaigi.confsched.model.createSampleEventMapEvent
import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.toPersistentList
import okio.IOException

public class FakeEventMapApiClient : EventMapApiClient {

public sealed class Status : EventMapApiClient {
public data object Operational : Status() {
override suspend fun eventMapEvents(): PersistentList<EventMapEvent> {
return EventMapResponse().toEventMapList()
return EventMapResponse().fake()
}
}

Expand All @@ -31,3 +33,11 @@ public class FakeEventMapApiClient : EventMapApiClient {
return status.eventMapEvents()
}
}

public fun EventMapResponse.fake(): PersistentList<EventMapEvent> {
return List(10) {
createSampleEventMapEvent(
isFavorite = it % 2 == 0,
)
}.toPersistentList()
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,28 @@
package io.github.droidkaigi.confsched.model

class EventMapEvent
import kotlinx.datetime.LocalTime

class EventMapEvent(
val name: String,
val roomName: String,
val dateLabel: String,
val isFavorite: Boolean,
val description: String,
private val startTime: LocalTime,
private val endTime: LocalTime,
) {
val timeDuration: String
get() = "$startTime ~ $endTime"
}

fun createSampleEventMapEvent(
isFavorite: Boolean = false,
) = EventMapEvent(
name = "ランチミートアップ",
roomName = "Arctic Fox",
dateLabel = "DAY1",
isFavorite = isFavorite,
description = "様々なテーマごとに集まって、一緒にランチを食べながらお話ししましょう。席に限りがありますので、お弁当受け取り後お早めにお越しください。",
startTime = LocalTime(10, 30),
endTime = LocalTime(12, 30),
)
2 changes: 2 additions & 0 deletions feature/eventmap/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ kotlin {
implementation(libs.kotlinxCoroutinesCore)
implementation(projects.core.designsystem)
implementation(libs.moleculeRuntime)
implementation(compose.components.resources)
implementation(compose.components.uiToolingPreview)
}
}
androidUnitTest {
Expand Down
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

composeResources 🎉

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package io.github.droidkaigi.confsched.eventmap

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.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.material.icons.Icons.AutoMirrored.Filled
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material3.ExperimentalMaterial3Api
Expand All @@ -22,18 +24,21 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import androidx.navigation.NavGraph.Companion.findStartDestination
import androidx.navigation.NavGraphBuilder
import androidx.navigation.compose.composable
import co.touchlab.kermit.Logger
import io.github.droidkaigi.confsched.compose.rememberEventEmitter
import io.github.droidkaigi.confsched.eventmap.component.EventMapItem
import io.github.droidkaigi.confsched.eventmap.component.EventMapTab
import io.github.droidkaigi.confsched.model.EventMapEvent
import io.github.droidkaigi.confsched.ui.SnackbarMessageEffect
import io.github.droidkaigi.confsched.ui.UserMessageStateHolder
import io.github.droidkaigi.confsched.ui.handleOnClickIfNotNavigating
import kotlinx.collections.immutable.PersistentList
import org.jetbrains.compose.ui.tooling.preview.Preview

const val eventMapScreenRoute = "eventMap"
const val EventMapScreenTestTag = "EventMapScreenTestTag"
Expand Down Expand Up @@ -123,7 +128,7 @@ fun EventMapScreen(
if (scrollBehavior != null) {
LargeTopAppBar(
title = {
Text(text = "EventMapEvent")
Text(text = "イベントマップ")
},
navigationIcon = {
IconButton(
Expand Down Expand Up @@ -164,14 +169,31 @@ private fun EventMap(
modifier: Modifier = Modifier,
) {
LazyColumn(
modifier = modifier,
modifier = modifier.padding(horizontal = 16.dp),
) {
items(eventMapEvents) {
item {
EventMapTab()
Spacer(Modifier.height(26.dp))
}
itemsIndexed(eventMapEvents) { index, eventMapEvent ->
EventMapItem(
eventMapEvent = it,
eventMapEvent = eventMapEvent,
onClick = onEventMapItemClick,
onClickFavorite = { /* TODO */ },
modifier = Modifier.fillMaxWidth(),
)
if (eventMapEvents.lastIndex != index) {
Spacer(modifier = Modifier.height(12.dp))
}
}
}
}

@Composable
@Preview
fun PreviewEventMapScreen() {
EventMapScreen(
onNavigationIconClick = { },
onEventMapItemClick = { },
)
}
Original file line number Diff line number Diff line change
@@ -1,39 +1,134 @@
package io.github.droidkaigi.confsched.eventmap.component

import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Star
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import io.github.droidkaigi.confsched.model.EventMapEvent

@Composable
fun EventMapItem(
eventMapEvent: EventMapEvent,
@Suppress("UnusedParameter")
onClick: (url: String) -> Unit,
onClickFavorite: (eventMapEvent: EventMapEvent) -> Unit,
modifier: Modifier = Modifier,
) {
Row(
val green = Color(0xFF45E761)
val gray = Color(0xFFC5C7C4)
Column(
modifier = modifier
.border(1.dp, gray, RoundedCornerShape(5.dp))
.background(Color.Transparent, RoundedCornerShape(5.dp))
.clickable {
// eventMapEvent.profileUrl?.let(onClick)
}
.padding(horizontal = 16.dp, vertical = 10.dp),
.padding(12.dp),
verticalArrangement = Arrangement.Top,
horizontalAlignment = Alignment.Start,
) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Start,
) {
ToolTip(
text = eventMapEvent.roomName,
icon = Icons.Filled.Star,
color = green,
)
Spacer(Modifier.width(4.dp))
ToolTip(
text = eventMapEvent.dateLabel,
color = Color(0xFFBFC9C2),
)
Spacer(Modifier.weight(1F))
Icon(
imageVector = Icons.Default.Star,
contentDescription = null,
modifier = Modifier.size(24.dp).clickable { onClickFavorite(eventMapEvent) },
tint = if (eventMapEvent.isFavorite) green else gray,
)
}
Spacer(Modifier.height(8.dp))
Text(
text = eventMapEvent.name,
fontSize = 17.sp,
lineHeight = 23.8.sp,
fontWeight = FontWeight.W600,
letterSpacing = 0.1.sp,
color = gray,
)
Spacer(Modifier.height(8.dp))
Text(
text = eventMapEvent.description,
fontSize = 13.sp,
lineHeight = 20.sp,
fontWeight = FontWeight.W400,
letterSpacing = 0.25.sp,
color = Color.White.copy(alpha = 0.7F),
)
Spacer(Modifier.height(8.dp))
Text(
text = eventMapEvent.timeDuration,
fontSize = 11.sp,
lineHeight = 15.sp,
fontWeight = FontWeight.W600,
letterSpacing = 0.1.sp,
color = green,
)
}
}

@Composable
private fun ToolTip(
text: String,
icon: ImageVector? = null,
color: Color = Color(0xFFC5C7C4),
backgroundColor: Color = Color.Transparent,
) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(23.dp),
modifier = Modifier
.border(1.dp, color)
.background(backgroundColor, RoundedCornerShape(0.dp))
.padding(vertical = 4.5.dp, horizontal = 8.dp),
) {
icon?.let {
Icon(
imageVector = icon,
contentDescription = null,
tint = color,
modifier = Modifier.size(12.dp),
)
Spacer(Modifier.width(3.dp))
}
Text(
text = "EventMapItem + $eventMapEvent",
style = MaterialTheme.typography.bodyLarge,
maxLines = 2,
overflow = TextOverflow.Ellipsis,
text = text,
fontSize = 12.sp,
lineHeight = 16.sp,
letterSpacing = 0.5.sp,
fontWeight = FontWeight.W500,
color = color,
)
}
}
Loading
Loading