Skip to content

Commit

Permalink
Merge pull request #169 from DroidKaigi/MrSmart00/feature/sponsors
Browse files Browse the repository at this point in the history
Add Sponsor feature with KMP
  • Loading branch information
MrSmart00 authored Jul 28, 2024
2 parents 93572d0 + ac1fb43 commit ff9ec20
Show file tree
Hide file tree
Showing 6 changed files with 170 additions and 14 deletions.
6 changes: 5 additions & 1 deletion app-ios/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,11 @@ let package = Package(
),
.target(
name: "SponsorFeature",
dependencies: [ .tca ]
dependencies: [
.tca,
.kmpClient,
.theme
]
),
.testTarget(
name: "SponsorFeatureTests",
Expand Down
2 changes: 1 addition & 1 deletion app-ios/Sources/App/RootReducer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ public struct RootReducer {
return .none

case .about(.view(.sponsorsTapped)):
state.paths.about.append(.sponsor(.init(text: "")))
state.paths.about.append(.sponsor(.init()))
return .none

case .about(.view(.acknowledgementsTapped)):
Expand Down
25 changes: 25 additions & 0 deletions app-ios/Sources/SponsorFeature/Localizable.xcstrings
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"sourceLanguage" : "en",
"strings" : {
"GOLD SPONSORS" : {

},
"PLATINUM SPONSORS" : {

},
"Sponsor" : {
"localizations" : {
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "スポンサー"
}
}
}
},
"SUPPORTERS" : {

}
},
"version" : "1.0"
}
51 changes: 46 additions & 5 deletions app-ios/Sources/SponsorFeature/SponsorReducer.swift
Original file line number Diff line number Diff line change
@@ -1,27 +1,68 @@
import ComposableArchitecture
import Foundation
import KMPClient
import shared

struct SponsorData: Equatable, Identifiable {
let id: String
let logo: URL
let link: URL
}

@Reducer
public struct SponsorReducer {
@Dependency(\.sponsorsClient) var sponsorsData

public init() { }

@ObservableState
public struct State: Equatable {
var text: String
var platinums = [SponsorData]()
var golds = [SponsorData]()
var supporters = [SponsorData]()

public init(text: String) {
self.text = text
}
public init() { }
}

public enum Action {
case onAppear
case response(Result<[Sponsor], any Error>)
}

public var body: some ReducerOf<Self> {
Reduce { state, action in
enum CancelID { case connection }

switch action {
case .onAppear:
state.text = "Sponsor Feature"
return .run { send in
for try await sponsors in try sponsorsData.streamSponsors() {
await send(.response(.success(sponsors)))
}
}
.cancellable(id: CancelID.connection)
case .response(.success(let sponsors)):
var platinums = [SponsorData]()
var golds = [SponsorData]()
var supporters = [SponsorData]()

sponsors.forEach {
switch $0.plan {
case .platinum:
platinums.append(.init(id: $0.name, logo: .init(string: $0.logo)!, link: .init(string: $0.link)!))
case .gold:
golds.append(.init(id: $0.name, logo: .init(string: $0.logo)!, link: .init(string: $0.link)!))
case .supporter:
supporters.append(.init(id: $0.name, logo: .init(string: $0.logo)!, link: .init(string: $0.link)!))
}
}

state.platinums = platinums
state.golds = golds
state.supporters = supporters
return .none
case .response(.failure(let error)):
print(error)
return .none
}
}
Expand Down
74 changes: 70 additions & 4 deletions app-ios/Sources/SponsorFeature/SponsorView.swift
Original file line number Diff line number Diff line change
@@ -1,21 +1,87 @@
import ComposableArchitecture
import SwiftUI
import Theme

public struct SponsorView: View {
private let store: StoreOf<SponsorReducer>
@State var selectedSponsorData: SponsorData?

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

public var body: some View {
Text(store.text)
.onAppear {
store.send(.onAppear)
ScrollView {
LazyVStack {
Text("PLATINUM SPONSORS")
.textStyle(.headlineSmall)
.foregroundStyle(AssetColors.Primary.primaryFixed.swiftUIColor)
.frame(maxWidth: .infinity, alignment: .leading)

ForEach(store.platinums, id: \.id) { platinum in
Button {
selectedSponsorData = platinum
} label: {
AsyncImage(url: platinum.logo) {
$0.image?
.resizable()
.scaledToFit()
}
.frame(height: 110)
}
}

Text("GOLD SPONSORS")
.textStyle(.headlineSmall)
.foregroundStyle(AssetColors.Primary.primaryFixed.swiftUIColor)
.frame(maxWidth: .infinity, alignment: .leading)

LazyVGrid(columns: Array(repeating: .init(.fixed(184)), count: 2)) {
ForEach(store.golds, id: \.id) { gold in
Button {
selectedSponsorData = gold
} label: {
AsyncImage(url: gold.logo) {
$0.image?
.resizable()
.scaledToFit()
}
.frame(height: 80)
}
}
}

Text("SUPPORTERS")
.textStyle(.headlineSmall)
.foregroundStyle(AssetColors.Primary.primaryFixed.swiftUIColor)
.frame(maxWidth: .infinity, alignment: .leading)

LazyVGrid(columns: Array(repeating: .init(.fixed(118)), count: 3)) {
ForEach(store.supporters, id: \.id) { supporter in
Button {
selectedSponsorData = supporter
} label: {
AsyncImage(url: supporter.logo) {
$0.image?
.resizable()
.scaledToFit()
}
.frame(height: 80)
}
}
}
}
.padding(16)
}
.background(AssetColors.Surface.surface.swiftUIColor)
.onAppear {
store.send(.onAppear)
}
.navigationBarTitleDisplayMode(.large)
.navigationTitle(String(localized: "Sponsor", bundle: .module))
}
}

#Preview {
SponsorView(store: .init(initialState: .init(text: "Hoge"), reducer: { SponsorReducer() }))
SponsorView(store: .init(initialState: .init(), reducer: { SponsorReducer() }))
}
26 changes: 23 additions & 3 deletions app-ios/Tests/SponsorFeatureTests/SponsorFeatureTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,31 @@ final class SponsorFeatureTests: XCTestCase {

@MainActor
func testExample() async throws {
let store = TestStore(initialState: SponsorReducer.State(text: "HOGE")) {
let store = TestStore(initialState: SponsorReducer.State()) {
SponsorReducer()
} withDependencies: {
$0.sponsorsClient.streamSponsors = {
AsyncThrowingStream {
$0.yield([
.init(name: "Hoge", logo: "https://avatars.githubusercontent.com/u/10727543?s=200&v=4", plan: .platinum, link: "https://2024.droidkaigi.jp/"),
.init(name: "Huga", logo: "https://avatars.githubusercontent.com/u/10727543?s=200&v=4", plan: .gold, link: "https://2024.droidkaigi.jp/"),
.init(name: "FUga", logo: "https://avatars.githubusercontent.com/u/10727543?s=200&v=4", plan: .supporter, link: "https://2024.droidkaigi.jp/"),
])
$0.finish()
}
}
}
await store.send(.onAppear) {
$0.text = "Sponsor Feature"
await store.send(.onAppear)
await store.receive(\.response.success) {
$0.platinums = [
.init(id: "Hoge", logo: .init(string: "https://avatars.githubusercontent.com/u/10727543?s=200&v=4")!, link: .init(string: "https://2024.droidkaigi.jp/")!)
]
$0.golds = [
.init(id: "Huga", logo: .init(string: "https://avatars.githubusercontent.com/u/10727543?s=200&v=4")!, link: .init(string: "https://2024.droidkaigi.jp/")!)
]
$0.supporters = [
.init(id: "FUga", logo: .init(string: "https://avatars.githubusercontent.com/u/10727543?s=200&v=4")!, link: .init(string: "https://2024.droidkaigi.jp/")!)
]
}
}

Expand Down

0 comments on commit ff9ec20

Please sign in to comment.