Add timelapse viewing functionality
This commit is contained in:
parent
51575e1e5a
commit
7f95910528
6 changed files with 118 additions and 5 deletions
|
@ -14,6 +14,7 @@
|
|||
030F700E2415C6B500A43F01 /* PreviewViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 030F700D2415C6B500A43F01 /* PreviewViewController.swift */; };
|
||||
030F70112415C6B500A43F01 /* PreviewViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 030F700F2415C6B500A43F01 /* PreviewViewController.xib */; };
|
||||
030F70162415C6B500A43F01 /* QuickLook.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 030F70082415C6B500A43F01 /* QuickLook.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
033F94F92648B8E200099FB7 /* TimelapseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 033F94F82648B8E200099FB7 /* TimelapseViewController.swift */; };
|
||||
036AFBB8241687680075400A /* ZIPFoundation in Frameworks */ = {isa = PBXBuildFile; productRef = 036AFBB7241687680075400A /* ZIPFoundation */; };
|
||||
036AFBBA24168C030075400A /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 036AFBB924168C030075400A /* ViewController.swift */; };
|
||||
036AFBE32417F0A00075400A /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 036AFBE12417F0A00075400A /* Main.storyboard */; };
|
||||
|
@ -87,6 +88,7 @@
|
|||
030F70102415C6B500A43F01 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/PreviewViewController.xib; sourceTree = "<group>"; };
|
||||
030F70122415C6B500A43F01 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
030F70132415C6B500A43F01 /* Quicklook.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Quicklook.entitlements; sourceTree = "<group>"; };
|
||||
033F94F82648B8E200099FB7 /* TimelapseViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelapseViewController.swift; sourceTree = "<group>"; };
|
||||
036AFBB924168C030075400A /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
|
||||
036AFBE22417F0A00075400A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||
036AFC0B241800350075400A /* Thumbnail.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = Thumbnail.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
|
@ -181,6 +183,7 @@
|
|||
037B4041241821D200392452 /* InfoViewController.swift */,
|
||||
03CB382324191F620078B3E5 /* cbridge.c */,
|
||||
03CB382224191F610078B3E5 /* ProcreateViewer-Bridging-Header.h */,
|
||||
033F94F82648B8E200099FB7 /* TimelapseViewController.swift */,
|
||||
);
|
||||
path = ProcreateViewer;
|
||||
sourceTree = "<group>";
|
||||
|
@ -413,6 +416,7 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
03CB3840241A5AED0078B3E5 /* Shared.swift in Sources */,
|
||||
033F94F92648B8E200099FB7 /* TimelapseViewController.swift in Sources */,
|
||||
036AFBBA24168C030075400A /* ViewController.swift in Sources */,
|
||||
03CB382424191F620078B3E5 /* cbridge.c in Sources */,
|
||||
030F6FF42415C5E300A43F01 /* Document.swift in Sources */,
|
||||
|
|
|
@ -6,8 +6,13 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations {
|
|||
NSApplication.shared.keyWindow?.contentViewController?.performSegue(withIdentifier: "showInfo", sender: self)
|
||||
}
|
||||
|
||||
@IBAction func showTimelapseAction(_ sender: Any) {
|
||||
NSApplication.shared.keyWindow?.contentViewController?.performSegue(withIdentifier: "showTimelapse", sender: self)
|
||||
}
|
||||
|
||||
func validateUserInterfaceItem(_ item: NSValidatedUserInterfaceItem) -> Bool {
|
||||
if(item.tag == 67) {
|
||||
// Show timelapse and show info buttons
|
||||
if(item.tag == 67 || item.tag == 68) {
|
||||
return NSApplication.shared.keyWindow != nil
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="15705" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="17156" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="15705"/>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.AVKitIBPlugin" version="17156"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="17156"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
|
@ -96,6 +98,12 @@
|
|||
<action selector="showInfoAction:" target="Voe-Tx-rLC" id="3A0-GP-3ZY"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Show Timelapse" tag="68" id="nSM-YZ-MTX">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="showTimelapseAction:" target="Voe-Tx-rLC" id="kfN-ET-oSo"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="hB3-LF-h0Y"/>
|
||||
<menuItem title="Enter Full Screen" keyEquivalent="f" id="4J7-dP-txa">
|
||||
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
|
||||
|
@ -184,7 +192,7 @@ Dk51bWJlciBvZiBMYXllcnM6A
|
|||
</textFieldCell>
|
||||
</textField>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="2oe-to-Rcz">
|
||||
<rect key="frame" x="407" y="13" width="59" height="32"/>
|
||||
<rect key="frame" x="414" y="14" width="53" height="32"/>
|
||||
<buttonCell key="cell" type="push" title="OK" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="BnS-yc-3ej">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
|
@ -218,6 +226,58 @@ DQ
|
|||
<point key="canvasLocation" x="786" y="298.5"/>
|
||||
</scene>
|
||||
<!--Window Controller-->
|
||||
<scene sceneID="IIQ-mF-530">
|
||||
<objects>
|
||||
<windowController id="qzy-T7-vHd" sceneMemberID="viewController">
|
||||
<window key="window" title="Timelapse" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" frameAutosaveName="" animationBehavior="default" id="px5-oy-UC5">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
|
||||
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
||||
<rect key="contentRect" x="268" y="330" width="480" height="270"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="1792" height="1095"/>
|
||||
<view key="contentView" id="VVC-fD-7H3">
|
||||
<rect key="frame" x="0.0" y="0.0" width="480" height="270"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="qzy-T7-vHd" id="pBE-dh-gi9"/>
|
||||
</connections>
|
||||
</window>
|
||||
<connections>
|
||||
<segue destination="2g9-GV-hNg" kind="relationship" relationship="window.shadowedContentViewController" id="Bfa-oy-KMO"/>
|
||||
</connections>
|
||||
</windowController>
|
||||
<customObject id="qKM-fu-CcY" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="716" y="847"/>
|
||||
</scene>
|
||||
<!--Timelapse View Controller-->
|
||||
<scene sceneID="6lP-oO-4ie">
|
||||
<objects>
|
||||
<viewController id="2g9-GV-hNg" customClass="TimelapseViewController" customModule="Procreate_Viewer" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" id="n7g-Sv-vdB">
|
||||
<rect key="frame" x="0.0" y="0.0" width="480" height="270"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<avPlayerView controlsStyle="minimal" videoGravity="resizeAspectFill" translatesAutoresizingMaskIntoConstraints="NO" id="zOe-qf-LSc">
|
||||
<rect key="frame" x="0.0" y="0.0" width="480" height="270"/>
|
||||
</avPlayerView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" secondItem="zOe-qf-LSc" secondAttribute="trailing" id="5e2-Uh-miL"/>
|
||||
<constraint firstAttribute="bottom" secondItem="zOe-qf-LSc" secondAttribute="bottom" id="Kfx-dj-9x8"/>
|
||||
<constraint firstItem="zOe-qf-LSc" firstAttribute="top" secondItem="n7g-Sv-vdB" secondAttribute="top" id="rwV-Dr-EPg"/>
|
||||
<constraint firstItem="zOe-qf-LSc" firstAttribute="leading" secondItem="n7g-Sv-vdB" secondAttribute="leading" id="uY5-WX-NhA"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="playerView" destination="zOe-qf-LSc" id="Iy7-O4-v4P"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<customObject id="LO0-g9-QLL" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="1339" y="769"/>
|
||||
</scene>
|
||||
<!--Window Controller-->
|
||||
<scene sceneID="R2V-B0-nI4">
|
||||
<objects>
|
||||
<windowController storyboardIdentifier="Document Window Controller" id="jGA-0Y-lOj" sceneMemberID="viewController">
|
||||
|
@ -250,6 +310,9 @@ DQ
|
|||
<rect key="frame" x="0.0" y="0.0" width="480" height="270"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" id="chN-IE-x52"/>
|
||||
<connections>
|
||||
<segue destination="qzy-T7-vHd" kind="show" identifier="showTimelapse" id="x99-kP-axt"/>
|
||||
</connections>
|
||||
</imageView>
|
||||
</subviews>
|
||||
</view>
|
||||
|
@ -260,7 +323,7 @@ DQ
|
|||
</viewController>
|
||||
<customObject id="2Tp-Fl-jBw" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="59" y="761"/>
|
||||
<point key="canvasLocation" x="132" y="725"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
|
|
37
ProcreateViewer/TimelapseViewController.swift
Normal file
37
ProcreateViewer/TimelapseViewController.swift
Normal file
|
@ -0,0 +1,37 @@
|
|||
import Foundation
|
||||
import Cocoa
|
||||
import AVKit
|
||||
import AVFoundation
|
||||
import ZIPFoundation
|
||||
|
||||
class TimelapseViewController: NSViewController {
|
||||
var document: Document?
|
||||
|
||||
@IBOutlet weak var playerView: AVPlayerView!
|
||||
|
||||
override func viewWillAppear() {
|
||||
super.viewDidAppear()
|
||||
|
||||
guard let archive = Archive(data: (document?.data)!, accessMode: Archive.AccessMode.read) else {
|
||||
return
|
||||
}
|
||||
|
||||
let directory = NSTemporaryDirectory()
|
||||
|
||||
var entries: [AVPlayerItem] = []
|
||||
for entry in archive.makeIterator() {
|
||||
if entry.path.contains(VideoPath) {
|
||||
let fileName = NSUUID().uuidString + ".mp4"
|
||||
|
||||
// This returns a URL? even though it is an NSURL class method
|
||||
let fullURL = NSURL.fileURL(withPathComponents: [directory, fileName])!
|
||||
|
||||
try? archive.extract(entry, to: fullURL)
|
||||
|
||||
entries.append(AVPlayerItem(url: fullURL))
|
||||
}
|
||||
}
|
||||
|
||||
playerView?.player = AVQueuePlayer(items: entries)
|
||||
}
|
||||
}
|
|
@ -14,6 +14,8 @@ class ViewController: NSViewController {
|
|||
if(segue.identifier == "showInfo") {
|
||||
// TODO: there HAS to be a better way to pass the Document class along...
|
||||
(segue.destinationController as! InfoViewController).document = self.view.window?.windowController?.document as? Document
|
||||
} else if(segue.identifier == "showTimelapse") {
|
||||
((segue.destinationController as! NSWindowController).contentViewController as! TimelapseViewController).document = self.view.window?.windowController?.document as? Document
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@ let NSKeyedArchiveVersion = 100000
|
|||
let ThumbnailPath = "QuickLook/Thumbnail.png"
|
||||
let DocumentArchivePath = "Document.archive"
|
||||
|
||||
let VideoPath = "video/segments/"
|
||||
|
||||
let DocumentClassName = "SilicaDocument"
|
||||
let TrackedTimeKey = "SilicaDocumentTrackedTimeKey"
|
||||
let LayersKey = "layers"
|
||||
|
|
Reference in a new issue