1
Fork 0

Add info window to show time tracked on a document

This commit is contained in:
Joshua Goins 2020-03-10 16:23:25 -04:00 committed by redstrate
parent 21392bd1cf
commit a57fbf2fab
6 changed files with 136 additions and 19 deletions

View file

@ -23,6 +23,7 @@
036AFC11241800350075400A /* ThumbnailProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 036AFC10241800350075400A /* ThumbnailProvider.swift */; }; 036AFC11241800350075400A /* ThumbnailProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 036AFC10241800350075400A /* ThumbnailProvider.swift */; };
036AFC16241800350075400A /* Thumbnail.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 036AFC0B241800350075400A /* Thumbnail.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 036AFC16241800350075400A /* Thumbnail.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 036AFC0B241800350075400A /* Thumbnail.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
036AFC1B241800850075400A /* ZIPFoundation in Frameworks */ = {isa = PBXBuildFile; productRef = 036AFC1A241800850075400A /* ZIPFoundation */; }; 036AFC1B241800850075400A /* ZIPFoundation in Frameworks */ = {isa = PBXBuildFile; productRef = 036AFC1A241800850075400A /* ZIPFoundation */; };
037B4042241821D200392452 /* InfoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 037B4041241821D200392452 /* InfoViewController.swift */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */ /* Begin PBXContainerItemProxy section */
@ -77,6 +78,7 @@
036AFC10241800350075400A /* ThumbnailProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThumbnailProvider.swift; sourceTree = "<group>"; }; 036AFC10241800350075400A /* ThumbnailProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThumbnailProvider.swift; sourceTree = "<group>"; };
036AFC12241800350075400A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; 036AFC12241800350075400A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
036AFC13241800350075400A /* Thumbnail.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Thumbnail.entitlements; sourceTree = "<group>"; }; 036AFC13241800350075400A /* Thumbnail.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Thumbnail.entitlements; sourceTree = "<group>"; };
037B4041241821D200392452 /* InfoViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfoViewController.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
@ -141,6 +143,7 @@
030F6FFD2415C5E400A43F01 /* Info.plist */, 030F6FFD2415C5E400A43F01 /* Info.plist */,
030F6FFE2415C5E400A43F01 /* ProcreateViewer.entitlements */, 030F6FFE2415C5E400A43F01 /* ProcreateViewer.entitlements */,
036AFBB924168C030075400A /* ViewController.swift */, 036AFBB924168C030075400A /* ViewController.swift */,
037B4041241821D200392452 /* InfoViewController.swift */,
); );
path = ProcreateViewer; path = ProcreateViewer;
sourceTree = "<group>"; sourceTree = "<group>";
@ -319,6 +322,7 @@
files = ( files = (
036AFBBA24168C030075400A /* ViewController.swift in Sources */, 036AFBBA24168C030075400A /* ViewController.swift in Sources */,
030F6FF42415C5E300A43F01 /* Document.swift in Sources */, 030F6FF42415C5E300A43F01 /* Document.swift in Sources */,
037B4042241821D200392452 /* InfoViewController.swift in Sources */,
030F6FF22415C5E300A43F01 /* AppDelegate.swift in Sources */, 030F6FF22415C5E300A43F01 /* AppDelegate.swift in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;

View file

@ -1,6 +1,17 @@
import Cocoa import Cocoa
@NSApplicationMain @NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate { class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations {
@IBAction func showInfoAction(_ sender: Any) {
NSApplication.shared.keyWindow?.contentViewController?.performSegue(withIdentifier: "showInfo", sender: self)
}
func validateUserInterfaceItem(_ item: NSValidatedUserInterfaceItem) -> Bool {
if(item.tag == 67) {
return NSApplication.shared.keyWindow != nil
}
return true
}
} }

View file

@ -90,25 +90,13 @@
<modifierMask key="keyEquivalentModifierMask"/> <modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="View" id="HyV-fh-RgO"> <menu key="submenu" title="View" id="HyV-fh-RgO">
<items> <items>
<menuItem title="Show Toolbar" keyEquivalent="t" id="snW-S8-Cw5"> <menuItem title="Show Info" tag="67" id="Fkh-F1-E0e">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="toggleToolbarShown:" target="Ady-hI-5gd" id="BXY-wc-z0C"/>
</connections>
</menuItem>
<menuItem title="Customize Toolbar…" id="1UK-8n-QPP">
<modifierMask key="keyEquivalentModifierMask"/> <modifierMask key="keyEquivalentModifierMask"/>
<connections> <connections>
<action selector="runToolbarCustomizationPalette:" target="Ady-hI-5gd" id="pQI-g3-MTW"/> <action selector="showInfoAction:" target="Voe-Tx-rLC" id="3A0-GP-3ZY"/>
</connections> </connections>
</menuItem> </menuItem>
<menuItem isSeparatorItem="YES" id="hB3-LF-h0Y"/> <menuItem isSeparatorItem="YES" id="hB3-LF-h0Y"/>
<menuItem title="Show Sidebar" keyEquivalent="s" id="kIP-vf-haE">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
<connections>
<action selector="toggleSidebar:" target="Ady-hI-5gd" id="iwa-gc-5KM"/>
</connections>
</menuItem>
<menuItem title="Enter Full Screen" keyEquivalent="f" id="4J7-dP-txa"> <menuItem title="Enter Full Screen" keyEquivalent="f" id="4J7-dP-txa">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/> <modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
<connections> <connections>
@ -164,9 +152,56 @@
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="ProcreateViewer" customModuleProvider="target"/> <customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="ProcreateViewer" customModuleProvider="target"/>
<customObject id="YLy-65-1bz" customClass="NSFontManager"/> <customObject id="YLy-65-1bz" customClass="NSFontManager"/>
<customObject id="Ady-hI-5gd" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/> <customObject id="Ady-hI-5gd" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
<userDefaultsController representsSharedInstance="YES" id="JdS-Pg-8N9"/>
</objects> </objects>
<point key="canvasLocation" x="75" y="0.0"/> <point key="canvasLocation" x="75" y="0.0"/>
</scene> </scene>
<!--Info View Controller-->
<scene sceneID="nJy-a4-E0d">
<objects>
<viewController showSeguePresentationStyle="single" id="wda-Mt-beD" customClass="InfoViewController" customModule="ProcreateViewer" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" id="3vu-Kd-l73">
<rect key="frame" x="0.0" y="0.0" width="480" height="85"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="u9u-el-oA4">
<rect key="frame" x="18" y="49" width="444" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" placeholderString="Time Spent" id="UBd-vS-gNL">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="2oe-to-Rcz">
<rect key="frame" x="407" y="13" width="59" 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"/>
<string key="keyEquivalent" base64-UTF8="YES">
DQ
</string>
</buttonCell>
<connections>
<action selector="dismissController:" target="wda-Mt-beD" id="LJb-SK-4qT"/>
</connections>
</button>
</subviews>
<constraints>
<constraint firstItem="2oe-to-Rcz" firstAttribute="top" secondItem="u9u-el-oA4" secondAttribute="bottom" constant="8" symbolic="YES" id="BYm-qe-WxD"/>
<constraint firstItem="u9u-el-oA4" firstAttribute="top" secondItem="3vu-Kd-l73" secondAttribute="top" constant="20" symbolic="YES" id="HaC-Tk-Y3y"/>
<constraint firstAttribute="trailing" secondItem="u9u-el-oA4" secondAttribute="trailing" constant="20" symbolic="YES" id="Qfn-KK-5Ya"/>
<constraint firstItem="u9u-el-oA4" firstAttribute="leading" secondItem="3vu-Kd-l73" secondAttribute="leading" constant="20" symbolic="YES" id="TpT-D9-UgA"/>
<constraint firstItem="2oe-to-Rcz" firstAttribute="trailing" secondItem="u9u-el-oA4" secondAttribute="trailing" id="ZND-Qt-9wv"/>
</constraints>
</view>
<connections>
<outlet property="timeSpentLabel" destination="u9u-el-oA4" id="LeI-31-Z8r"/>
</connections>
</viewController>
<customObject id="Tam-yi-Bux" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="786" y="286.5"/>
</scene>
<!--Window Controller--> <!--Window Controller-->
<scene sceneID="R2V-B0-nI4"> <scene sceneID="R2V-B0-nI4">
<objects> <objects>
@ -210,11 +245,12 @@
</view> </view>
<connections> <connections>
<outlet property="imageView" destination="ipM-NH-wUM" id="RT5-09-Hwj"/> <outlet property="imageView" destination="ipM-NH-wUM" id="RT5-09-Hwj"/>
<segue destination="wda-Mt-beD" kind="sheet" identifier="showInfo" id="obo-Yt-yny"/>
</connections> </connections>
</viewController> </viewController>
<customObject id="2Tp-Fl-jBw" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/> <customObject id="2Tp-Fl-jBw" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects> </objects>
<point key="canvasLocation" x="75" y="655"/> <point key="canvasLocation" x="59" y="761"/>
</scene> </scene>
</scenes> </scenes>
</document> </document>

View file

@ -1,8 +1,14 @@
import Cocoa import Cocoa
import ZIPFoundation import ZIPFoundation
struct DocumentInfo {
var tracked_time: Int = 0
}
class Document: NSDocument { class Document: NSDocument {
var image: NSImage? var info = DocumentInfo()
var thumbnail: NSImage? = nil
override init() { override init() {
super.init() super.init()
@ -19,6 +25,7 @@ class Document: NSDocument {
return return
} }
// load thumbnail
guard let entry = archive["QuickLook/Thumbnail.png"] else { guard let entry = archive["QuickLook/Thumbnail.png"] else {
return return
} }
@ -33,7 +40,39 @@ class Document: NSDocument {
Swift.print("Extracting entry from archive failed with error:\(error)") Swift.print("Extracting entry from archive failed with error:\(error)")
} }
image = NSImage(data: top_data) thumbnail = NSImage(data: top_data)
// load doc info
guard let document_entry = archive["Document.archive"] else {
return
}
var doc_data = Data()
do {
try archive.extract(document_entry, consumer: { (d) in
doc_data.append(d)
})
} catch {
Swift.print("Extracting entry from archive failed with error:\(error)")
}
// Document.archive is a binary plist (specifically a NSKeyedArchive), luckily swift has a built-in solution to decode it
var plistFormat = PropertyListSerialization.PropertyListFormat.binary
let plistBinary = doc_data
guard let propertyList = try? PropertyListSerialization.propertyList(from: plistBinary, options: [], format: &plistFormat) else {
fatalError("failed to deserialize")
}
// this is temporary, as we're just hoping that the keyed archive fits our requirements...
let dict = (propertyList as! NSDictionary);
let objects = dict["$objects"] as! NSArray
let tracked_time = (objects[1] as! NSDictionary)["SilicaDocumentTrackedTimeKey"]
info.tracked_time = (tracked_time as! NSNumber).intValue
} }
} }

View file

@ -0,0 +1,20 @@
import Foundation
import Cocoa
class InfoViewController: NSViewController {
var document: Document?
@IBOutlet weak var timeSpentLabel: NSTextField!
override func viewDidAppear() {
super.viewDidAppear()
let formatter = DateComponentsFormatter()
formatter.allowedUnits = [.hour, .minute, .second]
formatter.unitsStyle = .full
let formattedString = formatter.string(from: TimeInterval(document!.info.tracked_time))!
timeSpentLabel.stringValue = "Time Spent: " + formattedString
}
}

View file

@ -7,6 +7,13 @@ class ViewController: NSViewController {
override func viewWillAppear() { override func viewWillAppear() {
let document = self.view.window?.windowController?.document as? Document let document = self.view.window?.windowController?.document as? Document
imageView.image = document?.image imageView.image = document?.thumbnail
}
override func prepare(for segue: NSStoryboardSegue, sender: Any?) {
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
}
} }
} }