diff --git a/RF.xcodeproj/project.pbxproj b/RF.xcodeproj/project.pbxproj index 95817755..b40b56ff 100644 --- a/RF.xcodeproj/project.pbxproj +++ b/RF.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + 3B03E1EF2AE8FDA1006CC482 /* ScheduleService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B03E1EE2AE8FDA1006CC482 /* ScheduleService.swift */; }; + 3B03E1F12AE8FDD7006CC482 /* ScheduleList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B03E1F02AE8FDD7006CC482 /* ScheduleList.swift */; }; 3B0B35292A7A5A31003B2D8C /* SecretKey.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B0B35282A7A5A31003B2D8C /* SecretKey.plist */; }; 3B0BA20A2A8DEEAA00F7E818 /* GradientView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B0BA2092A8DEEAA00F7E818 /* GradientView.swift */; }; 3B0E2EB92A80FE9200797782 /* MeetingService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B0E2EB82A80FE9200797782 /* MeetingService.swift */; }; @@ -25,6 +27,8 @@ 3B267B8F2A861E3200F3949A /* GroupJoinRequestViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B267B8E2A861E3200F3949A /* GroupJoinRequestViewController.swift */; }; 3B267B922A86281100F3949A /* GroupJoinRequestViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B267B912A86281100F3949A /* GroupJoinRequestViewModel.swift */; }; 3B267B942A862AB100F3949A /* GroupJoinRequestTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B267B932A862AB100F3949A /* GroupJoinRequestTableViewCell.swift */; }; + 3B3698862B0457EE00BEB126 /* ChoiceMajorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B3698852B0457EE00BEB126 /* ChoiceMajorView.swift */; }; + 3B3698882B048DB000BEB126 /* ChoiceMajorViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B3698872B048DB000BEB126 /* ChoiceMajorViewModel.swift */; }; 3B5402BD2A6E76C100D0AD21 /* ListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B5402BC2A6E76C100D0AD21 /* ListViewController.swift */; }; 3B5402C02A6E7E0900D0AD21 /* ListTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B5402BF2A6E7E0900D0AD21 /* ListTableViewCell.swift */; }; 3B5402C32A6EA61700D0AD21 /* ListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B5402C22A6EA61700D0AD21 /* ListViewModel.swift */; }; @@ -126,7 +130,6 @@ 440B53CA2AC9421600D6607F /* SearchPWResultViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 440B53C92AC9421600D6607F /* SearchPWResultViewController.swift */; }; 443044BD2A67B434008A4087 /* UserInfoSelfViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 443044BC2A67B434008A4087 /* UserInfoSelfViewController.swift */; }; 44BBA9B12AB8B4B200EC43BB /* SearchIDViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44BBA9B02AB8B4B200EC43BB /* SearchIDViewController.swift */; }; - 44CC47732A8DE9A70025EAEC /* ProfileSettingTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44CC47722A8DE9A70025EAEC /* ProfileSettingTableViewCell.swift */; }; 44F82A112A56D5D4006B17F8 /* UIColor+Ext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44F82A102A56D5D4006B17F8 /* UIColor+Ext.swift */; }; 44F82A172A5C05A7006B17F8 /* UserInfoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44F82A162A5C05A7006B17F8 /* UserInfoViewController.swift */; }; 570063602A63D5120051F42A /* PersonnelStepper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5700635F2A63D5120051F42A /* PersonnelStepper.swift */; }; @@ -212,6 +215,8 @@ 1993FCFD8483C342C337F096 /* Pods_RF.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RF.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 2505DAF5F18952160CB2275D /* Pods-RF.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RF.debug.xcconfig"; path = "Target Support Files/Pods-RF/Pods-RF.debug.xcconfig"; sourceTree = ""; }; 2B0C13344295BF3D18F7D032 /* Pods-RF.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RF.release.xcconfig"; path = "Target Support Files/Pods-RF/Pods-RF.release.xcconfig"; sourceTree = ""; }; + 3B03E1EE2AE8FDA1006CC482 /* ScheduleService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScheduleService.swift; sourceTree = ""; }; + 3B03E1F02AE8FDD7006CC482 /* ScheduleList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScheduleList.swift; sourceTree = ""; }; 3B0B35282A7A5A31003B2D8C /* SecretKey.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = SecretKey.plist; sourceTree = ""; }; 3B0BA2092A8DEEAA00F7E818 /* GradientView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GradientView.swift; sourceTree = ""; }; 3B0E2EB82A80FE9200797782 /* MeetingService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeetingService.swift; sourceTree = ""; }; @@ -230,6 +235,8 @@ 3B267B8E2A861E3200F3949A /* GroupJoinRequestViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupJoinRequestViewController.swift; sourceTree = ""; }; 3B267B912A86281100F3949A /* GroupJoinRequestViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupJoinRequestViewModel.swift; sourceTree = ""; }; 3B267B932A862AB100F3949A /* GroupJoinRequestTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupJoinRequestTableViewCell.swift; sourceTree = ""; }; + 3B3698852B0457EE00BEB126 /* ChoiceMajorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChoiceMajorView.swift; sourceTree = ""; }; + 3B3698872B048DB000BEB126 /* ChoiceMajorViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChoiceMajorViewModel.swift; sourceTree = ""; }; 3B5402BC2A6E76C100D0AD21 /* ListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListViewController.swift; sourceTree = ""; }; 3B5402BF2A6E7E0900D0AD21 /* ListTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListTableViewCell.swift; sourceTree = ""; }; 3B5402C22A6EA61700D0AD21 /* ListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListViewModel.swift; sourceTree = ""; }; @@ -443,9 +450,18 @@ path = Pods; sourceTree = ""; }; + 3B03E1ED2AE8FD97006CC482 /* Schedule */ = { + isa = PBXGroup; + children = ( + 3B03E1EE2AE8FDA1006CC482 /* ScheduleService.swift */, + ); + path = Schedule; + sourceTree = ""; + }; 3B0E2EB72A80FE8400797782 /* Meeting */ = { isa = PBXGroup; children = ( + 3B03E1ED2AE8FD97006CC482 /* Schedule */, 3B6E6F152A94D2930002C6F3 /* Search */, 3B0E2EB82A80FE9200797782 /* MeetingService.swift */, 3BF2E7712A8CB32300FD09F7 /* DetailMeetingJoinService.swift */, @@ -742,6 +758,7 @@ 3BD700C42A793565005C7D7E /* ChoiceBornCountryView.swift */, 3BD700CE2A7962F0005C7D7E /* ChoiceInterestingCountryView.swift */, 3BD700D22A7963DD005C7D7E /* ChoiceInterestingLanguageView.swift */, + 3B3698852B0457EE00BEB126 /* ChoiceMajorView.swift */, ); path = ChooseUserInfo; sourceTree = ""; @@ -767,6 +784,7 @@ isa = PBXGroup; children = ( 3BD700C72A79364B005C7D7E /* ChoiceCountryViewModel.swift */, + 3B3698872B048DB000BEB126 /* ChoiceMajorViewModel.swift */, 3BD700D02A796312005C7D7E /* ChoiceInterestingCountryViewModel.swift */, 3BD700D42A796403005C7D7E /* ChoiceInterestingLanguageViewModel.swift */, ); @@ -849,6 +867,7 @@ 57DD3E6B2A810F60009F7139 /* Response.swift */, 3BF2E7652A8B50CC00FD09F7 /* Judge.swift */, 57AF3D572A85FE8800C09715 /* Papago.swift */, + 3B03E1F02AE8FDD7006CC482 /* ScheduleList.swift */, 570063D32A7A57110051F42A /* Meeting.swift */, 3B69EE3F2A81F522002DB6DF /* Enums.swift */, 3BD68EF62A779741003A57A7 /* SignIn.swift */, @@ -1281,6 +1300,7 @@ files = ( 570063E82A7D13480051F42A /* OtherMessageTableViewCell.swift in Sources */, 3B6C31252A7E17DC008FADA1 /* UserInfoSelfViewModel.swift in Sources */, + 3B03E1F12AE8FDD7006CC482 /* ScheduleList.swift in Sources */, 570063932A67B23A0051F42A /* RuleListViewController.swift in Sources */, 3B6BA9982A7FEC7F00A11FE4 /* EmailCustomTextField.swift in Sources */, 3BEEA2722AD578F200F6D5B7 /* MyPageReportApplyViewController.swift in Sources */, @@ -1339,7 +1359,6 @@ 3BC35CEF2A5C6C1B00D73163 /* UILabel+Ext.swift in Sources */, 572A9A322A5CB445004D2809 /* SetInterestViewController.swift in Sources */, 570063602A63D5120051F42A /* PersonnelStepper.swift in Sources */, - 572A9A3A2A5E80D1004D2809 /* Member.swift in Sources */, 440B53C62AC1725300D6607F /* SearchIDResultViewController.swift in Sources */, 57673EE42A58360B00A13D07 /* TagCollectionViewCell.swift in Sources */, 3B62877C2A84BF7200E00B09 /* CreateViewModel.swift in Sources */, @@ -1352,6 +1371,7 @@ 57BB1B412AD5799B00516897 /* PapagoService.swift in Sources */, 3BD68EF72A779741003A57A7 /* SignIn.swift in Sources */, 3B6E6F172A94D29D0002C6F3 /* SearchService.swift in Sources */, + 3B03E1EF2AE8FDA1006CC482 /* ScheduleService.swift in Sources */, 572DC2562A51C9BD00C0D6E1 /* SetNicknameViewController.swift in Sources */, 3B938C902A93847A00CBF734 /* MeetingManageUIButton.swift in Sources */, 57AF3D5C2A94957300C09715 /* ChatMenuOption.swift in Sources */, @@ -1407,12 +1427,14 @@ 3B15CD5A2A63ECB80096871F /* FilteringViewController.swift in Sources */, 5700639D2A6AC60C0051F42A /* NotiListTableViewCell.swift in Sources */, 3BEEA2702AD558EF00F6D5B7 /* MyPageReportViewController.swift in Sources */, + 3B3698882B048DB000BEB126 /* ChoiceMajorViewModel.swift in Sources */, 572A9A242A5AAE24004D2809 /* CALayer+Ext.swift in Sources */, 440B53C82AC29E2700D6607F /* SearchPWViewController.swift in Sources */, 3BF2E7662A8B50CC00FD09F7 /* Judge.swift in Sources */, 3B5402C72A6EA99E00D0AD21 /* ListCellViewModel.swift in Sources */, 3B935D582A56F00200FECE3A /* SignUpViewController.swift in Sources */, 572DC2312A51BF2400C0D6E1 /* SceneDelegate.swift in Sources */, + 3B3698862B0457EE00BEB126 /* ChoiceMajorView.swift in Sources */, 3B9BA8F12A724CB30043DDE6 /* MyPageViewController.swift in Sources */, 3BD68EFB2A779885003A57A7 /* SignInService.swift in Sources */, 57DD3E682A8106E7009F7139 /* Message.swift in Sources */, @@ -1607,7 +1629,6 @@ CODE_SIGN_ENTITLEMENTS = RF/RF.entitlements; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = ""; DEVELOPMENT_TEAM = SN5J3DYFX4; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = RF/Info.plist; diff --git a/RF/Constants/API/EndPoint.swift b/RF/Constants/API/EndPoint.swift index 83b1babd..909a5b9f 100644 --- a/RF/Constants/API/EndPoint.swift +++ b/RF/Constants/API/EndPoint.swift @@ -62,3 +62,8 @@ struct ReportPath { struct SearchPath { static let search = "/party/search" } + +/// Schedule +struct SchedulePath { + static let myList = "/schedule/user/:userId" +} diff --git a/RF/Constants/ViewConstants.swift b/RF/Constants/ViewConstants.swift index 8625caed..59b2962a 100644 --- a/RF/Constants/ViewConstants.swift +++ b/RF/Constants/ViewConstants.swift @@ -128,6 +128,8 @@ struct UserInfo { static let bornCountryPlaceHolder = "출생 국가를 선택해주세요" static let college = "대학교 선택" static let collegePlaceHolder = "대학교를 선택해주세요" + static let major = "전공 선택" + static let majorPlaceHolder = "전공을 선택해주세요" } // MARK: - DetailMeetingJoinPopUp diff --git a/RF/Models/Codable/Enums.swift b/RF/Models/Codable/Enums.swift index 2de25efc..16b2904f 100644 --- a/RF/Models/Codable/Enums.swift +++ b/RF/Models/Codable/Enums.swift @@ -23,19 +23,19 @@ final class EnumFile { service.getEnumList() .subscribe( onNext: { [weak self] data in + print(data) self?.enumList.accept(data) },onError: { error in print("EnumFile getEnumList error!") }) .disposed(by: disposeBag) - } } struct Enums: Codable { var country, interest, language, lifeStyle: [KVO]? - var mbti, preferAges, rule, university: [KVO]? + var mbti, preferAges, rule, university, major: [KVO]? enum CodingKeys: String, CodingKey { case country = "Country" @@ -46,6 +46,7 @@ struct Enums: Codable { case preferAges = "PreferAges" case rule = "Rule" case university = "University" + case major = "Major" } } diff --git a/RF/Models/Codable/ScheduleList.swift b/RF/Models/Codable/ScheduleList.swift new file mode 100644 index 00000000..d7e7afb0 --- /dev/null +++ b/RF/Models/Codable/ScheduleList.swift @@ -0,0 +1,18 @@ +// +// Schedule.swift +// RF +// +// Created by 정호진 on 10/25/23. +// + +import Foundation + +struct ScheduleList: Codable { + let id: Int? + let partyId: Int? + let partyName: String? + let scheduleName: String? + let localDateTime: String? + let location: String? + let participantCount: Int? +} diff --git a/RF/Models/Codable/User.swift b/RF/Models/Codable/User.swift index 4b094366..cbfe287a 100644 --- a/RF/Models/Codable/User.swift +++ b/RF/Models/Codable/User.swift @@ -17,6 +17,7 @@ struct User: Codable { let mbti: String? let profileImageUrl: String? let userId: Int? + let major: String? enum CodingKeys: String, CodingKey { case loginId @@ -28,6 +29,7 @@ struct User: Codable { case interest = "interests" case profileImageUrl = "imageFilePath" case mbti, userId + case major } } diff --git a/RF/Services/Meeting/Schedule/ScheduleService.swift b/RF/Services/Meeting/Schedule/ScheduleService.swift new file mode 100644 index 00000000..fd8fd825 --- /dev/null +++ b/RF/Services/Meeting/Schedule/ScheduleService.swift @@ -0,0 +1,43 @@ +// +// ScheduleService.swift +// RF +// +// Created by 정호진 on 10/25/23. +// + +import Foundation +import Alamofire +import RxSwift + +final class ScheduleService { + + func getMySchdule(year: Int, month: Int) -> Observable<[ScheduleList]> { + var url = Domain.restApi + SchedulePath.myList + let userId = UserDefaults.standard.string(forKey: "UserId") ?? "" + url = url.replacingOccurrences(of: ":userId", with: userId) + print(url) + print(year) + print(month) + + return Observable.create { observer in + AF.request(url, + method: .get, + parameters:["year": year, + "month": month]) + .validate(statusCode: 200..<201) + .responseDecodable(of: Response<[ScheduleList]>.self) { response in + print(response) + switch response.result { + case .success(let data): + observer.onNext(data.result ?? []) + case .failure(let error): + print("\(#function) error! \(error)") + } + } + + return Disposables.create() + } + + } + +} diff --git a/RF/Services/SignUp/SignUpService.swift b/RF/Services/SignUp/SignUpService.swift index 00c15486..941e7cce 100644 --- a/RF/Services/SignUp/SignUpService.swift +++ b/RF/Services/SignUp/SignUpService.swift @@ -79,7 +79,8 @@ final class SignUpService { interest: SignUpDataViewModel.viewModel.interestingRelay.value, mbti: SignUpDataViewModel.viewModel.mbtiRelay.value, profileImageUrl: nil, - userId: nil) + userId: nil, + major: SignUpDataViewModel.viewModel.major.value) print(body) return Observable.create { observer in diff --git a/RF/ViewModels/Meeting/Schedule/ScheduleFSCalendarCellViewModel.swift b/RF/ViewModels/Meeting/Schedule/ScheduleFSCalendarCellViewModel.swift index 7c9c52a6..5a28138b 100644 --- a/RF/ViewModels/Meeting/Schedule/ScheduleFSCalendarCellViewModel.swift +++ b/RF/ViewModels/Meeting/Schedule/ScheduleFSCalendarCellViewModel.swift @@ -11,13 +11,13 @@ import RxSwift final class ScheduleFSCalendarCellViewModel { /// 특정 날짜에 대한 일정 리스트 - var specificEventList : BehaviorRelay<[ScheduleEvent]> = BehaviorRelay(value: []) + var specificEventList : BehaviorRelay<[ScheduleList]> = BehaviorRelay(value: []) /// 테이블 뷰가 생성 되었는지 var isTableView: BehaviorRelay = BehaviorRelay(value: false) /// MARK: 특정 날짜에 대한 리스트에 데이터 넣기 - func inputData(events: [ScheduleEvent]){ + func inputData(events: [ScheduleList]){ specificEventList.accept(events) } diff --git a/RF/ViewModels/Meeting/Schedule/ScheduleViewModel.swift b/RF/ViewModels/Meeting/Schedule/ScheduleViewModel.swift index 3c8cbb9c..0af2da41 100644 --- a/RF/ViewModels/Meeting/Schedule/ScheduleViewModel.swift +++ b/RF/ViewModels/Meeting/Schedule/ScheduleViewModel.swift @@ -11,9 +11,10 @@ import RxRelay final class ScheduleViewModel { private let disposeBag = DisposeBag() + private let service = ScheduleService() /// 일정 리스트 - var eventList : BehaviorRelay<[ScheduleEvent]> = BehaviorRelay(value: []) + var eventList : BehaviorRelay<[ScheduleList]> = BehaviorRelay(value: []) /// MARK: Change Date -> String func formattingDate(date: Date) -> String{ @@ -34,25 +35,36 @@ final class ScheduleViewModel { } /// 테스트 데이터 넣어 놓은 함수 - func getData() { - var list: [ScheduleEvent] = [] + func getData(year: String, month: String) { + let year = Int(year) + let month = Int(month) - list.append(ScheduleEvent(date: "2023-08-23", description: "데모 데이",color: "00f44d")) - list.append(ScheduleEvent(date: "2023-08-24", description: "데모 데이",color: "00f44d")) - list.append(ScheduleEvent(date: "2023-08-15", description: "광복절",color: "FE4700")) - list.append(ScheduleEvent(date: "2023-08-11", description: "알프 모임",color: "00daf7")) - list.append(ScheduleEvent(date: "2023-07-25", description: "마라탕 먹방",color: "f1f900")) - list.append(ScheduleEvent(date: "2023-09-01", description: "개강 파티",color: "1dfc00")) + guard let year = year, let month = month else { return } + service.getMySchdule(year: year, month: month) + .subscribe(onNext: { [weak self] list in + guard let self = self else {return} + eventList.accept(list) + }) + .disposed(by: disposeBag) - self.eventList.accept(list) +// var list: [ScheduleList] = [] + +// list.append(ScheduleEvent(date: "2023-08-23", description: "데모 데이",color: "00f44d")) +// list.append(ScheduleEvent(date: "2023-08-24", description: "데모 데이",color: "00f44d")) +// list.append(ScheduleEvent(date: "2023-08-15", description: "광복절",color: "FE4700")) +// list.append(ScheduleEvent(date: "2023-08-11", description: "알프 모임",color: "00daf7")) +// list.append(ScheduleEvent(date: "2023-07-25", description: "마라탕 먹방",color: "f1f900")) +// list.append(ScheduleEvent(date: "2023-09-01", description: "개강 파티",color: "1dfc00")) + +// self.eventList.accept(list) } /// MARK: 날짜 변환 후 일정 리스트에 해당 날짜가 있는지 필터링 - func dateFiltering(date: Date) -> Observable<[ScheduleEvent]?>{ + func dateFiltering(date: Date) -> Observable<[ScheduleList]?>{ let list = eventList.value let date = String(formattingDate(date: date).split(separator: " ")[0]) - let event = list.filter({ date == $0.date ?? "" }) + let event = list.filter({ date == $0.localDateTime ?? "" }) return Observable.create { observer in if event.isEmpty{ diff --git a/RF/ViewModels/SignUp/ChooseUserInfo/ChoiceMajorViewModel.swift b/RF/ViewModels/SignUp/ChooseUserInfo/ChoiceMajorViewModel.swift new file mode 100644 index 00000000..20171c12 --- /dev/null +++ b/RF/ViewModels/SignUp/ChooseUserInfo/ChoiceMajorViewModel.swift @@ -0,0 +1,53 @@ +// +// ChoiceCountryViewModel.swift +// RF +// +// Created by 정호진 on 2023/08/01. +// + +import Foundation +import RxSwift +import RxRelay + +/// 학과 +final class ChoiceMajorViewModel{ + private let disposeBag = DisposeBag() + + /// MARK: 국가 리스트 + var majorRelay: BehaviorRelay<[KVO]> = BehaviorRelay(value: []) + + /// MARK: 필터링된 국가 + var filteringCountryRelay: BehaviorRelay<[KVO]> = BehaviorRelay(value: []) + + /// MARK: 선택된 나라 + var selectedCountry: BehaviorRelay = BehaviorRelay(value: KVO()) + + /// MARK: Check Filtering + var isFiltering: BehaviorRelay = BehaviorRelay(value: false) + + /// dummy data + func inputCountry(){ + var list: [KVO] = [] + + EnumFile.enumfile.enumList + .bind { enums in + list = enums.major ?? [] + } + .disposed(by: disposeBag) + + majorRelay.accept(list) + } + + /// MARK: 필터링 후 반환 + func filteringCountry(text: String) { + if text == ""{ + filteringCountryRelay.accept(majorRelay.value) + } + else{ + let list = majorRelay.value.filter { $0.value?.localizedCaseInsensitiveContains(text) ?? false } + filteringCountryRelay.accept(list) + } + } + +} + diff --git a/RF/ViewModels/SignUp/SignUpDataViewModel.swift b/RF/ViewModels/SignUp/SignUpDataViewModel.swift index 1a6c8e49..0aa3b726 100644 --- a/RF/ViewModels/SignUp/SignUpDataViewModel.swift +++ b/RF/ViewModels/SignUp/SignUpDataViewModel.swift @@ -46,6 +46,9 @@ final class SignUpDataViewModel { /// MARK: 선택한 관심 언어 var interestingLanguage: BehaviorRelay> = BehaviorRelay>(value: []) + /// MARK: 선택한 학과 + var major: BehaviorRelay = BehaviorRelay(value: "") + /// 선택한 라이프 스타일 var lifeStyleRelay: BehaviorRelay = BehaviorRelay(value: "") diff --git a/RF/ViewModels/SignUp/UserInfoViewModel.swift b/RF/ViewModels/SignUp/UserInfoViewModel.swift index 4e0356bd..77708d3d 100644 --- a/RF/ViewModels/SignUp/UserInfoViewModel.swift +++ b/RF/ViewModels/SignUp/UserInfoViewModel.swift @@ -20,6 +20,9 @@ final class UserInfoViewModel { /// MARK: 선택한 관심 언어 var interestingLanguage: BehaviorRelay> = BehaviorRelay>(value: []) + /// MARK: 선택한 학과 + var major: BehaviorRelay = BehaviorRelay(value: "") + private let disposeBag = DisposeBag() // MARK: - Logic @@ -30,6 +33,7 @@ final class UserInfoViewModel { let checkBorn = bornCountry.map { $0 != "" ? true : false } let checkCountry = interestingCountry.map { $0 != [] ? true : false } let checkLanguage = interestingLanguage.map { $0 != [] ? true : false } + let checkMajor = major.map { $0 != "" ? true : false } return Observable.create { [weak self] observer in @@ -37,8 +41,9 @@ final class UserInfoViewModel { Observable.combineLatest(checkBorn, checkCountry, checkLanguage, - resultSelector: { born, country, language in - born && country && language + checkMajor, + resultSelector: { born, country, language, major in + born && country && language && major }) .subscribe(onNext: { check in observer.onNext(check) diff --git a/RF/Views/Common/TabBarController.swift b/RF/Views/Common/TabBarController.swift index 960be3eb..54e5ba96 100644 --- a/RF/Views/Common/TabBarController.swift +++ b/RF/Views/Common/TabBarController.swift @@ -84,7 +84,7 @@ final class TabBarController: UITabBarController { /// MARK: ViewModel에서 데이터 얻는 함수 private func getData(){ - viewModel.getData() +// viewModel.getData() } } diff --git a/RF/Views/Meeting/Creating/SetDetailInfoViewController.swift b/RF/Views/Meeting/Creating/SetDetailInfoViewController.swift index 97962055..7bf001db 100644 --- a/RF/Views/Meeting/Creating/SetDetailInfoViewController.swift +++ b/RF/Views/Meeting/Creating/SetDetailInfoViewController.swift @@ -161,25 +161,25 @@ final class SetDetailInfoViewController: UIViewController { return button }() - // 활동 장소 - private lazy var placeLabel: UILabel = { - let label = UILabel() - label.text = "활동 장소" - label.font = UIFont.systemFont(ofSize: 15, weight: .medium) - label.textColor = TextColor.first.color - return label - }() - - private lazy var placeTextField: UITextField = { - let tf = UITextField() - tf.backgroundColor = ButtonColor.normal.color - tf.layer.cornerRadius = 5 - tf.placeholder = "장소를 입력해 주세요." - tf.font = UIFont.systemFont(ofSize: 15, weight: .medium) - tf.textAlignment = .right - tf.addHorizontalPadding(10) - return tf - }() +// // 활동 장소 +// private lazy var placeLabel: UILabel = { +// let label = UILabel() +// label.text = "활동 장소" +// label.font = UIFont.systemFont(ofSize: 15, weight: .medium) +// label.textColor = TextColor.first.color +// return label +// }() +// +// private lazy var placeTextField: UITextField = { +// let tf = UITextField() +// tf.backgroundColor = ButtonColor.normal.color +// tf.layer.cornerRadius = 5 +// tf.placeholder = "장소를 입력해 주세요." +// tf.font = UIFont.systemFont(ofSize: 15, weight: .medium) +// tf.textAlignment = .right +// tf.addHorizontalPadding(10) +// return tf +// }() // 두 번째 경계선 private lazy var secondDivLine: UIView = { @@ -289,9 +289,9 @@ final class SetDetailInfoViewController: UIViewController { containerView.addSubview(languageLabel) containerView.addSubview(languageButton) - // 활동 장소 - containerView.addSubview(placeLabel) - containerView.addSubview(placeTextField) +// // 활동 장소 +// containerView.addSubview(placeLabel) +// containerView.addSubview(placeTextField) // 두 번째 경계선 containerView.addSubview(secondDivLine) @@ -392,23 +392,23 @@ final class SetDetailInfoViewController: UIViewController { make.width.equalTo(130) } - // 활동 장소 - placeLabel.snp.makeConstraints { make in - make.top.equalTo(languageLabel.snp.bottom).offset(30) - make.height.equalTo(30) - make.leading.equalToSuperview().inset(30) - } - - placeTextField.snp.makeConstraints { make in - make.centerY.equalTo(placeLabel) - make.trailing.equalToSuperview().inset(30) - make.width.equalTo(200) - make.height.equalTo(placeLabel.snp.height).multipliedBy(1.2) - } +// // 활동 장소 +// placeLabel.snp.makeConstraints { make in +// make.top.equalTo(languageLabel.snp.bottom).offset(30) +// make.height.equalTo(30) +// make.leading.equalToSuperview().inset(30) +// } +// +// placeTextField.snp.makeConstraints { make in +// make.centerY.equalTo(placeLabel) +// make.trailing.equalToSuperview().inset(30) +// make.width.equalTo(200) +// make.height.equalTo(placeLabel.snp.height).multipliedBy(1.2) +// } // 두 번째 경계선 secondDivLine.snp.makeConstraints { make in - make.top.equalTo(placeLabel.snp.bottom).offset(30) + make.top.equalTo(languageLabel.snp.bottom).offset(30) make.horizontalEdges.equalToSuperview() make.height.equalTo(1) } @@ -456,13 +456,13 @@ final class SetDetailInfoViewController: UIViewController { }) .disposed(by: disposeBag) - placeTextField.rx.text - .bind { [weak self] text in - if let text = text{ - self?.viewModel.place.accept(text) - } - } - .disposed(by: disposeBag) +// placeTextField.rx.text +// .bind { [weak self] text in +// if let text = text{ +// self?.viewModel.place.accept(text) +// } +// } +// .disposed(by: disposeBag) viewModel.checkAllDatas() .subscribe(onNext:{ [weak self] check in diff --git a/RF/Views/Meeting/Schedule/ScheduleFSCalendarCell.swift b/RF/Views/Meeting/Schedule/ScheduleFSCalendarCell.swift index d4332e91..89e869a6 100644 --- a/RF/Views/Meeting/Schedule/ScheduleFSCalendarCell.swift +++ b/RF/Views/Meeting/Schedule/ScheduleFSCalendarCell.swift @@ -54,7 +54,7 @@ final class ScheduleFSCalendarCell: FSCalendarCell { } /// MARK: 일정을 넣는 함수 - func inputData(events: [ScheduleEvent]?){ + func inputData(events: [ScheduleList]?){ viewModel.isTableView .observe(on: MainScheduler.asyncInstance) .bind { [weak self] check in @@ -78,18 +78,19 @@ extension ScheduleFSCalendarCell: UITableViewDelegate, UITableViewDataSource{ guard let cell = tableView.dequeueReusableCell(withIdentifier: ScheduleTableViewCell.identifier, for: indexPath) as? ScheduleTableViewCell else { return UITableViewCell() } viewModel.specificEventList - .bind { events in + .bind(onNext: { events in if !events.isEmpty && indexPath.row < events.count{ - cell.inputData(text: events[indexPath.row].description ?? "", - backgroundColor: UIColor(hexCode: events[indexPath.row].color ?? "", alpha: 1)) + cell.inputData(text: events[indexPath.row].scheduleName ?? "", + backgroundColor: UIColor(hexCode: "000000", alpha: 1)) } else{ cell.inputData(text: "", backgroundColor: .clear) } cell.selectionStyle = .none - } + }) .disposed(by: disposeBag) + return cell } diff --git a/RF/Views/Meeting/Schedule/ScheduleViewController.swift b/RF/Views/Meeting/Schedule/ScheduleViewController.swift index 665c5ff3..aaa4bae6 100644 --- a/RF/Views/Meeting/Schedule/ScheduleViewController.swift +++ b/RF/Views/Meeting/Schedule/ScheduleViewController.swift @@ -119,7 +119,9 @@ final class ScheduleViewController: UIViewController{ /// MARK: ViewModel에서 데이터 얻는 함수 private func getData(){ - viewModel.getData() + let date = viewModel.formattingDate_HeaderView(date: calendarView.currentPage) + print(date) + viewModel.getData(year: String(date.split(separator: "-")[0]), month: String(date.split(separator: "-")[1])) } @@ -145,8 +147,6 @@ extension ScheduleViewController: FSCalendarDelegate, FSCalendarDataSource, FSCa guard let cell = calendar.cell(for: date, at: monthPosition) else { return } cell.titleLabel.textColor = .black - print(viewModel.formattingDate(date: date).split(separator: " ").first) - let schedulePopUpViewController = SchedulePopUpViewController() schedulePopUpViewController.selectedDate.onNext(String(describing: viewModel.formattingDate(date: date).split(separator: " ").first)) present(schedulePopUpViewController,animated: true) @@ -155,6 +155,7 @@ extension ScheduleViewController: FSCalendarDelegate, FSCalendarDataSource, FSCa func calendar(_ calendar: FSCalendar, cellFor date: Date, at position: FSCalendarMonthPosition) -> FSCalendarCell { guard let cell = calendar.dequeueReusableCell(withIdentifier: ScheduleFSCalendarCell.identifier, for: date, at: position) as? ScheduleFSCalendarCell else { return FSCalendarCell()} + cell.backgroundColor = .clear headerButton.setTitle("\(viewModel.formattingDate_HeaderView(date: calendarView.currentPage)) ", for: .normal) viewModel.dateFiltering(date: date) @@ -168,7 +169,10 @@ extension ScheduleViewController: FSCalendarDelegate, FSCalendarDataSource, FSCa func calendarCurrentPageDidChange(_ calendar: FSCalendar) { - viewModel.getData() + let date = viewModel.formattingDate_HeaderView(date: calendarView.currentPage) + print(date) + viewModel.getData(year: String(date.split(separator: "-")[0]), month: String(date.split(separator: "-")[1])) + calendar.reloadData() } } diff --git a/RF/Views/MyPage/MyPageMeetingDateViewController.swift b/RF/Views/MyPage/MyPageMeetingDateViewController.swift index 481193f7..5d7d79bd 100644 --- a/RF/Views/MyPage/MyPageMeetingDateViewController.swift +++ b/RF/Views/MyPage/MyPageMeetingDateViewController.swift @@ -216,7 +216,8 @@ class MyPageMeetingDateViewController: UIViewController { /// MARK: ViewModel에서 데이터 얻는 함수 private func getData(){ - viewModel.getData() + let date = viewModel.formattingDate_HeaderView(date: calendarView.currentPage) + viewModel.getData(year: String(date.split(separator: "-")[0]), month: String(date.split(separator: "-")[1])) } @@ -285,7 +286,8 @@ extension MyPageMeetingDateViewController: FSCalendarDelegate, FSCalendarDataSou } func calendarCurrentPageDidChange(_ calendar: FSCalendar) { - viewModel.getData()//ViewModel에서 데이터 얻는 함수 + let date = viewModel.formattingDate_HeaderView(date: calendarView.currentPage) + viewModel.getData(year: String(date.split(separator: "-")[0]), month: String(date.split(separator: "-")[1])) //CustomHeader의 날짜 label을 바꾸는 과정 self.calHeaderLabel.text = self.dateFormatter.string(from: calendar.currentPage) diff --git a/RF/Views/MyPage/MyPageViewController.swift b/RF/Views/MyPage/MyPageViewController.swift index bfbd222d..e09afb01 100644 --- a/RF/Views/MyPage/MyPageViewController.swift +++ b/RF/Views/MyPage/MyPageViewController.swift @@ -428,7 +428,7 @@ class MyPageViewController: UIViewController { } /// MARK: ViewModel에서 데이터 얻는 함수 private func getData(){ - viewModel.getData() +// viewModel.getData() if let img = URL(string: SignUpDataViewModel.viewModel.profileImageUrlRelay.value) { profileImageView.load(url: img) diff --git a/RF/Views/SignUp/ChooseUserInfo/ChoiceMajorView.swift b/RF/Views/SignUp/ChooseUserInfo/ChoiceMajorView.swift new file mode 100644 index 00000000..7b8070fb --- /dev/null +++ b/RF/Views/SignUp/ChooseUserInfo/ChoiceMajorView.swift @@ -0,0 +1,191 @@ +// +// ChoiceCountryTableView.swift +// RF +// +// Created by 정호진 on 2023/08/01. +// + +import Foundation +import UIKit +import SnapKit +import RxSwift + +final class ChoiceMajorView: UIViewController{ + + /// MARK: 제목 + private lazy var titleLabel: UILabel = { + let label = UILabel() + label.text = UserInfo.major + label.textColor = .black + label.font = .systemFont(ofSize: 20, weight: .bold) + return label + }() + + /// MARK: 검색 바 + private lazy var searchBar: UISearchBar = { + let bar = UISearchBar() + bar.backgroundColor = .clear + bar.placeholder = UserInfo.majorPlaceHolder + bar.searchBarStyle = .minimal + bar.showsCancelButton = true + UIBarButtonItem.appearance(whenContainedInInstancesOf: [UISearchBar.self]).title = "취소 " + return bar + }() + + /// MARK: 위쪽 백그라운드 + private lazy var topBackgroundView: UIView = { + let view = UIView() + view.backgroundColor = .systemGray6 + return view + }() + + /// MARK: 학과 선택하는 tableView + private lazy var tableView: UITableView = { + let table = UITableView() + table.backgroundColor = .clear + return table + }() + + private let viewModel = ChoiceMajorViewModel() + private let disposeBag = DisposeBag() + var selctedMajor: PublishSubject = PublishSubject() + + // MARK: view did load + override func viewDidLoad() { + super.viewDidLoad() + view.backgroundColor = .white + + addSubviews() + viewModel.inputCountry() + } + + override func touchesBegan(_ touches: Set, with event: UIEvent?) { + searchBar.resignFirstResponder() + } + + // MARK: - Functions + + private func addSubviews() { + view.addSubview(topBackgroundView) + + topBackgroundView.addSubview(titleLabel) + topBackgroundView.addSubview(searchBar) + searchBar.delegate = self + + view.addSubview(tableView) + + tableView.dataSource = self + tableView.delegate = self + tableView.register(ChooseUserTableViewCell.self, forCellReuseIdentifier: ChooseUserTableViewCell.identifer) + + configureConstraints() + } + + /// MARK: Set AutoLayout + private func configureConstraints() { + titleLabel.snp.makeConstraints { make in + make.top.equalTo(view.safeAreaLayoutGuide).offset(10) + make.centerX.equalToSuperview() + } + + searchBar.snp.makeConstraints { make in + make.top.equalTo(titleLabel.snp.bottom).offset(10) + make.leading.equalToSuperview() + make.trailing.equalToSuperview() + make.bottom.equalToSuperview() + } + + topBackgroundView.snp.makeConstraints { make in + make.top.equalToSuperview() + make.leading.trailing.equalToSuperview() + make.height.equalTo(view.safeAreaLayoutGuide.layoutFrame.height/8) + } + + tableView.snp.makeConstraints { make in + make.top.equalTo(searchBar.snp.bottom).offset(10) + make.leading.trailing.bottom.equalTo(view.safeAreaLayoutGuide) + } + } + +} + +extension ChoiceMajorView: UISearchBarDelegate{ + + /// 서치바 변화가 감지 되었을 때 + func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { + guard let text = searchBar.text?.lowercased() else { return } + + viewModel.isFiltering.accept(true) + viewModel.filteringCountry(text: text) + + tableView.reloadData() + } + + /// 서치바에서 검색버튼을 눌렀을 때 호출 + func searchBarSearchButtonClicked(_ searchBar: UISearchBar) { + searchBar.resignFirstResponder() + guard let text = searchBar.text?.lowercased() else { return } + + viewModel.filteringCountry(text: text) + viewModel.isFiltering.accept(false) + + tableView.reloadData() + } + + /// 서치바에서 취소 버튼을 눌렀을 때 호출 + func searchBarCancelButtonClicked(_ searchBar: UISearchBar) { + searchBar.text = "" + searchBar.resignFirstResponder() + + viewModel.isFiltering.accept(false) + viewModel.inputCountry() + + tableView.reloadData() + } + + /// 서치바 검색이 끝났을 때 호출 + func searchBarTextDidEndEditing(_ searchBar: UISearchBar) { + viewModel.isFiltering.accept(false) + viewModel.inputCountry() + + tableView.reloadData() + } + + func scrollViewDidScroll(_ scrollView: UIScrollView) { + searchBar.resignFirstResponder() + } +} + +extension ChoiceMajorView: UITableViewDelegate, UITableViewDataSource{ + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + guard let cell = tableView.dequeueReusableCell(withIdentifier: ChooseUserTableViewCell.identifer, for: indexPath) as? ChooseUserTableViewCell else { return UITableViewCell() } + + if viewModel.isFiltering.value{ + cell.inputValue(text: viewModel.filteringCountryRelay.value[indexPath.row].value ?? "") + } + else{ + cell.inputValue(text: viewModel.majorRelay.value[indexPath.row].value ?? "") + } + + return cell + } + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return viewModel.isFiltering.value ? viewModel.filteringCountryRelay.value.count : viewModel.majorRelay.value.count + } + + func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + return view.safeAreaLayoutGuide.layoutFrame.height/20 + } + + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + tableView.deselectRow(at: indexPath, animated: true) + + viewModel.isFiltering.value ? viewModel.selectedCountry.accept(viewModel.filteringCountryRelay.value[indexPath.row]) : viewModel.selectedCountry.accept(viewModel.majorRelay.value[indexPath.row]) + + selctedMajor.onNext(viewModel.selectedCountry.value) + dismiss(animated: true) + } + +} diff --git a/RF/Views/SignUp/UserInfoViewController.swift b/RF/Views/SignUp/UserInfoViewController.swift index 848857b9..0fd3cb15 100644 --- a/RF/Views/SignUp/UserInfoViewController.swift +++ b/RF/Views/SignUp/UserInfoViewController.swift @@ -95,6 +95,28 @@ final class UserInfoViewController: UIViewController { return button }() + /// MARK: 소속 학과 제목 + private lazy var majorLabel: UILabel = { + let label = UILabel() + label.text = "소속 학과" + label.font = UIFont.systemFont(ofSize: 16, weight: .regular) + label.numberOfLines = 1 + label.textColor = TextColor.first.color + return label + }() + + /// MARK: 소속 학과 선택하는 버튼 + private lazy var majorButton: UIButton = { + let button = UIButton() + button.setTitle(" 소속된 단과대를 선택해주세요", for: .normal) + button.setTitleColor(TextColor.secondary.color, for: .normal) + button.titleLabel?.font = UIFont.systemFont(ofSize: 14, weight: .regular) + button.backgroundColor = BackgroundColor.white.color + button.layer.cornerRadius = 5 + button.contentHorizontalAlignment = .left + return button + }() + /// MARK: Next Button private lazy var nextButton: UIButton = { let button = UIButton() @@ -133,6 +155,8 @@ final class UserInfoViewController: UIViewController { view.addSubview(nationButton) view.addSubview(favNationButton) view.addSubview(favLanguageButton) + view.addSubview(majorLabel) + view.addSubview(majorButton) configureConstraints() } @@ -183,6 +207,20 @@ final class UserInfoViewController: UIViewController { make.height.equalTo(47) } + // 소속 학과 + majorLabel.snp.makeConstraints { make in + make.top.equalTo(favLanguageButton.snp.bottom).offset(20) + make.leading.trailing.equalToSuperview().inset(20) + } + + // 소속 학과 설정 메뉴 버튼 + majorButton.snp.makeConstraints { make in + make.top.equalTo(majorLabel.snp.bottom).offset(20) + make.leading.trailing.equalToSuperview().inset(20) + make.height.equalTo(47) + } + + //다음 nextButton.snp.makeConstraints { make in make.leading.right.equalToSuperview().inset(30) @@ -238,6 +276,22 @@ final class UserInfoViewController: UIViewController { } .disposed(by: disposeBag) + majorButton.rx.tap + .bind { [weak self] in + guard let self = self else {return} + let choiceMajorView = ChoiceMajorView() + choiceMajorView.modalPresentationStyle = .formSheet + choiceMajorView.selctedMajor + .bind { [weak self] major in + guard let self = self else {return} + viewModel.major.accept(major.key ?? "") + majorButton.setTitle(" \(major.value ?? "")", for: .normal) + } + .disposed(by: disposeBag) + present(choiceMajorView, animated: true) + } + .disposed(by: disposeBag) + nextButton.rx.tap .bind { [weak self] in self?.selectedAll() @@ -258,6 +312,7 @@ final class UserInfoViewController: UIViewController { SignUpDataViewModel.viewModel.bornCountry.accept(self?.viewModel.bornCountry.value ?? "") SignUpDataViewModel.viewModel.interestingCountry.accept(self?.viewModel.interestingCountry.value ?? []) SignUpDataViewModel.viewModel.interestingLanguage.accept(self?.viewModel.interestingLanguage.value ?? []) + SignUpDataViewModel.viewModel.major.accept(self?.viewModel.major.value ?? "") } }) .disposed(by: disposeBag)