mirror of
https://github.com/zhigang1992/InTime.git
synced 2026-04-24 03:04:52 +08:00
Fix layout
This commit is contained in:
@@ -3,7 +3,6 @@
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="13196"/>
|
||||
<capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
<capability name="stacking Non-gravity area distributions on NSStackView" minToolsVersion="7.0" minSystemVersion="10.11"/>
|
||||
</dependencies>
|
||||
@@ -347,11 +346,11 @@
|
||||
<scene sceneID="R2V-B0-nI4">
|
||||
<objects>
|
||||
<windowController showSeguePresentationStyle="single" id="B8D-0N-5wS" customClass="FloatingPannel" customModule="FloatingToggl" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<window key="window" title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" showsToolbarButton="NO" visibleAtLaunch="NO" animationBehavior="default" id="IQv-IB-iLA" customClass="NSPanel">
|
||||
<window key="window" title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" showsToolbarButton="NO" animationBehavior="default" id="IQv-IB-iLA" customClass="NSPanel">
|
||||
<windowStyleMask key="styleMask" titled="YES" resizable="YES" utility="YES" nonactivatingPanel="YES" HUD="YES" fullSizeContentView="YES"/>
|
||||
<windowCollectionBehavior key="collectionBehavior" moveToActiveSpace="YES"/>
|
||||
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
||||
<rect key="contentRect" x="585" y="830" width="480" height="100"/>
|
||||
<windowPositionMask key="initialPositionMask" leftStrut="YES" bottomStrut="YES"/>
|
||||
<rect key="contentRect" x="95" y="73" width="426" height="100"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="1680" height="1027"/>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="B8D-0N-5wS" id="98r-iN-zZc"/>
|
||||
@@ -363,23 +362,23 @@
|
||||
</windowController>
|
||||
<customObject id="Oky-zY-oP4" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="75" y="250"/>
|
||||
<point key="canvasLocation" x="2" y="250"/>
|
||||
</scene>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="hIz-AP-VOD">
|
||||
<objects>
|
||||
<viewController id="XfG-lQ-9wD" customClass="ViewController" customModule="FloatingToggl" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" wantsLayer="YES" id="m2S-Jp-Qdl">
|
||||
<rect key="frame" x="0.0" y="0.0" width="580" height="60"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="364" height="60"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<stackView distribution="fill" orientation="horizontal" alignment="centerY" spacing="10" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="wu7-dI-dhr">
|
||||
<rect key="frame" x="20" y="0.0" width="560" height="60"/>
|
||||
<stackView distribution="fill" orientation="horizontal" alignment="centerY" spacing="20" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="wu7-dI-dhr">
|
||||
<rect key="frame" x="20" y="0.0" width="324" height="60"/>
|
||||
<subviews>
|
||||
<textField horizontalHuggingPriority="247" verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="BPy-6c-wmT">
|
||||
<rect key="frame" x="-2" y="20.5" width="438" height="19"/>
|
||||
<textField horizontalHuggingPriority="249" verticalHuggingPriority="750" horizontalCompressionResistancePriority="999" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="BPy-6c-wmT" customClass="AutoGrowTextField" customModule="FloatingToggl" customModuleProvider="target">
|
||||
<rect key="frame" x="-2" y="20.5" width="197" height="19"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="200" id="Tug-Tb-Szc"/>
|
||||
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="100" id="Tug-Tb-Szc"/>
|
||||
</constraints>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" placeholderString="What are you working on?" usesSingleLineMode="YES" id="Yb4-dr-ehw">
|
||||
<font key="font" metaFont="system" size="15"/>
|
||||
@@ -391,7 +390,7 @@
|
||||
</connections>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="TdA-qV-FLw">
|
||||
<rect key="frame" x="442" y="19.5" width="55" height="21"/>
|
||||
<rect key="frame" x="211" y="19.5" width="55" height="21"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="1:17:28" id="7aI-t8-bK1">
|
||||
<font key="font" size="15" name="HelveticaNeue"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
@@ -399,10 +398,9 @@
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<button translatesAutoresizingMaskIntoConstraints="NO" id="kag-yT-y1V">
|
||||
<rect key="frame" x="505" y="2.5" width="55" height="55"/>
|
||||
<rect key="frame" x="284" y="2.5" width="40" height="55"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="55" id="Gyb-XX-9Vm"/>
|
||||
<constraint firstAttribute="width" secondItem="kag-yT-y1V" secondAttribute="height" id="Xf4-F1-gUv"/>
|
||||
</constraints>
|
||||
<buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" image="Stop" imagePosition="overlaps" alignment="center" inset="2" id="LaA-Fa-c8O">
|
||||
<behavior key="behavior" pushIn="YES" changeContents="YES" lightByContents="YES"/>
|
||||
@@ -430,7 +428,7 @@
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="wu7-dI-dhr" firstAttribute="leading" secondItem="m2S-Jp-Qdl" secondAttribute="leading" constant="20" id="0Bk-A0-XKV"/>
|
||||
<constraint firstAttribute="trailing" secondItem="wu7-dI-dhr" secondAttribute="trailing" id="LPI-zO-QJY"/>
|
||||
<constraint firstAttribute="trailing" secondItem="wu7-dI-dhr" secondAttribute="trailing" constant="20" id="LPI-zO-QJY"/>
|
||||
<constraint firstAttribute="bottom" secondItem="wu7-dI-dhr" secondAttribute="bottom" id="PMU-dI-y8Q"/>
|
||||
<constraint firstItem="wu7-dI-dhr" firstAttribute="top" secondItem="m2S-Jp-Qdl" secondAttribute="top" id="fcA-No-1Cl"/>
|
||||
</constraints>
|
||||
@@ -443,7 +441,7 @@
|
||||
</viewController>
|
||||
<customObject id="rPt-NT-nkU" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="75" y="655"/>
|
||||
<point key="canvasLocation" x="-140.5" y="654"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
|
||||
@@ -7,9 +7,12 @@
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
import RxSwift
|
||||
|
||||
class FloatingPannel: NSWindowController {
|
||||
|
||||
let disposebag = DisposeBag()
|
||||
|
||||
override func windowDidLoad() {
|
||||
super.windowDidLoad()
|
||||
guard let panel = self.window as? NSPanel else {
|
||||
@@ -19,6 +22,15 @@ class FloatingPannel: NSWindowController {
|
||||
panel.isFloatingPanel = true
|
||||
panel.titleVisibility = .hidden
|
||||
panel.titlebarAppearsTransparent = true
|
||||
|
||||
}
|
||||
|
||||
override func mouseEntered(with event: NSEvent) {
|
||||
super.mouseEntered(with: event)
|
||||
}
|
||||
|
||||
override func mouseExited(with event: NSEvent) {
|
||||
super.mouseEntered(with: event)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -104,6 +104,8 @@ class TogglViewModel {
|
||||
|
||||
let input = Variable<String>("")
|
||||
|
||||
let active = Variable<Bool>(NSApplication.shared.isActive)
|
||||
|
||||
private let disposeBag = DisposeBag()
|
||||
|
||||
var completions: Driver<[String]> {
|
||||
@@ -132,6 +134,23 @@ class TogglViewModel {
|
||||
self?.keychain.delete(tokenKey)
|
||||
}
|
||||
}).disposed(by: self.disposeBag)
|
||||
|
||||
Observable.merge([
|
||||
NotificationCenter.default.rx
|
||||
.notification(NSApplication.didBecomeActiveNotification)
|
||||
.map({_ in true}),
|
||||
NotificationCenter.default.rx
|
||||
.notification(NSApplication.willResignActiveNotification)
|
||||
.map({_ in false})
|
||||
]).bind(to: self.active).disposed(by: self.disposeBag)
|
||||
|
||||
self.active.asDriver()
|
||||
.distinctUntilChanged()
|
||||
.filter({$0})
|
||||
.map({_ in ()})
|
||||
.drive(refresh)
|
||||
.disposed(by: self.disposeBag)
|
||||
|
||||
token.asDriver().flatMapLatest({ token -> Driver<TimeEntry?> in
|
||||
if let token = token {
|
||||
return self.refresh.asDriver(onErrorJustReturn: ()).startWith(()).flatMapLatest({_ in
|
||||
@@ -143,9 +162,11 @@ class TogglViewModel {
|
||||
return Driver<TimeEntry?>.just(nil)
|
||||
}).debug().drive(current).disposed(by: self.disposeBag)
|
||||
|
||||
token.asDriver().flatMapLatest({ token -> Driver<User?> in
|
||||
token.asDriver().flatMapLatest({[weak self] token -> Driver<User?> in
|
||||
if let token = token {
|
||||
return Endpoint<User>.me.request(with: token).map(Optional.some).asDriver(onErrorJustReturn: nil)
|
||||
return self?.current.asDriver().flatMapLatest({ _ in
|
||||
Endpoint<User>.me.request(with: token).map(Optional.some).asDriver(onErrorJustReturn: nil)
|
||||
}) ?? .just(nil)
|
||||
}
|
||||
return Driver<User?>.just(nil)
|
||||
}).debug().drive(user).disposed(by: self.disposeBag)
|
||||
@@ -178,6 +199,17 @@ class TogglViewModel {
|
||||
|
||||
}
|
||||
|
||||
class AutoGrowTextField: NSTextField {
|
||||
|
||||
override var intrinsicContentSize: NSSize {
|
||||
self.isEditable = false
|
||||
defer {
|
||||
self.isEditable = true
|
||||
}
|
||||
return super.intrinsicContentSize
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ViewController: NSViewController {
|
||||
|
||||
@@ -276,19 +308,33 @@ class ViewController: NSViewController {
|
||||
self?.timerLabel.stringValue = text
|
||||
}).disposed(by: self.disposeBag)
|
||||
|
||||
viewModel.current.asDriver().distinctUntilChanged({
|
||||
($0 == nil) == ($1 == nil)
|
||||
}).drive(onNext: {[weak self] current in
|
||||
let text = current?.description ?? ""
|
||||
self?.inputLabel.stringValue = text
|
||||
self?.viewModel.input.value = text
|
||||
self?.inputLabel.currentEditor()?.selectedRange.length = 0
|
||||
self?.inputLabel.window?.makeFirstResponder(nil)
|
||||
viewModel.current.asDriver().drive(onNext: {[weak self] current in
|
||||
self?.timerLabel.isHidden = current == nil
|
||||
self?.actionButton.isHidden = current == nil
|
||||
if let current = current {
|
||||
let text = current.description ?? "Untitled"
|
||||
self?.inputLabel.stringValue = text
|
||||
self?.viewModel.input.value = text
|
||||
self?.isShowingRecentEntries = false
|
||||
self?.inputLabel.window?.makeFirstResponder(nil)
|
||||
} else {
|
||||
self?.inputLabel.stringValue = ""
|
||||
self?.viewModel.input.value = ""
|
||||
}
|
||||
self?.placeCursorAtTheEnd()
|
||||
self?.resizeWindow()
|
||||
}).disposed(by: self.disposeBag)
|
||||
}
|
||||
|
||||
var trackingRect: NSView.TrackingRectTag?
|
||||
override func viewDidLayout() {
|
||||
super.viewDidLayout()
|
||||
if let t = trackingRect {
|
||||
view.removeTrackingRect(t)
|
||||
}
|
||||
trackingRect = view.addTrackingRect(view.bounds, owner: self, userData: nil, assumeInside: false)
|
||||
}
|
||||
|
||||
override func viewDidAppear() {
|
||||
super.viewDidAppear()
|
||||
if viewModel.token.value == nil {
|
||||
@@ -305,6 +351,8 @@ class ViewController: NSViewController {
|
||||
|
||||
if newValue {
|
||||
guard !recentItems.isEmpty else { return }
|
||||
guard inputLabel.currentEditor()?.selectedRange.length == 0 else { return }
|
||||
|
||||
recentItemVC.show(relativeTo: .zero, of: self.view, preferredEdge: .minY)
|
||||
} else {
|
||||
recentItemVC.close()
|
||||
@@ -312,6 +360,13 @@ class ViewController: NSViewController {
|
||||
}
|
||||
}
|
||||
|
||||
func resizeWindow() {
|
||||
guard let window = self.view.window else { return }
|
||||
let minSize = self.view.fittingSize
|
||||
window.setFrame(NSRect(origin: window.frame.origin, size: minSize), display: true)
|
||||
}
|
||||
|
||||
|
||||
@IBAction func presentRecentEntries(_ sender: NSMenuItem) {
|
||||
self.isShowingRecentEntries = !self.isShowingRecentEntries
|
||||
}
|
||||
@@ -320,6 +375,13 @@ class ViewController: NSViewController {
|
||||
self.viewModel.stopTimer()
|
||||
}
|
||||
|
||||
func placeCursorAtTheEnd() {
|
||||
guard let editor = self.inputLabel.currentEditor() else { return }
|
||||
|
||||
let string = self.inputLabel.stringValue as NSString
|
||||
editor.selectedRange = NSRange(location: string.length, length: 0)
|
||||
}
|
||||
|
||||
func presentSetToken() {
|
||||
let alert = NSAlert()
|
||||
alert.alertStyle = .informational
|
||||
@@ -379,7 +441,7 @@ extension ViewController: NSTextFieldDelegate {
|
||||
inputLabel.stringValue = recentItems[self.selectedRow]
|
||||
viewModel.input.value = recentItems[self.selectedRow]
|
||||
isShowingRecentEntries = false
|
||||
inputLabel.currentEditor()?.selectedRange.length = 0
|
||||
self.placeCursorAtTheEnd()
|
||||
}
|
||||
|
||||
func control(_ control: NSControl, textView: NSTextView, doCommandBy commandSelector: Selector) -> Bool {
|
||||
@@ -393,18 +455,9 @@ extension ViewController: NSTextFieldDelegate {
|
||||
selectedRow = selectedRow + 1
|
||||
isShowingRecentEntries = true
|
||||
case #selector(textView.insertTab(_:)):
|
||||
if recentItems.count > 1 {
|
||||
selectedRow = selectedRow + 1
|
||||
isShowingRecentEntries = true
|
||||
} else if recentItems.count == 1 {
|
||||
insertSelection()
|
||||
}
|
||||
insertSelection()
|
||||
case #selector(textView.insertNewline(_:)):
|
||||
if isShowingRecentEntries {
|
||||
insertSelection()
|
||||
} else {
|
||||
self.viewModel.startTimer()
|
||||
}
|
||||
self.viewModel.startTimer()
|
||||
default:
|
||||
return false
|
||||
}
|
||||
@@ -414,7 +467,6 @@ extension ViewController: NSTextFieldDelegate {
|
||||
override func controlTextDidChange(_ obj: Notification) {
|
||||
self.viewModel.input.value = inputLabel.stringValue
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension ViewController: NSTableViewDelegate, NSTableViewDataSource {
|
||||
@@ -433,6 +485,7 @@ extension ViewController: NSTableViewDelegate, NSTableViewDataSource {
|
||||
textField.drawsBackground = false
|
||||
textField.isEditable = false
|
||||
textField.isSelectable = false
|
||||
textField.usesSingleLineMode = true
|
||||
cell.addSubview(textField)
|
||||
cell.textField = textField
|
||||
cell.identifier = ViewController.identity
|
||||
|
||||
Reference in New Issue
Block a user