Compare commits

..

5 Commits

Author SHA1 Message Date
Shadowfacts 17f15db32d
Don't round bottom corners of asset picker
Corner radius doesn't match that used on 2019 iPad Pro, so rounding the
bottom corners results in the view controller beneath the asset picker
showing through in some split-screen configurations
2020-03-16 20:50:16 -04:00
Shadowfacts 1a11dd2a69
Present asset picker as popover in regular horizontal size class 2020-03-16 20:45:51 -04:00
Shadowfacts b5fa0bceab
Fix pasting using compose app shortcut while app isn't running 2020-03-16 19:09:25 -04:00
Shadowfacts c224d11417
Allow pasting and drag/dropping video attachments on compose screen 2020-03-16 19:05:58 -04:00
Shadowfacts bebf47f05c
Prevent incompatible items from being pasted on compose screen 2020-03-16 17:31:43 -04:00
6 changed files with 67 additions and 13 deletions

View File

@ -88,11 +88,16 @@ class MastodonController {
} }
} }
func getOwnInstance() { func getOwnInstance(completion: ((Instance) -> Void)? = nil) {
let request = Client.getInstance() if let instance = self.instance {
run(request) { (response) in completion?(instance)
guard case let .success(instance, _) = response else { fatalError() } } else {
self.instance = instance let request = Client.getInstance()
run(request) { (response) in
guard case let .success(instance, _) = response else { fatalError() }
self.instance = instance
completion?(instance)
}
} }
} }

View File

@ -27,6 +27,8 @@ final class CompositionAttachment: NSObject, Codable {
} }
private let imageType = kUTTypeImage as String private let imageType = kUTTypeImage as String
private let mp4Type = kUTTypeMPEG4 as String
private let quickTimeType = kUTTypeQuickTimeMovie as String
private let dataType = kUTTypeData as String private let dataType = kUTTypeData as String
extension CompositionAttachment: NSItemProviderWriting { extension CompositionAttachment: NSItemProviderWriting {
@ -61,7 +63,10 @@ extension CompositionAttachment: NSItemProviderWriting {
extension CompositionAttachment: NSItemProviderReading { extension CompositionAttachment: NSItemProviderReading {
static var readableTypeIdentifiersForItemProvider: [String] { static var readableTypeIdentifiersForItemProvider: [String] {
[typeIdentifier] + UIImage.readableTypeIdentifiersForItemProvider + NSURL.readableTypeIdentifiersForItemProvider // todo: is there a better way of handling movies than manually adding all possible UTI types?
// just using kUTTypeMovie doesn't work, because we need the actually type in order to get the file extension
// without the file extension, getting the thumbnail and exporting the video for attachment upload fails
[typeIdentifier] + UIImage.readableTypeIdentifiersForItemProvider + [mp4Type, quickTimeType] + NSURL.readableTypeIdentifiersForItemProvider
} }
static func object(withItemProviderData data: Data, typeIdentifier: String) throws -> Self { static func object(withItemProviderData data: Data, typeIdentifier: String) throws -> Self {
@ -69,6 +74,13 @@ extension CompositionAttachment: NSItemProviderReading {
return try PropertyListDecoder().decode(Self.self, from: data) return try PropertyListDecoder().decode(Self.self, from: data)
} else if UIImage.readableTypeIdentifiersForItemProvider.contains(typeIdentifier), let image = try? UIImage.object(withItemProviderData: data, typeIdentifier: typeIdentifier) { } else if UIImage.readableTypeIdentifiersForItemProvider.contains(typeIdentifier), let image = try? UIImage.object(withItemProviderData: data, typeIdentifier: typeIdentifier) {
return CompositionAttachment(data: .image(image)) as! Self return CompositionAttachment(data: .image(image)) as! Self
} else if typeIdentifier == mp4Type || typeIdentifier == quickTimeType {
let temporaryDirectoryURL = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)
let temporaryFileName = ProcessInfo().globallyUniqueString
let fileExt = UTTypeCopyPreferredTagWithClass(typeIdentifier as CFString, kUTTagClassFilenameExtension)!
let temporaryFileURL = temporaryDirectoryURL.appendingPathComponent(temporaryFileName).appendingPathExtension(fileExt.takeUnretainedValue() as String)
try data.write(to: temporaryFileURL)
return CompositionAttachment(data: .video(temporaryFileURL)) as! Self
} else if NSURL.readableTypeIdentifiersForItemProvider.contains(typeIdentifier), let url = try? NSURL.object(withItemProviderData: data, typeIdentifier: typeIdentifier) as URL { } else if NSURL.readableTypeIdentifiersForItemProvider.contains(typeIdentifier), let url = try? NSURL.object(withItemProviderData: data, typeIdentifier: typeIdentifier) as URL {
return CompositionAttachment(data: .video(url)) as! Self return CompositionAttachment(data: .video(url)) as! Self
} else { } else {

View File

@ -49,6 +49,21 @@ class AssetCollectionViewController: UICollectionViewController {
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
// use the safe area layout guide instead of letting it automatically use the safe area insets
// because otherwise, when presented in a popover with the arrow on the left or right side,
// the collection view content will be cut off by the width of the arrow because the popover
// doesn't respect safe area insets
collectionView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
view.safeAreaLayoutGuide.leadingAnchor.constraint(equalTo: collectionView.leadingAnchor),
view.safeAreaLayoutGuide.trailingAnchor.constraint(equalTo: collectionView.trailingAnchor),
// top ignores safe area because when presented in the sheet container, it simplifies the top content offset
view.topAnchor.constraint(equalTo: collectionView.topAnchor),
// bottom ignores safe area because we want cells to underflow bottom of the screen on notched iPhones
view.bottomAnchor.constraint(equalTo: collectionView.bottomAnchor),
])
view.backgroundColor = .systemBackground
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(donePressed)) navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(donePressed))
collectionView.alwaysBounceVertical = true collectionView.alwaysBounceVertical = true

View File

@ -33,6 +33,8 @@ class AssetPickerSheetContainerViewController: SheetContainerViewController {
override func viewDidLoad() { override func viewDidLoad() {
assetPicker.view.layer.cornerRadius = view.bounds.width * 0.02 assetPicker.view.layer.cornerRadius = view.bounds.width * 0.02
// don't round bottom corners, since they'll always be cut off by the device
assetPicker.view.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
super.viewDidLoad() super.viewDidLoad()
} }

View File

@ -108,6 +108,10 @@ class ComposeAttachmentsViewController: UITableViewController {
} }
override func canPaste(_ itemProviders: [NSItemProvider]) -> Bool { override func canPaste(_ itemProviders: [NSItemProvider]) -> Bool {
guard itemProviders.allSatisfy({ $0.canLoadObject(ofClass: CompositionAttachment.self) }) else {
return false
}
switch mastodonController.instance.instanceType { switch mastodonController.instance.instanceType {
case .pleroma: case .pleroma:
return true return true
@ -299,10 +303,20 @@ class ComposeAttachmentsViewController: UITableViewController {
// MARK: Interaction // MARK: Interaction
func addAttachmentPressed() { func addAttachmentPressed() {
let sheetContainer = AssetPickerSheetContainerViewController() if traitCollection.horizontalSizeClass == .compact {
sheetContainer.assetPicker.assetPickerDelegate = self let sheetContainer = AssetPickerSheetContainerViewController()
present(sheetContainer, animated: true) sheetContainer.assetPicker.assetPickerDelegate = self
//setOverrideTraitCollection(UITraitCollection(userInterfaceLevel: .elevated), forChild: sheetContainer) present(sheetContainer, animated: true)
} else {
let picker = AssetPickerViewController()
picker.assetPickerDelegate = self
picker.overrideUserInterfaceStyle = .dark
picker.modalPresentationStyle = .popover
present(picker, animated: true)
if let presentationController = picker.presentationController as? UIPopoverPresentationController {
presentationController.sourceView = tableView.cellForRow(at: IndexPath(row: 0, section: 1))
}
}
} }
} }

View File

@ -137,9 +137,15 @@ class ComposeViewController: UIViewController {
// we have to set the font here, because the monospaced digit font is not available in IB // we have to set the font here, because the monospaced digit font is not available in IB
charactersRemainingLabel.font = .monospacedDigitSystemFont(ofSize: 17, weight: .regular) charactersRemainingLabel.font = .monospacedDigitSystemFont(ofSize: 17, weight: .regular)
updateCharactersRemaining()
updatePlaceholder() updatePlaceholder()
// if the compose screen is opened via the home screen shortcut and app isn't running,
// the msatodon instance may not have been loaded yet
mastodonController.getOwnInstance { (_) in
DispatchQueue.main.async {
self.updateCharactersRemaining()
}
}
composeAttachmentsViewController = ComposeAttachmentsViewController(attachments: currentDraft?.attachments ?? [], mastodonController: mastodonController) composeAttachmentsViewController = ComposeAttachmentsViewController(attachments: currentDraft?.attachments ?? [], mastodonController: mastodonController)
composeRequiresAttachmentDescriptionsDidChange() composeRequiresAttachmentDescriptionsDidChange()
composeAttachmentsViewController.delegate = self composeAttachmentsViewController.delegate = self
@ -266,7 +272,7 @@ class ComposeViewController: UIViewController {
func updateCharactersRemaining() { func updateCharactersRemaining() {
let count = CharacterCounter.count(text: statusTextView.text) let count = CharacterCounter.count(text: statusTextView.text)
let cwCount = contentWarningEnabled ? (contentWarningTextField.text?.count ?? 0) : 0 let cwCount = contentWarningEnabled ? (contentWarningTextField.text?.count ?? 0) : 0
let remaining = (mastodonController.instance.maxStatusCharacters ?? 500) - count - cwCount let remaining = (mastodonController.instance?.maxStatusCharacters ?? 500) - count - cwCount
if remaining < 0 { if remaining < 0 {
charactersRemainingLabel.textColor = .red charactersRemainingLabel.textColor = .red
compositionState.formUnion(.tooManyCharacters) compositionState.formUnion(.tooManyCharacters)