Browse Source

Development

master
Dwayne Harris 6 years ago
parent
commit
dd5635612f
  1. 44
      elpha-ios.xcodeproj/project.pbxproj
  2. 21
      elpha-ios/AbstractStatusTableViewController.swift
  3. 12
      elpha-ios/Assets.xcassets/Icons/Placeholder Half.imageset/Contents.json
  4. BIN
      elpha-ios/Assets.xcassets/Icons/Placeholder Half.imageset/placeholder-half.pdf
  5. 12
      elpha-ios/Assets.xcassets/Icons/Placeholder Small.imageset/Contents.json
  6. BIN
      elpha-ios/Assets.xcassets/Icons/Placeholder Small.imageset/placeholder-small.pdf
  7. 12
      elpha-ios/Assets.xcassets/Icons/Placeholder.imageset/Contents.json
  8. BIN
      elpha-ios/Assets.xcassets/Icons/Placeholder.imageset/placeholder.pdf
  9. 207
      elpha-ios/AttachmentManager.swift
  10. 111
      elpha-ios/AttachmentsView.swift
  11. 49
      elpha-ios/AttachmentsView.xib
  12. 9
      elpha-ios/Base.lproj/Main.storyboard
  13. 24
      elpha-ios/ImageAttachmentCollectionViewCell.swift
  14. 39
      elpha-ios/ImageAttachmentCollectionViewCell.xib
  15. 2
      elpha-ios/MainStatusTableViewCell.swift
  16. 24
      elpha-ios/StatusTableViewController.swift
  17. 37
      elpha-ios/StatusView.swift
  18. 49
      elpha-ios/StatusView.xib
  19. 42
      elpha-ios/VideoAttachmentCollectionViewCell.swift
  20. 25
      elpha-ios/VideoAttachmentCollectionViewCell.xib

44
elpha-ios.xcodeproj/project.pbxproj

@ -41,7 +41,6 @@
157405A82150588A00EEAAEB /* InstanceViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 157405A72150588A00EEAAEB /* InstanceViewController.swift */; };
157405B12151A5DA00EEAAEB /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = 157405AF2151A5DA00EEAAEB /* README.md */; };
157405B42151A93E00EEAAEB /* InstancesDataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 157405B32151A93E00EEAAEB /* InstancesDataManager.swift */; };
1574148D2169AD0100C841BD /* AttachmentManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1574148C2169AD0100C841BD /* AttachmentManager.swift */; };
159026AE2162CF5600D362DD /* TimelineTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 159026AD2162CF5600D362DD /* TimelineTableViewCell.swift */; };
159026D02163069600D362DD /* Date+TimeAgo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 159026CF2163069600D362DD /* Date+TimeAgo.swift */; };
159048AF214F5015004F4014 /* InstancesTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 159048AE214F5015004F4014 /* InstancesTableViewCell.swift */; };
@ -60,8 +59,14 @@
15960E84213774FC00C38CE9 /* InstancesTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15960E83213774FC00C38CE9 /* InstancesTableViewController.swift */; };
159B553A219D11E600964AC0 /* ComposeAccessoryView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 159B5539219D11E600964AC0 /* ComposeAccessoryView.xib */; };
15A79B43215EB959007A326E /* CoreDataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15A79B42215EB959007A326E /* CoreDataManager.swift */; };
15A9AFD821AF8382008789E8 /* AttachmentsView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 15A9AFD721AF8382008789E8 /* AttachmentsView.xib */; };
15A9AFE721AFA243008789E8 /* AttachmentsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15A9AFE621AFA243008789E8 /* AttachmentsView.swift */; };
15B127922192467F00F4EF1D /* String+HtmlAttributed.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15B127912192467F00F4EF1D /* String+HtmlAttributed.swift */; };
15B127A32192486200F4EF1D /* UIColor+HexString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15B127A22192486200F4EF1D /* UIColor+HexString.swift */; };
15B7A56621B120CA00D20DBE /* VideoAttachmentCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15B7A56421B120CA00D20DBE /* VideoAttachmentCollectionViewCell.swift */; };
15B7A56721B120CA00D20DBE /* VideoAttachmentCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 15B7A56521B120CA00D20DBE /* VideoAttachmentCollectionViewCell.xib */; };
15B7A56A21B122FF00D20DBE /* ImageAttachmentCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15B7A56821B122FF00D20DBE /* ImageAttachmentCollectionViewCell.swift */; };
15B7A56B21B122FF00D20DBE /* ImageAttachmentCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 15B7A56921B122FF00D20DBE /* ImageAttachmentCollectionViewCell.xib */; };
15BB72AB2171A8D4002F1FA4 /* TimelinesTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15BB72AA2171A8D4002F1FA4 /* TimelinesTableViewCell.swift */; };
15C91A02216AB2D600D97DC3 /* AlertView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 15C91A01216AB2D600D97DC3 /* AlertView.xib */; };
15C91A04216AB32500D97DC3 /* AlertView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15C91A03216AB32500D97DC3 /* AlertView.swift */; };
@ -233,7 +238,6 @@
157405AF2151A5DA00EEAAEB /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
157405B32151A93E00EEAAEB /* InstancesDataManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstancesDataManager.swift; sourceTree = "<group>"; };
157405B7215890BC00EEAAEB /* Alamofire.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Alamofire.xcodeproj; path = Frameworks/Alamofire/Alamofire.xcodeproj; sourceTree = "<group>"; };
1574148C2169AD0100C841BD /* AttachmentManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttachmentManager.swift; sourceTree = "<group>"; };
159026AD2162CF5600D362DD /* TimelineTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineTableViewCell.swift; sourceTree = "<group>"; };
159026CF2163069600D362DD /* Date+TimeAgo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+TimeAgo.swift"; sourceTree = "<group>"; };
159048AE214F5015004F4014 /* InstancesTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstancesTableViewCell.swift; sourceTree = "<group>"; };
@ -254,8 +258,14 @@
15960E83213774FC00C38CE9 /* InstancesTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstancesTableViewController.swift; sourceTree = "<group>"; };
159B5539219D11E600964AC0 /* ComposeAccessoryView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ComposeAccessoryView.xib; sourceTree = "<group>"; };
15A79B42215EB959007A326E /* CoreDataManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreDataManager.swift; sourceTree = "<group>"; };
15A9AFD721AF8382008789E8 /* AttachmentsView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AttachmentsView.xib; sourceTree = "<group>"; };
15A9AFE621AFA243008789E8 /* AttachmentsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttachmentsView.swift; sourceTree = "<group>"; };
15B127912192467F00F4EF1D /* String+HtmlAttributed.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+HtmlAttributed.swift"; sourceTree = "<group>"; };
15B127A22192486200F4EF1D /* UIColor+HexString.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+HexString.swift"; sourceTree = "<group>"; };
15B7A56421B120CA00D20DBE /* VideoAttachmentCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoAttachmentCollectionViewCell.swift; sourceTree = "<group>"; };
15B7A56521B120CA00D20DBE /* VideoAttachmentCollectionViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = VideoAttachmentCollectionViewCell.xib; sourceTree = "<group>"; };
15B7A56821B122FF00D20DBE /* ImageAttachmentCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageAttachmentCollectionViewCell.swift; sourceTree = "<group>"; };
15B7A56921B122FF00D20DBE /* ImageAttachmentCollectionViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ImageAttachmentCollectionViewCell.xib; sourceTree = "<group>"; };
15BB72AA2171A8D4002F1FA4 /* TimelinesTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelinesTableViewCell.swift; sourceTree = "<group>"; };
15C91A01216AB2D600D97DC3 /* AlertView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AlertView.xib; sourceTree = "<group>"; };
15C91A03216AB32500D97DC3 /* AlertView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertView.swift; sourceTree = "<group>"; };
@ -290,7 +300,6 @@
isa = PBXGroup;
children = (
1539509021894A38009BA6E7 /* AlertManager.swift */,
1574148C2169AD0100C841BD /* AttachmentManager.swift */,
15960E7B213272CD00C38CE9 /* AuthenticationManager.swift */,
152FBCE521978C4A0079B3E8 /* CellHeightManager.swift */,
15A79B42215EB959007A326E /* CoreDataManager.swift */,
@ -306,14 +315,16 @@
children = (
15C91A03216AB32500D97DC3 /* AlertView.swift */,
15C91A01216AB2D600D97DC3 /* AlertView.xib */,
153418A121A0EEAC002F5F8A /* AttachmentInputView.swift */,
153418A321A0EEED002F5F8A /* AttachmentInputView.xib */,
15A9AFE621AFA243008789E8 /* AttachmentsView.swift */,
15A9AFD721AF8382008789E8 /* AttachmentsView.xib */,
15222806219D37A500D2E5A6 /* ComposeAccessoryView.swift */,
159B5539219D11E600964AC0 /* ComposeAccessoryView.xib */,
15131EF1216D8D570092B252 /* StatusView.swift */,
15131ED7216D8C680092B252 /* StatusView.xib */,
1534189D21A0E19F002F5F8A /* VisibilityInputView.swift */,
1534189F21A0E25A002F5F8A /* VisibilityInputView.xib */,
153418A121A0EEAC002F5F8A /* AttachmentInputView.swift */,
153418A321A0EEED002F5F8A /* AttachmentInputView.xib */,
);
name = "Reusable Views";
sourceTree = "<group>";
@ -435,12 +446,13 @@
151AD4AF2166DDA000F07403 /* Extensions */,
15960E7121322B9F00C38CE9 /* Keychain Helper */,
151AD4AC2166DD0200F07403 /* Managers */,
151AD4AD2166DD1B00F07403 /* Reusable Views */,
151AD4AB2166DCEE00F07403 /* Storyboards */,
152FBCE4219789450079B3E8 /* Abstract View Controllers */,
15960E782132383600C38CE9 /* View Controllers */,
151AD4AE2166DD3500F07403 /* Table View Cells */,
1562EEB121AB46DF003A2DCD /* Views */,
151AD4AD2166DD1B00F07403 /* Reusable Views */,
151AD4AE2166DD3500F07403 /* Table View Cells */,
15A9AFE821B10531008789E8 /* Collection View Cells */,
);
path = "elpha-ios";
sourceTree = "<group>";
@ -476,6 +488,17 @@
name = "View Controllers";
sourceTree = "<group>";
};
15A9AFE821B10531008789E8 /* Collection View Cells */ = {
isa = PBXGroup;
children = (
15B7A56821B122FF00D20DBE /* ImageAttachmentCollectionViewCell.swift */,
15B7A56921B122FF00D20DBE /* ImageAttachmentCollectionViewCell.xib */,
15B7A56421B120CA00D20DBE /* VideoAttachmentCollectionViewCell.swift */,
15B7A56521B120CA00D20DBE /* VideoAttachmentCollectionViewCell.xib */,
);
name = "Collection View Cells";
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@ -654,10 +677,13 @@
159B553A219D11E600964AC0 /* ComposeAccessoryView.xib in Resources */,
15C91A02216AB2D600D97DC3 /* AlertView.xib in Resources */,
153418A021A0E25A002F5F8A /* VisibilityInputView.xib in Resources */,
15B7A56B21B122FF00D20DBE /* ImageAttachmentCollectionViewCell.xib in Resources */,
15960E64213145E200C38CE9 /* Assets.xcassets in Resources */,
157405B12151A5DA00EEAAEB /* README.md in Resources */,
15960E62213145E100C38CE9 /* Main.storyboard in Resources */,
15B7A56721B120CA00D20DBE /* VideoAttachmentCollectionViewCell.xib in Resources */,
15131ED8216D8C680092B252 /* StatusView.xib in Resources */,
15A9AFD821AF8382008789E8 /* AttachmentsView.xib in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -675,6 +701,7 @@
15960E84213774FC00C38CE9 /* InstancesTableViewController.swift in Sources */,
15960E7021321FA500C38CE9 /* Elpha.xcdatamodeld in Sources */,
15F9981721629965009E58DA /* TimelineTableViewController.swift in Sources */,
15B7A56621B120CA00D20DBE /* VideoAttachmentCollectionViewCell.swift in Sources */,
157405B42151A93E00EEAAEB /* InstancesDataManager.swift in Sources */,
156FF0312174797E0074D9CA /* StatusTableViewController.swift in Sources */,
152FB0F8218ADC1A001D6574 /* AttachmentPageViewController.swift in Sources */,
@ -698,17 +725,18 @@
15960E7721322C6F00C38CE9 /* Configuration.swift in Sources */,
156FF07021779C570074D9CA /* MastodonAPI.swift in Sources */,
15341866219FF29D002F5F8A /* SettingsManager.swift in Sources */,
15A9AFE721AFA243008789E8 /* AttachmentsView.swift in Sources */,
15C91A04216AB32500D97DC3 /* AlertView.swift in Sources */,
15131EF6216DBA820092B252 /* AccountNavigationController.swift in Sources */,
15960E7521322BF800C38CE9 /* KeychainWrapper.swift in Sources */,
157405A82150588A00EEAAEB /* InstanceViewController.swift in Sources */,
15B7A56A21B122FF00D20DBE /* ImageAttachmentCollectionViewCell.swift in Sources */,
15960E7321322BC700C38CE9 /* KeychainItemAccessibility.swift in Sources */,
156FF051217683270074D9CA /* StatusTableViewCell.swift in Sources */,
159026D02163069600D362DD /* Date+TimeAgo.swift in Sources */,
152FBCD2219682E80079B3E8 /* AbstractStatusTableViewController.swift in Sources */,
15A79B43215EB959007A326E /* CoreDataManager.swift in Sources */,
15BB72AB2171A8D4002F1FA4 /* TimelinesTableViewCell.swift in Sources */,
1574148D2169AD0100C841BD /* AttachmentManager.swift in Sources */,
156FF015217289380074D9CA /* AccountTableViewCell.swift in Sources */,
15960E822136668500C38CE9 /* TimelinesNavigationController.swift in Sources */,
1506C5802199709200EFB483 /* SettingsTableViewController.swift in Sources */,

21
elpha-ios/AbstractStatusTableViewController.swift

@ -6,6 +6,7 @@
// Copyright © 2018 Elpha. All rights reserved.
//
import AVKit
import CoreData
import UIKit
import SafariServices
@ -66,11 +67,21 @@ class AbstractStatusTableViewController: UITableViewController, StatusViewDelega
}
func attachmentTapped(_ sender: Any, status: StatusMO, index: Int) {
if let controller = storyboard().instantiateViewController(withIdentifier: "AttachmentPageViewController") as? AttachmentPageViewController {
controller.status = status
controller.attachmentIndex = index
present(controller, animated: false)
if let attachment = status.attachments?[index] as? AttachmentMO, let attachmentType = AttachmentType(rawValue: attachment.type!) {
switch attachmentType {
case .video, .gifv:
let avController = AVPlayerViewController()
avController.player = AVPlayer(url: attachment.url!)
avController.entersFullScreenWhenPlaybackBegins = false
present(avController, animated: true)
default:
if let controller = storyboard().instantiateViewController(withIdentifier: "AttachmentPageViewController") as? AttachmentPageViewController {
controller.status = status
controller.attachmentIndex = index
present(controller, animated: false)
}
}
}
}

12
elpha-ios/Assets.xcassets/Icons/Placeholder Half.imageset/Contents.json

@ -0,0 +1,12 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "placeholder-half.pdf"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

BIN
elpha-ios/Assets.xcassets/Icons/Placeholder Half.imageset/placeholder-half.pdf

12
elpha-ios/Assets.xcassets/Icons/Placeholder Small.imageset/Contents.json

@ -0,0 +1,12 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "placeholder-small.pdf"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

BIN
elpha-ios/Assets.xcassets/Icons/Placeholder Small.imageset/placeholder-small.pdf

12
elpha-ios/Assets.xcassets/Icons/Placeholder.imageset/Contents.json

@ -0,0 +1,12 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "placeholder.pdf"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

BIN
elpha-ios/Assets.xcassets/Icons/Placeholder.imageset/placeholder.pdf

207
elpha-ios/AttachmentManager.swift

@ -1,207 +0,0 @@
//
// AttachmentManager.swift
// elpha-ios
//
// Created by Dwayne Harris on 10/6/18.
// Copyright © 2018 Elpha. All rights reserved.
//
import Kingfisher
import UIKit
protocol AttachmentManagerDelegate: class {
func attachmentTapped(_ sender: Any, index: Int)
}
class AttachmentManager: NSObject {
weak var delegate: AttachmentManagerDelegate?
@objc func attachmentTapped(_ gestureRecognizer: UITapGestureRecognizer) {
if let delegate = delegate, let name = gestureRecognizer.name {
delegate.attachmentTapped(self, index: Int(name)!)
}
}
func setupAttachmentView(_ view: UIView, withAttachments attachments: NSOrderedSet?) {
guard let attachments = attachments, attachments.count > 0 else {
return
}
let placeholder = UIImage(named: "Help")
let halfWidth = (view.frame.width / 2) - 1
let fullSize = CGSize(width: view.frame.width, height: view.frame.width)
let tallSize = CGSize(width: halfWidth, height: view.frame.width)
let smallSize = CGSize(width: halfWidth, height: halfWidth)
let fullResizingProcessor = ResizingImageProcessor(referenceSize: fullSize, mode: .aspectFill) >> CroppingImageProcessor(size: fullSize)
let tallResizingProcessor = ResizingImageProcessor(referenceSize: tallSize, mode: .aspectFill) >> CroppingImageProcessor(size: tallSize)
let smallResizingProcessor = ResizingImageProcessor(referenceSize: smallSize, mode: .aspectFill) >> CroppingImageProcessor(size: smallSize)
for subview in view.subviews as [UIView] {
subview.removeFromSuperview()
}
switch attachments.count {
case 0:
return
case 1:
let attachment = attachments.firstObject as! AttachmentMO
let imageView = UIImageView()
imageView.contentMode = UIImageView.ContentMode.scaleAspectFill
imageView.isUserInteractionEnabled = true
imageView.kf.indicatorType = .activity
imageView.kf.setImage(with: attachment.url!, placeholder: placeholder, options: [.processor(fullResizingProcessor)])
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(attachmentTapped))
tapGestureRecognizer.delegate = self
tapGestureRecognizer.numberOfTapsRequired = 1
tapGestureRecognizer.numberOfTouchesRequired = 1
tapGestureRecognizer.name = "0"
imageView.addGestureRecognizer(tapGestureRecognizer)
view.addSubview(imageView)
imageView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
imageView.topAnchor.constraint(equalTo: view.topAnchor),
imageView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
imageView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
imageView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
])
case 2:
let imageViews = [
UIImageView(),
UIImageView(),
]
for (index, imageView) in imageViews.enumerated() {
let attachment = attachments[index] as! AttachmentMO
imageView.contentMode = UIImageView.ContentMode.scaleAspectFill
imageView.isUserInteractionEnabled = true
imageView.kf.indicatorType = .activity
imageView.kf.setImage(with: attachment.url!, placeholder: placeholder, options: [.processor(tallResizingProcessor)])
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(attachmentTapped))
tapGestureRecognizer.delegate = self
tapGestureRecognizer.numberOfTapsRequired = 1
tapGestureRecognizer.numberOfTouchesRequired = 1
tapGestureRecognizer.name = String(index)
imageView.addGestureRecognizer(tapGestureRecognizer)
view.addSubview(imageView)
imageView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
imageView.topAnchor.constraint(equalTo: view.topAnchor),
imageView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
imageView.widthAnchor.constraint(equalToConstant: halfWidth),
])
}
NSLayoutConstraint.activate([
imageViews[0].leadingAnchor.constraint(equalTo: view.leadingAnchor),
imageViews[1].trailingAnchor.constraint(equalTo: view.trailingAnchor),
])
case 3:
let imageViews = [
UIImageView(),
UIImageView(),
UIImageView(),
]
for (index, imageView) in imageViews.enumerated() {
let attachment = attachments[index] as! AttachmentMO
var processor: ImageProcessor
if index == 0 {
processor = tallResizingProcessor
} else {
processor = smallResizingProcessor
}
imageView.contentMode = UIImageView.ContentMode.scaleAspectFill
imageView.isUserInteractionEnabled = true
imageView.kf.indicatorType = .activity
imageView.kf.setImage(with: attachment.url!, placeholder: placeholder, options: [.processor(processor)])
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(attachmentTapped))
tapGestureRecognizer.delegate = self
tapGestureRecognizer.numberOfTapsRequired = 1
tapGestureRecognizer.numberOfTouchesRequired = 1
tapGestureRecognizer.name = String(index)
imageView.addGestureRecognizer(tapGestureRecognizer)
view.addSubview(imageView)
imageView.translatesAutoresizingMaskIntoConstraints = false
if index == 0 {
NSLayoutConstraint.activate([
imageView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
imageView.topAnchor.constraint(equalTo: view.topAnchor),
imageView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
imageView.widthAnchor.constraint(equalToConstant: halfWidth),
])
} else {
NSLayoutConstraint.activate([
imageView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
imageView.widthAnchor.constraint(equalToConstant: halfWidth),
imageView.heightAnchor.constraint(equalToConstant: halfWidth),
])
}
}
NSLayoutConstraint.activate([
imageViews[1].topAnchor.constraint(equalTo: view.topAnchor),
imageViews[2].bottomAnchor.constraint(equalTo: view.bottomAnchor),
])
default:
let imageViews = [
UIImageView(),
UIImageView(),
UIImageView(),
UIImageView(),
]
for (index, imageView) in imageViews.enumerated() {
let attachment = attachments[index] as! AttachmentMO
imageView.contentMode = UIImageView.ContentMode.scaleAspectFill
imageView.isUserInteractionEnabled = true
imageView.kf.indicatorType = .activity
imageView.kf.setImage(with: attachment.url!, placeholder: placeholder, options: [.processor(smallResizingProcessor)])
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(attachmentTapped))
tapGestureRecognizer.delegate = self
tapGestureRecognizer.numberOfTapsRequired = 1
tapGestureRecognizer.numberOfTouchesRequired = 1
tapGestureRecognizer.name = String(index)
imageView.addGestureRecognizer(tapGestureRecognizer)
view.addSubview(imageView)
imageView.translatesAutoresizingMaskIntoConstraints = false
}
NSLayoutConstraint.activate([
imageViews[0].topAnchor.constraint(equalTo: view.topAnchor),
imageViews[0].leadingAnchor.constraint(equalTo: view.leadingAnchor),
imageViews[1].topAnchor.constraint(equalTo: view.topAnchor),
imageViews[1].trailingAnchor.constraint(equalTo: view.trailingAnchor),
imageViews[2].leadingAnchor.constraint(equalTo: view.leadingAnchor),
imageViews[2].bottomAnchor.constraint(equalTo: view.bottomAnchor),
imageViews[3].bottomAnchor.constraint(equalTo: view.bottomAnchor),
imageViews[3].trailingAnchor.constraint(equalTo: view.trailingAnchor),
])
}
}
}
extension AttachmentManager: UIGestureRecognizerDelegate {
}

111
elpha-ios/AttachmentsView.swift

@ -0,0 +1,111 @@
//
// AttachmentsView.swift
// elpha-ios
//
// Created by Dwayne Harris on 11/28/18.
// Copyright © 2018 Elpha. All rights reserved.
//
import UIKit
protocol AttachmentsViewDelegate: class {
func attachmentTapped(_ sender: Any, index: Int)
}
class AttachmentsView: UIView {
@IBOutlet var contentView: UIView!
@IBOutlet var attachmentsCollectionView: UICollectionView!
var attachments: [AttachmentMO]?
weak var delegate: AttachmentsViewDelegate?
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
private func setup() {
Bundle.main.loadNibNamed("AttachmentsView", owner: self, options: nil)
addSubview(contentView)
contentView.frame = self.bounds
contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
attachmentsCollectionView.dataSource = self
attachmentsCollectionView.delegate = self
attachmentsCollectionView.register(UINib(nibName: "ImageAttachmentCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "ImageAttachmentCollectionViewCell")
attachmentsCollectionView.register(UINib(nibName: "VideoAttachmentCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "VideoAttachmentCollectionViewCell")
}
func update(withAttachments attachments: [AttachmentMO]) {
self.attachments = attachments
attachmentsCollectionView.collectionViewLayout.invalidateLayout()
attachmentsCollectionView.reloadData()
attachmentsCollectionView.setNeedsLayout()
}
}
extension AttachmentsView: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return attachments?.count ?? 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let attachment = attachments?[indexPath.row] else {
fatalError("")
}
let attachmentType = AttachmentType(rawValue: attachment.type!)!
switch attachmentType {
case .gifv, .video:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "VideoAttachmentCollectionViewCell", for: indexPath) as! VideoAttachmentCollectionViewCell
cell.update(withAttachment: attachment)
return cell
default:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ImageAttachmentCollectionViewCell", for: indexPath) as! ImageAttachmentCollectionViewCell
cell.update(withAttachment: attachment)
return cell
}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
delegate?.attachmentTapped(self, index: indexPath.row)
}
}
extension AttachmentsView: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let halfWidth = (frame.size.width / 2) - 1
let tallSize = CGSize(width: halfWidth, height: frame.size.width)
let smallSize = CGSize(width: halfWidth, height: halfWidth)
switch attachments?.count ?? 0 {
case 1: return CGSize(width: frame.size.width, height: frame.size.width)
case 2: return tallSize
case 3: return indexPath.row == 0 ? tallSize : smallSize
case 4: return smallSize
default: return CGSize.zero
}
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 2
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets.zero
}
}

49
elpha-ios/AttachmentsView.xib

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="AttachmentsView" customModule="elpha_ios" customModuleProvider="target">
<connections>
<outlet property="attachmentsCollectionView" destination="XgR-gy-s01" id="392-HX-a4n"/>
<outlet property="contentView" destination="iN0-l3-epB" id="wc2-nq-QWB"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB">
<rect key="frame" x="0.0" y="0.0" width="375" height="375"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" scrollEnabled="NO" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" dataMode="none" prefetchingEnabled="NO" translatesAutoresizingMaskIntoConstraints="NO" id="XgR-gy-s01">
<rect key="frame" x="0.0" y="0.0" width="375" height="375"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<collectionViewFlowLayout key="collectionViewLayout" scrollDirection="horizontal" minimumLineSpacing="10" minimumInteritemSpacing="10" id="aaI-cP-xj8">
<size key="itemSize" width="50" height="50"/>
<size key="headerReferenceSize" width="0.0" height="0.0"/>
<size key="footerReferenceSize" width="0.0" height="0.0"/>
<inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
</collectionViewFlowLayout>
</collectionView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="XgR-gy-s01" secondAttribute="trailing" id="MKv-iq-hUD"/>
<constraint firstItem="XgR-gy-s01" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" id="MRt-HO-y16"/>
<constraint firstItem="XgR-gy-s01" firstAttribute="top" secondItem="vUN-kp-3ea" secondAttribute="top" id="ba3-15-hfG"/>
<constraint firstItem="vUN-kp-3ea" firstAttribute="bottom" secondItem="XgR-gy-s01" secondAttribute="bottom" id="yCC-41-Mwc"/>
</constraints>
<nil key="simulatedTopBarMetrics"/>
<nil key="simulatedBottomBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
<point key="canvasLocation" x="138.40000000000001" y="284.70764617691157"/>
</view>
</objects>
</document>

9
elpha-ios/Base.lproj/Main.storyboard

@ -1452,10 +1452,10 @@
</connections>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="bsb-4z-qCl">
<rect key="frame" x="0.0" y="150" width="375" height="415"/>
<rect key="frame" x="0.0" y="150" width="375" height="40"/>
<subviews>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" scrollEnabled="NO" editable="NO" text="Content" textAlignment="natural" translatesAutoresizingMaskIntoConstraints="NO" id="Qno-L9-nUh" customClass="UITextViewFixed" customModule="elpha_ios" customModuleProvider="target">
<rect key="frame" x="8" y="8" width="359" height="399"/>
<rect key="frame" x="8" y="8" width="359" height="24"/>
<color key="backgroundColor" name="Background Primary"/>
<color key="tintColor" name="Primary"/>
<color key="textColor" name="Text"/>
@ -1472,9 +1472,8 @@
<constraint firstAttribute="trailing" secondItem="Qno-L9-nUh" secondAttribute="trailing" constant="8" id="pub-Jf-c6W"/>
</constraints>
</view>
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="7SO-v5-Rfd">
<rect key="frame" x="0.0" y="565" width="375" height="375"/>
<color key="backgroundColor" white="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="7SO-v5-Rfd" customClass="AttachmentsView" customModule="elpha_ios" customModuleProvider="target">
<rect key="frame" x="0.0" y="190" width="375" height="375"/>
<constraints>
<constraint firstAttribute="width" secondItem="7SO-v5-Rfd" secondAttribute="height" multiplier="1:1" id="OxV-Aa-cex"/>
</constraints>

24
elpha-ios/ImageAttachmentCollectionViewCell.swift

@ -0,0 +1,24 @@
//
// ImageAttachmentCollectionViewCell.swift
// elpha-ios
//
// Created by Dwayne Harris on 11/29/18.
// Copyright © 2018 Elpha. All rights reserved.
//
import Kingfisher
import UIKit
class ImageAttachmentCollectionViewCell: UICollectionViewCell {
@IBOutlet var imageView: UIImageView!
var attachment: AttachmentMO?
override func awakeFromNib() {
super.awakeFromNib()
}
func update(withAttachment attachment: AttachmentMO) {
self.attachment = attachment
imageView.kf.setImage(with: attachment.url!, placeholder: UIImage(named: "Placeholder"))
}
}

39
elpha-ios/ImageAttachmentCollectionViewCell.xib

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="ImageAttachmentCollectionViewCell" id="gTV-IL-0wX" customClass="ImageAttachmentCollectionViewCell" customModule="elpha_ios" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="375" height="375"/>
<autoresizingMask key="autoresizingMask"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
<rect key="frame" x="0.0" y="0.0" width="375" height="375"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<imageView clipsSubviews="YES" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="X7C-Rz-5zN">
<rect key="frame" x="0.0" y="0.0" width="375" height="375"/>
</imageView>
</subviews>
</view>
<constraints>
<constraint firstAttribute="trailing" secondItem="X7C-Rz-5zN" secondAttribute="trailing" id="58Q-wS-bVY"/>
<constraint firstAttribute="bottom" secondItem="X7C-Rz-5zN" secondAttribute="bottom" id="A26-zo-rCZ"/>
<constraint firstItem="X7C-Rz-5zN" firstAttribute="top" secondItem="gTV-IL-0wX" secondAttribute="top" id="Cxe-QE-g8T"/>
<constraint firstItem="X7C-Rz-5zN" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" id="KZG-bH-MzT"/>
</constraints>
<viewLayoutGuide key="safeArea" id="ZTg-uK-7eu"/>
<connections>
<outlet property="imageView" destination="X7C-Rz-5zN" id="WMo-NR-zpQ"/>
</connections>
</collectionViewCell>
</objects>
</document>

2
elpha-ios/MainStatusTableViewCell.swift

@ -21,7 +21,7 @@ class MainStatusTableViewCell: UITableViewCell {
@IBOutlet var accountView: UIView!
@IBOutlet var timestampDateLabel: UILabel!
@IBOutlet var timestampTimeLabel: UILabel!
@IBOutlet var attachmentsView: UIView!
@IBOutlet var attachmentsView: AttachmentsView!
@IBOutlet var contentTextView: UITextViewFixed!
@IBOutlet var inReplyToView: UIView!
@IBOutlet var repliesView: UIView!

24
elpha-ios/StatusTableViewController.swift

@ -189,12 +189,11 @@ class StatusTableViewController: AbstractStatusTableViewController, UIGestureRec
}
cell.statusView.delegate = self
cell.statusView.update(withStatus: status)
cell.statusView.update(withStatus: status, excludeReplyView: true)
cell.statusView.topDividerView.isHidden = indexPath.row == 0
cell.statusView.bottomDividerView.isHidden = false
cell.statusView.topLoadMoreView.isHidden = true
cell.statusView.bottomLoadMoreView.isHidden = true
cell.statusView.replyView.isHidden = true
let statusCount = fetchedResultsController?.fetchedObjects?.count ?? 0
@ -229,16 +228,12 @@ class StatusTableViewController: AbstractStatusTableViewController, UIGestureRec
cell.contentTextView.attributedText = content.htmlAttributed(size: 16)
}
cell.attachmentsView.backgroundColor = UIColor.white
cell.attachmentsView.isHidden = true
if let attachments = status.attachments, attachments.count > 0 {
cell.attachmentsView.isHidden = false
cell.attachmentsView.isUserInteractionEnabled = true
let attachmentManager = AttachmentManager()
attachmentManager.delegate = self
attachmentManager.setupAttachmentView(cell.attachmentsView, withAttachments: attachments)
cell.attachmentsView.delegate = self
cell.attachmentsView.update(withAttachments: attachments.array as! [AttachmentMO])
} else {
cell.attachmentsView.isHidden = true
}
let dateFormatter = DateFormatter()
@ -268,15 +263,16 @@ class StatusTableViewController: AbstractStatusTableViewController, UIGestureRec
cell.favoritesImageView.image = UIImage(named: "Star Regular")
}
cell.inReplyToView.isHidden = true
cell.repliesView.isHidden = true
if let ancestors = status.ancestors, ancestors.count > 0 {
cell.inReplyToView.isHidden = false
} else {
cell.inReplyToView.isHidden = true
}
if let descendants = status.descendants, descendants.count > 0 {
cell.repliesView.isHidden = false
} else {
cell.repliesView.isHidden = true
}
}
}
@ -390,7 +386,7 @@ extension StatusTableViewController {
}
}
extension StatusTableViewController: AttachmentManagerDelegate {
extension StatusTableViewController: AttachmentsViewDelegate {
func attachmentTapped(_ sender: Any, index: Int) {
self.attachmentTapped(self, status: status!, index: index)
}

37
elpha-ios/StatusView.swift

@ -44,7 +44,7 @@ class StatusView: UIView {
@IBOutlet var favoritesLabel: UILabel!
@IBOutlet var topDividerView: UIView!
@IBOutlet var bottomDividerView: UIView!
@IBOutlet var attachmentsView: UIView!
@IBOutlet var attachmentsView: AttachmentsView!
@IBOutlet var detailsView: UIView!
@IBOutlet var spoilerImageView: UIImageView!
@IBOutlet var pinImageView: UIImageView!
@ -55,7 +55,6 @@ class StatusView: UIView {
var status: StatusMO?
var spoilerView: UIVisualEffectView?
var feedbackGenerator: UINotificationFeedbackGenerator?
var attachmentManager: AttachmentManager = AttachmentManager()
weak var delegate: StatusViewDelegate?
@ -225,7 +224,7 @@ class StatusView: UIView {
Bundle.main.loadNibNamed("StatusView", owner: self, options: nil)
addSubview(contentView)
contentView.frame = self.bounds
attachmentManager.delegate = self
attachmentsView.delegate = self
contentTextView.delegate = self
feedbackGenerator = UINotificationFeedbackGenerator()
@ -234,14 +233,10 @@ class StatusView: UIView {
replyAvatarImageView.setRoundedCorners()
}
public func update(withStatus status: StatusMO) {
public func update(withStatus status: StatusMO, excludeReplyView: Bool = false) {
self.status = status
let statusCellHidden = status.hidden
boostView.isHidden = true
replyView.isHidden = true
attachmentsView.backgroundColor = UIColor.white
attachmentsView.isHidden = true
spoilerImageView.isHidden = true
let avatarOptions: KingfisherOptionsInfo = SettingsManager.automaticallyPlayGIFs ? [] : [.onlyLoadFirstFrame]
@ -255,7 +250,9 @@ class StatusView: UIView {
if let attachments = status.attachments, attachments.count > 0 {
attachmentsView.isHidden = false
attachmentManager.setupAttachmentView(attachmentsView, withAttachments: attachments)
attachmentsView.update(withAttachments: attachments.array as! [AttachmentMO])
} else {
attachmentsView.isHidden = true
}
if let content = status.content {
@ -277,8 +274,8 @@ class StatusView: UIView {
blurEffectView.contentView.addSubview(spoilerText)
NSLayoutConstraint.activate([
spoilerText.leadingAnchor.constraint(equalTo: blurEffectView.leadingAnchor),
spoilerText.trailingAnchor.constraint(equalTo: blurEffectView.trailingAnchor),
spoilerText.leadingAnchor.constraint(equalTo: blurEffectView.leadingAnchor, constant: 8),
spoilerText.trailingAnchor.constraint(equalTo: blurEffectView.trailingAnchor, constant: -8),
spoilerText.centerYAnchor.constraint(equalTo: blurEffectView.centerYAnchor),
])
@ -349,6 +346,8 @@ class StatusView: UIView {
updateStatusContent(reblog)
} else {
boostView.isHidden = true
if let account = status.account {
avatarImageView.kf.setImage(with: account.avatarURL!, options: avatarOptions)
displayNameLabel.text = account.displayName
@ -358,18 +357,18 @@ class StatusView: UIView {
updateStatusContent(status)
}
if let replyAccountID = status.inReplyToAccountID {
if let replyAccount = MastodonDataManager.account(id: replyAccountID) {
replyView.isHidden = false
replyAvatarImageView.kf.setImage(with: replyAccount.avatarURL!, options: avatarOptions)
replyDisplayNameLabel.text = replyAccount.displayName
replyUsernameLabel.text = "@\(replyAccount.acct!)"
}
if let replyAccountID = status.inReplyToAccountID, let replyAccount = MastodonDataManager.account(id: replyAccountID), !excludeReplyView {
replyView.isHidden = false
replyAvatarImageView.kf.setImage(with: replyAccount.avatarURL!, options: avatarOptions)
replyDisplayNameLabel.text = replyAccount.displayName
replyUsernameLabel.text = "@\(replyAccount.acct!)"
} else {
replyView.isHidden = true
}
}
}
extension StatusView: AttachmentManagerDelegate {
extension StatusView: AttachmentsViewDelegate {
func attachmentTapped(_ sender: Any, index: Int) {
if let delegate = delegate, let status = status {
if let reblog = status.reblog {

49
elpha-ios/StatusView.xib

@ -51,25 +51,25 @@
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="7Og-IU-seR">
<rect key="frame" x="0.0" y="20" width="375" height="851"/>
<subviews>
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="bg1-Q4-Ru5">
<rect key="frame" x="0.0" y="-5" width="375" height="5"/>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="bg1-Q4-Ru5">
<rect key="frame" x="0.0" y="0.0" width="375" height="5"/>
<color key="backgroundColor" name="Background Secondary"/>
<constraints>
<constraint firstAttribute="height" constant="5" id="hYF-M2-gmn"/>
</constraints>
</view>
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="fjq-Ff-PVL">
<rect key="frame" x="0.0" y="0.0" width="375" height="0.0"/>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="fjq-Ff-PVL">
<rect key="frame" x="0.0" y="5" width="375" height="50"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="Up" translatesAutoresizingMaskIntoConstraints="NO" id="701-8A-mp6">
<rect key="frame" x="340" y="-10" width="20" height="20"/>
<rect key="frame" x="340" y="15" width="20" height="20"/>
<constraints>
<constraint firstAttribute="width" constant="20" id="BCi-a6-e9O"/>
<constraint firstAttribute="height" constant="20" id="cD5-It-mON"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Load More" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="IRZ-QQ-s88">
<rect key="frame" x="261.5" y="-8.5" width="68.5" height="17"/>
<rect key="frame" x="261.5" y="16.5" width="68.5" height="17"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<color key="textColor" name="Text"/>
<nil key="highlightedColor"/>
@ -88,8 +88,8 @@
<outletCollection property="gestureRecognizers" destination="7gE-ee-xzN" appends="YES" id="tk2-yl-qwQ"/>
</connections>
</view>
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Gnt-jG-tVj">
<rect key="frame" x="0.0" y="0.0" width="375" height="0.0"/>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Gnt-jG-tVj">
<rect key="frame" x="0.0" y="55" width="375" height="100"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="ecc-6t-6K0">
<rect key="frame" x="8" y="20" width="40" height="40"/>
@ -118,7 +118,7 @@
<nil key="highlightedColor"/>
</label>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="8qF-OR-rh0">
<rect key="frame" x="20" y="-7" width="335" height="2"/>
<rect key="frame" x="20" y="93" width="335" height="2"/>
<color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
<constraints>
<constraint firstAttribute="height" constant="2" id="Eyr-af-p55"/>
@ -156,8 +156,8 @@
<outletCollection property="gestureRecognizers" destination="2h0-to-AXg" appends="YES" id="ZUZ-hR-mUu"/>
</connections>
</view>
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="v8x-tf-zFb">
<rect key="frame" x="0.0" y="0.0" width="375" height="0.0"/>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="v8x-tf-zFb">
<rect key="frame" x="0.0" y="155" width="375" height="100"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="wte-HK-KxR">
<rect key="frame" x="8" y="20" width="40" height="40"/>
@ -186,7 +186,7 @@
<nil key="highlightedColor"/>
</label>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="LZx-68-NPT">
<rect key="frame" x="20" y="-7" width="335" height="2"/>
<rect key="frame" x="20" y="93" width="335" height="2"/>
<color key="backgroundColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="2" id="oQt-n9-x3j"/>
@ -225,7 +225,7 @@
</connections>
</view>
<view contentMode="scaleToFill" verticalHuggingPriority="249" translatesAutoresizingMaskIntoConstraints="NO" id="cAR-YB-u2k">
<rect key="frame" x="0.0" y="0.0" width="375" height="801"/>
<rect key="frame" x="0.0" y="255" width="375" height="116"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="50m-cW-QIF">
<rect key="frame" x="0.0" y="8" width="367" height="70"/>
@ -268,7 +268,7 @@
</connections>
</view>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" scrollEnabled="NO" editable="NO" text="Content" textAlignment="natural" translatesAutoresizingMaskIntoConstraints="NO" id="o7b-at-xQ9" customClass="UITextViewFixed" customModule="elpha_ios" customModuleProvider="target">
<rect key="frame" x="8" y="86" width="359" height="715"/>
<rect key="frame" x="8" y="86" width="359" height="22"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="tintColor" name="Primary"/>
<gestureRecognizers/>
@ -287,7 +287,7 @@
<constraint firstItem="o7b-at-xQ9" firstAttribute="leading" secondItem="cAR-YB-u2k" secondAttribute="leading" constant="8" id="2NC-sT-kEN"/>
<constraint firstAttribute="trailing" secondItem="50m-cW-QIF" secondAttribute="trailing" constant="8" id="FxM-Hx-2Do"/>
<constraint firstAttribute="trailing" secondItem="o7b-at-xQ9" secondAttribute="trailing" constant="8" id="Ops-Ze-Eya"/>
<constraint firstAttribute="bottom" secondItem="o7b-at-xQ9" secondAttribute="bottom" id="Wc8-dM-g26"/>
<constraint firstAttribute="bottom" secondItem="o7b-at-xQ9" secondAttribute="bottom" constant="8" id="Wc8-dM-g26"/>
<constraint firstItem="50m-cW-QIF" firstAttribute="top" secondItem="cAR-YB-u2k" secondAttribute="top" constant="8" id="dNY-jH-OpT"/>
<constraint firstItem="50m-cW-QIF" firstAttribute="leading" secondItem="cAR-YB-u2k" secondAttribute="leading" id="diD-1N-0MJ"/>
<constraint firstItem="o7b-at-xQ9" firstAttribute="top" secondItem="50m-cW-QIF" secondAttribute="bottom" constant="8" id="t4P-Dj-0Il"/>
@ -296,15 +296,14 @@
<outletCollection property="gestureRecognizers" destination="9fc-Py-yTV" appends="YES" id="nDQ-45-6W2"/>
</connections>
</view>
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="XuS-iF-YYL">
<rect key="frame" x="0.0" y="801" width="375" height="0.0"/>
<color key="backgroundColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="XuS-iF-YYL" customClass="AttachmentsView" customModule="elpha_ios" customModuleProvider="target">
<rect key="frame" x="0.0" y="371" width="375" height="375"/>
<constraints>
<constraint firstAttribute="width" secondItem="XuS-iF-YYL" secondAttribute="height" multiplier="1:1" priority="999" id="8CQ-GM-Un6"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="y5N-A7-27p">
<rect key="frame" x="0.0" y="801" width="375" height="50"/>
<rect key="frame" x="0.0" y="746" width="375" height="50"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="pJk-g2-yyR">
<rect key="frame" x="8" y="10" width="155" height="30"/>
@ -462,18 +461,18 @@
<constraint firstItem="ZKM-hs-NVu" firstAttribute="leading" secondItem="pJk-g2-yyR" secondAttribute="trailing" constant="8" id="s4k-Oq-Qhh"/>
</constraints>
</view>
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="0aT-X9-NYg">
<rect key="frame" x="0.0" y="851" width="375" height="0.0"/>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="0aT-X9-NYg">
<rect key="frame" x="0.0" y="796" width="375" height="50"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="Down" translatesAutoresizingMaskIntoConstraints="NO" id="zEk-jb-LHL">
<rect key="frame" x="15" y="-10" width="20" height="20"/>
<rect key="frame" x="15" y="15" width="20" height="20"/>
<constraints>
<constraint firstAttribute="width" constant="20" id="6Un-al-jZp"/>
<constraint firstAttribute="height" constant="20" id="M2K-o2-1k4"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Load More" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="znl-Zz-bfs">
<rect key="frame" x="45" y="-8.5" width="68.5" height="17"/>
<rect key="frame" x="45" y="16.5" width="68.5" height="17"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<color key="textColor" name="Text"/>
<nil key="highlightedColor"/>
@ -492,8 +491,8 @@
<outletCollection property="gestureRecognizers" destination="o5u-JP-Bmz" appends="YES" id="Wxi-2I-YXA"/>
</connections>
</view>
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="m4t-ve-E78">
<rect key="frame" x="0.0" y="851" width="375" height="0.0"/>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="m4t-ve-E78">
<rect key="frame" x="0.0" y="846" width="375" height="5"/>
<color key="backgroundColor" name="Background Secondary"/>
<constraints>
<constraint firstAttribute="height" priority="999" constant="5" id="QFa-Y9-r5a"/>

42
elpha-ios/VideoAttachmentCollectionViewCell.swift

@ -0,0 +1,42 @@
//
// VideoAttachmentCollectionViewCell.swift
// elpha-ios
//
// Created by Dwayne Harris on 11/29/18.
// Copyright © 2018 Elpha. All rights reserved.
//
import AVFoundation
import AVKit
import UIKit
class VideoAttachmentCollectionViewCell: UICollectionViewCell {
var attachment: AttachmentMO?
var player: AVQueuePlayer!
var playerLayer: AVPlayerLayer!
var playerLooper: AVPlayerLooper?
override func awakeFromNib() {
super.awakeFromNib()
player = AVQueuePlayer()
player.preventsDisplaySleepDuringVideoPlayback = false
player.usesExternalPlaybackWhileExternalScreenIsActive = false
player.isMuted = true
playerLayer = AVPlayerLayer(player: player)
playerLayer.videoGravity = .resizeAspectFill
}
func update(withAttachment attachment: AttachmentMO) {
self.attachment = attachment
layer.addSublayer(playerLayer)
playerLayer.frame = bounds
playerLooper = AVPlayerLooper(player: player!, templateItem: AVPlayerItem(url: attachment.url!))
if SettingsManager.automaticallyPlayGIFs {
player.play()
}
}
}

25
elpha-ios/VideoAttachmentCollectionViewCell.xib

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="VideoAttachmentCollectionViewCell" id="gTV-IL-0wX" customClass="VideoAttachmentCollectionViewCell" customModule="elpha_ios" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="50" height="50"/>
<autoresizingMask key="autoresizingMask"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
<rect key="frame" x="0.0" y="0.0" width="50" height="50"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
</view>
<viewLayoutGuide key="safeArea" id="ZTg-uK-7eu"/>
</collectionViewCell>
</objects>
</document>
Loading…
Cancel
Save