diff --git a/Projects/Core/Sources/Base/BaseViewController.swift b/Projects/Core/Sources/Base/BaseViewController.swift index ae037e81..e7f68b0a 100644 --- a/Projects/Core/Sources/Base/BaseViewController.swift +++ b/Projects/Core/Sources/Base/BaseViewController.swift @@ -28,7 +28,7 @@ open class BaseViewController: UIViewController { required public init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } - + open override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() @@ -37,8 +37,8 @@ open class BaseViewController: UIViewController { open override func viewDidLoad() { super.viewDidLoad() - bindViewModel() bindActions() + bindViewModel() layout() setupKeyboardHandling() attribute() diff --git a/Projects/Core/Sources/Coordinator/Stepper/PickleStepper.swift b/Projects/Core/Sources/Coordinator/Stepper/PickleStepper.swift index a0d5dede..fca4e15a 100644 --- a/Projects/Core/Sources/Coordinator/Stepper/PickleStepper.swift +++ b/Projects/Core/Sources/Coordinator/Stepper/PickleStepper.swift @@ -8,7 +8,7 @@ public class PickleStepper: Stepper { public var steps = PublishRelay() public var initialStep: Step { - return MGStep.home + return MGStep.pickleRequired } public init() { diff --git a/Projects/Core/Sources/Coordinator/Stepper/ShopStepper.swift b/Projects/Core/Sources/Coordinator/Stepper/ShopStepper.swift new file mode 100644 index 00000000..193eba40 --- /dev/null +++ b/Projects/Core/Sources/Coordinator/Stepper/ShopStepper.swift @@ -0,0 +1,18 @@ +import Foundation + +import RxFlow +import RxCocoa + +public class ShopStepper: Stepper { + public static let shared = ShopStepper() + + public var steps = PublishRelay() + + public var initialStep: Step { + return MGStep.shopIsRequired + } + + public init() { + + } +} diff --git a/Projects/Core/Sources/CoreData/CoreData.swift b/Projects/Core/Sources/CoreData/CoreData.swift new file mode 100644 index 00000000..4cb67004 --- /dev/null +++ b/Projects/Core/Sources/CoreData/CoreData.swift @@ -0,0 +1,33 @@ +import CoreData + +public class CoreDataStack { + public static let shared = CoreDataStack() + + lazy var persistentContainer: NSPersistentContainer = { + let container = NSPersistentContainer(name: "Model") + container.loadPersistentStores { storeDescription, error in + if let error = error as NSError? { + fatalError("Unresolved error \(error), \(error.userInfo)") + } + } + return container + }() + + public var context: NSManagedObjectContext { + return persistentContainer.viewContext + } + + public func saveContext() { + let context = persistentContainer.viewContext + if context.hasChanges { + do { + try context.save() + } catch { + let nserror = error as NSError + fatalError("Unresolved error \(nserror), \(nserror.userInfo)") + } + } + } + +} + diff --git a/Projects/Data/Sources/Repository/AuthRepository.swift b/Projects/Data/Sources/Repository/AuthRepository.swift index ae6e149f..5cd61279 100644 --- a/Projects/Data/Sources/Repository/AuthRepository.swift +++ b/Projects/Data/Sources/Repository/AuthRepository.swift @@ -50,6 +50,7 @@ public class AuthRepository: AuthRepositoryInterface { self.networkService = networkService } + // public func appleSingup(nickname: String, accessToken: String) -> Single { // return networkService.appleSignup(nickname: nickname, accessToken: accessToken) // } diff --git a/Projects/Data/Sources/Repository/PostureRepository.swift b/Projects/Data/Sources/Repository/PostureRepository.swift index 2817a8ab..8036ef04 100644 --- a/Projects/Data/Sources/Repository/PostureRepository.swift +++ b/Projects/Data/Sources/Repository/PostureRepository.swift @@ -15,14 +15,22 @@ public class PostureRepository: PostureRepositoryInterface { return networkService.requestPartData(type: type) } - public func getDetailData(type: PostureDetailType) -> Single { - return networkService.requestDetailData(type: type) + public func getDetailData(accessToken: String, id: Int) -> Single { + return networkService.requestDetailData(accessToken: accessToken, id: id) + .map(PoseDetailDTO.self) + .map { $0.toDomain() } } public func getSearchData() -> Single { return networkService.requestSearchData() } + public func getAllPoseData(accessToken: String, lastUpdated: String) -> Single { + return networkService.getAllPoseData(accessToken: accessToken, lastUpdated: lastUpdated) + .map(PostureAllDTO.self) + .map{ $0.toDomain() } + } + public init(networkService: PostureService) { self.networkService = networkService } diff --git a/Projects/Domain/Sources/Model/Posture/PostureDetailModel.swift b/Projects/Domain/Sources/Model/Posture/PostureDetailModel.swift index d27a2619..6c131bf4 100644 --- a/Projects/Domain/Sources/Model/Posture/PostureDetailModel.swift +++ b/Projects/Domain/Sources/Model/Posture/PostureDetailModel.swift @@ -1,6 +1,9 @@ import UIKit +import CoreData -public struct PostureDetailModel_temporary { +import Core + +public struct PostureDetailModel { public var needMachine: Bool public var category: [String] public var simpleName, exactName: String @@ -9,7 +12,7 @@ public struct PostureDetailModel_temporary { public var simplePart, exactPart, startPose, exerciseWay: [String] public var breatheWay, caution: [String] public var pickleImage: [UIImage] - + public init(needMachine: Bool, category: [String], simpleName: String, exactName: String, thumbnail: String, video: String, simplePart: [String], exactPart: [String], startPose: [String], exerciseWay: [String], breatheWay: [String], caution: [String], pickleImage: [UIImage]) { self.needMachine = needMachine self.category = category @@ -27,89 +30,78 @@ public struct PostureDetailModel_temporary { } } -public struct PostureDetailModel { - public var detailImage: UIImage - public var titleTextData: PostureDetailTitleTextModel - public var exerciseKindData: [PostureDetailExerciseKindModel] - public var exercisePartData: PostureDetailInfoModel - public var exerciseStartData: PostureDetailInfoModel - public var exerciseWayData: PostureDetailInfoModel - public var exerciseBreathData: PostureDetailInfoModel - public var exerciseCautionData: PostureDetailInfoModel - public var relatedPickleData: PostureDetailPickleModel - - public init(detailImage: UIImage, - titleTextData: PostureDetailTitleTextModel, - exerciseKindData: [PostureDetailExerciseKindModel], - exercisePartData: PostureDetailInfoModel, - exerciseStartData: PostureDetailInfoModel, - exerciseWayData: PostureDetailInfoModel, - exerciseBreathData: PostureDetailInfoModel, - exerciseCautionData: PostureDetailInfoModel, - relatedPickleData: PostureDetailPickleModel) - { - self.detailImage = detailImage - self.titleTextData = titleTextData - self.exerciseKindData = exerciseKindData - self.exercisePartData = exercisePartData - self.exerciseStartData = exerciseStartData - self.exerciseWayData = exerciseWayData - self.exerciseBreathData = exerciseBreathData - self.exerciseCautionData = exerciseCautionData - self.relatedPickleData = relatedPickleData - } -} - -public struct PostureDetailTitleTextModel { - public var englishName: String - public var koreanName: String - - public init(englishName: String, koreanName: String) { - self.englishName = englishName - self.koreanName = koreanName - } -} - -public struct PostureDetailExerciseKindModel { - public var exerciseTag: String - - public init(exerciseTag: String) { - self.exerciseTag = exerciseTag - } -} - -public struct PostureDetailInfoModel { - public var titleText: String - public var infoText: [PostureDetailInfoTextModel] - - public init(titleText: String, infoText: [PostureDetailInfoTextModel]) { - self.titleText = titleText - self.infoText = infoText - } -} +public struct PostureAllDataModel { + public var id: Int + public var category: [String] + public var needMachine: Bool + public var name: String + public var simplePart: [String] + public var exactPart: [String] + public var thumbnail: String -public struct PostureDetailInfoTextModel { - public var text: String - - public init(text: String) { - self.text = text + init(id: Int, category: [String], needMachine: Bool, name: String, simplePart: [String], exactPart: [String], thumbnail: String) { + self.id = id + self.category = category + self.needMachine = needMachine + self.name = name + self.simplePart = simplePart + self.exactPart = exactPart + self.thumbnail = thumbnail } } -public struct PostureDetailPickleModel{ - public var titleText: String - public var pickleImage: [PostureDetailPickleImageModel] +public struct PostureAllModel { + public var responses: [PostureAllDataModel] - public init(titleText: String, pickleImage: [PostureDetailPickleImageModel]) { - self.titleText = titleText - self.pickleImage = pickleImage - } -} - -public struct PostureDetailPickleImageModel { - public var image: UIImage - - public init(image: UIImage) { - self.image = image + init(responses: [PostureAllDataModel]) { + self.responses = responses } } +// +//extension CoreDataStack { +// public func savePostureAllModel(posture: PostureAllModel) { +// guard let entity = NSEntityDescription.entity(forEntityName: "PostureAllModel", in: context) else { +// fatalError("Failed to find entity description for PostureAllModel") +// } +// +// for pose in posture.responses { +// let postureObject = NSManagedObject(entity: entity, insertInto: context) +// postureObject.setValue(pose.id, forKey: "id") +// postureObject.setValue(pose.category, forKey: "category") +// postureObject.setValue(pose.needMachine, forKey: "needMachine") +// postureObject.setValue(pose.name, forKey: "name") +// postureObject.setValue(pose.simplePart, forKey: "simplePart") +// postureObject.setValue(pose.exactPart, forKey: "exactPart") +// postureObject.setValue(pose.thumbnail, forKey: "thumbnail") +// } +// saveContext() +// } +// +// public func fetchPostureAllModels() -> PostureAllModel { +// let fetchRequest: NSFetchRequest = NSFetchRequest(entityName: "PostureAllModel") +// +// do { +// let postureObjects = try context.fetch(fetchRequest) +// var postures: PostureAllModel = PostureAllModel(responses: []) +// +// for postureObject in postureObjects { +// let id = postureObject.value(forKey: "id") as! Int +// let category = postureObject.value(forKey: "category") as! [String] +// let needMachine = postureObject.value(forKey: "needMachine") as! Bool +// let name = postureObject.value(forKey: "name") as! String +// let simplePart = postureObject.value(forKey: "simplePart") as! [String] +// let exactPart = postureObject.value(forKey: "exactPart") as! [String] +// let thumbnail = postureObject.value(forKey: "thumbnail") as! String +// +// let posture = PostureAllDataModel(id: id, category: category, needMachine: needMachine, name: name, simplePart: simplePart, exactPart: exactPart, thumbnail: thumbnail) +// postures.responses.append(posture) +// } +// +// return postures +// } catch { +// print("Failed to fetch postures: \(error)") +// return PostureAllModel(responses: []) +// } +// } +//} +// diff --git a/Projects/Domain/Sources/RepositoryInterface/PostureRepositoryInterface.swift b/Projects/Domain/Sources/RepositoryInterface/PostureRepositoryInterface.swift index a25e09b5..3c9e9451 100644 --- a/Projects/Domain/Sources/RepositoryInterface/PostureRepositoryInterface.swift +++ b/Projects/Domain/Sources/RepositoryInterface/PostureRepositoryInterface.swift @@ -7,13 +7,10 @@ public enum PosturePartType { case back } -public enum PostureDetailType { - case pushUp -} - public protocol PostureRepositoryInterface { func getRecommandData() -> Single<[PostureRecommandModel]> func getPartData(type: PosturePartType) -> Single - func getDetailData(type: PostureDetailType) -> Single + func getDetailData(accessToken: String, id: Int) -> Single func getSearchData() -> Single + func getAllPoseData(accessToken: String, lastUpdated: String) -> Single } diff --git a/Projects/Domain/Sources/Response/PoseDTO.swift b/Projects/Domain/Sources/Response/PoseDTO.swift index 5b28b911..62b780d8 100644 --- a/Projects/Domain/Sources/Response/PoseDTO.swift +++ b/Projects/Domain/Sources/Response/PoseDTO.swift @@ -2,17 +2,17 @@ import Foundation import DSKit -struct PostureAllDTO: Decodable { - let responses: [PostureAllResponse] +public struct PostureAllDTO: Decodable { + public let responses: [PostureAllResponse] } -struct PostureAllResponse: Decodable { - let id: Int - let category: [String] - let needMachine: Bool - let name: String - let simplePart, exactPart: [String] - let thumbnail: String +public struct PostureAllResponse: Decodable { + public let id: Int + public let category: [String] + public let needMachine: Bool + public let name: String + public let simplePart, exactPart: [String] + public let thumbnail: String enum CodingKeys: String, CodingKey { case id, category @@ -24,18 +24,24 @@ struct PostureAllResponse: Decodable { } } -extension PostureAllDTO { -// func toDomain() -> SelfCareDetailProfileModel { -// return .init( -// userImage: profileImage, -// userName: nickName, -// userWakaTime: userWakaTime, -// userBageLevel: userBageLevel -// ) -// } +public extension PostureAllDTO { + public func toDomain() -> PostureAllModel { + let dataModels = responses.map { response in + PostureAllDataModel( + id: response.id, + category: response.category, + needMachine: response.needMachine, + name: response.name, + simplePart: response.simplePart, + exactPart: response.exactPart, + thumbnail: response.thumbnail + ) + } + return PostureAllModel(responses: dataModels) + } } -struct PoseDetailDTO: Decodable { +public struct PoseDetailDTO: Decodable { let needMachine: Bool let category: [String] let simpleName, exactName: String @@ -59,8 +65,8 @@ struct PoseDetailDTO: Decodable { } } -extension PoseDetailDTO { - func toDomain() -> PostureDetailModel_temporary { +public extension PoseDetailDTO { + func toDomain() -> PostureDetailModel { return .init(needMachine: needMachine, category: category, simpleName: simpleName, exactName: exactName, thumbnail: thumbnail, video: video, simplePart: simplePart, exactPart: exactPart, startPose: startPose, exerciseWay: exerciseWay, breatheWay: breatheWay, caution: caution, pickleImage: [ DSKitAsset.Assets.posturePickleTest1.image, DSKitAsset.Assets.posturePickleTest2.image, diff --git a/Projects/Domain/Sources/UseCase/PostureUseCase.swift b/Projects/Domain/Sources/UseCase/PostureUseCase.swift index 74636de2..a9855e65 100644 --- a/Projects/Domain/Sources/UseCase/PostureUseCase.swift +++ b/Projects/Domain/Sources/UseCase/PostureUseCase.swift @@ -1,27 +1,39 @@ import UIKit import RxSwift +import RxCocoa + +import Core +import Moya + +import MGLogger +import TokenManager public protocol PostureUseCase { var recommandData: PublishSubject<[PostureRecommandModel]> { get } var partData: PublishSubject { get } var detailData: PublishSubject { get } var searchData: PublishSubject { get } + var poseAllData: PublishSubject { get } func getRecommandData() func getPartData(type: PosturePartType) - func getDetailData(type: PostureDetailType) + func getDetailData(id: Int) func getSearchData() + func getAllPoseData() } public class DefaultPostureUseCase { private let repository: PostureRepositoryInterface private let disposeBag = DisposeBag() + + private let accessToken = TokenManagerImpl().get(key: .accessToken) public let recommandData = PublishSubject<[PostureRecommandModel]>() public let partData = PublishSubject() public let detailData = PublishSubject() public let searchData = PublishSubject() + public let poseAllData = PublishSubject() public init(repository: PostureRepositoryInterface) { self.repository = repository @@ -50,8 +62,8 @@ extension DefaultPostureUseCase: PostureUseCase { }).disposed(by: disposeBag) } - public func getDetailData(type: PostureDetailType) { - repository.getDetailData(type: type) + public func getDetailData(id: Int) { + repository.getDetailData(accessToken: accessToken ?? "", id: id) .subscribe(onSuccess: { [weak self] detailData in self?.detailData.onNext(detailData) }, @@ -69,4 +81,15 @@ extension DefaultPostureUseCase: PostureUseCase { print("PostureUseCase getSearchData error occurred: \(error)") }).disposed(by: disposeBag) } + + public func getAllPoseData() { + let accessToken = TokenManagerImpl().get(key: .accessToken) + repository.getAllPoseData(accessToken: accessToken!, lastUpdated: "2000-01-01T03:12") + .subscribe(onSuccess: { [weak self] poseData in + MGLogger.debug("좋았쒀 영촤~ : \(poseData.responses)") + self?.poseAllData.onNext(poseData) + }, onFailure: { error in + print("poseData error : \(error)") + }).disposed(by: disposeBag) + } } diff --git a/Projects/Features/AuthFeature/Sources/IntroScene/ViewModel/SplashViewModel.swift b/Projects/Features/AuthFeature/Sources/IntroScene/ViewModel/SplashViewModel.swift index 8b9b0b44..8d9b57a5 100644 --- a/Projects/Features/AuthFeature/Sources/IntroScene/ViewModel/SplashViewModel.swift +++ b/Projects/Features/AuthFeature/Sources/IntroScene/ViewModel/SplashViewModel.swift @@ -30,6 +30,7 @@ public class SplashViewModel: AuthViewModelType { self.disposeBag = DisposeBag() useCase.tokenReIssue() +// useCase.getAllPoseData() } public func transform(_ input: Input, action: (Output) -> Void) -> Output { diff --git a/Projects/Features/PickleFeature/Sources/PickleScene/VC/PicklePreparingViewController.swift b/Projects/Features/PickleFeature/Sources/PickleScene/VC/PicklePreparingViewController.swift new file mode 100644 index 00000000..01188aa3 --- /dev/null +++ b/Projects/Features/PickleFeature/Sources/PickleScene/VC/PicklePreparingViewController.swift @@ -0,0 +1,62 @@ +import UIKit + +import RxSwift +import RxCocoa + +import MGLogger +import DSKit +import Core + +public class PicklePreparingViewController: BaseViewController { + + private let backgroundView = UIView() + + private let preparingImageView = UIImageView().then { + $0.image = DSKitAsset.Assets.preparingImage.image + $0.backgroundColor = .clear + } + private let preparingTitle = MGLabel(text: "피클은 아직 개발중이에요", font: UIFont.Pretendard.titleMedium, isCenter: true) + private let preparingInfo = MGLabel(text: "현재 탭은 개발중입니다.\n빠른 시일 내에 더욱 나은 모습으로 찾아뵙겠습니다.", font: UIFont.Pretendard.bodyMedium, isCenter: true, numberOfLineCount: 2) + + public override func viewDidLoad() { + super.viewDidLoad() + + view.backgroundColor = .white + print("asdfasdfasfdasdf") + } + + public override func layout() { + super.layout() + + view.addSubviews([backgroundView]) + backgroundView.addSubviews([preparingImageView, preparingTitle, preparingInfo]) + + backgroundView.snp.makeConstraints { + $0.centerY.equalToSuperview().inset(40.0) + $0.centerX.equalToSuperview() + $0.width.equalToSuperview().inset(55.0) + $0.height.equalTo(228) + } + + preparingImageView.snp.makeConstraints { + $0.width.height.equalTo(120.0) + $0.top.equalToSuperview() + $0.centerX.equalToSuperview() + } + + preparingTitle.snp.makeConstraints { + $0.top.equalTo(preparingImageView.snp.bottom).offset(24.0) + $0.width.equalToSuperview() + $0.height.equalTo(32.0) + $0.centerX.equalToSuperview() + } + + preparingInfo.snp.makeConstraints { + $0.top.equalTo(preparingTitle.snp.bottom).offset(12.0) + $0.width.equalToSuperview() + $0.height.equalTo(40.0) + $0.centerX.equalToSuperview() + } + + } +} diff --git a/Projects/Features/PostureFeature/Demo/Sources/SceneDelegate.swift b/Projects/Features/PostureFeature/Demo/Sources/SceneDelegate.swift index a1c004dd..42691bb2 100644 --- a/Projects/Features/PostureFeature/Demo/Sources/SceneDelegate.swift +++ b/Projects/Features/PostureFeature/Demo/Sources/SceneDelegate.swift @@ -9,6 +9,8 @@ import MGNetworks import MGFlow +import TokenManager + class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? @@ -22,12 +24,6 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { window = UIWindow(frame: scene.coordinateSpace.bounds) window?.windowScene = scene -// -// let useCase = DefaultPostureUseCase(repository: PostureRepository(networkService: PostureService())) -// let viewModel = PostureDetailViewModel(useCase: useCase) -// let viewController = PostureDetailViewController(viewModel) -// -// window?.rootViewController = viewController mainFlow = PostureFlow() diff --git a/Projects/Features/PostureFeature/Sources/PostureScene/View/Detail/PostureDetailNavigationBar.swift b/Projects/Features/PostureFeature/Sources/PostureScene/View/Detail/PostureDetailNavigationBar.swift new file mode 100644 index 00000000..5c3c8861 --- /dev/null +++ b/Projects/Features/PostureFeature/Sources/PostureScene/View/Detail/PostureDetailNavigationBar.swift @@ -0,0 +1,57 @@ +import UIKit + +import RxSwift +import RxCocoa + +import Core +import DSKit + +final class PostureDetailNavigationBar: BaseView { + + public var leftButtonTap: ControlEvent { + return leftButton.rx.tap + } + + private let leftButton = MGImageButton(image: DSKitAsset.Assets.blackLeftBarArrow.image) + + private lazy var leftItemsStackView = UIStackView(arrangedSubviews: [leftButton]).then { + $0.axis = .horizontal + $0.spacing = 4 + $0.distribution = .fillEqually + } + + override init(frame: CGRect) { super.init(frame: frame) } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + public override func attribute() { + self.backgroundColor = .clear + } + + public override func layout() { + self.addSubviews([leftItemsStackView]) + + leftButton.snp.makeConstraints { + $0.width.height.equalTo(24.0) + } + + self.snp.makeConstraints { + $0.height.equalTo(48) + } + + leftItemsStackView.snp.makeConstraints { + $0.top.bottom.equalToSuperview().inset(12.0) + $0.leading.equalToSuperview().offset(20) + } + } +} + +extension PostureDetailNavigationBar { + @discardableResult + public func setLeftButtonImage(image: UIImage) -> Self { + self.leftButton.setImage(image, for: .normal) + return self + } +} diff --git a/Projects/Features/PostureFeature/Sources/PostureScene/View/Detail/PostureDetailViewController.swift b/Projects/Features/PostureFeature/Sources/PostureScene/View/Detail/PostureDetailViewController.swift index 2226461b..d4ac23de 100644 --- a/Projects/Features/PostureFeature/Sources/PostureScene/View/Detail/PostureDetailViewController.swift +++ b/Projects/Features/PostureFeature/Sources/PostureScene/View/Detail/PostureDetailViewController.swift @@ -15,11 +15,15 @@ import MGLogger import PostureFeatureInterface -public class PostureDetailViewController: BaseViewController { +public class PostureDetailViewController: BaseViewController, UIGestureRecognizerDelegate { + + public var id: Int = 112 + + private var naviBar = PostureDetailNavigationBar() private var postureDetailTableView = UITableView().then { - $0.register(PostureDetailImageTableViewCell.self, - forCellReuseIdentifier: PostureDetailImageTableViewCell.identifier) + $0.register(PostureDetailVideoTableViewCell.self, + forCellReuseIdentifier: PostureDetailVideoTableViewCell.identifier) $0.register(PostureDetailTitleTableViewCell.self, forCellReuseIdentifier: PostureDetailTitleTableViewCell.identifier) $0.register(PostureDetailTagTableViewCell.self, @@ -43,33 +47,35 @@ public class PostureDetailViewController: BaseViewController CGFloat { + let combinedString = muscleGroups.joined(separator: ", ") + + let result = [combinedString] + return calculateCellHeight(text: result) } - private func calculateCellHeight(model: [PostureDetailInfoTextModel]) -> CGFloat { - let model = model + func formatTexts(_ texts: [String]) -> [String] { + return texts.map { text -> String in + guard text.count > 24 else { return text } + + return stride(from: 0, to: text.count, by: 24).map { startIndex in + let endIndex = text.index(text.startIndex, offsetBy: startIndex + 24, limitedBy: text.endIndex) ?? text.endIndex + let range = text.index(text.startIndex, offsetBy: startIndex).. CGFloat { + let text = formatTexts(text) var lineCount = 0 - var modelCount = model.count + var modelCount = text.count var middleDistance = 12 - for data in model { - lineCount += data.text.components(separatedBy: "\n").count - 1 + for data in text { + lineCount += data.components(separatedBy: "\n").count - 1 } if modelCount == 1 { @@ -126,15 +164,15 @@ extension PostureDetailViewController: UITableViewDelegate { case 2: return 60 case 3: - return calculateCellHeight(model: postureDetailModel.exercisePartData.infoText) + return calculateCategoryCellHeight(muscleGroups: postureDetailModel.exactPart) case 4: - return calculateCellHeight(model: postureDetailModel.exerciseStartData.infoText) + return calculateCellHeight(text: postureDetailModel.startPose) case 5: - return calculateCellHeight(model: postureDetailModel.exerciseWayData.infoText) + return calculateCellHeight(text: postureDetailModel.exerciseWay) case 6: - return calculateCellHeight(model: postureDetailModel.exerciseBreathData.infoText) + return calculateCellHeight(text: postureDetailModel.breatheWay) case 7: - return calculateCellHeight(model: postureDetailModel.exerciseCautionData.infoText) + return calculateCellHeight(text: postureDetailModel.caution) case 8: return 360 default: @@ -158,9 +196,9 @@ extension PostureDetailViewController: UITableViewDataSource { switch indexPath.row { case 0: let cell = postureDetailTableView.dequeueReusableCell( - withIdentifier: PostureDetailImageTableViewCell.identifier, - for: indexPath) as? PostureDetailImageTableViewCell - let model = postureDetailModel.detailImage + withIdentifier: PostureDetailVideoTableViewCell.identifier, + for: indexPath) as? PostureDetailVideoTableViewCell + let model = postureDetailModel.video cell?.setup(with: model) cell?.selectionStyle = .none return cell ?? UITableViewCell() @@ -168,7 +206,7 @@ extension PostureDetailViewController: UITableViewDataSource { let cell = postureDetailTableView.dequeueReusableCell( withIdentifier: PostureDetailTitleTableViewCell.identifier, for: indexPath) as? PostureDetailTitleTableViewCell - let model = postureDetailModel.titleTextData + let model = [postureDetailModel.simpleName, postureDetailModel.exactName] cell?.setup(with: model) cell?.selectionStyle = .none return cell ?? UITableViewCell() @@ -176,7 +214,7 @@ extension PostureDetailViewController: UITableViewDataSource { let cell = postureDetailTableView.dequeueReusableCell( withIdentifier: PostureDetailTagTableViewCell.identifier, for: indexPath) as? PostureDetailTagTableViewCell - let model = postureDetailModel.exerciseKindData + let model = postureDetailModel.category cell?.setup(with: model) cell?.selectionStyle = .none return cell ?? UITableViewCell() @@ -184,47 +222,47 @@ extension PostureDetailViewController: UITableViewDataSource { let cell = postureDetailTableView.dequeueReusableCell( withIdentifier: PostureDetailTableViewCell.identifier, for: indexPath) as? PostureDetailTableViewCell - let model = postureDetailModel.exercisePartData - cell?.setup(with: model) + let model = formatTexts([postureDetailModel.exactPart.joined(separator: ", ")]) + cell?.setup(with: model, titleText: "자극 부위") cell?.selectionStyle = .none return cell ?? UITableViewCell() case 4: let cell = postureDetailTableView.dequeueReusableCell( withIdentifier: PostureDetailTableViewCell.identifier, for: indexPath) as? PostureDetailTableViewCell - let model = postureDetailModel.exerciseStartData - cell?.setup(with: model) + let model = formatTexts(postureDetailModel.startPose) + cell?.setup(with: model, titleText: "시작 자세") cell?.selectionStyle = .none return cell ?? UITableViewCell() case 5: let cell = postureDetailTableView.dequeueReusableCell( withIdentifier: PostureDetailTableViewCell.identifier, for: indexPath) as? PostureDetailTableViewCell - let model = postureDetailModel.exerciseWayData - cell?.setup(with: model) + let model = formatTexts(postureDetailModel.exerciseWay) + cell?.setup(with: model, titleText: "운동 방법") cell?.selectionStyle = .none return cell ?? UITableViewCell() case 6: let cell = postureDetailTableView.dequeueReusableCell( withIdentifier: PostureDetailTableViewCell.identifier, for: indexPath) as? PostureDetailTableViewCell - let model = postureDetailModel.exerciseBreathData - cell?.setup(with: model) + let model = formatTexts(postureDetailModel.breatheWay) + cell?.setup(with: model, titleText: "호흡법") cell?.selectionStyle = .none return cell ?? UITableViewCell() case 7: let cell = postureDetailTableView.dequeueReusableCell( withIdentifier: PostureDetailTableViewCell.identifier, for: indexPath) as? PostureDetailTableViewCell - let model = postureDetailModel.exerciseCautionData - cell?.setup(with: model) + let model = formatTexts(postureDetailModel.caution) + cell?.setup(with: model, titleText: "주의 사항") cell?.selectionStyle = .none return cell ?? UITableViewCell() case 8: let cell = postureDetailTableView.dequeueReusableCell( withIdentifier: PostureDetailPickeTableViewCell.identifier, for: indexPath) as? PostureDetailPickeTableViewCell - let model = postureDetailModel.relatedPickleData + let model = postureDetailModel.pickleImage cell?.setup(with: model) cell?.selectionStyle = .none return cell ?? UITableViewCell() diff --git a/Projects/Features/PostureFeature/Sources/PostureScene/View/PostureMainNavigationBar.swift b/Projects/Features/PostureFeature/Sources/PostureScene/View/Detail/PostureMainNavigationBar.swift similarity index 100% rename from Projects/Features/PostureFeature/Sources/PostureScene/View/PostureMainNavigationBar.swift rename to Projects/Features/PostureFeature/Sources/PostureScene/View/Detail/PostureMainNavigationBar.swift diff --git a/Projects/Features/PostureFeature/Sources/PostureScene/View/PostureMainViewController.swift b/Projects/Features/PostureFeature/Sources/PostureScene/View/PostureMainViewController.swift index 7909d568..e02b1ab0 100644 --- a/Projects/Features/PostureFeature/Sources/PostureScene/View/PostureMainViewController.swift +++ b/Projects/Features/PostureFeature/Sources/PostureScene/View/PostureMainViewController.swift @@ -49,7 +49,7 @@ public class PostureMainViewController: BaseViewController private lazy var pagingTabBar = MGPagingTabBar(categoryTitleList: categoryTitleList) - lazy var postureUseCase = DefaultPostureUseCase(repository: PostureRepository(networkService: PostureService())) + lazy var postureUseCase = DefaultPostureUseCase(repository: PostureRepository(networkService: DefaultPostureService())) lazy var recommandViewController = PostureRecommandViewController(PostureRecommandViewModel(useCase: postureUseCase)) lazy var chestViewController = PostureChestViewController(PostureChestViewModel(useCase: postureUseCase)) @@ -109,7 +109,8 @@ public class PostureMainViewController: BaseViewController containerView.snp.makeConstraints { $0.top.equalTo(pagingTabBar.snp.bottom) - $0.leading.trailing.bottom.equalToSuperview() + $0.leading.trailing.equalToSuperview() + $0.bottom.equalTo(view.safeAreaLayoutGuide.snp.bottom) } } diff --git a/Projects/Features/PostureFeature/Sources/PostureScene/View/Tab/PostureChestViewController.swift b/Projects/Features/PostureFeature/Sources/PostureScene/View/Tab/PostureChestViewController.swift index 648087ce..6fd6f21f 100644 --- a/Projects/Features/PostureFeature/Sources/PostureScene/View/Tab/PostureChestViewController.swift +++ b/Projects/Features/PostureFeature/Sources/PostureScene/View/Tab/PostureChestViewController.swift @@ -21,6 +21,7 @@ public class PostureChestViewController: BaseViewController + let getDetailData: Driver } public struct Output { @@ -43,8 +43,8 @@ public class PostureDetailViewModel: PostureViewModelType { input.getDetailData .asObservable() .withUnretained(self) - .subscribe(onNext: { owner, _ in - owner.useCase.getDetailData(type: .pushUp) + .subscribe(onNext: { owner, id in + owner.useCase.getDetailData(id: id) }).disposed(by: disposeBag) return output diff --git a/Projects/Features/PostureFeature/Sources/Supporter/Detail/CollectionViewCell/PostureDetailTagCollectionViewCell.swift b/Projects/Features/PostureFeature/Sources/Supporter/Detail/CollectionViewCell/PostureDetailTagCollectionViewCell.swift index 57cf00c8..fd860a1f 100644 --- a/Projects/Features/PostureFeature/Sources/Supporter/Detail/CollectionViewCell/PostureDetailTagCollectionViewCell.swift +++ b/Projects/Features/PostureFeature/Sources/Supporter/Detail/CollectionViewCell/PostureDetailTagCollectionViewCell.swift @@ -22,8 +22,8 @@ public class PostureDetailTagCollectionViewCell: UICollectionViewCell { } public extension PostureDetailTagCollectionViewCell { - func setup(with model: PostureDetailExerciseKindModel) { - tagLabel.updateData(text: model.exerciseTag) + func setup(with text: String) { + tagLabel.updateData(text: text) layout() } diff --git a/Projects/Features/PostureFeature/Sources/Supporter/Detail/PostureDetailTableViewCell.swift b/Projects/Features/PostureFeature/Sources/Supporter/Detail/PostureDetailTableViewCell.swift index 81204cca..fa654ae4 100644 --- a/Projects/Features/PostureFeature/Sources/Supporter/Detail/PostureDetailTableViewCell.swift +++ b/Projects/Features/PostureFeature/Sources/Supporter/Detail/PostureDetailTableViewCell.swift @@ -41,7 +41,7 @@ public class PostureDetailTableViewCell: BaseTableViewCell { return collectionView }() - private var detailTextModel: [PostureDetailInfoTextModel] = [] { + private var detailTextModel: [String] = [] { didSet { detailTextCollectionView.reloadData() } @@ -88,18 +88,18 @@ public class PostureDetailTableViewCell: BaseTableViewCell { } public extension PostureDetailTableViewCell { - func setup(with model: PostureDetailInfoModel) { - switch model.infoText.count { + func setup(with model: [String], titleText: String) { + switch model.count { case 1: - contentsLabel.changeText(text: "\(model.infoText[0].text)") + contentsLabel.changeText(text: "\(model[0])") detailTextCollectionView.isHidden = true contentsLabel.isHidden = false default: - detailTextModel = model.infoText + detailTextModel = model detailTextCollectionView.isHidden = false contentsLabel.isHidden = true } - titleLabel.changeText(text: model.titleText) + titleLabel.changeText(text: titleText) } } @@ -109,9 +109,9 @@ extension PostureDetailTableViewCell: UICollectionViewDelegateFlowLayout { layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath ) -> CGSize { - let lineCount = detailTextModel[indexPath.row].text.components(separatedBy: "\n").count - 1 + let lineCount = detailTextModel[indexPath.row].components(separatedBy: "\n").count - 1 - return CGSize(width: self.frame.width, height: 32.0 + (CGFloat(lineCount) * 20.0)) + return CGSize(width: self.containerView.frame.width, height: 32.0 + (CGFloat(lineCount) * 20.0)) } public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat { diff --git a/Projects/Features/PostureFeature/Sources/Supporter/Detail/PostureDetailTextCollectionViewCell.swift b/Projects/Features/PostureFeature/Sources/Supporter/Detail/PostureDetailTextCollectionViewCell.swift index c8f4e040..00b42acd 100644 --- a/Projects/Features/PostureFeature/Sources/Supporter/Detail/PostureDetailTextCollectionViewCell.swift +++ b/Projects/Features/PostureFeature/Sources/Supporter/Detail/PostureDetailTextCollectionViewCell.swift @@ -22,8 +22,8 @@ public class PostureDetailTextCollectionViewCell: UICollectionViewCell { } public extension PostureDetailTextCollectionViewCell { - func setup(index: Int, with model: [PostureDetailInfoTextModel]) { - detailInfoLabel.setup(index: index, text: model[index - 1].text) + func setup(index: Int, with model: [String]) { + detailInfoLabel.setup(index: index, text: model[index - 1]) layout() } diff --git a/Projects/Features/PostureFeature/Sources/Supporter/Detail/TableViewCell/PostureDetailImageTableViewCell.swift b/Projects/Features/PostureFeature/Sources/Supporter/Detail/TableViewCell/PostureDetailImageTableViewCell.swift index 95354517..b16acc87 100644 --- a/Projects/Features/PostureFeature/Sources/Supporter/Detail/TableViewCell/PostureDetailImageTableViewCell.swift +++ b/Projects/Features/PostureFeature/Sources/Supporter/Detail/TableViewCell/PostureDetailImageTableViewCell.swift @@ -3,33 +3,62 @@ import UIKit import SnapKit import Then -import DSKit import Core +import AVKit +import DSKit -public class PostureDetailImageTableViewCell: BaseTableViewCell { - - static let identifier: String = "PostureDetailImageTableViewCell" - - private var postureImageView = UIImageView().then { - $0.backgroundColor = .gray - $0.contentMode = .scaleAspectFit +public class PostureDetailVideoTableViewCell: BaseTableViewCell { + + static let identifier: String = "PostureDetailVideoTableViewCell" + + private var videoContainerView = UIView().then { + $0.backgroundColor = DSKitAsset.Colors.gray25.color } - + + private var player: AVPlayer? + private var playerLayer: AVPlayerLayer? + public override func layout() { super.layout() - - contentView.addSubviews([postureImageView]) - - postureImageView.snp.makeConstraints { - $0.width.equalToSuperview() - $0.height.equalToSuperview() - $0.top.equalToSuperview() + + contentView.addSubview(videoContainerView) + + videoContainerView.snp.makeConstraints { + $0.edges.equalToSuperview() } } -} - -public extension PostureDetailImageTableViewCell { - func setup(with image: UIImage) { - postureImageView.image = image + + public func setup(with url: String) { + + let dummyURL = URL(string: "https://maeumgagym-bucket.s3.ap-northeast-2.amazonaws.com/%E1%84%85%E1%85%A5%E1%84%89%E1%85%B5%E1%84%8B%E1%85%A1%E1%86%AB+%E1%84%90%E1%85%B3%E1%84%8B%E1%85%B1%E1%84%89%E1%85%B3%E1%84%90%E1%85%B3/06871201-Russian-Twist_waist.hevc.mp4")! + let videoURL = URL(string: url) + player?.pause() + + player = AVPlayer(url: videoURL ?? dummyURL) + NotificationCenter.default.addObserver(self, + selector: #selector(playerItemDidReachEnd(notification:)), + name: .AVPlayerItemDidPlayToEndTime, + object: player?.currentItem) + + playerLayer?.removeFromSuperlayer() + playerLayer = AVPlayerLayer(player: player) + playerLayer?.videoGravity = .resizeAspect + + if let playerLayer = playerLayer { + videoContainerView.layer.addSublayer(playerLayer) + playerLayer.frame = videoContainerView.bounds + } + + player?.play() + } + + @objc func playerItemDidReachEnd(notification: Notification) { + player?.seek(to: CMTime.zero) + player?.play() + } + + override public func layoutSubviews() { + super.layoutSubviews() + playerLayer?.frame = videoContainerView.bounds } } diff --git a/Projects/Features/PostureFeature/Sources/Supporter/Detail/TableViewCell/PostureDetailInfoTableViewCell.swift b/Projects/Features/PostureFeature/Sources/Supporter/Detail/TableViewCell/PostureDetailInfoTableViewCell.swift index 5764d764..8a01116b 100644 --- a/Projects/Features/PostureFeature/Sources/Supporter/Detail/TableViewCell/PostureDetailInfoTableViewCell.swift +++ b/Projects/Features/PostureFeature/Sources/Supporter/Detail/TableViewCell/PostureDetailInfoTableViewCell.swift @@ -1,117 +1,117 @@ -import UIKit - -import SnapKit -import Then - -import DSKit -import Core -import Domain - -public class PostureDetailInfoTableViewCell: BaseTableViewCell { - - static let identifier: String = "PostureDetailInfoTableViewCell" - - private var containerView = BaseView() - - private var titleLabel = MGLabel(font: UIFont.Pretendard.titleMedium, - textColor: .black, - isCenter: false - ) - - private var detailTextCollectionView: UICollectionView = { - let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout().then { - $0.scrollDirection = .vertical - $0.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 16, right: 0) - } - - let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout).then { - $0.register(PostureDetailTextCollectionViewCell.self, - forCellWithReuseIdentifier: PostureDetailTextCollectionViewCell.identifier) - $0.translatesAutoresizingMaskIntoConstraints = false - $0.showsHorizontalScrollIndicator = false - $0.showsVerticalScrollIndicator = false - $0.backgroundColor = .white - } - return collectionView - }() - - private var detailTextModel: [PostureDetailInfoTextModel] = [] { - didSet { - detailTextCollectionView.reloadData() - } - } - - public override func attribute() { - super.attribute() - - backgroundColor = .white - detailTextCollectionView.delegate = self - detailTextCollectionView.dataSource = self - } - - public override func layout() { - super.layout() - - contentView.addSubviews([containerView]) - containerView.addSubviews([titleLabel, detailTextCollectionView]) - - containerView.snp.makeConstraints { - $0.top.equalToSuperview().offset(24.0) - $0.trailing.leading.equalToSuperview().inset(20.0) - $0.bottom.equalToSuperview() - } - - titleLabel.snp.makeConstraints { - $0.top.equalToSuperview().offset(12.0) - $0.leading.trailing.equalToSuperview() - $0.height.equalTo(32.0) - } - - detailTextCollectionView.snp.makeConstraints { - $0.top.equalTo(titleLabel.snp.bottom).offset(24.0) - $0.leading.trailing.equalToSuperview() - $0.bottom.equalToSuperview() - } - } -} - -public extension PostureDetailInfoTableViewCell { - func setup(with model: PostureDetailInfoModel) { - detailTextModel = model.infoText - titleLabel.changeText(text: model.titleText) - } -} - -extension PostureDetailInfoTableViewCell: UICollectionViewDelegateFlowLayout { - public func collectionView( - _ collectionView: UICollectionView, - layout collectionViewLayout: UICollectionViewLayout, - sizeForItemAt indexPath: IndexPath - ) -> CGSize { - let lineCount = detailTextModel[indexPath.row].text.components(separatedBy: "\n").count - 1 - - return CGSize(width: detailTextCollectionView.frame.width, height: 32.0 + (CGFloat(lineCount) * 20.0)) - } -} - -extension PostureDetailInfoTableViewCell: UICollectionViewDataSource { - public func collectionView( - _ collectionView: UICollectionView, - numberOfItemsInSection section: Int - ) -> Int { - return detailTextModel.count - } - - public func collectionView( - _ collectionView: UICollectionView, - cellForItemAt indexPath: IndexPath - ) -> UICollectionViewCell { - let cell = collectionView.dequeueReusableCell( - withReuseIdentifier: PostureDetailTextCollectionViewCell.identifier, - for: indexPath - ) as? PostureDetailTextCollectionViewCell - let model = detailTextModel - cell?.setup(index: indexPath.row + 1, with: model) - return cell ?? UICollectionViewCell() - } -} +//import UIKit +// +//import SnapKit +//import Then +// +//import DSKit +//import Core +//import Domain +// +//public class PostureDetailInfoTableViewCell: BaseTableViewCell { +// +// static let identifier: String = "PostureDetailInfoTableViewCell" +// +// private var containerView = BaseView() +// +// private var titleLabel = MGLabel(font: UIFont.Pretendard.titleMedium, +// textColor: .black, +// isCenter: false +// ) +// +// private var detailTextCollectionView: UICollectionView = { +// let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout().then { +// $0.scrollDirection = .vertical +// $0.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 16, right: 0) +// } +// +// let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout).then { +// $0.register(PostureDetailTextCollectionViewCell.self, +// forCellWithReuseIdentifier: PostureDetailTextCollectionViewCell.identifier) +// $0.translatesAutoresizingMaskIntoConstraints = false +// $0.showsHorizontalScrollIndicator = false +// $0.showsVerticalScrollIndicator = false +// $0.backgroundColor = .white +// } +// return collectionView +// }() +// +// private var detailTextModel: [String] = [] { +// didSet { +// detailTextCollectionView.reloadData() +// } +// } +// +// public override func attribute() { +// super.attribute() +// +// backgroundColor = .white +// detailTextCollectionView.delegate = self +// detailTextCollectionView.dataSource = self +// } +// +// public override func layout() { +// super.layout() +// +// contentView.addSubviews([containerView]) +// containerView.addSubviews([titleLabel, detailTextCollectionView]) +// +// containerView.snp.makeConstraints { +// $0.top.equalToSuperview().offset(24.0) +// $0.trailing.leading.equalToSuperview().inset(20.0) +// $0.bottom.equalToSuperview() +// } +// +// titleLabel.snp.makeConstraints { +// $0.top.equalToSuperview().offset(12.0) +// $0.leading.trailing.equalToSuperview() +// $0.height.equalTo(32.0) +// } +// +// detailTextCollectionView.snp.makeConstraints { +// $0.top.equalTo(titleLabel.snp.bottom).offset(24.0) +// $0.leading.trailing.equalToSuperview() +// $0.bottom.equalToSuperview() +// } +// } +//} +// +//public extension PostureDetailInfoTableViewCell { +// func setup(with model: PostureDetailInfoModel) { +// detailTextModel = model +// titleLabel.changeText(text: model.titleText) +// } +//} +// +//extension PostureDetailInfoTableViewCell: UICollectionViewDelegateFlowLayout { +// public func collectionView( +// _ collectionView: UICollectionView, +// layout collectionViewLayout: UICollectionViewLayout, +// sizeForItemAt indexPath: IndexPath +// ) -> CGSize { +// let lineCount = detailTextModel[indexPath.row].text.components(separatedBy: "\n").count - 1 +// +// return CGSize(width: detailTextCollectionView.frame.width, height: 32.0 + (CGFloat(lineCount) * 20.0)) +// } +//} +// +//extension PostureDetailInfoTableViewCell: UICollectionViewDataSource { +// public func collectionView( +// _ collectionView: UICollectionView, +// numberOfItemsInSection section: Int +// ) -> Int { +// return detailTextModel.count +// } +// +// public func collectionView( +// _ collectionView: UICollectionView, +// cellForItemAt indexPath: IndexPath +// ) -> UICollectionViewCell { +// let cell = collectionView.dequeueReusableCell( +// withReuseIdentifier: PostureDetailTextCollectionViewCell.identifier, +// for: indexPath +// ) as? PostureDetailTextCollectionViewCell +// let model = detailTextModel +// cell?.setup(index: indexPath.row + 1, with: model) +// return cell ?? UICollectionViewCell() +// } +//} diff --git a/Projects/Features/PostureFeature/Sources/Supporter/Detail/TableViewCell/PostureDetailPickeTableViewCell.swift b/Projects/Features/PostureFeature/Sources/Supporter/Detail/TableViewCell/PostureDetailPickeTableViewCell.swift index 6a998a7c..c820ecf2 100644 --- a/Projects/Features/PostureFeature/Sources/Supporter/Detail/TableViewCell/PostureDetailPickeTableViewCell.swift +++ b/Projects/Features/PostureFeature/Sources/Supporter/Detail/TableViewCell/PostureDetailPickeTableViewCell.swift @@ -35,7 +35,7 @@ public class PostureDetailPickeTableViewCell: BaseTableViewCell { return collectionView }() - var pickleData: [PostureDetailPickleImageModel] = [] { + var pickleData: [UIImage] = [] { didSet { pickleCollectionView.reloadData() } @@ -77,9 +77,9 @@ public class PostureDetailPickeTableViewCell: BaseTableViewCell { } public extension PostureDetailPickeTableViewCell { - func setup(with model: PostureDetailPickleModel) { - titleLabel.changeText(text: model.titleText) - pickleData = model.pickleImage + func setup(with model: [UIImage]) { + titleLabel.changeText(text: "관련 피클") + pickleData = model } } @@ -119,7 +119,7 @@ extension PostureDetailPickeTableViewCell: UICollectionViewDataSource { for: indexPath ) as? PostureDetailPickleCollectionViewCell let model = pickleData[indexPath.row] - cell?.setup(image: model.image) + cell?.setup(image: model) return cell ?? UICollectionViewCell() } } diff --git a/Projects/Features/PostureFeature/Sources/Supporter/Detail/TableViewCell/PostureDetailTagTableViewCell.swift b/Projects/Features/PostureFeature/Sources/Supporter/Detail/TableViewCell/PostureDetailTagTableViewCell.swift index 24e91dbd..e4847fe1 100644 --- a/Projects/Features/PostureFeature/Sources/Supporter/Detail/TableViewCell/PostureDetailTagTableViewCell.swift +++ b/Projects/Features/PostureFeature/Sources/Supporter/Detail/TableViewCell/PostureDetailTagTableViewCell.swift @@ -32,7 +32,7 @@ public class PostureDetailTagTableViewCell: BaseTableViewCell { return collectionView }() - private var postureDetailTagModel: [PostureDetailExerciseKindModel] = [] { + private var postureDetailTagModel: [String] = [] { didSet { detailTagCollectionView.reloadData() } @@ -65,7 +65,7 @@ public class PostureDetailTagTableViewCell: BaseTableViewCell { } public extension PostureDetailTagTableViewCell { - func setup(with model: [PostureDetailExerciseKindModel]) { + func setup(with model: [String]) { postureDetailTagModel = model } } diff --git a/Projects/Features/PostureFeature/Sources/Supporter/Detail/TableViewCell/PostureDetailTitleTableViewCell.swift b/Projects/Features/PostureFeature/Sources/Supporter/Detail/TableViewCell/PostureDetailTitleTableViewCell.swift index a188f645..b60aa308 100644 --- a/Projects/Features/PostureFeature/Sources/Supporter/Detail/TableViewCell/PostureDetailTitleTableViewCell.swift +++ b/Projects/Features/PostureFeature/Sources/Supporter/Detail/TableViewCell/PostureDetailTitleTableViewCell.swift @@ -48,8 +48,8 @@ public class PostureDetailTitleTableViewCell: BaseTableViewCell { } public extension PostureDetailTitleTableViewCell { - func setup(with model: PostureDetailTitleTextModel) { - englishTitle.changeText(text: model.englishName) - koreanTitle.changeText(text: model.koreanName) + func setup(with model: [String]) { + englishTitle.changeText(text: model[0]) + koreanTitle.changeText(text: model[1]) } } diff --git a/Projects/Features/PostureFeature/Sources/Supporter/Tab/Part/PosturePartTableViewCell.swift b/Projects/Features/PostureFeature/Sources/Supporter/Tab/Part/PosturePartTableViewCell.swift index 5b057c5e..9c3c45bb 100644 --- a/Projects/Features/PostureFeature/Sources/Supporter/Tab/Part/PosturePartTableViewCell.swift +++ b/Projects/Features/PostureFeature/Sources/Supporter/Tab/Part/PosturePartTableViewCell.swift @@ -10,6 +10,7 @@ import Domain public class PosturePartTableViewCell: BaseTableViewCell { static let identifier: String = "PosturePartTableViewCell" + public var id: Int = 0 private let postureImageView = UIImageView().then { $0.backgroundColor = DSKitAsset.Colors.gray25.color diff --git a/Projects/Features/ShopFeature/Demo/Sources/Application/SceneDelegate.swift b/Projects/Features/ShopFeature/Demo/Sources/Application/SceneDelegate.swift index 2cd84e88..77084f6d 100644 --- a/Projects/Features/ShopFeature/Demo/Sources/Application/SceneDelegate.swift +++ b/Projects/Features/ShopFeature/Demo/Sources/Application/SceneDelegate.swift @@ -4,12 +4,14 @@ import RxFlow import RxSwift import RxCocoa import Core +import MGFlow + class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? var coordinator = FlowCoordinator() - var disposeBag = DisposeBag() + var mainFlow: ShopFlow! func scene(_ scene: UIScene, willConnectTo session: UISceneSession, @@ -19,12 +21,11 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { window = UIWindow(frame: scene.coordinateSpace.bounds) window?.windowScene = scene - let stepper = TestAppStepper() - let initFlow = InitFlow() + let mainFlow = ShopFlow() - coordinator.coordinate(flow: initFlow, with: stepper) - Flows.use(initFlow, when: .created) { root in - self.window?.backgroundColor = UIColor.white + coordinator.coordinate(flow: mainFlow, with: OneStepper(withSingleStep: MGStep.shopIsRequired)) + + Flows.use(mainFlow, when: .created) { root in self.window?.rootViewController = root self.window?.makeKey() } diff --git a/Projects/Features/ShopFeature/Sources/ShopScene/View/ShopViewController.swift b/Projects/Features/ShopFeature/Sources/ShopScene/View/ShopViewController.swift index 0c5f319b..449ce20b 100644 --- a/Projects/Features/ShopFeature/Sources/ShopScene/View/ShopViewController.swift +++ b/Projects/Features/ShopFeature/Sources/ShopScene/View/ShopViewController.swift @@ -1,15 +1,62 @@ import UIKit -import DSKit + import RxSwift import RxCocoa + import MGLogger +import DSKit +import Core -public class ShopViewController: UIViewController { +public class ShopViewController: BaseViewController { + + private let backgroundView = UIView() + + private let preparingImageView = UIImageView().then { + $0.image = DSKitAsset.Assets.preparingImage.image + $0.backgroundColor = .clear + } + private let preparingTitle = MGLabel(text: "샵은 아직 개발중이에요", font: UIFont.Pretendard.titleMedium, isCenter: true) + private let preparingInfo = MGLabel(text: "현재 탭은 개발중입니다.\n빠른 시일 내에 더욱 나은 모습으로 찾아뵙겠습니다.", font: UIFont.Pretendard.bodyMedium, isCenter: true, numberOfLineCount: 2) public override func viewDidLoad() { super.viewDidLoad() - view.backgroundColor = .red + view.backgroundColor = .white print("asdfasdfasfdasdf") } + + public override func layout() { + super.layout() + + view.addSubviews([backgroundView]) + backgroundView.addSubviews([preparingImageView, preparingTitle, preparingInfo]) + + backgroundView.snp.makeConstraints { + $0.centerY.equalToSuperview().inset(40.0) + $0.centerX.equalToSuperview() + $0.width.equalToSuperview().inset(55.0) + $0.height.equalTo(228) + } + + preparingImageView.snp.makeConstraints { + $0.width.height.equalTo(120.0) + $0.top.equalToSuperview() + $0.centerX.equalToSuperview() + } + + preparingTitle.snp.makeConstraints { + $0.top.equalTo(preparingImageView.snp.bottom).offset(24.0) + $0.width.equalToSuperview() + $0.height.equalTo(32.0) + $0.centerX.equalToSuperview() + } + + preparingInfo.snp.makeConstraints { + $0.top.equalTo(preparingTitle.snp.bottom).offset(12.0) + $0.width.equalToSuperview() + $0.height.equalTo(40.0) + $0.centerX.equalToSuperview() + } + + } } diff --git a/Projects/Modules/DSKit/Resources/Assets.xcassets/Icons/preparingImage.imageset/Contents.json b/Projects/Modules/DSKit/Resources/Assets.xcassets/Icons/preparingImage.imageset/Contents.json new file mode 100644 index 00000000..14d4117f --- /dev/null +++ b/Projects/Modules/DSKit/Resources/Assets.xcassets/Icons/preparingImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "preparingImage.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "preparingImage@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "preparingImage@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Projects/Modules/DSKit/Resources/Assets.xcassets/Icons/preparingImage.imageset/preparingImage.png b/Projects/Modules/DSKit/Resources/Assets.xcassets/Icons/preparingImage.imageset/preparingImage.png new file mode 100644 index 00000000..671e1e81 Binary files /dev/null and b/Projects/Modules/DSKit/Resources/Assets.xcassets/Icons/preparingImage.imageset/preparingImage.png differ diff --git a/Projects/Modules/DSKit/Resources/Assets.xcassets/Icons/preparingImage.imageset/preparingImage@2x.png b/Projects/Modules/DSKit/Resources/Assets.xcassets/Icons/preparingImage.imageset/preparingImage@2x.png new file mode 100644 index 00000000..8fc4dced Binary files /dev/null and b/Projects/Modules/DSKit/Resources/Assets.xcassets/Icons/preparingImage.imageset/preparingImage@2x.png differ diff --git a/Projects/Modules/DSKit/Resources/Assets.xcassets/Icons/preparingImage.imageset/preparingImage@3x.png b/Projects/Modules/DSKit/Resources/Assets.xcassets/Icons/preparingImage.imageset/preparingImage@3x.png new file mode 100644 index 00000000..a77636e6 Binary files /dev/null and b/Projects/Modules/DSKit/Resources/Assets.xcassets/Icons/preparingImage.imageset/preparingImage@3x.png differ diff --git a/Projects/Modules/MGFlow/Sources/Flow/InitFlow.swift b/Projects/Modules/MGFlow/Sources/Flow/InitFlow.swift index c0330238..1daea53f 100644 --- a/Projects/Modules/MGFlow/Sources/Flow/InitFlow.swift +++ b/Projects/Modules/MGFlow/Sources/Flow/InitFlow.swift @@ -52,11 +52,14 @@ public class InitFlow: Flow { pickle.tabBarItem = MGTabBarTypeItem(.pickle) selfCare.tabBarItem = MGTabBarTypeItem(.selfCare) + self.rootViewController.setViewControllers([home, posture, shop, pickle, selfCare], animated: true) + self.rootViewController.navigationController?.isNavigationBarHidden = true + self.rootViewController.tabBar.backgroundColor = .white } return .multiple(flowContributors: [ FlowContributor.contribute(withNextPresentable: homeFlow, withNextStepper: OneStepper(withSingleStep: MGStep.home)), - FlowContributor.contribute(withNextPresentable: postureFlow, withNextStepper: OneStepper(withSingleStep: MGStep.postureIsRequired)), + FlowContributor.contribute(withNextPresentable: postureFlow, withNextStepper: OneStepper(withSingleStep: MGStep.postureMainIsRequired)), FlowContributor.contribute(withNextPresentable: shopFlow, withNextStepper: OneStepper(withSingleStep: MGStep.shopIsRequired)), FlowContributor.contribute(withNextPresentable: pickleFlow, withNextStepper: OneStepper(withSingleStep: MGStep.pickleRequired)), FlowContributor.contribute(withNextPresentable: selfCareFlow, withNextStepper: OneStepper(withSingleStep: MGStep.selfCareIsRequired)), diff --git a/Projects/Modules/MGFlow/Sources/Flow/PickleFlow.swift b/Projects/Modules/MGFlow/Sources/Flow/PickleFlow.swift index 530e7f7a..57e80d33 100644 --- a/Projects/Modules/MGFlow/Sources/Flow/PickleFlow.swift +++ b/Projects/Modules/MGFlow/Sources/Flow/PickleFlow.swift @@ -10,7 +10,7 @@ import Core public class PickleFlow: Flow { private var rootViewController: UINavigationController! - var viewController: PickleViewController! + var viewController: PicklePreparingViewController! public var root: Presentable { return self.rootViewController @@ -24,7 +24,7 @@ public class PickleFlow: Flow { guard let step = step as? MGStep else { return .none } switch step { - case .pickle: + case .pickleRequired: return setupPickleScreen() default: return .none @@ -32,7 +32,7 @@ public class PickleFlow: Flow { } private func setupViewController() { - viewController = PickleViewController() + viewController = PicklePreparingViewController(Int()) rootViewController = UINavigationController(rootViewController: viewController) } @@ -40,6 +40,7 @@ public class PickleFlow: Flow { rootViewController.tabBarItem.title = "피클" rootViewController.tabBarItem.image = DSKitAsset.Assets.baPickleTapBar.image rootViewController.tabBarItem.selectedImage = DSKitAsset.Assets.blPeopleTapBar.image + rootViewController.isNavigationBarHidden = true return .one(flowContributor: .contribute(withNextPresentable: self.root, withNextStepper: PickleStepper.shared)) } } diff --git a/Projects/Modules/MGFlow/Sources/Flow/PostureFlow.swift b/Projects/Modules/MGFlow/Sources/Flow/PostureFlow.swift index 9a2cf309..e4ddf2e5 100644 --- a/Projects/Modules/MGFlow/Sources/Flow/PostureFlow.swift +++ b/Projects/Modules/MGFlow/Sources/Flow/PostureFlow.swift @@ -52,15 +52,15 @@ public class PostureFlow: Flow { return navigateToSearchViewScreen() case .postureBack: return popupViewController() - case .postureDetailIsRequired(withDetailId: 0): - return navigateToSearchViewScreen() + case .postureDetailIsRequired(let id): + return navigateToDetailViewScreen(id: id) default: return .none } } private func setupService() { - postureService = PostureService() + postureService = DefaultPostureService() postureRepository = PostureRepository(networkService: postureService) useCase = DefaultPostureUseCase(repository: postureRepository) viewModel = PostureMainViewModel(useCase: useCase) @@ -83,7 +83,15 @@ public class PostureFlow: Flow { private func navigateToSearchViewScreen() -> FlowContributors { let vc = PostureSearchViewController(PostureSearchViewModel(useCase: self.useCase)) rootViewController.pushViewController(vc, animated: true) - MainTabBarContoller.shared.tabBar.isHidden = false + MainTabBarContoller.shared.tabBar.isHidden = true + return .none + } + + private func navigateToDetailViewScreen(id: Int) -> FlowContributors { + let vc = PostureDetailViewController(PostureDetailViewModel(useCase: self.useCase)) + vc.id = id + rootViewController.pushViewController(vc, animated: true) + MainTabBarContoller.shared.tabBar.isHidden = true return .none } diff --git a/Projects/Modules/MGFlow/Sources/Flow/ShopFlow.swift b/Projects/Modules/MGFlow/Sources/Flow/ShopFlow.swift index c23a9a09..8f9bf819 100644 --- a/Projects/Modules/MGFlow/Sources/Flow/ShopFlow.swift +++ b/Projects/Modules/MGFlow/Sources/Flow/ShopFlow.swift @@ -4,21 +4,54 @@ import RxSwift import RxCocoa import DSKit +import ShopFeature +import Core + public class ShopFlow: Flow { + + private var rootViewController: UINavigationController! + + var viewController: ShopViewController! + public var root: Presentable { return self.rootViewController } + + public init() { + setupViewController() + } + + public func navigate(to step: Step) -> FlowContributors { + guard let step = step as? MGStep else { return .none } - private let rootViewController = UINavigationController() + switch step { + case .shopIsRequired: + return setupPostureMainScreen() + default: + return .none + } + } - public init() { - let viewController = UIViewController() - viewController.view.backgroundColor = .white - viewController.tabBarItem = UITabBarItem(title: "샵", image: DSKitAsset.Assets.baShopTapBar.image, selectedImage: DSKitAsset.Assets.blShopTapBar.image) + private func setupViewController() { + viewController = ShopViewController(Int()) + rootViewController = UINavigationController(rootViewController: viewController) + } + + private func setupPostureMainScreen() -> FlowContributors { + rootViewController.view.backgroundColor = .white + rootViewController.tabBarItem.title = "샵" + rootViewController.tabBarItem.image = DSKitAsset.Assets.baShopTapBar.image + rootViewController.tabBarItem.selectedImage = DSKitAsset.Assets.blShopTapBar.image rootViewController.setViewControllers([viewController], animated: false) + rootViewController.isNavigationBarHidden = true + return .one(flowContributor: .contribute(withNextPresentable: self.root, withNextStepper: ShopStepper.shared)) } - public func navigate(to step: Step) -> FlowContributors { + private func popupViewController() -> FlowContributors { + rootViewController.popToRootViewController(animated: true) + if rootViewController.viewControllers.count == 1 { + MainTabBarContoller.shared.tabBar.isHidden = false + } return .none } } diff --git a/Projects/Modules/MGNetworks/Sources/API/Pose/PostureAPI.swift b/Projects/Modules/MGNetworks/Sources/API/Pose/PostureAPI.swift index 284a0b56..388af2c0 100644 --- a/Projects/Modules/MGNetworks/Sources/API/Pose/PostureAPI.swift +++ b/Projects/Modules/MGNetworks/Sources/API/Pose/PostureAPI.swift @@ -64,7 +64,7 @@ extension PostureAPI: BaseAPI { let parameters: [String: Any] = [ "last_updated": last_updated ] - return .requestParameters(parameters: parameters, encoding: JSONEncoding.default) + return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString) case let .postureAdd(_, simple_name, exact_name, @@ -77,7 +77,7 @@ extension PostureAPI: BaseAPI { breathe_way, caution, need_machine): - var params: [String: Any] = [ + let params: [String: Any] = [ "simple_name": simple_name, "exact_name": exact_name, "thumbnail": thumbnail, diff --git a/Projects/Modules/MGNetworks/Sources/Service/PostureService.swift b/Projects/Modules/MGNetworks/Sources/Service/PostureService.swift index a9d9a3d1..73f6909b 100644 --- a/Projects/Modules/MGNetworks/Sources/Service/PostureService.swift +++ b/Projects/Modules/MGNetworks/Sources/Service/PostureService.swift @@ -1,11 +1,28 @@ import UIKit import RxSwift +import RxCocoa + +import RxMoya +import Moya -import Domain import DSKit +import Domain +import TokenManager + +public protocol PostureService { + func requestRecommandData() -> Single<[PostureRecommandModel]> + func requestPartData(type: PosturePartType) -> Single + func requestDetailData(accessToken: String, id: Int) -> Single + func requestSearchData() -> Single + func getAllPoseData(accessToken: String, lastUpdated: String) -> Single +} -public class PostureService { +public class DefaultPostureService: NSObject { + let postureProvider = MoyaProvider() +} + +extension DefaultPostureService: PostureService { public func requestRecommandData() -> Single<[PostureRecommandModel]> { let postureRecommandData: [PostureRecommandModel] = [ @@ -41,11 +58,12 @@ public class PostureService { } } - public func requestDetailData(type: PostureDetailType) -> Single { - switch type { - case .pushUp: - return requestPushUpData() - } + public func requestDetailData(accessToken: String, id: Int) -> Single { + postureProvider.rx.request(.postureShow(accessToken: accessToken, id: id)).filterSuccessfulStatusCodes() + } + + public func getAllPoseData(accessToken: String, lastUpdated: String) -> Single { + return postureProvider.rx.request(.postureAllShow(accessToken: accessToken, last_updated: lastUpdated)).filterSuccessfulStatusCodes() } public func requestSearchData() -> Single { @@ -76,13 +94,9 @@ public class PostureService { ) ) } - - public init() { - - } } -private extension PostureService { +private extension DefaultPostureService { func requestChestData() -> Single { return Single.just( @@ -166,62 +180,43 @@ private extension PostureService { } } -private extension PostureService { - func requestPushUpData() -> Single{ - return Single.just( - PostureDetailModel( - detailImage: DSKitAsset.Assets.pushUp.image, - titleTextData: PostureDetailTitleTextModel(englishName: "푸쉬업", koreanName: "팔굽혀펴기"), - exerciseKindData: [PostureDetailExerciseKindModel(exerciseTag: "맨몸"), - PostureDetailExerciseKindModel(exerciseTag: "가슴")], - exercisePartData: - PostureDetailInfoModel( - titleText: "자극 부위", - infoText: - [ - PostureDetailInfoTextModel(text: "대흉근, 삼두근, 이두근"), - ]), - exerciseStartData: - PostureDetailInfoModel( - titleText: "시작 자세", - infoText: - [ - PostureDetailInfoTextModel(text: "양팔을 가슴 옆에 두고 바닥에 엎드립니다."), - ]), - exerciseWayData: - PostureDetailInfoModel( - titleText: "운동 방법", - infoText: - [ - PostureDetailInfoTextModel(text: "양팔을 가슴 옆에 두고 바닥에 엎드립니다."), - PostureDetailInfoTextModel(text: "복근과 둔근에 힘을 준 상태로 팔꿈치를 피며\n올라옵니다."), - PostureDetailInfoTextModel(text: "천천히 팔꿈치를 굽히며 시작 자세로 돌아갑니다."), - ]), - exerciseBreathData: - PostureDetailInfoModel( - titleText: "호흡법", - infoText: - [ - PostureDetailInfoTextModel(text: "흡 하 흡 하 흡흡흡 하하하"), - ]), - exerciseCautionData: - PostureDetailInfoModel( - titleText: "주의 사항", - infoText: - [ - PostureDetailInfoTextModel(text: "양팔을 가슴 옆에 두고 바닥에 엎드립니다."), - PostureDetailInfoTextModel(text: "복근과 둔근에 힘을 준 상태로 팔꿈치를 피며\n올라옵니다.") - ]), - relatedPickleData: - PostureDetailPickleModel( - titleText: "관련 피클", - pickleImage: [ - PostureDetailPickleImageModel(image: DSKitAsset.Assets.posturePickleTest1.image), - PostureDetailPickleImageModel(image: DSKitAsset.Assets.posturePickleTest2.image), - PostureDetailPickleImageModel(image: DSKitAsset.Assets.posturePickleTest3.image), - PostureDetailPickleImageModel(image: DSKitAsset.Assets.posturePickleTest4.image), - ]) - ) - ) - } -} +//private extension PostureService { +// func requestPushUpData() -> Single{ +// return Single.just( +// PostureDetailModel_temporary( +// needMachine: false, +// category: ["복근", "등"], +// simpleName: "러시안 트위스트", +// exactName: "러시안 트위스트", +// thumbnail: "", +// video: "", +// simplePart: ["복근", "등"], +// exactPart: ["복근", "내복사근"], +// startPose: [ +// "바닥에 앉아 무릎을 구부리고", +// " 발뒤꿈치를 바닥에 대거나 약간 들고", +// " 상체를 약간 뒤로 기울여 균형을 잡으세요." +// ], +// exerciseWay: [ +// "양손을 가슴 앞에서 모으거나 손가락을 서로 걸어 잡습니다.", +// "상체를 좌우로 돌려가며 손을 바닥 가까이로 움직입니다.", +// "한쪽으로 돌린 후 반대쪽으로 같은 방법으로 돌립니다." +// ], +// breatheWay: [ +// "상체를 한쪽으로 돌릴 때 숨을 내쉬고", +// "중앙으로 돌아올 때 숨을 들이마십니다." +// ], +// caution: [ +// "허리에 무리가 가지 않도록 상체를 너무 많이 뒤로 기울이지 않고", +// "동작을 천천히 제어하여 안정적으로 수행하세요." +// ], +// pickleImage: [ +// DSKitAsset.Assets.posturePickleTest1.image, +// DSKitAsset.Assets.posturePickleTest2.image, +// DSKitAsset.Assets.posturePickleTest3.image, +// DSKitAsset.Assets.posturePickleTest4.image, +// ] +// ) +// ) +// } +//}