Skip to content

Commit

Permalink
Merge pull request #913 from DroidKaigi/ios-staffs-base
Browse files Browse the repository at this point in the history
[iOS] Implement staffs base
  • Loading branch information
ry-itto authored Aug 23, 2023
2 parents 2be2fbb + c69270f commit dc8ce0e
Show file tree
Hide file tree
Showing 11 changed files with 206 additions and 17 deletions.
21 changes: 21 additions & 0 deletions app-ios/Modules/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,8 @@ var package = Package(
"Component",
"KMPContainer",
"Model",
"shared",
.product(name: "Dependencies", package: "swift-dependencies"),
]
),
.testTarget(
Expand All @@ -154,6 +156,24 @@ var package = Package(
]
),

.target(
name: "Staff",
dependencies: [
"Assets",
"Component",
"KMPContainer",
"Model",
"shared",
.product(name: "Dependencies", package: "swift-dependencies"),
]
),
.testTarget(
name: "StaffTests",
dependencies: [
"Staff"
]
),

.target(
name: "Stamps",
dependencies: [
Expand Down Expand Up @@ -196,6 +216,7 @@ var package = Package(
"FloorMap",
"Session",
"Sponsor",
"Staff",
"Stamps",
"Theme",
"Timetable",
Expand Down
19 changes: 14 additions & 5 deletions app-ios/Modules/Sources/About/AboutView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,21 @@ enum AboutRouting: Hashable {
case contributors
case license
case sponsors
case staffs
}

public struct AboutView<ContributorView: View, SponsorView: View>: View {
public struct AboutView<ContributorView: View, StaffView: View, SponsorView: View>: View {
private let contributorViewProvider: ViewProvider<Void, ContributorView>
private let staffViewProvider: ViewProvider<Void, StaffView>
private let sponsorViewProvider: ViewProvider<Void, SponsorView>

public init(
contributorViewProvider: @escaping ViewProvider<Void, ContributorView>,
staffViewProvider: @escaping ViewProvider<Void, StaffView>,
sponsorViewProvider: @escaping ViewProvider<Void, SponsorView>
) {
self.contributorViewProvider = contributorViewProvider
self.staffViewProvider = staffViewProvider
self.sponsorViewProvider = sponsorViewProvider
}

Expand Down Expand Up @@ -56,10 +60,12 @@ public struct AboutView<ContributorView: View, SponsorView: View>: View {
.clipShape(RoundedRectangle(cornerRadius: 12))
Spacer().frame(height: 32)
SectionTitle(title: "Credits")
ListTile(
icon: Assets.Icons.sentimentVerySatisfied.swiftUIImage,
title: "スタッフ"
)
NavigationLink(value: AboutRouting.staffs) {
ListTile(
icon: Assets.Icons.sentimentVerySatisfied.swiftUIImage,
title: "スタッフ"
)
}
Divider()
NavigationLink(value: AboutRouting.contributors) {
ListTile(
Expand Down Expand Up @@ -123,6 +129,8 @@ public struct AboutView<ContributorView: View, SponsorView: View>: View {
switch routing {
case .contributors:
contributorViewProvider(())
case .staffs:
staffViewProvider(())
case .sponsors:
sponsorViewProvider(())
case .license:
Expand All @@ -136,6 +144,7 @@ public struct AboutView<ContributorView: View, SponsorView: View>: View {
#Preview {
AboutView(
contributorViewProvider: {_ in EmptyView()},
staffViewProvider: {_ in EmptyView()},
sponsorViewProvider: {_ in EmptyView()}
)
}
8 changes: 4 additions & 4 deletions app-ios/Modules/Sources/Component/SafariLink.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import SafariServices
import SwiftUI

public struct SafariLink<Content>: View where Content: View {

@State private var isSheetPresented: Bool = false

private let url: URL
private let configuration: SFSafariViewController.Configuration
private let content: () -> Content

public init(
url: URL,
configuration: SFSafariViewController.Configuration? = nil,
Expand All @@ -20,7 +20,7 @@ public struct SafariLink<Content>: View where Content: View {
self.configuration = configuration ?? defaultConfiguration
self.content = content
}

public var body: some View {
Button {
isSheetPresented = true
Expand Down
8 changes: 4 additions & 4 deletions app-ios/Modules/Sources/Component/SafariView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import SwiftUI
public struct SafariView: UIViewControllerRepresentable {
private let url: URL
private let configuration: SFSafariViewController.Configuration

public init(
url: URL,
configuration: SFSafariViewController.Configuration? = nil
Expand All @@ -14,17 +14,17 @@ public struct SafariView: UIViewControllerRepresentable {
defaultConfiguration.barCollapsingEnabled = false
self.configuration = configuration ?? defaultConfiguration
}

public func makeUIViewController(context: Context) -> some UIViewController {
let safariViewController = SFSafariViewController(
url: url,
configuration: configuration
)
return safariViewController
}

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

}
}

Expand Down
22 changes: 18 additions & 4 deletions app-ios/Modules/Sources/Contributor/ContributorView.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import Component
import Model
import SwiftUI

public struct ContributorView: View {
@State var presentingURL: IdentifiableURL?
@ObservedObject var viewModel: ContributorViewModel = .init()

public init() {}
Expand All @@ -20,17 +22,29 @@ public struct ContributorView: View {
ScrollView {
LazyVStack(spacing: 20) {
ForEach(contributors, id: \.id) { contributor in
PersonLabel(
name: contributor.username,
iconUrlString: contributor.iconUrl
)
Button {
if let profileUrl = contributor.profileUrl {
presentingURL = IdentifiableURL(string: profileUrl)
}
} label: {
PersonLabel(
name: contributor.username,
iconUrlString: contributor.iconUrl
)
}
}
}
.padding(16)
}
}
}
.navigationTitle("Contributor")
.sheet(item: $presentingURL) { url in
if let url = url.id {
SafariView(url: url)
.ignoresSafeArea()
}
}
}
}

Expand Down
39 changes: 39 additions & 0 deletions app-ios/Modules/Sources/KMPContainer/StaffsDataProvider.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import Dependencies
import shared

public struct StaffsDataProvider {
private static var staffRepository: StaffRepository {
Container.shared.get(type: StaffRepository.self)
}

public let refresh: () async throws -> Void
public let staffs: () -> AsyncThrowingStream<[Staff], Error>
}

extension StaffsDataProvider: DependencyKey {
@MainActor
public static var liveValue: StaffsDataProvider = StaffsDataProvider(
refresh: { @MainActor in
try await staffRepository.refresh()
},
staffs: {
staffRepository.staffs().stream()
}
)

public static var testValue: StaffsDataProvider = StaffsDataProvider(
refresh: {},
staffs: {
.init {
Staff.companion.fakes()
}
}
)
}

public extension DependencyValues {
var staffsData: StaffsDataProvider {
get { self[StaffsDataProvider.self] }
set { self[StaffsDataProvider.self] = newValue }
}
}
13 changes: 13 additions & 0 deletions app-ios/Modules/Sources/Model/IdentifiableURL.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import Foundation

public struct IdentifiableURL: Identifiable {
public var id: URL?

public init(_ id: URL?) {
self.id = id
}

public init(string: String) {
self.id = URL(string: string)
}
}
4 changes: 4 additions & 0 deletions app-ios/Modules/Sources/Navigation/RootView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Contributor
import FloorMap
import Session
import Sponsor
import Staff
import Stamps
import SwiftUI
import Theme
Expand Down Expand Up @@ -61,6 +62,9 @@ public struct RootView: View {
contributorViewProvider: { _ in
ContributorView()
},
staffViewProvider: { _ in
StaffView()
},
sponsorViewProvider: { _ in
SponsorView()
}
Expand Down
52 changes: 52 additions & 0 deletions app-ios/Modules/Sources/Staff/StaffView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import Component
import Model
import shared
import SwiftUI

public struct StaffView: View {
@State var presentingURL: IdentifiableURL?
@ObservedObject var viewModel: StaffViewModel = .init()

public init() {}

public var body: some View {
Group {
switch viewModel.state.staffs {
case .initial, .loading:
ProgressView()
.task {
await viewModel.load()
}
case .failed:
EmptyView()
case .loaded(let staffs):
ScrollView {
LazyVStack(spacing: 20) {
ForEach(staffs, id: \.id) { staff in
Button {
presentingURL = IdentifiableURL(string: staff.profileUrl)
} label: {
PersonLabel(
name: staff.username,
iconUrlString: staff.iconUrl
)
}
}
}
.padding(16)
}
}
}
.navigationTitle("Staff")
.sheet(item: $presentingURL) { url in
if let url = url.id {
SafariView(url: url)
.ignoresSafeArea()
}
}
}
}

#Preview {
StaffView()
}
26 changes: 26 additions & 0 deletions app-ios/Modules/Sources/Staff/StaffViewModel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import Dependencies
import Foundation
import KMPContainer
import Model
import shared

struct StaffState: ViewModelState {
var staffs: LoadingState<[Staff]> = .initial
}

@MainActor
final class StaffViewModel: ObservableObject {
@Dependency(\.staffsData) var staffsData
@Published private(set) var state: StaffState = .init()

func load() async {
state.staffs = .loading
do {
for try await staffs in staffsData.staffs() {
state.staffs = .loaded(staffs)
}
} catch let error {
state.staffs = .failed(error)
}
}
}
11 changes: 11 additions & 0 deletions app-ios/Modules/Tests/StaffTests/StaffTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
@testable import Staff
import XCTest

final class StaffTests: XCTestCase {
func testExample() throws {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct
// results.
XCTAssertEqual("Hello, World!", "Hello, World!")
}
}

0 comments on commit dc8ce0e

Please sign in to comment.