feat: implement emojis preloading logic

This commit is contained in:
CMK 2021-03-15 19:25:44 +08:00
parent 9f02197873
commit 1a60428f2a
6 changed files with 60 additions and 31 deletions

View File

@ -142,8 +142,8 @@
DB45FB0F25CA87D0005A8AC7 /* AuthenticationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB45FB0E25CA87D0005A8AC7 /* AuthenticationService.swift */; };
DB45FB1D25CA9D23005A8AC7 /* APIService+HomeTimeline.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB45FB1C25CA9D23005A8AC7 /* APIService+HomeTimeline.swift */; };
DB49A61425FF2C5600B98345 /* EmojiService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB49A61325FF2C5600B98345 /* EmojiService.swift */; };
DB49A61F25FF32AA00B98345 /* EmojiService+CustomEmoji.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB49A61E25FF32AA00B98345 /* EmojiService+CustomEmoji.swift */; };
DB49A62525FF334C00B98345 /* EmojiService+CustomEmoji+LoadState.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB49A62425FF334C00B98345 /* EmojiService+CustomEmoji+LoadState.swift */; };
DB49A61F25FF32AA00B98345 /* EmojiService+CustomEmojiViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB49A61E25FF32AA00B98345 /* EmojiService+CustomEmojiViewModel.swift */; };
DB49A62525FF334C00B98345 /* EmojiService+CustomEmojiViewModel+LoadState.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB49A62425FF334C00B98345 /* EmojiService+CustomEmojiViewModel+LoadState.swift */; };
DB49A62B25FF36C700B98345 /* APIService+CustomEmoji.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB49A62A25FF36C700B98345 /* APIService+CustomEmoji.swift */; };
DB5086A525CC0B7000C2C187 /* AvatarBarButtonItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB5086A425CC0B7000C2C187 /* AvatarBarButtonItem.swift */; };
DB5086AB25CC0BBB00C2C187 /* AvatarConfigurableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB5086AA25CC0BBB00C2C187 /* AvatarConfigurableView.swift */; };
@ -412,8 +412,8 @@
DB45FB0E25CA87D0005A8AC7 /* AuthenticationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationService.swift; sourceTree = "<group>"; };
DB45FB1C25CA9D23005A8AC7 /* APIService+HomeTimeline.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+HomeTimeline.swift"; sourceTree = "<group>"; };
DB49A61325FF2C5600B98345 /* EmojiService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiService.swift; sourceTree = "<group>"; };
DB49A61E25FF32AA00B98345 /* EmojiService+CustomEmoji.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "EmojiService+CustomEmoji.swift"; sourceTree = "<group>"; };
DB49A62425FF334C00B98345 /* EmojiService+CustomEmoji+LoadState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "EmojiService+CustomEmoji+LoadState.swift"; sourceTree = "<group>"; };
DB49A61E25FF32AA00B98345 /* EmojiService+CustomEmojiViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "EmojiService+CustomEmojiViewModel.swift"; sourceTree = "<group>"; };
DB49A62425FF334C00B98345 /* EmojiService+CustomEmojiViewModel+LoadState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "EmojiService+CustomEmojiViewModel+LoadState.swift"; sourceTree = "<group>"; };
DB49A62A25FF36C700B98345 /* APIService+CustomEmoji.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+CustomEmoji.swift"; sourceTree = "<group>"; };
DB5086A425CC0B7000C2C187 /* AvatarBarButtonItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AvatarBarButtonItem.swift; sourceTree = "<group>"; };
DB5086AA25CC0BBB00C2C187 /* AvatarConfigurableView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AvatarConfigurableView.swift; sourceTree = "<group>"; };
@ -995,8 +995,8 @@
isa = PBXGroup;
children = (
DB49A61325FF2C5600B98345 /* EmojiService.swift */,
DB49A61E25FF32AA00B98345 /* EmojiService+CustomEmoji.swift */,
DB49A62425FF334C00B98345 /* EmojiService+CustomEmoji+LoadState.swift */,
DB49A61E25FF32AA00B98345 /* EmojiService+CustomEmojiViewModel.swift */,
DB49A62425FF334C00B98345 /* EmojiService+CustomEmojiViewModel+LoadState.swift */,
);
path = EmojiService;
sourceTree = "<group>";
@ -1710,7 +1710,7 @@
2D82B9FF25E7863200E36F0F /* OnboardingViewControllerAppearance.swift in Sources */,
5DF1054725F8870E00D6C0D4 /* VideoPlayerViewModel.swift in Sources */,
2D38F1E525CD46C100561493 /* HomeTimelineViewModel.swift in Sources */,
DB49A61F25FF32AA00B98345 /* EmojiService+CustomEmoji.swift in Sources */,
DB49A61F25FF32AA00B98345 /* EmojiService+CustomEmojiViewModel.swift in Sources */,
2D76316B25C14D4C00929FB9 /* PublicTimelineViewModel.swift in Sources */,
2DA6055125F74407006356F9 /* AudioContainerViewModel.swift in Sources */,
0FB3D2FE25E4CB6400AAD544 /* PickServerTitleCell.swift in Sources */,
@ -1793,7 +1793,7 @@
DB0140AE25C40C7300F9F3CF /* MastodonPinBasedAuthenticationViewModel.swift in Sources */,
2D32EAAC25CB96DC00C9ED86 /* TimelineMiddleLoaderTableViewCell.swift in Sources */,
2D5A3D6225CFD9CB002347D6 /* HomeTimelineViewController+DebugAction.swift in Sources */,
DB49A62525FF334C00B98345 /* EmojiService+CustomEmoji+LoadState.swift in Sources */,
DB49A62525FF334C00B98345 /* EmojiService+CustomEmojiViewModel+LoadState.swift in Sources */,
DB9D6BFF25E4F5940051B173 /* ProfileViewController.swift in Sources */,
0FB3D30825E524C600AAD544 /* PickServerCategoriesCell.swift in Sources */,
DB789A1225F9F2CC0071ACA0 /* ComposeViewModel.swift in Sources */,

View File

@ -123,6 +123,18 @@ extension MainTabBarController {
}
}
.store(in: &disposeBag)
context.authenticationService.activeMastodonAuthenticationBox
.receive(on: DispatchQueue.main)
.sink { [weak self] activeMastodonAuthenticationBox in
guard let self = self else { return }
guard let activeMastodonAuthenticationBox = activeMastodonAuthenticationBox else { return }
let domain = activeMastodonAuthenticationBox.domain
// trigger dequeue to preload emojis
_ = self.context.emojiService.dequeueCustomEmojiViewModel(for: domain)
}
.store(in: &disposeBag)
#if DEBUG
// selectedIndex = 1

View File

@ -1,5 +1,5 @@
//
// APIService+CustomEmoji.swift
// APIService+CustomEmojiViewModel.swift
// Mastodon
//
// Created by MainasuK Cirno on 2021-3-15.

View File

@ -1,5 +1,5 @@
//
// EmojiService+CustomEmoji+LoadState.swift
// EmojiService+CustomEmojiViewModel+LoadState.swift
// Mastodon
//
// Created by MainasuK Cirno on 2021-3-15.
@ -9,11 +9,11 @@ import os.log
import Foundation
import GameplayKit
extension EmojiService.CustomEmoji {
extension EmojiService.CustomEmojiViewModel {
class LoadState: GKState {
weak var viewModel: EmojiService.CustomEmoji?
weak var viewModel: EmojiService.CustomEmojiViewModel?
init(viewModel: EmojiService.CustomEmoji) {
init(viewModel: EmojiService.CustomEmojiViewModel) {
self.viewModel = viewModel
}
@ -23,24 +23,24 @@ extension EmojiService.CustomEmoji {
}
}
extension EmojiService.CustomEmoji.LoadState {
extension EmojiService.CustomEmojiViewModel.LoadState {
class Initial: EmojiService.CustomEmoji.LoadState {
class Initial: EmojiService.CustomEmojiViewModel.LoadState {
override func isValidNextState(_ stateClass: AnyClass) -> Bool {
return stateClass == Loading.self
}
}
class Loading: EmojiService.CustomEmoji.LoadState {
class Loading: EmojiService.CustomEmojiViewModel.LoadState {
override func isValidNextState(_ stateClass: AnyClass) -> Bool {
return stateClass == Fail.self || stateClass == Finish.self
}
override func didEnter(from previousState: GKState?) {
super.didEnter(from: previousState)
guard let viewModel = viewModel, let stateMachine = stateMachine else { return }
guard let viewModel = viewModel, let apiService = viewModel.service?.apiService, let stateMachine = stateMachine else { return }
viewModel.context.apiService.customEmoji(domain: viewModel.domain)
apiService.customEmoji(domain: viewModel.domain)
.receive(on: DispatchQueue.main)
.sink { completion in
switch completion {
@ -59,7 +59,7 @@ extension EmojiService.CustomEmoji.LoadState {
}
}
class Fail: EmojiService.CustomEmoji.LoadState {
class Fail: EmojiService.CustomEmojiViewModel.LoadState {
override func isValidNextState(_ stateClass: AnyClass) -> Bool {
return stateClass == Loading.self || stateClass == Finish.self
}
@ -76,7 +76,7 @@ extension EmojiService.CustomEmoji.LoadState {
}
}
class Finish: EmojiService.CustomEmoji.LoadState {
class Finish: EmojiService.CustomEmojiViewModel.LoadState {
override func isValidNextState(_ stateClass: AnyClass) -> Bool {
// one time task
return false

View File

@ -1,5 +1,5 @@
//
// EmojiService+CustomEmoji.swift
// EmojiService+CustomEmojiViewModel.swift
// Mastodon
//
// Created by MainasuK Cirno on 2021-3-15.
@ -11,13 +11,13 @@ import GameplayKit
import MastodonSDK
extension EmojiService {
final class CustomEmoji {
final class CustomEmojiViewModel {
var disposeBag = Set<AnyCancellable>()
// input
let domain: String
let context: AppContext
weak var service: EmojiService?
// output
private(set) lazy var stateMachine: GKStateMachine = {
@ -33,12 +33,9 @@ extension EmojiService {
}()
let emojis = CurrentValueSubject<[Mastodon.Entity.Emoji], Never>([])
init(domain: String, context: AppContext) {
init(domain: String, service: EmojiService) {
self.domain = domain
self.context = context
// trigger loading
stateMachine.enter(LoadState.Loading.self)
self.service = service
}
}

View File

@ -12,15 +12,35 @@ import MastodonSDK
final class EmojiService {
let workingQueue = DispatchQueue(label: "com.twidere.twiderex.video-playback-service.working-queue")
weak var apiService: APIService?
// ouput
let workingQueue = DispatchQueue(label: "org.joinmastodon.Mastodon.EmojiService.working-queue")
private(set) var customEmojiViewModelDict: [String: CustomEmojiViewModel] = [:]
init(apiService: APIService) {
self.apiService = apiService
}
}
extension EmojiService {
func dequeueCustomEmojiViewModel(for domain: String) -> CustomEmojiViewModel? {
var _customEmojiViewModel: CustomEmojiViewModel?
workingQueue.sync {
if let viewModel = customEmojiViewModelDict[domain] {
_customEmojiViewModel = viewModel
} else {
let viewModel = CustomEmojiViewModel(domain: domain, service: self)
_customEmojiViewModel = viewModel
// trigger loading
viewModel.stateMachine.enter(CustomEmojiViewModel.LoadState.Loading.self)
}
}
return _customEmojiViewModel
}
}