Skip to content

Commit

Permalink
Merge pull request #24 from ayroblu/ux-improvements
Browse files Browse the repository at this point in the history
Fix build + make screenshot open over where it was created
  • Loading branch information
kentya6 authored May 26, 2022
2 parents 886e99f + 453662a commit 4d36cd0
Show file tree
Hide file tree
Showing 12 changed files with 296 additions and 18 deletions.
109 changes: 109 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
name: CI

on:
push:
branches: [ master ]
tags:
- 'v*'
pull_request:
branches: [ master ]

jobs:
build:
runs-on: [ macos-latest ]

steps:
- name: Select latest Xcode
run: "sudo xcode-select -s /Applications/Xcode_13.2.app"
- name: Install the Apple certificate and provisioning profile
env:
BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }}
P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
# BUILD_PROVISION_PROFILE_BASE64: ${{ secrets.BUILD_PROVISION_PROFILE_BASE64 }}
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
run: |
# create variables
CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
PP_PATH=$RUNNER_TEMP/build_pp.mobileprovision
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
# import certificate and provisioning profile from secrets
echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode --output $CERTIFICATE_PATH
#echo -n "$BUILD_PROVISION_PROFILE_BASE64" | base64 --decode --output $PP_PATH
# create temporary keychain
security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
# import certificate to keychain
security import $CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
security list-keychain -d user -s $KEYCHAIN_PATH
# apply provisioning profile
# mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
# cp $PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles
- name: Install deps
run: |
brew install make create-dmg ripgrep
echo "/usr/local/opt/make/libexec/gnubin" >> $GITHUB_PATH
- uses: actions/checkout@v2

- uses: actions/cache@v1
id: carthage-cache
with:
path: Carthage
key: ${{ runner.os }}-carthage-${{ hashFiles('**/Cartfile.resolved') }}

- name: Carthage
if: steps.carthage-cache.outputs.cache-hit != 'true'
run: |
carthage bootstrap --use-xcframeworks
- name: Build and make dmg
run: |
make dmg
- name: Upload artifacts
uses: actions/[email protected]
with:
name: Fuwari
path: ./dist

pre-release:
needs: build
runs-on: [ macos-latest ]
if: "!startsWith(github.ref, 'refs/tags/v')"
steps:
- uses: actions/download-artifact@v2
with:
name: Fuwari
path: ./dist

- uses: "marvinpinto/action-automatic-releases@latest"
with:
repo_token: "${{ secrets.GITHUB_TOKEN }}"
automatic_release_tag: "latest"
prerelease: true
title: "Development Build"
files: |
dist/Fuwari.dmg
release:
needs: build
runs-on: [ macos-latest ]
if: "startsWith(github.ref, 'refs/tags/v')"
steps:
- uses: actions/download-artifact@v2
with:
name: Fuwari
path: ./dist

- uses: "marvinpinto/action-automatic-releases@latest"
with:
repo_token: "${{ secrets.GITHUB_TOKEN }}"
prerelease: false
files: |
dist/Fuwari.dmg
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,6 @@ fastlane/report.xml
fastlane/Preview.html
fastlane/screenshots
fastlane/test_output

/dist
/artifacts
2 changes: 1 addition & 1 deletion Cartfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
github "Clipy/Magnet" == 3.2.0
github "Clipy/LoginServiceKit" == 2.2.0
github "Clipy/LoginServiceKit" == 2.3.0
github "Clipy/KeyHolder" == 4.0.0
github "Clipy/Sauce" == 2.1.0
2 changes: 1 addition & 1 deletion Cartfile.resolved
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
github "Clipy/KeyHolder" "v4.0.0"
github "Clipy/LoginServiceKit" "v2.2.0"
github "Clipy/LoginServiceKit" "v2.3.0"
github "Clipy/Magnet" "v3.2.0"
github "Clipy/Sauce" "v2.1.0"
8 changes: 8 additions & 0 deletions ExportOptions.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>method</key>
<string>mac-application</string>
</dict>
</plist>
8 changes: 6 additions & 2 deletions Fuwari.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
objects = {

/* Begin PBXBuildFile section */
30C4E09427CEC8B900EBDCBB /* Regex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30C4E09327CEC8B900EBDCBB /* Regex.swift */; };
BE23E42F1DFA1623004DA6B7 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE23E42E1DFA1623004DA6B7 /* Constants.swift */; };
BE38949F263C20EA00131366 /* KeyHolder.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = CAD92F1F25FE3B6B008D6CF8 /* KeyHolder.xcframework */; };
BE3894A0263C20EA00131366 /* KeyHolder.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = CAD92F1F25FE3B6B008D6CF8 /* KeyHolder.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
Expand Down Expand Up @@ -59,6 +60,7 @@
/* End PBXCopyFilesBuildPhase section */

/* Begin PBXFileReference section */
30C4E09327CEC8B900EBDCBB /* Regex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Regex.swift; sourceTree = "<group>"; };
BE23E42E1DFA1623004DA6B7 /* Constants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
BE357092263FE10900F8C5E0 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/GeneralPreferenceViewController.strings; sourceTree = "<group>"; };
BE3570932640406F00F8C5E0 /* Fuwari.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Fuwari.entitlements; sourceTree = "<group>"; };
Expand Down Expand Up @@ -172,6 +174,7 @@
children = (
BE23E42E1DFA1623004DA6B7 /* Constants.swift */,
BE5896A01DFCED26007CE7AC /* LocalizedString.swift */,
30C4E09327CEC8B900EBDCBB /* Regex.swift */,
);
name = Utility;
sourceTree = "<group>";
Expand Down Expand Up @@ -291,6 +294,7 @@
BE7E825B1DF74A2D00F3F2F8 /* FloatWindow.swift in Sources */,
BEF57FE51DFD46AE006595B6 /* PreferencesWindowController.swift in Sources */,
BE85482020F975E00035BC60 /* NSMenu+Extension.swift in Sources */,
30C4E09427CEC8B900EBDCBB /* Regex.swift in Sources */,
BEF57FEF1DFD58D4006595B6 /* NSColor+Fuwari.swift in Sources */,
BEC844F91DED859300A4A57A /* ViewController.swift in Sources */,
BE85482420FB5C640035BC60 /* FloatView.swift in Sources */,
Expand Down Expand Up @@ -489,7 +493,7 @@
"$(inherited)",
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.12;
MACOSX_DEPLOYMENT_TARGET = 10.13;
MARKETING_VERSION = 0.6.0;
PRODUCT_BUNDLE_IDENTIFIER = com.appknop.fuwari;
PRODUCT_NAME = "$(TARGET_NAME)";
Expand Down Expand Up @@ -518,7 +522,7 @@
"$(inherited)",
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.12;
MACOSX_DEPLOYMENT_TARGET = 10.13;
MARKETING_VERSION = 0.6.0;
PRODUCT_BUNDLE_IDENTIFIER = com.appknop.fuwari;
PRODUCT_NAME = "$(TARGET_NAME)";
Expand Down
2 changes: 1 addition & 1 deletion Fuwari/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {

override init() {
// Initialize UserDefaults value
defaults.register(defaults: [Constants.UserDefaults.movingOpacity: 0.4])
defaults.register(defaults: [Constants.UserDefaults.movingOpacity: 1.0])
defaults.register(defaults: [Constants.UserDefaults.uploadConfirmationItem: true])
}

Expand Down
6 changes: 5 additions & 1 deletion Fuwari/FloatWindow.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import Cocoa
import Magnet
import Carbon

protocol FloatDelegate: class {
protocol FloatDelegate: AnyObject {
func save(floatWindow: FloatWindow, image: CGImage)
func close(floatWindow: FloatWindow)
}
Expand Down Expand Up @@ -165,6 +165,10 @@ class FloatWindow: NSWindow {
override func mouseUp(with event: NSEvent) {
alphaValue = windowOpacity
closeButton.alphaValue = closeButtonOpacity
// Double click to close
if event.clickCount >= 2 {
closeWindow()
}
}

@objc private func saveImage() {
Expand Down
42 changes: 42 additions & 0 deletions Fuwari/Regex.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//
// Regex.swift
// Fuwari
//
// Created by Ben Lu on 01/03/2022.
// Copyright © 2022 AppKnop. All rights reserved.
//

import Foundation

struct Regex {
static func match(str: String, regexPattern: String) -> NSTextCheckingResult? {
let strRange = NSRange(str.startIndex..<str.endIndex, in: str)

let regex = try! NSRegularExpression(
pattern: regexPattern,
options: []
)
let matches = regex.matches(
in: str,
options: [],
range: strRange
)

return matches.first
}

static func getGroup(match: NSTextCheckingResult, name: String, str: String) throws -> String {
let matchRange = match.range(withName: name)

// Extract the substring matching the named capture group
if let substringRange = Range(matchRange, in: str) {
let capture = String(str[substringRange])
return capture
}
throw RegexError.missingGroup(name: name)
}
}

enum RegexError: Error {
case missingGroup(name: String)
}
48 changes: 40 additions & 8 deletions Fuwari/ScreenshotManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,59 @@
import Cocoa

class ScreenshotManager: NSObject {

static let shared = ScreenshotManager()

private var eventHandler: ((URL) -> Void)?
func eventHandler(eventHandler: @escaping (URL) -> Void) {
private var eventHandler: ((URL, NSRect?) -> Void)?

func eventHandler(eventHandler: @escaping (URL, NSRect?) -> Void) {
self.eventHandler = eventHandler
}

func startCapture() {
let fileUrl = FileManager.default.temporaryDirectory.appendingPathComponent("fuwari-temporary-screenshot.png")
let captureProcess = Process()
let pipe = Pipe()
captureProcess.launchPath = "/usr/sbin/screencapture"
captureProcess.arguments = ["-x", "-i"] + [fileUrl.path]
captureProcess.standardOutput = Pipe()
captureProcess.arguments = ["-x", "-i", "-o"] + [fileUrl.path]
captureProcess.environment = ["OS_ACTIVITY_DT_MODE": "YES"]
captureProcess.standardError = pipe
captureProcess.terminationHandler = { task in
guard task.terminationStatus == 0 else { return }
let output = pipe.fileHandleForReading.availableData
let str = String(decoding: output, as: UTF8.self)
let rect = self.extractCoordinates(str: str)
DispatchQueue.main.async { [weak self] in
self?.eventHandler?(fileUrl)
self?.eventHandler?(fileUrl, rect)
}
}
captureProcess.launch()
}

func extractCoordinates(str: String) -> NSRect? {
// Note, not found when capturing a window, rather than a selection
let capturePattern = #"captureRect = \((?<x>[\d.]+), (?<y>[\d.]+), (?<width>[\d.]+), (?<height>[\d.]+)\)"#

guard let match = Regex.match(str: str, regexPattern: capturePattern) else {
return nil
}

let getIntFromRegexGroup = {(name: String) throws -> Int in
Int(round(Float(try Regex.getGroup(match: match, name: name, str: str))!))
}

do {
return try NSRect(
x: getIntFromRegexGroup("x"),
y: getIntFromRegexGroup("y"),
width: getIntFromRegexGroup("width"),
height: getIntFromRegexGroup("height")
)
} catch RegexError.missingGroup(let name) {
print("missing group: \(name)")
return nil
} catch {
return nil
}
}
}
22 changes: 18 additions & 4 deletions Fuwari/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ class ViewController: NSViewController, NSWindowDelegate {
oldApp = NSWorkspace.shared.frontmostApplication
oldApp?.activate(options: .activateIgnoringOtherApps)

ScreenshotManager.shared.eventHandler {
imageUrl in
ScreenshotManager.shared.eventHandler { imageUrl, rectMaybeConst in
let mainScreen = NSScreen.screens.first
let currentScreen = NSScreen.screens.first { $0.frame.contains(NSEvent.mouseLocation) }
guard let currentScaleFactor = currentScreen?.backingScaleFactor else { return }
let mouseLocation = NSEvent.mouseLocation
Expand All @@ -34,8 +34,22 @@ class ViewController: NSViewController, NSWindowDelegate {
let context = CIContext(options: nil)

guard let cgImage = context.createCGImage(ciImage, from: ciImage.extent) else { return }

self.createFloatWindow(rect: NSRect(x: Int(mouseLocation.x) - cgImage.width / Int(2 * currentScaleFactor), y: Int(mouseLocation.y) - cgImage.height / Int(2 * currentScaleFactor), width: Int(CGFloat(cgImage.width) / currentScaleFactor), height: Int(CGFloat(cgImage.height) / currentScaleFactor)), image: cgImage)
var rectMaybe = rectMaybeConst
if let height = mainScreen?.frame.size.height, let rect = rectMaybe {
rectMaybe = NSRect(
x: rect.minX,
y: height - rect.maxY,
width: rect.width,
height: rect.height
)
}
let rect = rectMaybe ?? NSRect(
x: Int(mouseLocation.x) - cgImage.width / Int(2 * currentScaleFactor),
y: Int(mouseLocation.y) - cgImage.height / Int(2 * currentScaleFactor),
width: Int(CGFloat(cgImage.width) / currentScaleFactor),
height: Int(CGFloat(cgImage.height) / currentScaleFactor)
)
self.createFloatWindow(rect: rect, image: cgImage)
try? FileManager.default.removeItem(at: imageUrl)
}
}
Expand Down
Loading

0 comments on commit 4d36cd0

Please sign in to comment.