Skip to content

Commit

Permalink
Merge branch 'main' into design/display_a_shadow_instead_of_a_line
Browse files Browse the repository at this point in the history
  • Loading branch information
Corvus400 authored Sep 3, 2024
2 parents 34f00d1 + cf6bcdc commit a3e7f02
Show file tree
Hide file tree
Showing 44 changed files with 653 additions and 109 deletions.
4 changes: 2 additions & 2 deletions app-android/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@

<activity
android:name="com.google.android.gms.oss.licenses.OssLicensesMenuActivity"
android:theme="@style/Theme.AppCompat.DayNight.DarkActionBar" />
android:theme="@style/Theme.KaigiApp.Licenses" />

<activity
android:name="com.google.android.gms.oss.licenses.OssLicensesActivity"
android:theme="@style/Theme.AppCompat.DayNight.DarkActionBar" />
android:theme="@style/Theme.KaigiApp.Licenses" />

<provider
android:name="androidx.core.content.FileProvider"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,8 @@ private class ExternalNavController(

fun onShareClick(timetableItem: TimetableItem) {
shareNavigator.share(
"[${timetableItem.room.name.currentLangTitle}] ${timetableItem.startsTimeString} - ${timetableItem.endsTimeString}\n" +
"[${timetableItem.room.name.currentLangTitle}] ${timetableItem.formattedMonthAndDayString} " +
"${timetableItem.startsTimeString} - ${timetableItem.endsTimeString}\n" +
"${timetableItem.title.currentLangTitle}\n" +
timetableItem.url,
)
Expand Down
4 changes: 4 additions & 0 deletions app-android/src/main/res/values/themes.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,8 @@
<style name="Theme.KaigiApp" parent="android:Theme.Material.NoActionBar">
<item name="android:statusBarColor">@android:color/transparent</item>
</style>

<style name="Theme.KaigiApp.Licenses" parent="Theme.AppCompat.DayNight.DarkActionBar">
<item name="android:windowOptOutEdgeToEdgeEnforcement">true</item>
</style>
</resources>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="permission_required">セッションを予定として追加するには、カレンダーへのアクセス権限が必要です。</string>
<string name="open_settings">設定を開く</string>
</resources>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="permission_required">To add a session as a scheduled event, you need access permission to the calendar.</string>
<string name="open_settings">Open settings.</string>
</resources>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package io.github.droidkaigi.confsched.shared

import conference_app_2024.app_ios_shared.generated.resources.Res

object AppIosSharedRes {
val drawable = Res.drawable
val string = Res.string
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ package io.github.droidkaigi.confsched.shared
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Surface
import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
import androidx.compose.material3.windowsizeclass.WindowSizeClass
import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
Expand All @@ -20,15 +22,21 @@ import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController
import co.touchlab.kermit.Logger
import conference_app_2024.app_ios_shared.generated.resources.permission_required
import conference_app_2024.app_ios_shared.generated.resources.open_settings
import io.github.droidkaigi.confsched.about.aboutScreen
import io.github.droidkaigi.confsched.about.aboutScreenRoute
import io.github.droidkaigi.confsched.about.navigateAboutScreen
import io.github.droidkaigi.confsched.compose.rememberEventFlow
import io.github.droidkaigi.confsched.contributors.contributorsScreenRoute
import io.github.droidkaigi.confsched.contributors.contributorsScreens
import io.github.droidkaigi.confsched.data.Repositories
import io.github.droidkaigi.confsched.designsystem.theme.KaigiTheme
import io.github.droidkaigi.confsched.designsystem.theme.dotGothic16FontFamily
import io.github.droidkaigi.confsched.droidkaigiui.NavHostWithSharedAxisX
import io.github.droidkaigi.confsched.droidkaigiui.SnackbarMessageEffect
import io.github.droidkaigi.confsched.droidkaigiui.UserMessageStateHolder
import io.github.droidkaigi.confsched.droidkaigiui.compositionlocal.LocalSnackbarHostState
import io.github.droidkaigi.confsched.eventmap.eventMapScreenRoute
import io.github.droidkaigi.confsched.eventmap.eventMapScreens
import io.github.droidkaigi.confsched.eventmap.navigateEventMapScreen
Expand Down Expand Up @@ -76,6 +84,7 @@ import io.github.droidkaigi.confsched.staff.staffScreenRoute
import io.github.droidkaigi.confsched.staff.staffScreens
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import org.jetbrains.compose.resources.stringResource
import platform.EventKit.EKEntityType.EKEntityTypeEvent
import platform.EventKit.EKEvent
import platform.EventKit.EKEventStore
Expand All @@ -86,23 +95,26 @@ import platform.Foundation.NSDate
import platform.Foundation.NSURL
import platform.Foundation.dateWithTimeIntervalSince1970
import platform.UIKit.UIApplication
import platform.UIKit.UIApplicationOpenSettingsURLString
import platform.UIKit.UIViewController
import platform.darwin.NSObject

private object ExternalNavControllerLink {
var onLicenseScreenRequest: (() -> Unit)? = null
}
data class IosComposeKaigiAppUiState(
val userMessageStateHolder: UserMessageStateHolder,
val shouldGoToSettingsApp: Boolean,
)

@OptIn(ExperimentalMaterial3WindowSizeClassApi::class)
@Suppress("UNUSED")
fun kaigiAppController(
repositories: Repositories,
onLicenseScreenRequest: () -> Unit,
): UIViewController = ComposeUIViewController {
ExternalNavControllerLink.onLicenseScreenRequest = onLicenseScreenRequest
val snackbarHostState = remember { SnackbarHostState() }

CompositionLocalProvider(
LocalRepositories provides repositories.map
LocalRepositories provides repositories.map,
LocalSnackbarHostState provides snackbarHostState
) {
val windowSizeClass = calculateWindowSizeClass()

Expand All @@ -121,6 +133,8 @@ fun kaigiAppController(
KaigiApp(
windowSize = windowSizeClass,
fontFamily = fontFamily,
snackbarHostState = snackbarHostState,
onLicenseScreenRequest = onLicenseScreenRequest,
)
}
}
Expand All @@ -129,17 +143,48 @@ fun kaigiAppController(
fun KaigiApp(
windowSize: WindowSizeClass,
fontFamily: FontFamily?,
snackbarHostState: SnackbarHostState,
onLicenseScreenRequest: () -> Unit,
modifier: Modifier = Modifier,
externalNavController: ExternalNavController = rememberExternalNavController(),
) {
val eventFlow = rememberEventFlow<IosComposeKaigiAppEvent>()
val uiState = iosComposeKaigiAppPresenter(events = eventFlow)

SnackbarMessageEffect(
snackbarHostState = snackbarHostState,
userMessageStateHolder = uiState.userMessageStateHolder,
)

LaunchedEffect(uiState.shouldGoToSettingsApp) {
if (uiState.shouldGoToSettingsApp) {
eventFlow.tryEmit(IosComposeKaigiAppEvent.SettingsAppNavigated)
externalNavController.navigateToSettingsApp()
}
}

KaigiTheme(
fontFamily = fontFamily,
) {
Surface(
modifier = modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background,
) {
val snackbarMessage = stringResource(AppIosSharedRes.string.permission_required)
val snackbarActionLabel = stringResource(AppIosSharedRes.string.open_settings)

KaigiNavHost(
windowSize = windowSize,
externalNavController = externalNavController,
onLicenseScreenRequest = onLicenseScreenRequest,
onAccessCalendarIsDenied = {
eventFlow.tryEmit(
IosComposeKaigiAppEvent.ShowRequiresAuthorization(
snackbarMessage = snackbarMessage,
actionLabel = snackbarActionLabel,
)
)
}
)
}
}
Expand All @@ -148,19 +193,27 @@ fun KaigiApp(
@Composable
private fun KaigiNavHost(
windowSize: WindowSizeClass,
externalNavController: ExternalNavController,
onLicenseScreenRequest: () -> Unit,
onAccessCalendarIsDenied: () -> Unit,
navController: NavHostController = rememberNavController(),
externalNavController: ExternalNavController = rememberExternalNavController()
) {
NavHostWithSharedAxisX(navController = navController, startDestination = mainScreenRoute) {
mainScreen(
windowSize = windowSize,
navController = navController,
externalNavController = externalNavController,
onLicenseScreenRequest = onLicenseScreenRequest,
)
sessionScreens(
onNavigationIconClick = navController::popBackStack,
onLinkClick = externalNavController::navigate,
onCalendarRegistrationClick = externalNavController::navigateToCalendarRegistration,
onCalendarRegistrationClick = { timetableItem ->
externalNavController.navigateToCalendarRegistration(
timetableItem = timetableItem,
onAccessCalendarIsDenied = onAccessCalendarIsDenied,
)
},
onShareClick = externalNavController::onShareClick,
onFavoriteListClick = {
navController.navigate(
Expand Down Expand Up @@ -205,6 +258,7 @@ private fun NavGraphBuilder.mainScreen(
windowSize: WindowSizeClass,
navController: NavHostController,
externalNavController: ExternalNavController,
onLicenseScreenRequest: () -> Unit,
) {
mainScreen(
windowSize = windowSize,
Expand Down Expand Up @@ -246,7 +300,7 @@ private fun NavGraphBuilder.mainScreen(
}

AboutItem.Contributors -> navController.navigate(contributorsScreenRoute)
AboutItem.License -> externalNavController.navigateToLicenseScreen()
AboutItem.License -> onLicenseScreenRequest()
AboutItem.Medium -> externalNavController.navigate(
url = "https://medium.com/droidkaigi",
)
Expand Down Expand Up @@ -319,7 +373,7 @@ private fun rememberExternalNavController(): ExternalNavController {
}
}

private class ExternalNavController(
class ExternalNavController(
private val shareNavigator: ShareNavigator,
private val coroutineScope: CoroutineScope,
) {
Expand All @@ -334,20 +388,18 @@ private class ExternalNavController(
UIApplication.sharedApplication.openURL(nsUrl)
}

fun navigateToLicenseScreen() {
ExternalNavControllerLink.onLicenseScreenRequest?.invoke()
}

/**
* Navigate to Calendar Registration
*/
fun navigateToCalendarRegistration(timetableItem: TimetableItem) {
fun navigateToCalendarRegistration(
timetableItem: TimetableItem,
onAccessCalendarIsDenied: () -> Unit,
) {
val eventStore = EKEventStore()

eventStore.requestAccessToEntityType(EKEntityTypeEvent) { granted, error ->
if (granted.not()) {
// TODO Display a message asking the user to add permissions.
// TODO Otherwise, the privileges will remain permanently denied.
onAccessCalendarIsDenied()
Logger.e("Calendar access was denied by the user.")
return@requestAccessToEntityType
}
Expand Down Expand Up @@ -394,6 +446,13 @@ private class ExternalNavController(
}
}

fun navigateToSettingsApp() {
val settingsUrl = NSURL.URLWithString(UIApplicationOpenSettingsURLString)
if (settingsUrl != null) {
UIApplication.sharedApplication.openURL(settingsUrl)
}
}

fun onShareClick(timetableItem: TimetableItem) {
shareNavigator.share(
"[${timetableItem.room.name.currentLangTitle}] ${timetableItem.startsTimeString} - ${timetableItem.endsTimeString}\n" +
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package io.github.droidkaigi.confsched.shared

import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import io.github.droidkaigi.confsched.compose.EventEffect
import io.github.droidkaigi.confsched.compose.EventFlow
import io.github.droidkaigi.confsched.droidkaigiui.UserMessageResult.ActionPerformed
import io.github.droidkaigi.confsched.droidkaigiui.providePresenterDefaults
import io.github.droidkaigi.confsched.shared.IosComposeKaigiAppEvent.SettingsAppNavigated
import io.github.droidkaigi.confsched.shared.IosComposeKaigiAppEvent.ShowRequiresAuthorization

sealed interface IosComposeKaigiAppEvent {
data class ShowRequiresAuthorization(
val snackbarMessage: String,
val actionLabel: String,
) : IosComposeKaigiAppEvent

data object SettingsAppNavigated : IosComposeKaigiAppEvent
}

@Composable
fun iosComposeKaigiAppPresenter(
events: EventFlow<IosComposeKaigiAppEvent>
) : IosComposeKaigiAppUiState = providePresenterDefaults { userMessageStateHolder ->
var shouldGoToSettingsApp by remember { mutableStateOf(false) }

EventEffect(events) { event ->
when (event) {
is ShowRequiresAuthorization -> {
val result = userMessageStateHolder.showMessage(
message = event.snackbarMessage,
actionLabel = event.actionLabel,
)
if (result == ActionPerformed) {
shouldGoToSettingsApp = true
}
}

SettingsAppNavigated -> {
shouldGoToSettingsApp = false
}
}
}
IosComposeKaigiAppUiState(
userMessageStateHolder = userMessageStateHolder,
shouldGoToSettingsApp = shouldGoToSettingsApp,
)
}
1 change: 0 additions & 1 deletion app-ios/Sources/AboutFeature/AboutView.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import ComposableArchitecture
import SwiftUI
import LicenseList
import Theme

@ViewAction(for: AboutReducer.self)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Foundation
import SwiftUI
import Theme

private actor CircularUserIconInMemoryCache {
static let shared = CircularUserIconInMemoryCache()
Expand Down Expand Up @@ -35,6 +36,10 @@ public struct CircularUserIcon: View {
}
}
.clipShape(Circle())
.overlay(
Circle()
.stroke(AssetColors.Outline.outline.swiftUIColor, lineWidth: 1)
)
.task {
if let data = await CircularUserIconInMemoryCache.shared.data(urlString: urlString) {
iconData = data
Expand Down
4 changes: 0 additions & 4 deletions app-ios/Sources/StaffFeature/StaffLabel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,6 @@ struct StaffLabel: View {
HStack(alignment: .center, spacing: 12) {
CircularUserIcon(urlString: icon.absoluteString)
.frame(width: 52, height: 52)
.overlay(
Circle()
.stroke(AssetColors.Outline.outline.swiftUIColor, lineWidth: 1)
)

Text(name)
.textStyle(.bodyLarge)
Expand Down
11 changes: 2 additions & 9 deletions app-ios/Sources/TimetableFeature/TimetableGridCard.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,8 @@ public struct TimetableGridCard: View {

ForEach(timetableItem.speakers, id: \.id) { speaker in
HStack(spacing: 8) {
Group {
AsyncImage(url: URL(string: speaker.iconUrl)) {
$0.resizable()
} placeholder: {
Color.gray
}
}
.frame(width: 32, height: 32)
.clipShape(Circle())
CircularUserIcon(urlString: speaker.iconUrl)
.frame(width: 32, height: 32)

Text(speaker.name)
.textStyle(.titleSmall)
Expand Down
Loading

0 comments on commit a3e7f02

Please sign in to comment.