2021-03-18 10:33:07 +01:00
//
// C o m p o s e V i e w M o d e l + P u b l i s h S t a t e . s w i f t
// M a s t o d o n
//
// C r e a t e d b y M a i n a s u K C i r n o o n 2 0 2 1 - 3 - 1 8 .
//
import os . log
import Foundation
2021-03-18 12:42:26 +01:00
import Combine
2021-03-18 10:33:07 +01:00
import GameplayKit
import MastodonSDK
extension ComposeViewModel {
class PublishState : GKState {
weak var viewModel : ComposeViewModel ?
init ( viewModel : ComposeViewModel ) {
self . viewModel = viewModel
}
override func didEnter ( from previousState : GKState ? ) {
os_log ( " %{public}s[%{public}ld], %{public}s: enter %s, previous: %s " , ( ( #file as NSString ) . lastPathComponent ) , #line , #function , self . debugDescription , previousState . debugDescription )
}
}
}
extension ComposeViewModel . PublishState {
class Initial : ComposeViewModel . PublishState {
override func isValidNextState ( _ stateClass : AnyClass ) -> Bool {
return stateClass = = Publishing . self
}
}
class Publishing : ComposeViewModel . PublishState {
2021-03-18 12:42:26 +01:00
var publishingSubscription : AnyCancellable ?
2021-03-18 10:33:07 +01:00
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 mastodonAuthenticationBox = viewModel . activeAuthenticationBox . value else {
stateMachine . enter ( Fail . self )
return
}
2021-03-19 12:49:48 +01:00
let domain = mastodonAuthenticationBox . domain
let attachmentServices = viewModel . attachmentServices . value
let mediaIDs = attachmentServices . compactMap { attachmentService in
2021-03-18 12:42:26 +01:00
attachmentService . attachment . value ? . id
}
2021-03-24 08:08:00 +01:00
let pollOptions : [ String ] ? = {
guard viewModel . isPollComposing . value else { return nil }
return viewModel . pollAttributes . value . map { attribute in attribute . option . value }
} ( )
let pollExpiresIn : Int ? = {
guard viewModel . isPollComposing . value else { return nil }
return viewModel . pollExpiresOptionAttribute . expiresOption . value . seconds
} ( )
2021-03-19 12:49:48 +01:00
let updateMediaQuerySubscriptions : [ AnyPublisher < Mastodon . Response . Content < Mastodon . Entity . Attachment > , Error > ] = {
var subscriptions : [ AnyPublisher < Mastodon . Response . Content < Mastodon . Entity . Attachment > , Error > ] = [ ]
for attachmentService in attachmentServices {
guard let attachmentID = attachmentService . attachment . value ? . id else { continue }
let description = attachmentService . description . value ? . trimmingCharacters ( in : . whitespacesAndNewlines ) ? ? " "
guard ! description . isEmpty else { continue }
let query = Mastodon . API . Media . UpdateMediaQuery (
file : nil ,
thumbnail : nil ,
description : description ,
focus : nil
)
let subscription = viewModel . context . apiService . updateMedia (
domain : domain ,
attachmentID : attachmentID ,
query : query ,
mastodonAuthenticationBox : mastodonAuthenticationBox
)
subscriptions . append ( subscription )
}
return subscriptions
} ( )
publishingSubscription = Publishers . MergeMany ( updateMediaQuerySubscriptions )
. collect ( )
. flatMap { attachments -> AnyPublisher < Mastodon . Response . Content < Mastodon . Entity . Status > , Error > in
let query = Mastodon . API . Statuses . PublishStatusQuery (
status : viewModel . composeStatusAttribute . composeContent . value ,
2021-03-24 08:08:00 +01:00
mediaIDs : mediaIDs . isEmpty ? nil : mediaIDs ,
pollOptions : pollOptions ,
pollExpiresIn : pollExpiresIn
2021-03-19 12:49:48 +01:00
)
return viewModel . context . apiService . publishStatus (
domain : domain ,
query : query ,
mastodonAuthenticationBox : mastodonAuthenticationBox
)
}
. receive ( on : DispatchQueue . main )
. sink { completion in
switch completion {
case . failure ( let error ) :
os_log ( . info , log : . debug , " %{public}s[%{public}ld], %{public}s: publish status %s " , ( ( #file as NSString ) . lastPathComponent ) , #line , #function , error . localizedDescription )
stateMachine . enter ( Fail . self )
case . finished :
os_log ( . info , log : . debug , " %{public}s[%{public}ld], %{public}s: publish status success " , ( ( #file as NSString ) . lastPathComponent ) , #line , #function )
stateMachine . enter ( Finish . self )
}
} receiveValue : { response in
os_log ( . info , log : . debug , " %{public}s[%{public}ld], %{public}s: status %s published: %s " , ( ( #file as NSString ) . lastPathComponent ) , #line , #function , response . value . id , response . value . uri )
2021-03-18 10:33:07 +01:00
}
}
}
class Fail : ComposeViewModel . PublishState {
override func isValidNextState ( _ stateClass : AnyClass ) -> Bool {
// a l l o w d i s c a r d p u b l i s h i n g
return stateClass = = Publishing . self || stateClass = = Finish . self
}
}
class Finish : ComposeViewModel . PublishState {
override func isValidNextState ( _ stateClass : AnyClass ) -> Bool {
return false
}
}
}