Skip to content

Commit 2626256

Browse files
committed
Refactor media insertion code to an helper class.
1 parent 4237063 commit 2626256

3 files changed

Lines changed: 136 additions & 113 deletions

File tree

Example/AztecExample.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
FF629DC9223BC418004C4106 /* videoShortcodes.html in Resources */ = {isa = PBXBuildFile; fileRef = FF629DC8223BC418004C4106 /* videoShortcodes.html */; };
4444
FF9AF5481DB0E4E200C42ED3 /* AttachmentDetailsViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FF9AF5471DB0E4E200C42ED3 /* AttachmentDetailsViewController.storyboard */; };
4545
FFC41BDE20DBC7BA004DFB4D /* video.html in Resources */ = {isa = PBXBuildFile; fileRef = FFC41BDD20DBC7BA004DFB4D /* video.html */; };
46+
FFFA53D023C4A64200829A43 /* MediaInsertionHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFFA53CF23C4A64200829A43 /* MediaInsertionHelper.swift */; };
4647
/* End PBXBuildFile section */
4748

4849
/* Begin PBXContainerItemProxy section */
@@ -160,6 +161,7 @@
160161
FF629DC8223BC418004C4106 /* videoShortcodes.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = videoShortcodes.html; sourceTree = "<group>"; };
161162
FF9AF5471DB0E4E200C42ED3 /* AttachmentDetailsViewController.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = AttachmentDetailsViewController.storyboard; sourceTree = "<group>"; };
162163
FFC41BDD20DBC7BA004DFB4D /* video.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = video.html; sourceTree = "<group>"; };
164+
FFFA53CF23C4A64200829A43 /* MediaInsertionHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaInsertionHelper.swift; sourceTree = "<group>"; };
163165
/* End PBXFileReference section */
164166

165167
/* Begin PBXFrameworksBuildPhase section */
@@ -255,6 +257,7 @@
255257
FF9AF5471DB0E4E200C42ED3 /* AttachmentDetailsViewController.storyboard */,
256258
607FACD71AFB9204008FA782 /* ViewController.swift */,
257259
E63EF92A1D36A60B00B5BA4B /* EditorDemoController.swift */,
260+
FFFA53CF23C4A64200829A43 /* MediaInsertionHelper.swift */,
258261
B5DB1C361EC630E10005E623 /* UnknownEditorViewController.swift */,
259262
607FACD91AFB9204008FA782 /* Main.storyboard */,
260263
607FACDC1AFB9204008FA782 /* Images.xcassets */,
@@ -471,6 +474,7 @@
471474
isa = PBXSourcesBuildPhase;
472475
buildActionMask = 2147483647;
473476
files = (
477+
FFFA53D023C4A64200829A43 /* MediaInsertionHelper.swift in Sources */,
474478
B5DB1C371EC630E10005E623 /* UnknownEditorViewController.swift in Sources */,
475479
599F25701D8BCF57002871D6 /* AppDelegate.swift in Sources */,
476480
59D2873B1D8C599B00B99C80 /* AttachmentDetailsViewController.swift in Sources */,

Example/Example/EditorDemoController.swift

Lines changed: 30 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,7 @@ import Photos
88
import UIKit
99
import WordPressEditor
1010

11-
class EditorDemoController: UIViewController {
12-
13-
fileprivate var mediaErrorMode = false
11+
class EditorDemoController: UIViewController {
1412

1513
fileprivate(set) lazy var formatBar: Aztec.FormatBar = {
1614
return self.createToolbar()
@@ -27,6 +25,10 @@ class EditorDemoController: UIViewController {
2725
return editorView.htmlTextView
2826
}
2927
}
28+
29+
fileprivate(set) lazy var mediaInsertionHelper: MediaInsertionHelper = {
30+
return MediaInsertionHelper(textView: self.richTextView, messageAttributes: Constants.mediaMessageAttributes)
31+
}()
3032

3133
fileprivate(set) lazy var editorView: Aztec.EditorView = {
3234
let defaultHTMLFont: UIFont
@@ -1108,8 +1110,7 @@ extension EditorDemoController: TextViewAttachmentDelegate {
11081110
return nil
11091111
}
11101112

1111-
// TODO: start fake upload process
1112-
return saveToDisk(image: image)
1113+
return mediaInsertionHelper.saveToDisk(image: image)
11131114
}
11141115

11151116
func textView(_ textView: TextView, deletedAttachment attachment: MediaAttachment) {
@@ -1148,7 +1149,7 @@ extension EditorDemoController: TextViewAttachmentDelegate {
11481149
// and mark the newly tapped attachment
11491150
if attachment.message == nil {
11501151
let message = NSLocalizedString("Options", comment: "Options to show when tapping on a media object on the post/page editor.")
1151-
attachment.message = NSAttributedString(string: message, attributes: mediaMessageAttributes)
1152+
attachment.message = NSAttributedString(string: message, attributes: Constants.mediaMessageAttributes)
11521153
}
11531154
attachment.overlayImage = Gridicon.iconOfType(.pencil, withSize: CGSize(width: 32.0, height: 32.0)).withRenderingMode(.alwaysTemplate)
11541155
richTextView.refresh(attachment)
@@ -1203,13 +1204,13 @@ let info = convertFromUIImagePickerControllerInfoKeyDictionary(info)
12031204
}
12041205

12051206
// Insert Image + Reclaim Focus
1206-
insertImage(image)
1207+
mediaInsertionHelper.insertImage(image)
12071208

12081209
case typeMovie:
12091210
guard let videoURL = info[convertFromUIImagePickerControllerInfoKey(UIImagePickerController.InfoKey.mediaURL)] as? URL else {
12101211
return
12111212
}
1212-
insertVideo(videoURL)
1213+
mediaInsertionHelper.insertVideo(videoURL)
12131214
default:
12141215
print("Media type not supported: \(mediaType)")
12151216
}
@@ -1312,97 +1313,10 @@ private extension EditorDemoController {
13121313
task.resume()
13131314
}
13141315
}
1315-
// MARK: - Misc
1316-
//
1317-
private extension EditorDemoController
1318-
{
1319-
func saveToDisk(image: UIImage) -> URL {
1320-
let fileName = "\(ProcessInfo.processInfo.globallyUniqueString)_file.jpg"
1321-
1322-
guard let data = image.jpegData(compressionQuality: 0.9) else {
1323-
fatalError("Could not conert image to JPEG.")
1324-
}
1325-
1326-
let fileURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(fileName)
1327-
1328-
guard (try? data.write(to: fileURL, options: [.atomic])) != nil else {
1329-
fatalError("Could not write the image to disk.")
1330-
}
1331-
1332-
return fileURL
1333-
}
1334-
1335-
func insertImage(_ image: UIImage) {
1336-
1337-
let fileURL = saveToDisk(image: image)
1338-
1339-
let attachment = richTextView.replaceWithImage(at: richTextView.selectedRange, sourceURL: fileURL, placeHolderImage: image)
1340-
attachment.size = .full
1341-
attachment.alignment = ImageAttachment.Alignment.none
1342-
if let attachmentRange = richTextView.textStorage.ranges(forAttachment: attachment).first {
1343-
richTextView.setLink(fileURL, inRange: attachmentRange)
1344-
}
1345-
let imageID = attachment.identifier
1346-
let progress = Progress(parent: nil, userInfo: [MediaProgressKey.mediaID: imageID])
1347-
progress.totalUnitCount = 100
1348-
1349-
Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(EditorDemoController.timerFireMethod(_:)), userInfo: progress, repeats: true)
1350-
}
1351-
1352-
func insertVideo(_ videoURL: URL) {
1353-
let asset = AVURLAsset(url: videoURL, options: nil)
1354-
let imgGenerator = AVAssetImageGenerator(asset: asset)
1355-
imgGenerator.appliesPreferredTrackTransform = true
1356-
guard let cgImage = try? imgGenerator.copyCGImage(at: CMTimeMake(value: 0, timescale: 1), actualTime: nil) else {
1357-
return
1358-
}
1359-
let posterImage = UIImage(cgImage: cgImage)
1360-
let posterURL = saveToDisk(image: posterImage)
1361-
let attachment = richTextView.replaceWithVideo(at: richTextView.selectedRange, sourceURL: URL(string:"placeholder://")!, posterURL: posterURL, placeHolderImage: posterImage)
1362-
let mediaID = attachment.identifier
1363-
let progress = Progress(parent: nil, userInfo: [MediaProgressKey.mediaID: mediaID, MediaProgressKey.videoURL:videoURL])
1364-
progress.totalUnitCount = 100
1365-
1366-
Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(EditorDemoController.timerFireMethod(_:)), userInfo: progress, repeats: true)
1367-
}
1368-
1369-
@objc func timerFireMethod(_ timer: Timer) {
1370-
guard let progress = timer.userInfo as? Progress,
1371-
let imageId = progress.userInfo[MediaProgressKey.mediaID] as? String,
1372-
let attachment = richTextView.attachment(withId: imageId)
1373-
else {
1374-
timer.invalidate()
1375-
return
1376-
}
1377-
progress.completedUnitCount += 1
1378-
1379-
attachment.progress = progress.fractionCompleted
1380-
if mediaErrorMode && progress.fractionCompleted >= 0.25 {
1381-
timer.invalidate()
1382-
let message = NSAttributedString(string: "Upload failed!", attributes: mediaMessageAttributes)
1383-
attachment.message = message
1384-
attachment.overlayImage = Gridicon.iconOfType(.refresh)
1385-
}
1386-
if progress.fractionCompleted >= 1 {
1387-
timer.invalidate()
1388-
attachment.progress = nil
1389-
if let videoAttachment = attachment as? VideoAttachment, let videoURL = progress.userInfo[MediaProgressKey.videoURL] as? URL {
1390-
videoAttachment.updateURL(videoURL)
1391-
}
1392-
}
1393-
richTextView.refresh(attachment, overlayUpdateOnly: true)
1394-
}
1395-
1396-
var mediaMessageAttributes: [NSAttributedString.Key: Any] {
1397-
let paragraphStyle = NSMutableParagraphStyle()
1398-
paragraphStyle.alignment = .center
1399-
1400-
let attributes: [NSAttributedString.Key: Any] = [.font: UIFont.systemFont(ofSize: 15, weight: .semibold),
1401-
.paragraphStyle: paragraphStyle,
1402-
.foregroundColor: UIColor.white]
1403-
return attributes
1404-
}
14051316

1317+
// MARK: - Media Attachment Actions
1318+
//
1319+
extension EditorDemoController {
14061320
func displayActions(forAttachment attachment: MediaAttachment, position: CGPoint) {
14071321
let mediaID = attachment.identifier
14081322
let title: String = NSLocalizedString("Media Options", comment: "Title for action sheet with media options.")
@@ -1449,14 +1363,14 @@ private extension EditorDemoController
14491363
}
14501364

14511365
func displayDetailsForAttachment(_ attachment: ImageAttachment, position:CGPoint) {
1452-
1366+
14531367
let caption = richTextView.caption(for: attachment)
14541368
let detailsViewController = AttachmentDetailsViewController.controller(for: attachment, with: caption)
1455-
1369+
14561370
let linkInfo = richTextView.linkInfo(for: attachment)
14571371
let linkRange = linkInfo?.range
14581372
let linkUpdateRange = linkRange ?? richTextView.textStorage.ranges(forAttachment: attachment).first!
1459-
1373+
14601374
if let linkURL = linkInfo?.url {
14611375
detailsViewController.linkURL = linkURL
14621376
}
@@ -1475,33 +1389,32 @@ private extension EditorDemoController
14751389
attachment.size = size
14761390
attachment.updateURL(srcURL)
14771391
}
1478-
1392+
14791393
if let caption = caption, caption.length > 0 {
14801394
self.richTextView.replaceCaption(for: attachment, with: caption)
14811395
} else {
14821396
self.richTextView.removeCaption(for: attachment)
14831397
}
1484-
1398+
14851399
if let newLinkURL = linkURL {
14861400
self.richTextView.setLink(newLinkURL, inRange: linkUpdateRange)
14871401
} else if linkURL != nil {
14881402
self.richTextView.removeLink(inRange: linkUpdateRange)
14891403
}
14901404
}
1491-
1405+
14921406
let selectedRange = richTextView.selectedRange
1493-
1494-
detailsViewController.onDismiss = { [unowned self] in
1407+
1408+
detailsViewController.onDismiss = { [unowned self] in
14951409
self.richTextView.becomeFirstResponder()
14961410
self.richTextView.selectedRange = selectedRange
14971411
}
14981412

1499-
let navigationController = UINavigationController(rootViewController: detailsViewController)
1413+
let navigationController = UINavigationController(rootViewController: detailsViewController)
15001414
present(navigationController, animated: true, completion: nil)
15011415
}
15021416
}
15031417

1504-
15051418
extension EditorDemoController {
15061419

15071420
static var tintedMissingImage: UIImage = {
@@ -1522,12 +1435,16 @@ extension EditorDemoController {
15221435
static let lists = [TextList.Style.unordered, .ordered]
15231436
static let moreAttachmentText = "more"
15241437
static let titleInsets = UIEdgeInsets(top: 5, left: 0, bottom: 5, right: 0)
1525-
}
1438+
static var mediaMessageAttributes: [NSAttributedString.Key: Any] {
1439+
let paragraphStyle = NSMutableParagraphStyle()
1440+
paragraphStyle.alignment = .center
15261441

1527-
struct MediaProgressKey {
1528-
static let mediaID = ProgressUserInfoKey("mediaID")
1529-
static let videoURL = ProgressUserInfoKey("videoURL")
1530-
}
1442+
let attributes: [NSAttributedString.Key: Any] = [.font: UIFont.systemFont(ofSize: 15, weight: .semibold),
1443+
.paragraphStyle: paragraphStyle,
1444+
.foregroundColor: UIColor.white]
1445+
return attributes
1446+
}
1447+
}
15311448
}
15321449

15331450
extension FormattingIdentifier {
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import Foundation
2+
import UIKit
3+
import Aztec
4+
import AVFoundation
5+
import Gridicons
6+
7+
class MediaInsertionHelper
8+
{
9+
fileprivate var mediaErrorMode = false
10+
11+
struct MediaProgressKey {
12+
static let mediaID = ProgressUserInfoKey("mediaID")
13+
static let videoURL = ProgressUserInfoKey("videoURL")
14+
}
15+
16+
let richTextView: TextView
17+
18+
var mediaMessageAttributes: [NSAttributedString.Key: Any]
19+
20+
init(textView: TextView, messageAttributes: [NSAttributedString.Key: Any]) {
21+
self.richTextView = textView
22+
self.mediaMessageAttributes = messageAttributes
23+
}
24+
25+
func saveToDisk(image: UIImage) -> URL {
26+
let fileName = "\(ProcessInfo.processInfo.globallyUniqueString)_file.jpg"
27+
28+
guard let data = image.jpegData(compressionQuality: 0.9) else {
29+
fatalError("Could not conert image to JPEG.")
30+
}
31+
32+
let fileURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(fileName)
33+
34+
guard (try? data.write(to: fileURL, options: [.atomic])) != nil else {
35+
fatalError("Could not write the image to disk.")
36+
}
37+
38+
return fileURL
39+
}
40+
41+
func insertImage(_ image: UIImage) {
42+
43+
let fileURL = saveToDisk(image: image)
44+
45+
let attachment = richTextView.replaceWithImage(at: richTextView.selectedRange, sourceURL: fileURL, placeHolderImage: image)
46+
attachment.size = .full
47+
attachment.alignment = ImageAttachment.Alignment.none
48+
if let attachmentRange = richTextView.textStorage.ranges(forAttachment: attachment).first {
49+
richTextView.setLink(fileURL, inRange: attachmentRange)
50+
}
51+
let imageID = attachment.identifier
52+
let progress = Progress(parent: nil, userInfo: [MediaProgressKey.mediaID: imageID])
53+
progress.totalUnitCount = 100
54+
55+
Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(MediaInsertionHelper.timerFireMethod(_:)), userInfo: progress, repeats: true)
56+
}
57+
58+
func insertVideo(_ videoURL: URL) {
59+
let asset = AVURLAsset(url: videoURL, options: nil)
60+
let imgGenerator = AVAssetImageGenerator(asset: asset)
61+
imgGenerator.appliesPreferredTrackTransform = true
62+
guard let cgImage = try? imgGenerator.copyCGImage(at: CMTimeMake(value: 0, timescale: 1), actualTime: nil) else {
63+
return
64+
}
65+
let posterImage = UIImage(cgImage: cgImage)
66+
let posterURL = saveToDisk(image: posterImage)
67+
let attachment = richTextView.replaceWithVideo(at: richTextView.selectedRange, sourceURL: URL(string:"placeholder://")!, posterURL: posterURL, placeHolderImage: posterImage)
68+
let mediaID = attachment.identifier
69+
let progress = Progress(parent: nil, userInfo: [MediaProgressKey.mediaID: mediaID, MediaProgressKey.videoURL:videoURL])
70+
progress.totalUnitCount = 100
71+
72+
Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(MediaInsertionHelper.timerFireMethod(_:)), userInfo: progress, repeats: true)
73+
}
74+
75+
@objc func timerFireMethod(_ timer: Timer) {
76+
guard let progress = timer.userInfo as? Progress,
77+
let imageId = progress.userInfo[MediaProgressKey.mediaID] as? String,
78+
let attachment = richTextView.attachment(withId: imageId)
79+
else {
80+
timer.invalidate()
81+
return
82+
}
83+
progress.completedUnitCount += 1
84+
85+
attachment.progress = progress.fractionCompleted
86+
if mediaErrorMode && progress.fractionCompleted >= 0.25 {
87+
timer.invalidate()
88+
let message = NSAttributedString(string: "Upload failed!", attributes: mediaMessageAttributes)
89+
attachment.message = message
90+
attachment.overlayImage = Gridicon.iconOfType(.refresh)
91+
}
92+
if progress.fractionCompleted >= 1 {
93+
timer.invalidate()
94+
attachment.progress = nil
95+
if let videoAttachment = attachment as? VideoAttachment, let videoURL = progress.userInfo[MediaProgressKey.videoURL] as? URL {
96+
videoAttachment.updateURL(videoURL)
97+
}
98+
}
99+
richTextView.refresh(attachment, overlayUpdateOnly: true)
100+
}
101+
102+
}

0 commit comments

Comments
 (0)