Skip to content

Commit

Permalink
refactor(style-schedule): Create PauseItem and ScheduleItemCard compo…
Browse files Browse the repository at this point in the history
…nents.
  • Loading branch information
GerardPaligot committed Oct 22, 2023
1 parent c43a670 commit 43a21e8
Show file tree
Hide file tree
Showing 47 changed files with 854 additions and 441 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ class MainActivity : ComponentActivity() {
val agendaRepository = AgendaRepository.Factory.create(
api = api,
scheduleDao = ScheduleDao(db, settings, platform),
speakerDao = SpeakerDao(db),
speakerDao = SpeakerDao(db, platform),
talkDao = TalkDao(db),
eventDao = EventDao(db, settings),
partnerDao = PartnerDao(db = db, platform = platform),
Expand All @@ -89,7 +89,7 @@ class MainActivity : ComponentActivity() {
qrCodeGenerator = QrCodeGeneratorAndroid()
)
val speakerRepository = SpeakerRepository.Factory.create(
speakerDao = SpeakerDao(db),
speakerDao = SpeakerDao(db, platform),
eventDao = EventDao(db, settings)
)
val scheduler = AlarmScheduler(
Expand Down
Binary file not shown.
2 changes: 1 addition & 1 deletion iosApp/iosApp/ViewModelFactory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class ViewModelFactory: ObservableObject {
self.agendaRepository = AgendaRepositoryImpl(
api: api,
scheduleDao: ScheduleDao(db: db, settings: settings, platform: platform),
speakerDao: SpeakerDao(db: db),
speakerDao: SpeakerDao(db: db, platform: platform),
talkDao: TalkDao(db: db),
eventDao: EventDao(db: db, settings: settings),
partnerDao: PartnerDao(db: db, platform: platform),
Expand Down
6 changes: 6 additions & 0 deletions iosApp/iosApp/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@
"textJobRequirements" = "years min";
"textJobPropulsed" = "Propulsed by";
"textFeedbackNotStarted" = "Wait a little, you will be able to give feedbacks when the session has started.";
"text_schedule_minutes" = "%@ minutes";
"text_speakers_list.one" = "%@ and %@ other";
"text_speakers_list.other" = "%@ and %@ others";
"text_level_beginner" = "Débutant";
"text_level_intermediate" = "Intermédiaire";
"text_level_advanced" = "Avancé";

"actionFeedback" = "Give your feedback";
"actionItinerary" = "Itinerary";
Expand Down
6 changes: 6 additions & 0 deletions iosApp/iosApp/fr.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@
"textJobRequirements" = "années min";
"textJobPropulsed" = "Propulsé par";
"textFeedbackNotStarted" = "Encore un peu de patience, vous pourrez partagez vos feedbacks lorsque la session démarrera.";
"text_schedule_minutes" = "%@ minutes";
"text_speakers_list.one" = "%@ et %@ autre";
"text_speakers_list.other" = "%@ and %@ autres";
"text_level_beginner" = "Beginner";
"text_level_intermediate" = "Intermediate";
"text_level_advanced" = "Advanced";

"actionFeedback" = "Donne ton feedback";
"actionItinerary" = "Itinéraire";
Expand Down
1 change: 1 addition & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ include(":theme-m3:infos:infos-feature")
include(":theme-m3:event-list:event-list-ui")
include(":theme-m3:event-list:event-list-feature")
include(":theme-m3:navigation")
include(":theme-m3:style:schedules")
include(":theme-m3:style:speakers")
include(":theme-m3:style:theme")
include(":ui-camera")
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,27 @@ actual class Platform actual constructor(private val context: PlatformContext) {
actual val hasSupportSVG: Boolean = true
actual fun getString(key: String): String {
val androidContext = context.context
val resourceId = androidContext.resources.getIdentifier(key, "string", androidContext.packageName)
val resourceId =
androidContext.resources.getIdentifier(key, "string", androidContext.packageName)
if (resourceId == 0) return key
return androidContext.getString(resourceId)
}

actual fun getString(key: String, count: Int, args: List<Any>): String {
val androidContext = context.context
val resourceId =
androidContext.resources.getIdentifier(key, "plurals", androidContext.packageName)
if (resourceId == 0) return key
return androidContext.resources.getQuantityString(resourceId, count, args)
}

actual fun getString(key: String, args: List<Any>): String {
val androidContext = context.context
val resourceId =
androidContext.resources.getIdentifier(key, "string", androidContext.packageName)
if (resourceId == 0) return key
return androidContext.getString(resourceId, *args.toTypedArray())
}
}

actual class DecimalFormat {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ expect class Platform(context: PlatformContext) {
val fileEngine: FileEngine
val hasSupportSVG: Boolean
fun getString(key: String): String
fun getString(key: String, count: Int, args: List<Any>): String
fun getString(key: String, args: List<Any>): String
}

expect class DecimalFormat() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,13 @@ class ScheduleDao(
} else {
emptyList()
}
it.convertTalkItemUi(speakers)
} + breaks.map { it.convertTalkItemUi(platform::getString) }
it.convertTalkItemUi(
getString = platform::getString,
getStringArg = platform::getString,
getPluralsArg = platform::getString,
speakers = speakers
)
} + breaks.map { it.convertTalkItemUi(platform::getString, platform::getString) }
sessions.distinctBy { it.date }
.associate {
it.date to AgendaUi(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,18 @@ import kotlinx.coroutines.IO
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
import org.gdglille.devfest.Platform
import org.gdglille.devfest.database.mappers.SpeakerMappers
import org.gdglille.devfest.database.mappers.convertTalkItemUi
import org.gdglille.devfest.db.Conferences4HallDatabase
import org.gdglille.devfest.models.ui.SpeakerItemUi
import org.gdglille.devfest.models.ui.SpeakerUi
import org.gdglille.devfest.models.ui.TalkItemUi

class SpeakerDao(private val db: Conferences4HallDatabase) {
class SpeakerDao(
private val db: Conferences4HallDatabase,
private val platform: Platform
) {
fun fetchSpeaker(eventId: String, speakerId: String): Flow<SpeakerUi> {
return combine(
db.speakerQueries.selectSpeaker(speakerId, eventId, SpeakerMappers.speakerUi)
Expand All @@ -42,10 +46,13 @@ class SpeakerDao(private val db: Conferences4HallDatabase) {
talks
.map { talk ->
talk.convertTalkItemUi(
db.sessionQueries
getString = platform::getString,
getStringArg = platform::getString,
getPluralsArg = platform::getString,
session = db.sessionQueries
.selectSessionByTalkId(eventId, talk.id)
.executeAsOne(),
db.sessionQueries
speakers = db.sessionQueries
.selectSpeakersByTalkId(eventId, talk.id)
.executeAsList()
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,18 @@ import org.gdglille.devfest.models.ui.SpeakerItemUi
import org.gdglille.devfest.models.ui.TalkItemUi
import org.gdglille.devfest.models.ui.TalkUi
import kotlin.reflect.KFunction1
import kotlin.reflect.KFunction2
import kotlin.reflect.KFunction3

private const val BREAK_TITLE = "break"
private const val MaxSpeakersCount = 3

fun SelectSessions.convertCategoryUi() = CategoryUi(
id = category_id, name = categoryName, color = categoryColor, icon = categoryIcon
)

fun SelectBreakSessions.convertCategoryUi() = CategoryUi(
id = id, name = BREAK_TITLE, color = null, icon = null
id = id, name = BREAK_TITLE, color = "", icon = null
)

fun SelectTalksBySpeakerId.convertCategoryUi() = CategoryUi(
Expand All @@ -53,10 +56,27 @@ fun SelectFormats.convertFormatUi() = FormatUi(
id = id, name = name, time = time.toInt()
)

fun SelectSessions.convertTalkItemUi(speakers: List<SelectSpeakersByTalkId>): TalkItemUi {
fun SelectSessions.convertTalkItemUi(
getString: KFunction1<String, String>,
getStringArg: KFunction2<String, List<String>, String>,
getPluralsArg: KFunction3<String, Int, List<Any>, String>,
speakers: List<SelectSpeakersByTalkId>
): TalkItemUi {
val startDateTime = start_time.toLocalDateTime()
val endDateTime = end_time.toLocalDateTime()
val diff = endDateTime.toInstant(TimeZone.UTC).minus(startDateTime.toInstant(TimeZone.UTC))
val timeInMinutes = diff.inWholeMinutes.toInt()
val count = (speakers.size - MaxSpeakersCount).coerceAtLeast(minimumValue = 0)
val maxSpeakers = speakers.take(MaxSpeakersCount)
val speakersJoined = maxSpeakers.joinToString(", ") { it.display_name }
val speakersLabel = if (count == 0) speakersJoined
else getPluralsArg("text_speakers_list", count, listOf(speakersJoined, count))
val level = when (level) {
"advanced" -> getString("text_level_advanced")
"intermediate" -> getString("text_level_intermediate")
"beginner" -> getString("text_level_beginner")
else -> level
}
return TalkItemUi(
id = id,
order = order_.toInt(),
Expand All @@ -67,20 +87,24 @@ fun SelectSessions.convertTalkItemUi(speakers: List<SelectSpeakersByTalkId>): Ta
slotTime = startDateTime.formatHoursMinutes(),
startTime = start_time,
endTime = end_time,
timeInMinutes = diff.inWholeMinutes.toInt(),
timeInMinutes = timeInMinutes,
time = getStringArg("text_schedule_minutes", listOf(timeInMinutes.toString())),
category = convertCategoryUi(),
speakers = speakers.map { it.display_name }.toImmutableList(),
speakersAvatar = speakers.map { it.photo_url }.toImmutableList(),
speakers = maxSpeakers.map { it.display_name }.toImmutableList(),
speakersAvatar = maxSpeakers.map { it.photo_url }.toImmutableList(),
speakersLabel = speakersLabel,
isFavorite = is_favorite
)
}

fun SelectBreakSessions.convertTalkItemUi(
getString: KFunction1<String, String>
getString: KFunction1<String, String>,
getStringArg: KFunction2<String, List<String>, String>
): TalkItemUi {
val startDateTime = start_time.toLocalDateTime()
val endDateTime = end_time.toLocalDateTime()
val diff = endDateTime.toInstant(TimeZone.UTC).minus(startDateTime.toInstant(TimeZone.UTC))
val timeInMinutes = diff.inWholeMinutes.toInt()
return TalkItemUi(
id = id,
order = order_.toInt(),
Expand All @@ -91,21 +115,38 @@ fun SelectBreakSessions.convertTalkItemUi(
slotTime = startDateTime.formatHoursMinutes(),
startTime = start_time,
endTime = end_time,
timeInMinutes = diff.inWholeMinutes.toInt(),
timeInMinutes = timeInMinutes,
time = getStringArg("text_schedule_minutes", listOf(timeInMinutes.toString())),
category = convertCategoryUi(),
speakers = persistentListOf(),
speakersAvatar = persistentListOf(),
speakersLabel = "",
isFavorite = false
)
}

fun SelectTalksBySpeakerId.convertTalkItemUi(
getString: KFunction1<String, String>,
getStringArg: KFunction2<String, List<String>, String>,
getPluralsArg: KFunction3<String, Int, List<Any>, String>,
session: SelectSessionByTalkId,
speakers: List<SelectSpeakersByTalkId>
): TalkItemUi {
val startTime = session.start_time.toLocalDateTime()
val endTime = session.end_time.toLocalDateTime()
val diff = endTime.toInstant(TimeZone.UTC).minus(startTime.toInstant(TimeZone.UTC))
val timeInMinutes = diff.inWholeMinutes.toInt()
val count = (speakers.size - MaxSpeakersCount).coerceAtLeast(minimumValue = 0)
val maxSpeakers = speakers.take(MaxSpeakersCount)
val speakersJoined = maxSpeakers.joinToString(", ") { it.display_name }
val speakersLabel = if (count == 0) speakersJoined
else getPluralsArg("text_speakers_list", count, listOf(speakersJoined, count))
val level = when (level) {
"advanced" -> getString("text_level_advanced")
"intermediate" -> getString("text_level_intermediate")
"beginner" -> getString("text_level_beginner")
else -> level
}
return TalkItemUi(
id = id,
order = session.order_.toInt(),
Expand All @@ -116,10 +157,12 @@ fun SelectTalksBySpeakerId.convertTalkItemUi(
slotTime = startTime.formatHoursMinutes(),
startTime = session.start_time,
endTime = session.end_time,
timeInMinutes = diff.inWholeMinutes.toInt(),
timeInMinutes = timeInMinutes,
time = getStringArg("text_schedule_minutes", listOf(timeInMinutes.toString())),
category = convertCategoryUi(),
speakers = speakers.map { it.display_name }.toImmutableList(),
speakersAvatar = speakers.map { it.photo_url }.toImmutableList(),
speakers = maxSpeakers.map { it.display_name }.toImmutableList(),
speakersAvatar = maxSpeakers.map { it.photo_url }.toImmutableList(),
speakersLabel = speakersLabel,
isFavorite = session.is_favorite
)
}
Expand Down
37 changes: 37 additions & 0 deletions shared/core/src/iosMain/kotlin/org/gdglille/devfest/Platform.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ import platform.Foundation.NSBundle
import platform.Foundation.NSData
import platform.Foundation.NSNumber
import platform.Foundation.NSNumberFormatter
import platform.Foundation.NSString
import platform.Foundation.NSURL
import platform.Foundation.dataWithBytes
import platform.Foundation.stringWithFormat
import platform.UIKit.UIImage
import platform.UIKit.UIImageJPEGRepresentation
import platform.posix.memcpy
Expand All @@ -30,6 +32,10 @@ actual class Platform actual constructor(context: PlatformContext) {
)
actual val hasSupportSVG: Boolean = false
actual fun getString(key: String): String = key.localized()
actual fun getString(key: String, count: Int, args: List<Any>): String =
key.localized(count, *args.toTypedArray())
actual fun getString(key: String, args: List<Any>): String =
key.localized(*args.toTypedArray())
}

fun String.localized(): String {
Expand All @@ -47,6 +53,37 @@ fun String.localized(): String {
return this
}

fun String.localized(count: Int, vararg arguments: Any?): String {
val quantity = when (count) {
0 -> "zero"
1 -> "one"
2 -> "two"
else -> "other"
}
return "$this.$quantity".localized(arguments)
}

fun String.localized(vararg arguments: Any?): String {
val format = localized()
// Shorten the variable name
val a = arguments
// Kotlin does not support passing variadic parameters to Objective-C
// We implement calling the method with up to 9 arguments which is enough in practice
return when (arguments.size) {
0 -> NSString.stringWithFormat(format)
1 -> NSString.stringWithFormat(format, a[0])
2 -> NSString.stringWithFormat(format, a[0], a[1])
3 -> NSString.stringWithFormat(format, a[0], a[1], a[2])
4 -> NSString.stringWithFormat(format, a[0], a[1], a[2], a[3])
5 -> NSString.stringWithFormat(format, a[0], a[1], a[2], a[3], a[4])
6 -> NSString.stringWithFormat(format, a[0], a[1], a[2], a[3], a[4], a[5])
7 -> NSString.stringWithFormat(format, a[0], a[1], a[2], a[3], a[4], a[5], a[6])
8 -> NSString.stringWithFormat(format, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7])
9 -> NSString.stringWithFormat(format, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8])
else -> error("Too many arguments.")
}
}

actual class DecimalFormat {
actual fun format(number: Int): String {
val formatter = NSNumberFormatter()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,19 @@ data class AgendaUi(
val fake = AgendaUi(
onlyFavorites = false,
talks = persistentMapOf(
"10:00" to persistentListOf(TalkItemUi.fake, TalkItemUi.fake),
"11:00" to persistentListOf(TalkItemUi.fake, TalkItemUi.fake),
"10:00" to persistentListOf(
TalkItemUi.fake.copy(id = "1"),
TalkItemUi.fake.copy(id = "2")
),
"11:00" to persistentListOf(
TalkItemUi.fake.copy(id = "3"),
TalkItemUi.fake.copy(id = "4")
),
"12:00" to persistentListOf(TalkItemUi.fakePause),
"13:00" to persistentListOf(TalkItemUi.fake, TalkItemUi.fake),
"13:00" to persistentListOf(
TalkItemUi.fake.copy(id = "5"),
TalkItemUi.fake.copy(id = "6")
),
)
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package org.gdglille.devfest.models.ui
data class CategoryUi(
val id: String,
val name: String,
val color: String?,
val color: String,
val icon: String?
) {
companion object {
Expand Down
Loading

0 comments on commit 43a21e8

Please sign in to comment.