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

[Feat] #360 - 솝탬프 개선 #365

Merged
merged 13 commits into from
Apr 10, 2024
47 changes: 32 additions & 15 deletions SOPT-iOS/Projects/Data/Sources/Repository/RankingRepository.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,39 @@ import Domain
import Networks

public class RankingRepository {
private let rankService: RankService
private let cancelBag = CancelBag()
public init(service: RankService) {
self.rankService = service
}

private let rankService: RankService
private let cancelBag = CancelBag()

public init(service: RankService) {
self.rankService = service
}
}

extension RankingRepository: RankingRepositoryInterface {
public func fetchRankingListModel(isCurrentGeneration: Bool) -> AnyPublisher<[Domain.RankingModel], Error> {
return self.rankService
.fetchRankingList(isCurrentGeneration: isCurrentGeneration)
.map({ entity in
entity.map { $0.toDomain() }
})
.eraseToAnyPublisher()
}
public func fetchRankingListModel(isCurrentGeneration: Bool) -> AnyPublisher<[Domain.RankingModel], Error> {
return self.rankService
.fetchRankingList(isCurrentGeneration: isCurrentGeneration)
.map({ entity in
entity.map { $0.toDomain() }
})
.eraseToAnyPublisher()
}

public func fetchPartRanking() -> AnyPublisher<[Domain.PartRankingModel], Error> {
return self.rankService
.fetchPartRanking()
.map {
$0.map { $0.toDomain() }
}.eraseToAnyPublisher()
}

public func fetchRankingListInPart(part: String) -> AnyPublisher<[RankingModel], Error> {
return self.rankService
.fetchRankingListInPart(part: part)
.map {
$0.map { $0.toDomain() }
}
.eraseToAnyPublisher()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// PartRankingTransform.swift
// Data
//
// Created by Aiden.lee on 2024/04/05.
// Copyright © 2024 SOPT-iOS. All rights reserved.
//

import Foundation

import Core
import Domain
import Networks

extension PartRankingEntity {
public func toDomain() -> PartRankingModel {
return .init(part: part, rank: rank, points: points)
}
}

29 changes: 29 additions & 0 deletions SOPT-iOS/Projects/Domain/Sources/Model/PartRankingModel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//
// PartRankingModel.swift
// Domain
//
// Created by Aiden.lee on 2024/04/05.
// Copyright © 2024 SOPT-iOS. All rights reserved.
//

import Foundation

public struct PartRankingModel: Hashable {
public let part: String
public let rank: Int
public let points: Int

public init(part: String, rank: Int, points: Int) {
self.part = part
self.rank = rank
self.points = points
}
}

public struct PartRankingChartModel: Hashable {
public let ranking: [PartRankingModel]

public init(ranking: [PartRankingModel]) {
self.ranking = ranking
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,7 @@
import Combine

public protocol RankingRepositoryInterface {
func fetchRankingListModel(isCurrentGeneration: Bool) -> AnyPublisher<[RankingModel], Error>
func fetchRankingListModel(isCurrentGeneration: Bool) -> AnyPublisher<[RankingModel], Error>
func fetchPartRanking() -> AnyPublisher<[Domain.PartRankingModel], Error>
func fetchRankingListInPart(part: String) -> AnyPublisher<[RankingModel], Error>
}
117 changes: 71 additions & 46 deletions SOPT-iOS/Projects/Domain/Sources/UseCase/RankingUseCase.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,57 +11,82 @@ import Combine
import Core

public protocol RankingUseCase {
func fetchRankingList(isCurrentGeneration: Bool)
func findMyRanking()
var rankingListModelFetched: CurrentValueSubject<[RankingModel], Error> { get }
var myRanking: PassthroughSubject<(section: Int, item: Int), Error> { get set }
func fetchRankingList(isCurrentGeneration: Bool)
func fetchRankingList(part: String)
func findMyRanking()
func fetchPartRanking()

var rankingListModelFetched: CurrentValueSubject<[RankingModel], Error> { get }
var myRanking: PassthroughSubject<(section: Int, item: Int), Error> { get set }
var partRanking: PassthroughSubject<[PartRankingModel], Error> { get }
}

public class DefaultRankingUseCase {

private let repository: RankingRepositoryInterface
private var cancelBag = CancelBag()
public var rankingListModelFetched = CurrentValueSubject<[RankingModel], Error>([])
public var myRanking = PassthroughSubject<(section: Int, item: Int), Error>()

public init(repository: RankingRepositoryInterface) {
self.repository = repository
}

private let repository: RankingRepositoryInterface
private var cancelBag = CancelBag()
public var rankingListModelFetched = CurrentValueSubject<[RankingModel], Error>([])
public var myRanking = PassthroughSubject<(section: Int, item: Int), Error>()
public let partRanking = PassthroughSubject<[PartRankingModel], Error>()

public init(repository: RankingRepositoryInterface) {
self.repository = repository
}
}

extension DefaultRankingUseCase: RankingUseCase {
public func fetchRankingList(isCurrentGeneration: Bool) {
self.repository
.fetchRankingListModel(isCurrentGeneration: isCurrentGeneration)
.map { model in
var newModel = model
let myRankingIndex = self.findMyRankingIndex(model: model)
newModel[myRankingIndex].setMyRanking(true)
return newModel
}
.withUnretained(self)
.sink { completion in
print(completion)
} receiveValue: { owner, model in
owner.rankingListModelFetched.send(model)
}.store(in: self.cancelBag)
}

public func findMyRanking() {
let myRankingIndex = self.findMyRankingIndex(model: rankingListModelFetched.value)

if myRankingIndex > 2 {
myRanking.send((1, myRankingIndex - 3))
} else {
myRanking.send((0, 0))
}
}

private func findMyRankingIndex(model: [RankingModel]) -> Int {
let myUserName = UserDefaultKeyList.User.soptampName
let index = model.firstIndex { model in
model.username == myUserName
} ?? 0
return index
public func fetchRankingList(isCurrentGeneration: Bool) {
self.repository
.fetchRankingListModel(isCurrentGeneration: isCurrentGeneration)
.map { model in
var newModel = model
let myRankingIndex = self.findMyRankingIndex(model: model)
newModel[myRankingIndex].setMyRanking(true)
return newModel
}
.withUnretained(self)
.sink { completion in
print(completion)
} receiveValue: { owner, model in
owner.rankingListModelFetched.send(model)
}.store(in: self.cancelBag)
}

public func fetchPartRanking() {
self.repository
.fetchPartRanking()
.sink { completion in
print(completion)
} receiveValue: { [weak self] rankingModels in
self?.partRanking.send(rankingModels)
}.store(in: cancelBag)
}

public func fetchRankingList(part: String) {
self.repository
.fetchRankingListInPart(part: part)
.sink { completion in
print(completion)
} receiveValue: { [weak self] rankingModels in
self?.rankingListModelFetched.send(rankingModels)
}.store(in: cancelBag)
}

public func findMyRanking() {
let myRankingIndex = self.findMyRankingIndex(model: rankingListModelFetched.value)

if myRankingIndex > 2 {
myRanking.send((1, myRankingIndex - 3))
} else {
myRanking.send((0, 0))
}
}

private func findMyRankingIndex(model: [RankingModel]) -> Int {
let myUserName = UserDefaultKeyList.User.soptampName
let index = model.firstIndex { model in
model.username == myUserName
} ?? 0
return index
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//
// Part.swift
// StampFeatureInterface
//
// Created by Aiden.lee on 2024/04/06.
// Copyright © 2024 SOPT-iOS. All rights reserved.
//

import Foundation

public enum Part: String, CaseIterable {
case plan = "기획"
case design = "디자인"
case web = "웹"
case ios = "아요"
case android = "안드"
case server = "서버"

public func uppercasedName() -> String {
switch self {
case .plan: return "PLAN"
case .design: return "DESIGN"
case .web: return "WEB"
case .ios: return "IOS"
case .android: return "ANDROID"
case .server: return "SERVER"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import BaseFeatureDependency
public enum RankingViewType {
case all
case currentGeneration(info: UsersActiveGenerationStatusViewResponse)
case partRanking
case individualRankingInPart(part: Part)
}

public protocol StampFeatureViewBuildable {
Expand All @@ -29,5 +31,6 @@ public protocol StampFeatureViewBuildable {
completionHandler: (() -> Void)?
) -> MissionCompletedViewControllable
func makeRankingVC(rankingViewType: RankingViewType) -> RankingViewControllable
func makePartRankingVC(rankingViewType: RankingViewType) -> PartRankingViewControllable
func makeStampGuideVC() -> StampGuideViewControllable
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,27 @@ import Domain

public protocol MissionListViewControllable: ViewControllable & MissionListCoordinatable { }
public protocol MissionListCoordinatable {
var onSwiped: (() -> Void)? { get set }
var onNaviBackTap: (() -> Void)? { get set }
var onRankingButtonTap: ((RankingViewType) -> Void)? { get set }
var onCurrentGenerationRankingButtonTap: ((RankingViewType) -> Void)? { get set }
var onGuideTap: (() -> Void)? { get set }
var onCellTap: ((MissionListModel, _ username: String?) -> Void)? { get set }
var onSwiped: (() -> Void)? { get set }
var onNaviBackTap: (() -> Void)? { get set }
var onPartRankingButtonTap: ((RankingViewType) -> Void)? { get set }
var onCurrentGenerationRankingButtonTap: ((RankingViewType) -> Void)? { get set }
var onGuideTap: (() -> Void)? { get set }
var onCellTap: ((MissionListModel, _ username: String?) -> Void)? { get set }
}
public protocol ListDetailViewControllable: ViewControllable & ListDetailCoordinatable { }
public protocol ListDetailCoordinatable {
var onComplete: ((StarViewLevel, (() -> Void)?) -> Void)? { get set }
var onComplete: ((StarViewLevel, (() -> Void)?) -> Void)? { get set }
}
public protocol MissionCompletedViewControllable: ViewControllable { }
public protocol RankingViewControllable: ViewControllable & RankingCoordinatable { }
public protocol RankingCoordinatable {
var onCellTap: ((_ username: String, _ sentence: String) -> Void)? { get set }
var onSwiped: (() -> Void)? { get set }
var onNaviBackTap: (() -> Void)? { get set }
var onCellTap: ((_ username: String, _ sentence: String) -> Void)? { get set }
var onNaviBackTap: (() -> Void)? { get set }
}

public protocol PartRankingCoordinatable {
var onCellTap: ((_ part: Part) -> Void)? { get set }
var onNaviBackTap: (() -> Void)? { get set }
}
public protocol PartRankingViewControllable: ViewControllable & PartRankingCoordinatable { }
public protocol StampGuideViewControllable: ViewControllable { }
Loading