Skip to content

Commit

Permalink
Merge branch 'main' into raseln/implement_contributors_count_ui
Browse files Browse the repository at this point in the history
# Conflicts:
#	app-ios/Sources/ContributorFeature/KmpPresenterContributorView.swift
  • Loading branch information
raseln committed Sep 6, 2024
2 parents d5513a1 + a44ef3f commit f9e609f
Show file tree
Hide file tree
Showing 66 changed files with 579 additions and 213 deletions.
6 changes: 6 additions & 0 deletions app-android/src/main/res/values-v35/themes.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.KaigiApp.Licenses" parent="Theme.AppCompat.DayNight.DarkActionBar">
<item name="android:windowOptOutEdgeToEdgeEnforcement">true</item>
</style>
</resources>
2 changes: 1 addition & 1 deletion app-android/src/main/res/values/themes.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@
</style>

<style name="Theme.KaigiApp.Licenses" parent="Theme.AppCompat.DayNight.DarkActionBar">
<item name="android:windowOptOutEdgeToEdgeEnforcement">true</item>
<!-- Overridden by v35 -->
</style>
</resources>
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package io.github.droidkaigi.confsched.shared

import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
import androidx.compose.material3.windowsizeclass.WindowSizeClass.Companion.calculateFromSize
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.remember
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.platform.LocalDensity
import androidx.lifecycle.compose.LocalLifecycleOwner
Expand All @@ -17,6 +19,7 @@ import io.github.droidkaigi.confsched.data.Repositories
import io.github.droidkaigi.confsched.data.auth.Authenticator
import io.github.droidkaigi.confsched.data.auth.User
import io.github.droidkaigi.confsched.data.remoteconfig.FakeRemoteConfigApi
import io.github.droidkaigi.confsched.droidkaigiui.compositionlocal.LocalSnackbarHostState
import io.github.droidkaigi.confsched.model.compositionlocal.LocalRepositories
import io.github.takahirom.roborazzi.captureRoboImage
import kotlin.test.Test
Expand Down Expand Up @@ -45,12 +48,16 @@ class IosComposeKaigiTest {
)
runComposeUiTest {
setContent {
val snackbarHostState = remember { SnackbarHostState() }

CompositionLocalProvider(
LocalLifecycleOwner provides object : LifecycleOwner {
override val lifecycle: Lifecycle = LifecycleRegistry(this)
},
LocalRepositories provides kmpEntryPoint.get<Repositories>().map,
LocalSnackbarHostState provides snackbarHostState
) {

KaigiApp(
windowSize = calculateFromSize(
size = Size(
Expand All @@ -60,6 +67,8 @@ class IosComposeKaigiTest {
density = LocalDensity.current,
),
fontFamily = null,
snackbarHostState = snackbarHostState,
onLicenseScreenRequest = {},
)
}
}
Expand Down
1 change: 1 addition & 0 deletions app-ios/App/App.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import App
import ComposableArchitecture
import SwiftUI
import Theme
import KMPClientLive

final class AppDelegate: NSObject, UIApplicationDelegate {
let store = Store(
Expand Down
20 changes: 12 additions & 8 deletions app-ios/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ let package = Package(
.eventMapFeature,
.tca,
.kmpClient,
.KMPClientLive,
.licenseList,
]
),
Expand All @@ -85,14 +86,20 @@ let package = Package(
name: "KMPClient",
dependencies: [
.kmpModule,
.firebaseAuth,
.firebaseRemoteConfig,
.tca,
.model,
.licenseList,
]
),


.target(
name: "KMPClientLive",
dependencies: [
.kmpClient,
.firebaseAuth,
.firebaseRemoteConfig,
]
),

.target(
name: "EventKitClient",
dependencies: [
Expand All @@ -105,8 +112,6 @@ let package = Package(
dependencies: [
.kmpClient,
.kmpModule,
.firebaseAuth,
.firebaseRemoteConfig,
.tca,
.commonComponents,
]
Expand All @@ -116,8 +121,6 @@ let package = Package(
dependencies: [
.app,
.timetableFeature,
.firebaseAuth,
.firebaseRemoteConfig,
.tca
]
),
Expand Down Expand Up @@ -293,6 +296,7 @@ extension Target.Dependency {
static let profileCardFeature: Target.Dependency = "ProfileCardFeature"
static let kmpModule: Target.Dependency = "KmpModule"
static let kmpClient: Target.Dependency = "KMPClient"
static let KMPClientLive: Target.Dependency = "KMPClientLive"
static let eventKitClient: Target.Dependency = "EventKitClient"
static let theme: Target.Dependency = "Theme"
static let commonComponents: Target.Dependency = "CommonComponents"
Expand Down
3 changes: 2 additions & 1 deletion app-ios/Sources/App/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import KMPClient

@Reducer
public struct AppDelegateReducer {
@Dependency(\.firebaseAppClient) var firebaseAppClient
public struct State: Equatable {
public init() {}
}
Expand All @@ -15,7 +16,7 @@ public struct AppDelegateReducer {
Reduce { state, action in
switch action {
case .didFinishLaunching:
prepareFirebase()
firebaseAppClient.prepareFirebase()

return .none
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,26 @@
import SwiftUI
import LicenseList
@preconcurrency import shared
import shared
import ComposableArchitecture

public struct KmpAppComposeViewControllerWrapper: UIViewControllerRepresentable {
public init() {}
@MainActor
struct KmpAppComposeViewControllerWrapper: UIViewControllerRepresentable {
@Dependency(\.containerClient) var containerClient

public func makeUIViewController(context: Context) -> UIViewController {
let container = Container.shared
let repositories: any Repositories = container.get(type: (any Repositories).self)
return IosComposeKaigiAppKt.kaigiAppController(
repositories: repositories,
init() {}

func makeUIViewController(context: Context) -> UIViewController {
IosComposeKaigiAppKt.kaigiAppController(
repositories: containerClient.repositories(),
onLicenseScreenRequest: {
openLicenseScreen()
}
)
}

public func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
}

private func openLicenseScreen() {
if let windowScene = UIApplication.shared.connectedScenes.first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene {
if let rootViewController = windowScene.windows.first?.rootViewController {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,28 @@
import SwiftUI
import shared
import ComposableArchitecture

public struct KmpProfileCardComposeViewControllerWrapper: UIViewControllerRepresentable {
public init() {}

public func makeUIViewController(context: Context) -> UIViewController {
struct KmpProfileCardComposeViewControllerWrapper: UIViewControllerRepresentable {
@Dependency(\.containerClient) var containerClient

init() {}

func makeUIViewController(context: Context) -> UIViewController {
profileCardViewController(
repositories: Container.shared.get(type: (any Repositories).self),
repositories: containerClient.repositories(),
onClickShareProfileCard: { image, text in
let activityViewController = UIActivityViewController(activityItems: [text, image], applicationActivities: nil)
if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
let keyWindow = windowScene.windows.first(where: { $0.isKeyWindow }),
let rootViewController = keyWindow.rootViewController {
let keyWindow = windowScene.windows.first(where: { $0.isKeyWindow }),
let rootViewController = keyWindow.rootViewController {
rootViewController.present(activityViewController, animated: true, completion: nil)
} else {
print("Unable to find the root view controller.")
}
}
)
}
public func updateUIViewController(_ uiViewController: UIViewController, context: Context) {

func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import SwiftUI
import shared
import ComposableArchitecture

struct KmpContributorComposeViewControllerWrapper: UIViewControllerRepresentable {
public typealias URLString = String

let repositories: any Repositories
private let onContributorsItemClick: (URLString) -> Void

init(onContributorsItemClick: @escaping (URLString) -> Void) {
@Dependency(\.containerClient) var containerClient

self.repositories = containerClient.repositories()
self.onContributorsItemClick = onContributorsItemClick
}

func makeUIViewController(context: Context) -> UIViewController {
return contributorsViewController(
repositories: repositories,
onContributorsItemClick: onContributorsItemClick
)
}

func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Model
import SwiftUI
@preconcurrency import shared
import Theme
import ComposableArchitecture

struct KmpPresenterContributorView: View {
private let repositories: any Repositories
Expand All @@ -12,37 +13,42 @@ struct KmpPresenterContributorView: View {
@State private var currentState: ContributorsUiState? = nil

init(onContributorButtonTapped: @escaping (URL) -> Void) {
self.repositories = Container.shared.get(type: (any Repositories).self)
@Dependency(\.containerClient) var containerClient

self.repositories = containerClient.repositories()
self.events = SkieKotlinSharedFlowFactory<any ContributorsScreenEvent>()
.createSkieKotlinSharedFlow(replay: 0, extraBufferCapacity: 0)
self.onContributorButtonTapped = onContributorButtonTapped
}

var body: some View {
Group {
if let contributors = currentState.map(\.contributors) {
ScrollView {
LazyVStack(spacing: 0) {

ContributorsCountItem(totalContributor: contributors.count)
.frame(maxWidth: .infinity)
.padding(.horizontal, 16)
.padding(.vertical, 10)

ForEach(contributors, id: \.id) { value in
let contributor = Model.Contributor(
id: Int(value.id),
userName: value.username,
profileUrl: value.profileUrl.map { URL(string: $0)! } ,
iconUrl: URL(string: value.iconUrl)!
)
ContributorListItemView(
contributor: contributor,
onContributorButtonTapped: onContributorButtonTapped
)
if let state = currentState {
if let existsState = state as? Exists {
ScrollView {
LazyVStack(spacing: 0) {

ContributorsCountItem(totalContributor: existsState.contributors.count)
.frame(maxWidth: .infinity)
.padding(.horizontal, 16)
.padding(.vertical, 10)

ForEach(existsState.contributors, id: \.id) { value in
let contributor = Model.Contributor(
id: Int(value.id),
userName: value.username,
profileUrl: value.profileUrl.map { URL(string: $0)! },
iconUrl: URL(string: value.iconUrl)!
)
ContributorListItemView(
contributor: contributor,
onContributorButtonTapped: onContributorButtonTapped
)
}
}
}
} else if state is Loading {
ProgressView()
}
} else {
ProgressView()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import Theme
struct SwiftUIContributorView: View {
private let store: StoreOf<ContributorReducer>

public init(store: StoreOf<ContributorReducer>) {
init(store: StoreOf<ContributorReducer>) {
self.store = store
}

Expand Down
26 changes: 26 additions & 0 deletions app-ios/Sources/KMPClient/Client.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@ import shared
import Model

extension DependencyValues {
public var firebaseAppClient: FirebaseAppClient {
get { self[FirebaseAppClient.self] }
set { self[FirebaseAppClient.self] = newValue }
}

public var containerClient: ContainerClient {
get { self[ContainerClient.self] }
set { self[ContainerClient.self] = newValue }
}

public var timetableClient: TimetableClient {
get { self[TimetableClient.self] }
set { self[TimetableClient.self] = newValue }
Expand Down Expand Up @@ -35,6 +45,22 @@ extension DependencyValues {
}
}

@DependencyClient
public struct FirebaseAppClient: Sendable {
public var prepareFirebase: @Sendable () -> ()
}

@DependencyClient
public struct ContainerClient: Sendable {
private class DefaultRepositories: Repositories {
var map = [AnyHashable: Any]()
}

public var repositories: @Sendable () -> any Repositories = {
DefaultRepositories()
}
}

@DependencyClient
public struct TimetableClient: Sendable {
public var streamTimetable: @Sendable () throws -> AsyncThrowingStream<Timetable, any Error>
Expand Down
10 changes: 10 additions & 0 deletions app-ios/Sources/KMPClient/TestKey.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
import Dependencies

extension FirebaseAppClient: TestDependencyKey {
public static let previewValue: Self = Self()
public static let testValue: Self = Self()
}

extension ContainerClient: TestDependencyKey {
public static let previewValue: Self = Self()
public static let testValue: Self = Self()
}

extension TimetableClient: TestDependencyKey {
public static let previewValue: Self = Self()

Expand Down
Loading

0 comments on commit f9e609f

Please sign in to comment.