Skip to content

Commit

Permalink
refactoring LetterBoxViewModel
Browse files Browse the repository at this point in the history
  • Loading branch information
Hyunsik-Yoo committed Jul 25, 2020
1 parent 53030f0 commit e57006f
Show file tree
Hide file tree
Showing 10 changed files with 210 additions and 164 deletions.
22 changes: 21 additions & 1 deletion thereto-ios/thereto-ios.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
6E644FB82400E961002292FC /* LetterSearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E644FB72400E961002292FC /* LetterSearchView.swift */; };
6E644FBA2400ED37002292FC /* LetterSearchVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E644FB92400ED37002292FC /* LetterSearchVC.swift */; };
6E6587E624663EE8001D9C8E /* HTTPUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E6587E524663EE8001D9C8E /* HTTPUtils.swift */; };
6E6CEE1E24CC1ABD00489532 /* LetterBoxViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E6CEE1D24CC1ABD00489532 /* LetterBoxViewModel.swift */; };
6E6F0E8F2439CBFD00FD3F08 /* BaseViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E6F0E8E2439CBFD00FD3F08 /* BaseViewModel.swift */; };
6E6F0E912439D1D300FD3F08 /* FacebookManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E6F0E902439D1D300FD3F08 /* FacebookManager.swift */; };
6E6F0E932439D95900FD3F08 /* CommonResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E6F0E922439D95900FD3F08 /* CommonResponse.swift */; };
Expand Down Expand Up @@ -199,6 +200,7 @@
6E644FB72400E961002292FC /* LetterSearchView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LetterSearchView.swift; sourceTree = "<group>"; };
6E644FB92400ED37002292FC /* LetterSearchVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LetterSearchVC.swift; sourceTree = "<group>"; };
6E6587E524663EE8001D9C8E /* HTTPUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HTTPUtils.swift; sourceTree = "<group>"; };
6E6CEE1D24CC1ABD00489532 /* LetterBoxViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LetterBoxViewModel.swift; sourceTree = "<group>"; };
6E6F0E8E2439CBFD00FD3F08 /* BaseViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseViewModel.swift; sourceTree = "<group>"; };
6E6F0E902439D1D300FD3F08 /* FacebookManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FacebookManager.swift; sourceTree = "<group>"; };
6E6F0E922439D95900FD3F08 /* CommonResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommonResponse.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -478,6 +480,22 @@
path = "letter-search";
sourceTree = "<group>";
};
6E6CEE1B24CC1A4600489532 /* splash */ = {
isa = PBXGroup;
children = (
6EB13D5E24B1ADE600923402 /* SplashTests.swift */,
);
path = splash;
sourceTree = "<group>";
};
6E6CEE1C24CC1A9400489532 /* letterbox */ = {
isa = PBXGroup;
children = (
6E6CEE1D24CC1ABD00489532 /* LetterBoxViewModel.swift */,
);
path = letterbox;
sourceTree = "<group>";
};
6E804B3623ADEEA4009574CD /* add-friend */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -526,6 +544,8 @@
6EB13D5D24B1ADE600923402 /* theretoTests */ = {
isa = PBXGroup;
children = (
6E6CEE1C24CC1A9400489532 /* letterbox */,
6E6CEE1B24CC1A4600489532 /* splash */,
6EF1130224C3EAE900F7B8D2 /* membership */,
6EDAF17724B6061C00BFA770 /* mock-service */,
6EB13D6024B1ADE600923402 /* Info.plist */,
Expand Down Expand Up @@ -672,7 +692,6 @@
isa = PBXGroup;
children = (
6EAB3A8424C1F00800D1AF50 /* SignInTests.swift */,
6EB13D5E24B1ADE600923402 /* SplashTests.swift */,
6EF1130324C3EB4900F7B8D2 /* ProfileTests.swift */,
);
path = membership;
Expand Down Expand Up @@ -909,6 +928,7 @@
6EAB3A8524C1F00800D1AF50 /* SignInTests.swift in Sources */,
6EF1130424C3EB4900F7B8D2 /* ProfileTests.swift in Sources */,
6EDAF17924B6066200BFA770 /* UserMockService.swift in Sources */,
6E6CEE1E24CC1ABD00489532 /* LetterBoxViewModel.swift in Sources */,
6EB13D5F24B1ADE600923402 /* SplashTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
44 changes: 21 additions & 23 deletions thereto-ios/thereto-ios/features/friends/FriendListViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,35 +29,33 @@ class FriendListViewModel: BaseViewModel {
}

func fetchFriends() {
self.showLoadingPublisher.onNext(true)
userService.getUserInfo(token: userDefaults.getUserToken()!) { [weak self] (userObservable) in
showLoadingPublisher.onNext(true)
userService.getUserInfo(token: userDefaults.getUserToken()!).subscribe(onNext: { [weak self] (user) in
guard let self = self else { return }
userObservable.subscribe(onNext: { (user) in
self.userService.getFriends(id: self.userDefaults.getUserToken()!) { (friendsObservable) in
friendsObservable.subscribe(onNext: { (friends) in
let filterFriends = friends.filter { $0.requestState == .FRIEND }.sorted { (friend1, friend2) -> Bool in
friend1.favorite && !friend2.favorite
}
self.friendsPublisher.onNext((user, filterFriends))
self.showLoadingPublisher.onNext(false)
}, onError: { (error) in
if let error = error as? CommonError {
self.showAlertPublisher.onNext(("친구 조회 오류", error.description))
} else {
self.showAlertPublisher.onNext(("친구 조회 오류", error.localizedDescription))
}
self.showLoadingPublisher.onNext(false)
}).disposed(by: self.disposeBag)
}
}, onError: { (error) in
self.userService.getFriends(id: self.userDefaults.getUserToken()!) { (friendsObservable) in
friendsObservable.subscribe(onNext: { (friends) in
let filterFriends = friends.filter { $0.requestState == .FRIEND }.sorted { (friend1, friend2) -> Bool in
friend1.favorite && !friend2.favorite
}
self.friendsPublisher.onNext((user, filterFriends))
self.showLoadingPublisher.onNext(false)
}, onError: { (error) in
if let error = error as? CommonError {
self.showAlertPublisher.onNext(("친구 조회 오류", error.description))
} else {
self.showAlertPublisher.onNext(("친구 조회 오류", error.localizedDescription))
}
self.showLoadingPublisher.onNext(false)
}).disposed(by: self.disposeBag)
}
}, onError: { [weak self] (error) in
guard let self = self else { return }
if let error = error as? CommonError {
self.showAlertPublisher.onNext(("내 정보 조회 오류", error.description))
} else {
self.showAlertPublisher.onNext(("내 정보 조회 오류", error.localizedDescription))
}
self.showLoadingPublisher.onNext(false)
}).disposed(by: self.disposeBag)
}

}).disposed(by: disposeBag)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -138,24 +138,23 @@ class AddFriendViewModel: BaseViewModel {
}

func fetchMyInfo() {
self.showLoadingPublisher.onNext(true)
userService.getUserInfo(token: userDefaults.getUserToken()!) { [weak self] (userObservable) in
showLoadingPublisher.onNext(true)
userService.getUserInfo(token: userDefaults.getUserToken()!).subscribe(onNext: { [weak self] (user) in
guard let self = self else { return }
userObservable.subscribe(onNext: { (user) in
var my2Friend = Friend(user: user)
my2Friend.receivedCount = 0
my2Friend.sentCount = 0
my2Friend.requestState = .WAIT
self.myInfoPublisher.onNext(my2Friend)
self.showLoadingPublisher.onNext(false)
}, onError: { (error) in
var my2Friend = Friend(user: user)
my2Friend.receivedCount = 0
my2Friend.sentCount = 0
my2Friend.requestState = .WAIT
self.myInfoPublisher.onNext(my2Friend)
self.showLoadingPublisher.onNext(false)
}, onError: { [weak self ] (error) in
guard let self = self else { return }
if let error = error as? CommonError {
self.showAlertPublisher.onNext(("내정보 조회 오류", error.description))
} else {
self.showAlertPublisher.onNext(("내정보 조회 오류", error.localizedDescription))
}
self.showLoadingPublisher.onNext(false)
}).disposed(by: self.disposeBag)
}
}).disposed(by: disposeBag)
}
}
6 changes: 3 additions & 3 deletions thereto-ios/thereto-ios/features/letterbox/LetterBoxVC.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import CoreLocation
class LetterBoxVC: BaseVC {

private lazy var letterBoxView = LetterBoxView(frame: self.view.frame)
private var viewModel = LetterBoxViewModel(userDefaults: UserDefaultsUtil(),
private let viewModel = LetterBoxViewModel(userDefaults: UserDefaultsUtil(),
letterService: LetterSerivce(),
userService: UserService())

Expand All @@ -26,12 +26,12 @@ class LetterBoxVC: BaseVC {
setupNavigation()
letterBoxView.topBar.setLetterBoxMode()
setupTableView()
viewModel.input.setupLocationManager.onNext(())
viewModel.setupLocationManager()
}

override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
viewModel.input.getLetters.onNext(())
viewModel.fetchLetters()
}

override func bindViewModel() {
Expand Down
163 changes: 72 additions & 91 deletions thereto-ios/thereto-ios/features/letterbox/LetterBoxViewModel.swift
Original file line number Diff line number Diff line change
@@ -1,43 +1,36 @@
import RxSwift
import RxCocoa
import CoreLocation

class LetterBoxViewModel: BaseViewModel {
var input: Input
var output: Output
let input = Input()
let output = Output()

var userDefaults: UserDefaultsUtil
var letterService: LetterServiceProtocol
var userService: UserServiceProtocol

struct Input {
var getLetters: AnyObserver<Void>
var setupLocationManager: AnyObserver<Void>
var myLocation: AnyObserver<CLLocation>
var selectItem: AnyObserver<Int>
var selectItem = PublishSubject<Int>()
}

struct Output {
var letters: Observable<[Letter]>
var showAlerts: Observable<(String, String)>
var showLoading: Observable<Bool>
var showLocationError: Observable<Void>
var goToLetterDetail: Observable<Letter>
var showFarAway: Observable<(Letter, CLLocation)>
var letters = PublishRelay<[Letter]>()
var showAlerts = PublishRelay<(String, String)>()
var showLoading = PublishRelay<Bool>()
var showLocationError = PublishRelay<Void>()
var goToLetterDetail = PublishRelay<Letter>()
var showFarAway = PublishRelay<(Letter, CLLocation)>()
}

let getLettersPublisher = PublishSubject<Void>()
let setupLocationManagerPublisher = PublishSubject<Void>()
let myLocationPublisher = PublishSubject<CLLocation>()
let selectItemPublisher = PublishSubject<Int>()

let lettersPublisher = PublishSubject<[Letter]>()
let showAlertsPublisher = PublishSubject<(String, String)>()
let showLoadingPublisher = PublishSubject<Bool>()
let showLocationErrorPublisher = PublishSubject<Void>()
let goToLetterDetailPublisher = PublishSubject<Letter>()
let showFarAwayPublisher = PublishSubject<(Letter, CLLocation)>()

// 위치 관련 변수
private var locationManager = CLLocationManager()
private let myLocationPublisher = PublishSubject<CLLocation>()


deinit {
locationManager.stopUpdatingLocation()
}

init(userDefaults: UserDefaultsUtil,
letterService: LetterServiceProtocol,
Expand All @@ -46,87 +39,75 @@ class LetterBoxViewModel: BaseViewModel {
self.letterService = letterService
self.userService = userService

input = Input(getLetters: getLettersPublisher.asObserver(),
setupLocationManager: setupLocationManagerPublisher.asObserver(),
myLocation: myLocationPublisher.asObserver(),
selectItem: selectItemPublisher.asObserver())
output = Output(letters: lettersPublisher,
showAlerts: showAlertsPublisher,
showLoading: showLoadingPublisher,
showLocationError: showLocationErrorPublisher,
goToLetterDetail: goToLetterDetailPublisher,
showFarAway: showFarAwayPublisher)
super.init()

setupLocationManagerPublisher.bind { [weak self] (_) in
guard let self = self else { return }
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
}.disposed(by: disposeBag)

getLettersPublisher.bind { [weak self] (_) in
guard let self = self else { return }
let token = self.userDefaults.getUserToken()!

self.showLoadingPublisher.onNext(true)
letterService.getLetters(receiverId: token) { (lettersObservable) in
lettersObservable.subscribe(onNext: { (letters) in
// 튜토리얼카드 삭제하지 않았을 경우에는 튜토리얼 카드 추가
if !userDefaults.isTutorialFinished() {
userService.getUserInfo(token: userDefaults.getUserToken()!) { [weak self] (userObservable) in
guard let self = self else { return }
userObservable.subscribe(onNext: { (user) in
var letters = letters
let tutorialLetter = self.createTutorialCard(user: user)
letters.append(tutorialLetter)
self.lettersPublisher.onNext(letters)
self.showLoadingPublisher.onNext(false)
}, onError: { (error) in
self.showAlertsPublisher.onNext(("내정보 조회 오류", error.localizedDescription))
self.showLoadingPublisher.onNext(false)
}).disposed(by: self.disposeBag)
}
} else {
self.lettersPublisher.onNext(letters)
self.showLoadingPublisher.onNext(false)
}
}, onError: { (error) in
self.showAlertsPublisher.onNext(("편지 조회 오류", error.localizedDescription))
self.showLoadingPublisher.onNext(false)
}).disposed(by: self.disposeBag)
}


}.disposed(by: disposeBag)

selectItemPublisher.withLatestFrom(Observable.combineLatest(selectItemPublisher, lettersPublisher, myLocationPublisher))
.bind(onNext: { [weak self] (index, letters, myLocation) in
input.selectItem.withLatestFrom(output.letters) { $1[$0] }
.withLatestFrom(myLocationPublisher) { ($0, $1) }
.bind { [weak self] (letter, myLocation) in
guard let self = self else { return }

// 위,경도 0,0 일경우는 권한문제이므로 에러 표시
if myLocation.coordinate.latitude == 0 && myLocation.coordinate.longitude == 0 {
self.showLocationErrorPublisher.onNext(())
self.output.showLocationError.accept(())
} else {
let letter = letters[index]

if letter.id == "tutorial" || letter.isRead {
self.goToLetterDetailPublisher.onNext(letter)
self.output.goToLetterDetail.accept(letter)
} else {
// 거리 계산해서 300 안에 있으면 들어가고 아니면 오류창 출력
if self.getDistance(location: letter.location, location2: myLocation) <= 300 {
self.goToLetterDetailPublisher.onNext(letter)
self.output.goToLetterDetail.accept(letter)
} else {
self.showFarAwayPublisher.onNext((letter, myLocation))
self.output.showFarAway.accept((letter, myLocation))
}
}
}
}).disposed(by: disposeBag)
}.disposed(by: disposeBag)
}

deinit {
locationManager.stopUpdatingLocation()
func setupLocationManager() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
}

func fetchLetters() {
let token = userDefaults.getUserToken()!

output.showLoading.accept(true)
letterService.fetchLetters(receiverId: token)
.subscribe(onNext: { [weak self] (letters) in
guard let self = self else { return }
// 튜토리얼 카드를 지우지 않았다면 맨 마지막에 튜토리얼 카드 붙여주기
if !self.userDefaults.isTutorialFinished() {
self.userService
.getUserInfo(token: token)
.subscribe(onNext: { (user) in
var letters = letters
let tutorialLetter = self.createTutorialCard(user: user)

letters.append(tutorialLetter)
self.output.letters.accept(letters)
self.output.showLoading.accept(false)
}, onError: { (error) in
if let error = error as? CommonError {
self.output.showAlerts.accept(("내정보 조회 오류", error.description))
} else {
self.output.showAlerts.accept(("내정보 조회 오류", error.localizedDescription))
}
self.output.showLoading.accept(false)
}).disposed(by: self.disposeBag)
} else {
self.output.letters.accept(letters)
self.output.showLoading.accept(false)
}}, onError: { [weak self] (error) in
guard let self = self else { return }
if let error = error as? CommonError {
self.output.showAlerts.accept(("편지 조회 오류", error.description))
} else {
self.output.showAlerts.accept(("편지 조회 오류", error.localizedDescription))
}
self.output.showLoading.accept(false)
}).disposed(by: disposeBag)
}


Expand Down Expand Up @@ -157,10 +138,10 @@ extension LetterBoxViewModel: CLLocationManagerDelegate {

func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
if (error as NSError).code == 1 {
self.showLocationErrorPublisher.onNext(())
self.output.showLocationError.accept(())
self.myLocationPublisher.onNext(CLLocation(latitude: 0, longitude: 0))
} else {
self.showAlertsPublisher.onNext(("LocationManager error", error.localizedDescription))
self.output.showAlerts.accept(("위치 에러", error.localizedDescription))
}
}
}
Expand Down
Loading

0 comments on commit e57006f

Please sign in to comment.