Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[iOS] Implement staffs base #913

Merged
merged 3 commits into from
Aug 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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!")
}
}
Loading