2023-04-19 01:55:14 +00:00
//
// S h a r e V i e w C o n t r o l l e r . s w i f t
// S h a r e E x t e n s i o n
//
// C r e a t e d b y S h a d o w f a c t s o n 4 / 1 7 / 2 3 .
// C o p y r i g h t © 2 0 2 3 S h a d o w f a c t s . A l l r i g h t s r e s e r v e d .
//
import SwiftUI
import UserAccounts
import ComposeUI
import UniformTypeIdentifiers
import TuskerPreferences
2023-04-21 21:24:40 +00:00
import Combine
2023-04-19 01:55:14 +00:00
class ShareViewController : UIViewController {
private var state : State = . loading
required init ? ( coder : NSCoder ) {
super . init ( coder : coder )
}
override func viewDidLoad ( ) {
super . viewDidLoad ( )
view . tintColor = Preferences . shared . accentColor . color
if let account = UserAccountsManager . shared . getMostRecentAccount ( ) {
Task { @ MainActor in
let draft = await createDraft ( account : account )
state = . ok
let context = ShareMastodonContext ( accountInfo : account )
let host = ShareHostingController ( draft : draft , mastodonContext : context )
let nav = UINavigationController ( rootViewController : host )
self . addChild ( nav )
nav . view . translatesAutoresizingMaskIntoConstraints = false
self . view . addSubview ( nav . view )
NSLayoutConstraint . activate ( [
nav . view . leadingAnchor . constraint ( equalTo : self . view . leadingAnchor ) ,
nav . view . trailingAnchor . constraint ( equalTo : self . view . trailingAnchor ) ,
nav . view . topAnchor . constraint ( equalTo : self . view . topAnchor ) ,
nav . view . bottomAnchor . constraint ( equalTo : self . view . bottomAnchor ) ,
] )
nav . didMove ( toParent : self )
}
} else {
state = . notLoggedIn
}
}
private func createDraft ( account : UserAccountInfo ) async -> Draft {
let ( text , attachments ) = await getDraftConfigurationFromExtensionContext ( )
2023-04-23 01:16:30 +00:00
let draft = DraftsPersistentContainer . shared . createDraft (
2023-04-19 01:55:14 +00:00
accountID : account . id ,
text : text ,
contentWarning : " " ,
inReplyToID : nil ,
2023-04-20 02:27:25 +00:00
visibility : Preferences . shared . defaultPostVisibility ,
2023-04-19 01:55:14 +00:00
localOnly : false
)
2023-04-23 01:16:30 +00:00
for attachment in attachments {
DraftsPersistentContainer . shared . viewContext . insert ( attachment )
}
draft . draftAttachments = attachments
2023-04-19 01:55:14 +00:00
return draft
}
private func getDraftConfigurationFromExtensionContext ( ) async -> ( String , [ DraftAttachment ] ) {
guard let extensionContext ,
let inputItem = ( extensionContext . inputItems as ? [ NSExtensionItem ] ) ? . first ,
let itemProvider = inputItem . attachments ? . first else {
return ( " " , [ ] )
}
if let url : NSURL = await getObject ( from : itemProvider ) {
if let title = inputItem . attributedTitle ? ? inputItem . attributedContentText {
return ( " \n \n \( title . string ) \n \( url . absoluteString ? ? " " ) " , [ ] )
} else {
return ( " \n \n \( url . absoluteString ? ? " " ) " , [ ] )
}
} else if let text : NSString = await getObject ( from : itemProvider ) {
return ( " \n \n \( text ) " , [ ] )
} else if let attributedContent = inputItem . attributedContentText {
return ( " \n \n \( attributedContent . string ) " , [ ] )
} else {
2023-04-23 02:43:00 +00:00
let attachments = await withTaskGroup ( of : DraftAttachment ? . self , returning : [ DraftAttachment ] . self ) { group in
for provider in inputItem . attachments ! {
group . addTask { @ MainActor in
await self . getObject ( from : provider )
}
}
return await group . reduce ( into : [ ] , { partialResult , result in
if let result {
partialResult . append ( result )
}
} )
}
return ( " " , attachments )
2023-04-19 01:55:14 +00:00
}
}
private func getObject < T : NSItemProviderReading > ( from itemProvider : NSItemProvider ) async -> T ? {
guard itemProvider . canLoadObject ( ofClass : T . self ) else {
return nil
}
return await withCheckedContinuation ( { continuation in
itemProvider . loadObject ( ofClass : T . self ) { object , error in
continuation . resume ( returning : object as ? T )
}
} )
}
override func viewDidAppear ( _ animated : Bool ) {
super . viewDidAppear ( animated )
if case . notLoggedIn = state {
let alert = UIAlertController ( title : " Not Logged In " , message : " You need to log in to an account through the app before you can post. " , preferredStyle : . alert )
alert . addAction ( UIAlertAction ( title : " OK " , style : . default , handler : { [ unowned self ] _ in
self . extensionContext ! . cancelRequest ( withError : Error . notLoggedIn )
} ) )
present ( alert , animated : true )
}
}
enum State {
case loading
case notLoggedIn
case ok
}
enum Error : Swift . Error {
case notLoggedIn
}
}