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 )
2023-05-04 14:01:32 +00:00
host . view . translatesAutoresizingMaskIntoConstraints = false
addChild ( host )
self . view . addSubview ( host . view )
2023-04-19 01:55:14 +00:00
NSLayoutConstraint . activate ( [
2023-05-04 14:01:32 +00:00
host . view . leadingAnchor . constraint ( equalTo : self . view . leadingAnchor ) ,
host . view . trailingAnchor . constraint ( equalTo : self . view . trailingAnchor ) ,
host . view . topAnchor . constraint ( equalTo : self . view . topAnchor ) ,
host . view . bottomAnchor . constraint ( equalTo : self . view . bottomAnchor ) ,
2023-04-19 01:55:14 +00:00
] )
2023-05-04 14:01:32 +00:00
host . didMove ( toParent : self )
2023-04-19 01:55:14 +00:00
}
} 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 ,
2023-05-13 02:00:00 +00:00
let inputItem = ( extensionContext . inputItems as ? [ NSExtensionItem ] ) ? . first else {
2023-04-19 01:55:14 +00:00
return ( " " , [ ] )
}
2023-05-13 02:00:00 +00:00
var text : String = " "
var url : URL ?
var attachments : [ DraftAttachment ] = [ ]
for itemProvider in inputItem . attachments ? ? [ ] {
if let attached : NSURL = await getObject ( from : itemProvider ) {
if url = = nil {
url = attached as URL
2023-04-23 02:43:00 +00:00
}
2023-05-13 02:00:00 +00:00
} else if let s : NSString = await getObject ( from : itemProvider ) {
if text . isEmpty {
text = s as String
}
} else if let attachment : DraftAttachment = await getObject ( from : itemProvider ) {
attachments . append ( attachment )
}
}
if text . isEmpty ,
let s = inputItem . attributedTitle ? ? inputItem . attributedContentText {
text = s . string
}
if let url {
if ! text . isEmpty {
text += " \n "
2023-04-23 02:43:00 +00:00
}
2023-05-13 02:00:00 +00:00
text += url . absoluteString
}
if ! text . isEmpty {
text = " \n \n \( text ) "
2023-04-19 01:55:14 +00:00
}
2023-05-13 02:00:00 +00:00
return ( text , 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
}
}