diff --git a/shared/di/src/commonMain/kotlin/fr/androidmakers/di/DomainModule.kt b/shared/di/src/commonMain/kotlin/fr/androidmakers/di/DomainModule.kt index 13fabc13..bc046b57 100644 --- a/shared/di/src/commonMain/kotlin/fr/androidmakers/di/DomainModule.kt +++ b/shared/di/src/commonMain/kotlin/fr/androidmakers/di/DomainModule.kt @@ -1,5 +1,6 @@ package fr.androidmakers.di +import fr.androidmakers.domain.interactor.ApplyForAppClinicUseCase import fr.androidmakers.domain.interactor.GetAfterpartyVenueUseCase import fr.androidmakers.domain.interactor.GetAgendaUseCase import fr.androidmakers.domain.interactor.GetConferenceVenueUseCase @@ -36,4 +37,5 @@ val domainModule = module { factory { GetFavoriteSessionsUseCase(get()) } factory { OpenPartnerLinkUseCase(get()) } factory { OpenLinkUseCase(get()) } + factory { ApplyForAppClinicUseCase(get()) } } diff --git a/shared/domain/src/commonMain/kotlin/fr/androidmakers/domain/interactor/ApplyForAppClinicUseCase.kt b/shared/domain/src/commonMain/kotlin/fr/androidmakers/domain/interactor/ApplyForAppClinicUseCase.kt new file mode 100644 index 00000000..31b5cdc6 --- /dev/null +++ b/shared/domain/src/commonMain/kotlin/fr/androidmakers/domain/interactor/ApplyForAppClinicUseCase.kt @@ -0,0 +1,12 @@ +package fr.androidmakers.domain.interactor + +import fr.androidmakers.domain.model.APPLY_FOR_APP_CLINIC_MAILTO_URL +import fr.androidmakers.domain.utils.UrlOpener + +class ApplyForAppClinicUseCase( + private val urlOpener: UrlOpener +) { + operator fun invoke() { + urlOpener.openUrl(APPLY_FOR_APP_CLINIC_MAILTO_URL) + } +} diff --git a/shared/domain/src/commonMain/kotlin/fr/androidmakers/domain/model/AppClinic.kt b/shared/domain/src/commonMain/kotlin/fr/androidmakers/domain/model/AppClinic.kt new file mode 100644 index 00000000..e9a584e1 --- /dev/null +++ b/shared/domain/src/commonMain/kotlin/fr/androidmakers/domain/model/AppClinic.kt @@ -0,0 +1,7 @@ +package fr.androidmakers.domain.model + +fun Session.isAppClinic(): Boolean { + return tags.contains("App Clinic") +} + +const val APPLY_FOR_APP_CLINIC_MAILTO_URL = "mailto:app.clinic@paug.fr?subject=App-Clinic%20-%20%5BYOUR_APP%5D&body=Hi%20Android%20Makers%2C%0A%0AI'm%20interested%20in%20participating%20in%20the%20App-Clinic.%20Below%20are%20the%20details%20of%20my%20app%3A%0A%0A%20%20%20%20Name%3A%0A%20%20%20%20Short%20Description%3A%0A%20%20%20%20Company%3A%0A%20%20%20%20Store%20URL%20(or%20link%20to%20an%20APK%20file)%3A%0A%20%20%20%20Requirements%3A%0A%20%20%20%20Anything%20Else%3F%3A%0A%0A%0ABest%2C%0A%5BYour%20Name%5D" \ No newline at end of file diff --git a/shared/ui/src/commonMain/kotlin/com/androidmakers/di/ViewModelModule.kt b/shared/ui/src/commonMain/kotlin/com/androidmakers/di/ViewModelModule.kt index 0782f380..fd9db9fd 100644 --- a/shared/ui/src/commonMain/kotlin/com/androidmakers/di/ViewModelModule.kt +++ b/shared/ui/src/commonMain/kotlin/com/androidmakers/di/ViewModelModule.kt @@ -16,7 +16,7 @@ val viewModelModule = module { factory { VenueViewModel(get(), get(), get()) } factory { (speakerId: String) -> SpeakerDetailsViewModel(speakerId, get(), get()) } factory { AgendaLayoutViewModel(get()) } - factory { AgendaPagerViewModel(get(), get(), get()) } - factory { (sessionId: String) -> SessionDetailViewModel(sessionId, get(), get(), get(), get(), get(), get(), get()) } + factory { AgendaPagerViewModel(get(), get(), get(), get()) } + factory { (sessionId: String) -> SessionDetailViewModel(sessionId, get(), get(), get(), get(), get(), get(), get(), get()) } factory { AboutViewModel(get(), get(), get(), get(), get()) } } diff --git a/shared/ui/src/commonMain/kotlin/com/androidmakers/ui/agenda/AgendaColumn.kt b/shared/ui/src/commonMain/kotlin/com/androidmakers/ui/agenda/AgendaColumn.kt index c8709c90..09e59dec 100644 --- a/shared/ui/src/commonMain/kotlin/com/androidmakers/ui/agenda/AgendaColumn.kt +++ b/shared/ui/src/commonMain/kotlin/com/androidmakers/ui/agenda/AgendaColumn.kt @@ -26,6 +26,7 @@ import androidx.compose.ui.unit.dp import fr.paug.androidmakers.ui.MR import com.androidmakers.ui.model.UISession import dev.icerock.moko.resources.compose.stringResource +import fr.androidmakers.domain.interactor.ApplyForAppClinicUseCase import org.jetbrains.compose.ui.tooling.preview.Preview @OptIn(ExperimentalFoundationApi::class) @@ -34,6 +35,7 @@ fun AgendaColumn( sessionsPerStartTime: Map>, onSessionClicked: (UISession) -> Unit, onSessionBookmarked: (UISession, Boolean) -> Unit, + onApplyForAppClinicClicked: () -> Unit, ) { val listState = rememberLazyListState() @@ -65,7 +67,8 @@ fun AgendaColumn( modifier = Modifier.animateItemPlacement(), uiSession = uiSession, onSessionClicked = onSessionClicked, - onSessionBookmarked = onSessionBookmarked + onSessionBookmarked = onSessionBookmarked, + onApplyForAppClinic = onApplyForAppClinicClicked ) } } diff --git a/shared/ui/src/commonMain/kotlin/com/androidmakers/ui/agenda/AgendaPager.kt b/shared/ui/src/commonMain/kotlin/com/androidmakers/ui/agenda/AgendaPager.kt index 5096c1c0..b3f89d6c 100644 --- a/shared/ui/src/commonMain/kotlin/com/androidmakers/ui/agenda/AgendaPager.kt +++ b/shared/ui/src/commonMain/kotlin/com/androidmakers/ui/agenda/AgendaPager.kt @@ -19,6 +19,7 @@ import com.androidmakers.ui.common.EmptyLayout import com.androidmakers.ui.common.SessionFilter import com.androidmakers.ui.common.SwipeRefreshableLceLayout import com.androidmakers.ui.model.UISession +import fr.androidmakers.domain.interactor.ApplyForAppClinicUseCase import fr.androidmakers.domain.utils.formatShortTime import kotlinx.coroutines.launch import moe.tlaster.precompose.koin.koinViewModel @@ -81,6 +82,7 @@ fun AgendaPager( AgendaColumn( sessionsPerStartTime = addSeparators(items), onSessionClicked = onSessionClicked, + onApplyForAppClinicClicked = viewModel::applyForAppClinic, onSessionBookmarked = { uiSession, bookmarked -> viewModel.setSessionBookmark(uiSession, bookmarked) } diff --git a/shared/ui/src/commonMain/kotlin/com/androidmakers/ui/agenda/AgendaPagerViewModel.kt b/shared/ui/src/commonMain/kotlin/com/androidmakers/ui/agenda/AgendaPagerViewModel.kt index 536fd639..3458a467 100644 --- a/shared/ui/src/commonMain/kotlin/com/androidmakers/ui/agenda/AgendaPagerViewModel.kt +++ b/shared/ui/src/commonMain/kotlin/com/androidmakers/ui/agenda/AgendaPagerViewModel.kt @@ -6,14 +6,16 @@ import fr.androidmakers.domain.interactor.GetFavoriteSessionsUseCase import fr.androidmakers.domain.interactor.SetSessionBookmarkUseCase import fr.androidmakers.domain.model.Agenda import com.androidmakers.ui.model.UISession +import fr.androidmakers.domain.interactor.ApplyForAppClinicUseCase import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.launch import moe.tlaster.precompose.viewmodel.viewModelScope class AgendaPagerViewModel( - private val getAgendaUseCase: GetAgendaUseCase, - private val setSessionBookmarkUseCase: SetSessionBookmarkUseCase, - private val getFavoriteSessionsUseCase: GetFavoriteSessionsUseCase + private val getAgendaUseCase: GetAgendaUseCase, + private val setSessionBookmarkUseCase: SetSessionBookmarkUseCase, + private val getFavoriteSessionsUseCase: GetFavoriteSessionsUseCase, + private val applyForAppClinicUseCase: ApplyForAppClinicUseCase, ) : LceViewModel() { override fun produce(): Flow> { return getAgendaUseCase() @@ -28,4 +30,8 @@ class AgendaPagerViewModel( fun setSessionBookmark(uiSession: UISession, bookmark: Boolean) = viewModelScope.launch { setSessionBookmarkUseCase(uiSession.id, bookmark) } + + fun applyForAppClinic() { + applyForAppClinicUseCase() + } } diff --git a/shared/ui/src/commonMain/kotlin/com/androidmakers/ui/agenda/AgendaRow.kt b/shared/ui/src/commonMain/kotlin/com/androidmakers/ui/agenda/AgendaRow.kt index 609c7c3f..2dc162d9 100644 --- a/shared/ui/src/commonMain/kotlin/com/androidmakers/ui/agenda/AgendaRow.kt +++ b/shared/ui/src/commonMain/kotlin/com/androidmakers/ui/agenda/AgendaRow.kt @@ -10,6 +10,7 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.rounded.BookmarkAdd import androidx.compose.material.icons.rounded.BookmarkRemove import androidx.compose.material.ripple.rememberRipple +import androidx.compose.material3.Button import androidx.compose.material3.Icon import androidx.compose.material3.IconToggleButton import androidx.compose.material3.ListItem @@ -27,7 +28,9 @@ import androidx.compose.ui.unit.dp import com.androidmakers.ui.common.EmojiUtils import com.androidmakers.ui.model.UISession import com.androidmakers.ui.theme.AMColor +import dev.icerock.moko.resources.compose.stringResource import fr.androidmakers.domain.model.Session +import fr.paug.androidmakers.ui.MR import kotlinx.datetime.Instant import kotlinx.datetime.toInstant import org.jetbrains.compose.ui.tooling.preview.Preview @@ -64,6 +67,7 @@ fun AgendaRow( modifier: Modifier = Modifier, onSessionClicked: (UISession) -> Unit, onSessionBookmarked: (UISession, Boolean) -> Unit, + onApplyForAppClinic: () -> Unit, ) { ListItem( modifier = modifier, @@ -82,6 +86,19 @@ fun AgendaRow( modifier = maybeClickable(uiSession, onSessionClicked).padding(top = 12.dp), horizontalAlignment = Alignment.Start, ) { + + if(uiSession.isAppClinic) { + Button( + onClick = onApplyForAppClinic, + modifier = Modifier.padding(bottom = 8.dp) + ) { + Text( + text = stringResource(MR.strings.session_app_clinic_apply), + style = MaterialTheme.typography.labelMedium + ) + } + } + val speakers = uiSession.speakers.joinToString(", ") { it.name } if (speakers.isNotBlank()) { Text( @@ -156,7 +173,7 @@ fun UISession.formattedDuration(): String { @Preview @Composable private fun AgendaRowPreview() { - AgendaRow(fakeUiSession, onSessionClicked = {}, onSessionBookmarked = { _,_ -> }) + AgendaRow(fakeUiSession, onSessionClicked = {}, onSessionBookmarked = { _,_ -> }, onApplyForAppClinic = {}) } private val fakeUiSession = UISession( diff --git a/shared/ui/src/commonMain/kotlin/com/androidmakers/ui/agenda/AgendaUtils.kt b/shared/ui/src/commonMain/kotlin/com/androidmakers/ui/agenda/AgendaUtils.kt index 04ea4ad8..812b6c4f 100644 --- a/shared/ui/src/commonMain/kotlin/com/androidmakers/ui/agenda/AgendaUtils.kt +++ b/shared/ui/src/commonMain/kotlin/com/androidmakers/ui/agenda/AgendaUtils.kt @@ -6,6 +6,7 @@ import fr.androidmakers.domain.model.Agenda import fr.androidmakers.domain.model.Room import fr.androidmakers.domain.model.Session import fr.androidmakers.domain.model.Speaker +import fr.androidmakers.domain.model.isAppClinic import fr.androidmakers.domain.utils.eventTimeZone import fr.androidmakers.domain.utils.formatMediumDate import kotlinx.datetime.LocalDate @@ -47,7 +48,8 @@ fun Session.toUISession( room = rooms[roomId]?.name ?: "unknown", speakers = this.speakers.mapNotNull { speakers[it]?.toUISpeaker() }, isServiceSession = isServiceSession, - isFavorite = isFavorite + isFavorite = isFavorite, + isAppClinic = isAppClinic() ) } diff --git a/shared/ui/src/commonMain/kotlin/com/androidmakers/ui/agenda/SessionDetailLayout.kt b/shared/ui/src/commonMain/kotlin/com/androidmakers/ui/agenda/SessionDetailLayout.kt index c0cd26d1..e6066ea8 100644 --- a/shared/ui/src/commonMain/kotlin/com/androidmakers/ui/agenda/SessionDetailLayout.kt +++ b/shared/ui/src/commonMain/kotlin/com/androidmakers/ui/agenda/SessionDetailLayout.kt @@ -28,6 +28,7 @@ import androidx.compose.material.icons.rounded.BookmarkRemove import androidx.compose.material.icons.rounded.Info import androidx.compose.material.icons.rounded.Public import androidx.compose.material.icons.rounded.Share +import androidx.compose.material3.Button import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.ExperimentalMaterial3Api @@ -47,6 +48,7 @@ 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.text.font.FontWeight import androidx.compose.ui.text.intl.Locale import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp @@ -63,6 +65,7 @@ import dev.icerock.moko.resources.compose.painterResource import dev.icerock.moko.resources.compose.stringResource import fr.androidmakers.domain.model.SocialsItem import fr.androidmakers.domain.model.Speaker +import fr.androidmakers.domain.model.isAppClinic import fr.androidmakers.domain.utils.removeHtmlTags import fr.paug.androidmakers.ui.MR import io.openfeedback.m3.OpenFeedback @@ -90,6 +93,9 @@ fun SessionDetailScreen( }, onOpenLink = { viewModel.openLink(it) + }, + onApplyForAppClinic = { + viewModel.applyForAppClinic() } ) } @@ -102,6 +108,7 @@ fun SessionDetailLayout( onBookmarkClick: (bookmarked: Boolean) -> Unit, onShareSession: () -> Unit, onOpenLink: (SocialsItem) -> Unit, + onApplyForAppClinic: () -> Unit, ) { val formattedDateAndRoom: String? = if (sessionDetailState is Lce.Content) { sessionDetailState.content.formattedDateAndRoom() @@ -165,6 +172,7 @@ fun SessionDetailLayout( sessionDetails = sessionDetailState.content, formattedDateAndRoom = formattedDateAndRoom!!, openLink = onOpenLink, + onApplyForAppClinic = onApplyForAppClinic, modifier = Modifier.padding(innerPadding) ) } @@ -178,6 +186,7 @@ private fun SessionDetails( sessionDetails: SessionDetailState, formattedDateAndRoom: String, openLink: (SocialsItem) -> Unit, + onApplyForAppClinic: () -> Unit, ) { Column( @@ -216,6 +225,20 @@ private fun SessionDetails( style = MaterialTheme.typography.bodyLarge, ) + if(sessionDetails.session.isAppClinic()) { + Button( + onClick = onApplyForAppClinic, + modifier = Modifier.padding(top = 16.dp) + .align(Alignment.CenterHorizontally), + ) { + Text( + text = stringResource(MR.strings.session_app_clinic_apply), + style = MaterialTheme.typography.bodyLarge, + fontWeight = FontWeight.Bold, + ) + } + } + ChipList(sessionDetails) Speakers( @@ -428,5 +451,6 @@ private fun SessionDetailLayoutLoadingPreview() { onBookmarkClick = {}, onShareSession = {}, onOpenLink = {}, + onApplyForAppClinic = {} ) } diff --git a/shared/ui/src/commonMain/kotlin/com/androidmakers/ui/agenda/SessionDetailViewModel.kt b/shared/ui/src/commonMain/kotlin/com/androidmakers/ui/agenda/SessionDetailViewModel.kt index 93905337..73835ce8 100644 --- a/shared/ui/src/commonMain/kotlin/com/androidmakers/ui/agenda/SessionDetailViewModel.kt +++ b/shared/ui/src/commonMain/kotlin/com/androidmakers/ui/agenda/SessionDetailViewModel.kt @@ -2,6 +2,7 @@ package com.androidmakers.ui.agenda import com.androidmakers.ui.model.Lce import com.androidmakers.ui.model.SessionDetailState +import fr.androidmakers.domain.interactor.ApplyForAppClinicUseCase import fr.androidmakers.domain.interactor.OpenLinkUseCase import fr.androidmakers.domain.interactor.SetSessionBookmarkUseCase import fr.androidmakers.domain.interactor.ShareSessionUseCase @@ -30,7 +31,8 @@ class SessionDetailViewModel( private val speakersRepository: SpeakersRepository, private val setSessionBookmarkUseCase: SetSessionBookmarkUseCase, private val shareSessionUseCase: ShareSessionUseCase, - private val openLinkUseCase: OpenLinkUseCase, + private val openLinkUseCase: OpenLinkUseCase, + private val applyForAppClinicUseCase: ApplyForAppClinicUseCase, ) : ViewModel() { private val session = sessionsRepository.getSession(sessionId) @@ -100,4 +102,8 @@ class SessionDetailViewModel( fun openLink(socialsItem: SocialsItem) { socialsItem.url?.let { openLinkUseCase(it) } } + + fun applyForAppClinic() { + applyForAppClinicUseCase() + } } diff --git a/shared/ui/src/commonMain/kotlin/com/androidmakers/ui/model/uimodel.kt b/shared/ui/src/commonMain/kotlin/com/androidmakers/ui/model/uimodel.kt index eb3442d6..8a7d4727 100644 --- a/shared/ui/src/commonMain/kotlin/com/androidmakers/ui/model/uimodel.kt +++ b/shared/ui/src/commonMain/kotlin/com/androidmakers/ui/model/uimodel.kt @@ -13,6 +13,7 @@ class UISession( val speakers: List, val isServiceSession: Boolean, var isFavorite: Boolean, + var isAppClinic: Boolean = false, ) { class Speaker(val name: String) } diff --git a/shared/ui/src/commonMain/moko-resources/base/strings.xml b/shared/ui/src/commonMain/moko-resources/base/strings.xml index 3e19a17f..6cd3e397 100644 --- a/shared/ui/src/commonMain/moko-resources/base/strings.xml +++ b/shared/ui/src/commonMain/moko-resources/base/strings.xml @@ -81,6 +81,6 @@ %1$s / %2$s / %3$s %1$s / %2$s %1$s, %2$s - + Apply for App-Clinic diff --git a/shared/ui/src/commonMain/moko-resources/fr/strings.xml b/shared/ui/src/commonMain/moko-resources/fr/strings.xml index c24b5910..9ef853e6 100644 --- a/shared/ui/src/commonMain/moko-resources/fr/strings.xml +++ b/shared/ui/src/commonMain/moko-resources/fr/strings.xml @@ -77,4 +77,6 @@ AMxDC24 AndroidMakersFR + Proposer mon application +