Files
Yusuke Hosonuma 275f8f321f refactor: package
2022-04-27 13:49:36 +09:00

141 lines
4.6 KiB
Swift
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//
// PatternService.swift
// LifeGameApp
//
// Created by Yusuke Hosonuma on 2020/09/12.
//
import Foundation
import Combine
import FirebaseFirestore
// Note:
//
// This service is designed by fail-safe,
// therefore some method call is return empty (publisher) that login is neeeded.
public struct PatternURL {
public let url: URL
public let stared: Bool
}
final public class PatternService {
public static let shared = PatternService()
private let authentication: Authentication = .shared
private let patternIDRepository: FirestorePatternIndexRepository = .shared
private var staredRepository: FirestoreStaredRepository? { authentication.repositories?.stared }
private var historyRepository: FirestoreHistoryRepository? { authentication.repositories?.history }
public func patternURLs(by type: String? = nil) -> AnyPublisher<[PatternURL], Never> {
patternIDRepository
.all
.map { document -> [URL] in
if let type = type {
// TODO:
return document.data.filter { $0.patternType == type }.map(\.jsonURL)
} else {
return document.data.map(\.jsonURL)
}
}
.combineLatest(listenStaredPatternURLs())
.map { allURLs, staredURLs in
allURLs.map {
PatternURL(url: $0, stared: staredURLs.contains($0))
}
}
.eraseToAnyPublisher()
}
public func fetch(from url: URL) -> AnyPublisher<PatternItem?, Never> {
let patternPublisher = URLSession.shared
.dataTaskPublisher(for: url)
.retry(3)
.map { (data, response) -> Data in
data
}
.decode(type: LifeWikiPattern.self, decoder: JSONDecoder())
return Publishers.Zip(patternPublisher, staredPatternIDs().setFailureType(to: Error.self))
.map { pattern, staredIds in
PatternItem(
patternID: pattern.id,
title: pattern.title,
board: pattern.makeBoard(),
stared: staredIds.contains(pattern.id)
)
}
.replaceError(with: nil) // TODO:
.receive(on: RunLoop.main)
.eraseToAnyPublisher()
}
// MARK: - Star
public func staredPatternURLs(by type: String? = nil) -> AnyPublisher<[PatternURL], Never> {
guard let staredRepository = staredRepository else {
return Just([]).eraseToAnyPublisher()
}
return staredRepository
.all()
.map { urls in
urls.map { PatternURL(url: $0.jsonURL, stared: true) }
}
.eraseToAnyPublisher()
}
public func listenStaredPatternURLs() -> AnyPublisher<[URL], Never> {
guard let staredRepository = staredRepository else {
return Just([]).eraseToAnyPublisher()
}
return staredRepository
.publisher
.map { $0.map(\.jsonURL) }
.eraseToAnyPublisher()
}
public func toggleStar(item: PatternItem) {
guard let staredRepository = staredRepository else { return }
if item.stared {
staredRepository.delete(by: item.patternID)
} else {
staredRepository.setData(StaredDocument(patternID: item.patternID))
}
}
// MARK: - History
public func recordHistory(patternID: String) {
guard let historyRepository = historyRepository else { return }
historyRepository.setData(by: patternID, document: HistoryDocument())
}
public func listenHistoryPatternURLs() -> AnyPublisher<[URL], Never> {
guard let historyRepository = historyRepository else {
return Just([]).eraseToAnyPublisher()
}
return historyRepository
.publisher
.map { $0.map(\.jsonURL) }
.eraseToAnyPublisher()
}
// MARK: - Private
private func staredPatternIDs() -> AnyPublisher<[String], Never> {
guard let staredRepository = staredRepository else {
return Just([]).eraseToAnyPublisher()
}
return staredRepository // TODO:
.all()
.map { $0.map(\.patternID) }
.eraseToAnyPublisher()
}
}