mirror of
https://github.com/grishka/NearDrop.git
synced 2026-04-03 01:36:15 +02:00
@@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="22505" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="23504" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="22505"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="23504"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
@@ -22,6 +22,10 @@
|
||||
<outlet property="progressProgressBar" destination="J5x-hu-Kn5" id="vYH-DN-03b"/>
|
||||
<outlet property="progressState" destination="y8I-D3-scQ" id="Tj3-xa-8VG"/>
|
||||
<outlet property="progressView" destination="Q9K-dc-THx" id="LlE-4d-mI5"/>
|
||||
<outlet property="qrCodeButton" destination="ZsR-MN-QVA" id="KaY-NO-F5z"/>
|
||||
<outlet property="qrCodeSheetView" destination="cIc-n7-hIV" id="Ol8-aW-fH0"/>
|
||||
<outlet property="qrCodeView" destination="9Hk-Pa-eYI" id="Weo-3l-5pN"/>
|
||||
<outlet property="qrCodeWrapView" destination="dq7-IV-6Ef" id="V35-5n-nyq"/>
|
||||
<outlet property="view" destination="1" id="2"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
@@ -94,12 +98,28 @@ Gw
|
||||
<customView translatesAutoresizingMaskIntoConstraints="NO" id="ACO-U2-AZj">
|
||||
<rect key="frame" x="0.0" y="40" width="404" height="146"/>
|
||||
</customView>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="ZsR-MN-QVA">
|
||||
<rect key="frame" x="3" y="3" width="125" height="32"/>
|
||||
<buttonCell key="cell" type="push" title="Use QR code..." bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="Ll5-lP-3bU">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="100" id="7o5-tK-dlg"/>
|
||||
</constraints>
|
||||
<connections>
|
||||
<action selector="useQrCode:" target="-2" id="BS0-WG-B7q"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstAttribute="bottom" secondItem="ZsR-MN-QVA" secondAttribute="bottom" constant="10" id="76Q-6H-r3I"/>
|
||||
<constraint firstItem="OEz-QK-nem" firstAttribute="top" secondItem="1xF-vr-5sH" secondAttribute="bottom" constant="10" id="852-oh-vM0"/>
|
||||
<constraint firstItem="ZsR-MN-QVA" firstAttribute="leading" secondItem="1" secondAttribute="leading" constant="10" id="CHP-wF-HhN"/>
|
||||
<constraint firstItem="OEz-QK-nem" firstAttribute="leading" secondItem="afM-Om-nLQ" secondAttribute="trailing" constant="5" id="CIj-Dk-Md0"/>
|
||||
<constraint firstAttribute="trailing" secondItem="ACO-U2-AZj" secondAttribute="trailing" id="HIg-sX-IK0"/>
|
||||
<constraint firstItem="ACO-U2-AZj" firstAttribute="leading" secondItem="1" secondAttribute="leading" id="IGL-2g-wpe"/>
|
||||
<constraint firstItem="ZsR-MN-QVA" firstAttribute="top" secondItem="ACO-U2-AZj" secondAttribute="bottom" constant="10" id="K9U-z1-gie"/>
|
||||
<constraint firstItem="afM-Om-nLQ" firstAttribute="leading" secondItem="1" secondAttribute="leading" constant="10" id="LK2-cg-qcY"/>
|
||||
<constraint firstItem="NVE-vN-dkz" firstAttribute="top" secondItem="ACO-U2-AZj" secondAttribute="bottom" constant="10" id="RSD-PX-W0H"/>
|
||||
<constraint firstAttribute="bottom" secondItem="NVE-vN-dkz" secondAttribute="bottom" constant="10" id="USG-Gg-of3"/>
|
||||
@@ -256,6 +276,82 @@ Gw
|
||||
</scroller>
|
||||
<point key="canvasLocation" x="-397.5" y="30"/>
|
||||
</scrollView>
|
||||
<customView id="cIc-n7-hIV">
|
||||
<rect key="frame" x="0.0" y="0.0" width="380" height="400"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<subviews>
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" verticalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="oJM-qC-yyW">
|
||||
<rect key="frame" x="8" y="358" width="364" height="32"/>
|
||||
<textFieldCell key="cell" alignment="center" title="Scan this QR code with an Android device. The transfer will begin automatically." id="d3J-ot-h5d">
|
||||
<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="pLr-Yq-OMn">
|
||||
<rect key="frame" x="301" y="3" width="76" height="32"/>
|
||||
<buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="9EW-Db-fGL">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
<string key="keyEquivalent" base64-UTF8="YES">
|
||||
Gw
|
||||
</string>
|
||||
<connections>
|
||||
<action selector="dismissQrCodeSheet:" target="-2" id="OX6-j3-Dag"/>
|
||||
</connections>
|
||||
</buttonCell>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="60" id="eRJ-dH-AQv"/>
|
||||
</constraints>
|
||||
</button>
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" verticalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="mP8-S4-SUv">
|
||||
<rect key="frame" x="8" y="40" width="364" height="42"/>
|
||||
<textFieldCell key="cell" alignment="center" id="uuF-4K-rMR">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<string key="title">If this doesn't work, make sure that the device and your Mac are on the same network, and that the router isn't blocking LAN communication.</string>
|
||||
<color key="textColor" name="secondaryLabelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<customView translatesAutoresizingMaskIntoConstraints="NO" id="dq7-IV-6Ef">
|
||||
<rect key="frame" x="80" y="113" width="220" height="220"/>
|
||||
<subviews>
|
||||
<customView translatesAutoresizingMaskIntoConstraints="NO" id="lnf-Ci-bVP" customClass="QrCodeBackgroundView" customModule="ShareExtension" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="0.0" width="220" height="220"/>
|
||||
</customView>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="250" verticalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="9Hk-Pa-eYI">
|
||||
<rect key="frame" x="0.0" y="0.0" width="220" height="220"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" id="J6N-uf-WsV"/>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="lnf-Ci-bVP" firstAttribute="leading" secondItem="dq7-IV-6Ef" secondAttribute="leading" id="16L-0N-tMO"/>
|
||||
<constraint firstItem="9Hk-Pa-eYI" firstAttribute="top" secondItem="dq7-IV-6Ef" secondAttribute="top" id="22t-Se-FtM"/>
|
||||
<constraint firstAttribute="bottom" secondItem="lnf-Ci-bVP" secondAttribute="bottom" id="9XU-id-5Lj"/>
|
||||
<constraint firstItem="9Hk-Pa-eYI" firstAttribute="leading" secondItem="dq7-IV-6Ef" secondAttribute="leading" id="KWg-eg-4sO"/>
|
||||
<constraint firstAttribute="width" constant="220" id="drn-Gr-Tx6"/>
|
||||
<constraint firstAttribute="trailing" secondItem="9Hk-Pa-eYI" secondAttribute="trailing" id="fif-Sg-QCc"/>
|
||||
<constraint firstAttribute="bottom" secondItem="9Hk-Pa-eYI" secondAttribute="bottom" id="iVK-yf-1Ev"/>
|
||||
<constraint firstAttribute="height" constant="220" id="l69-dh-xwJ"/>
|
||||
<constraint firstAttribute="trailing" secondItem="lnf-Ci-bVP" secondAttribute="trailing" id="pva-qe-Ibk"/>
|
||||
<constraint firstItem="lnf-Ci-bVP" firstAttribute="top" secondItem="dq7-IV-6Ef" secondAttribute="top" id="yOu-Bz-qVZ"/>
|
||||
</constraints>
|
||||
</customView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="oJM-qC-yyW" firstAttribute="leading" secondItem="cIc-n7-hIV" secondAttribute="leading" constant="10" id="HaS-Sl-afe"/>
|
||||
<constraint firstItem="dq7-IV-6Ef" firstAttribute="centerX" secondItem="cIc-n7-hIV" secondAttribute="centerX" id="Iip-bT-bl3"/>
|
||||
<constraint firstItem="dq7-IV-6Ef" firstAttribute="top" secondItem="oJM-qC-yyW" secondAttribute="bottom" constant="25" id="YMN-xe-7cI"/>
|
||||
<constraint firstAttribute="trailing" secondItem="pLr-Yq-OMn" secondAttribute="trailing" constant="10" id="cAr-rb-sXX"/>
|
||||
<constraint firstItem="oJM-qC-yyW" firstAttribute="top" secondItem="cIc-n7-hIV" secondAttribute="top" constant="10" id="gts-uR-3Ej"/>
|
||||
<constraint firstAttribute="trailing" secondItem="oJM-qC-yyW" secondAttribute="trailing" constant="10" id="hwy-vE-lHk"/>
|
||||
<constraint firstAttribute="bottom" secondItem="pLr-Yq-OMn" secondAttribute="bottom" constant="10" id="jpn-he-6Ju"/>
|
||||
<constraint firstItem="pLr-Yq-OMn" firstAttribute="top" secondItem="mP8-S4-SUv" secondAttribute="bottom" constant="10" id="sbP-BO-Te7"/>
|
||||
<constraint firstItem="mP8-S4-SUv" firstAttribute="leading" secondItem="cIc-n7-hIV" secondAttribute="leading" constant="10" id="vUz-rq-dbN"/>
|
||||
<constraint firstAttribute="trailing" secondItem="mP8-S4-SUv" secondAttribute="trailing" constant="10" id="way-Az-buy"/>
|
||||
</constraints>
|
||||
<point key="canvasLocation" x="-13" y="400"/>
|
||||
</customView>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="NSCaution" width="32" height="32"/>
|
||||
|
||||
46
ShareExtension/QrCodeBackgroundView.swift
Normal file
46
ShareExtension/QrCodeBackgroundView.swift
Normal file
@@ -0,0 +1,46 @@
|
||||
//
|
||||
// QrCodeBackgroundView.swift
|
||||
// ShareExtension
|
||||
//
|
||||
// Created by Grishka on 07.08.2025.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Metal
|
||||
import MetalKit
|
||||
|
||||
class QrCodeBackgroundView:MTKView{
|
||||
private var commandQueue:MTLCommandQueue?
|
||||
private var commandBuffer:MTLCommandBuffer?
|
||||
|
||||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
isPaused=true
|
||||
enableSetNeedsDisplay=false
|
||||
device=MTLCreateSystemDefaultDevice()
|
||||
let brightness=1.5
|
||||
clearColor=MTLClearColor(red: brightness, green: brightness, blue: brightness, alpha: 1)
|
||||
|
||||
let mtlLayer:CAMetalLayer=(layer as? CAMetalLayer)!
|
||||
mtlLayer.wantsExtendedDynamicRangeContent=true
|
||||
mtlLayer.cornerRadius=20
|
||||
mtlLayer.masksToBounds=true
|
||||
colorspace=CGColorSpace(name: CGColorSpace.extendedSRGB)
|
||||
colorPixelFormat = .rgba16Float
|
||||
|
||||
commandQueue=device!.makeCommandQueue()
|
||||
commandBuffer=commandQueue!.makeCommandBuffer()
|
||||
draw()
|
||||
}
|
||||
|
||||
override func draw(_ dirtyRect: NSRect) {
|
||||
guard let commandBuffer=commandBuffer else {return}
|
||||
if let descriptor=currentRenderPassDescriptor, let encoder=commandBuffer.makeRenderCommandEncoder(descriptor: descriptor){
|
||||
encoder.endEncoding()
|
||||
if let currentDrawable=currentDrawable{
|
||||
commandBuffer.present(currentDrawable)
|
||||
}
|
||||
}
|
||||
commandBuffer.commit()
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@
|
||||
import Foundation
|
||||
import Cocoa
|
||||
import NearbyShare
|
||||
import QRCode
|
||||
|
||||
class ShareViewController: NSViewController, ShareExtensionDelegate{
|
||||
|
||||
@@ -15,6 +16,7 @@ class ShareViewController: NSViewController, ShareExtensionDelegate{
|
||||
private var foundDevices:[RemoteDeviceInfo]=[]
|
||||
private var chosenDevice:RemoteDeviceInfo?
|
||||
private var lastError:Error?
|
||||
private var sheetWindow:NSWindow?
|
||||
|
||||
@IBOutlet var filesIcon:NSImageView?
|
||||
@IBOutlet var filesLabel:NSTextField?
|
||||
@@ -30,6 +32,11 @@ class ShareViewController: NSViewController, ShareExtensionDelegate{
|
||||
@IBOutlet var progressState:NSTextField?
|
||||
@IBOutlet var progressDeviceIconWrap:NSView?
|
||||
@IBOutlet var progressDeviceSecondaryIcon:NSImageView?
|
||||
@IBOutlet var qrCodeButton:NSButton?
|
||||
|
||||
@IBOutlet var qrCodeSheetView:NSView?
|
||||
@IBOutlet var qrCodeView:NSImageView?
|
||||
@IBOutlet var qrCodeWrapView:NSView?
|
||||
|
||||
override var nibName: NSNib.Name? {
|
||||
return NSNib.Name("ShareViewController")
|
||||
@@ -38,7 +45,6 @@ class ShareViewController: NSViewController, ShareExtensionDelegate{
|
||||
override func loadView() {
|
||||
super.loadView()
|
||||
|
||||
// Insert code here to customize the view
|
||||
let item = self.extensionContext!.inputItems[0] as! NSExtensionItem
|
||||
if let attachments = item.attachments {
|
||||
for attachment in attachments as NSArray{
|
||||
@@ -99,6 +105,13 @@ class ShareViewController: NSViewController, ShareExtensionDelegate{
|
||||
|
||||
progressDeviceIconWrap!.wantsLayer=true
|
||||
progressDeviceIconWrap!.layer!.masksToBounds=false
|
||||
|
||||
qrCodeWrapView!.wantsLayer=true
|
||||
qrCodeWrapView!.layer!.masksToBounds=false
|
||||
qrCodeWrapView!.layer!.shadowColor = .black
|
||||
qrCodeWrapView!.layer!.shadowOpacity=0.3
|
||||
qrCodeWrapView!.layer!.shadowRadius=12
|
||||
qrCodeWrapView!.layer!.shadowOffset=CGSizeMake(0, -5)
|
||||
}
|
||||
|
||||
override func viewDidLoad(){
|
||||
@@ -122,6 +135,39 @@ class ShareViewController: NSViewController, ShareExtensionDelegate{
|
||||
self.extensionContext!.cancelRequest(withError: cancelError)
|
||||
}
|
||||
|
||||
@IBAction func useQrCode(_ sender: AnyObject?) {
|
||||
let window=contentWrap!.window!
|
||||
let sheetWindow=NSWindow()
|
||||
sheetWindow.contentView=qrCodeSheetView!
|
||||
let size=NSSize(width: 380, height: 400)
|
||||
sheetWindow.contentMaxSize=size
|
||||
sheetWindow.contentMinSize=size
|
||||
sheetWindow.setContentSize(size)
|
||||
|
||||
let qrKey=NearbyConnectionManager.shared.generateQrCodeKey()
|
||||
let qrCodeImage=try! QRCode.build
|
||||
.text("https://quickshare.google/qrcode#key=\(qrKey)")
|
||||
.backgroundColor(CGColor(srgbRed: 1, green: 1, blue: 1, alpha: 0))
|
||||
.quietZonePixelCount(3)
|
||||
.onPixels.shape(.circle())
|
||||
.eye.shape(.roundedPointing())
|
||||
.errorCorrection(.low)
|
||||
.generate.image(dimension: Int(qrCodeView!.frame.width)*2)
|
||||
qrCodeView!.image=NSImage(cgImage: qrCodeImage, size: qrCodeImage.size)
|
||||
|
||||
self.sheetWindow=sheetWindow
|
||||
window.beginSheet(sheetWindow) { response in
|
||||
self.sheetWindow=nil
|
||||
NearbyConnectionManager.shared.clearQrCodeKey()
|
||||
}
|
||||
}
|
||||
|
||||
@IBAction func dismissQrCodeSheet(_ sender: AnyObject?){
|
||||
contentWrap!.window!.endSheet(sheetWindow!)
|
||||
sheetWindow=nil
|
||||
NearbyConnectionManager.shared.clearQrCodeKey()
|
||||
}
|
||||
|
||||
private func urlsReady(){
|
||||
for url in urls{
|
||||
if url.isFileURL{
|
||||
@@ -172,6 +218,11 @@ class ShareViewController: NSViewController, ShareExtensionDelegate{
|
||||
}
|
||||
}
|
||||
|
||||
func startTransferWithQrCode(device: RemoteDeviceInfo){
|
||||
dismissQrCodeSheet(nil)
|
||||
selectDevice(device: device)
|
||||
}
|
||||
|
||||
func connectionWasEstablished(pinCode: String) {
|
||||
progressState?.stringValue=String(format:NSLocalizedString("PinCode", value: "PIN: %@", comment: ""), arguments: [pinCode])
|
||||
progressProgressBar?.isIndeterminate=false
|
||||
@@ -224,6 +275,7 @@ class ShareViewController: NSViewController, ShareExtensionDelegate{
|
||||
NearbyConnectionManager.shared.stopDeviceDiscovery()
|
||||
listViewWrapper?.animator().isHidden=true
|
||||
progressView?.animator().isHidden=false
|
||||
qrCodeButton?.animator().isHidden=true
|
||||
progressDeviceName?.stringValue=device.name
|
||||
progressDeviceIcon?.image=imageForDeviceType(type: device.type)
|
||||
progressProgressBar?.startAnimation(nil)
|
||||
|
||||
@@ -5,8 +5,20 @@
|
||||
/* Class = "NSButtonCell"; title = "Cancel"; ObjectID = "6Up-t3-mwm"; */
|
||||
"6Up-t3-mwm.title" = "Отменить";
|
||||
|
||||
/* Class = "NSButtonCell"; title = "Cancel"; ObjectID = "9EW-Db-fGL"; */
|
||||
"9EW-Db-fGL.title" = "Отменить";
|
||||
|
||||
/* Class = "NSButtonCell"; title = "Use QR code..."; ObjectID = "Ll5-lP-3bU"; */
|
||||
"Ll5-lP-3bU.title" = "Использовать QR-код...";
|
||||
|
||||
/* Class = "NSTextFieldCell"; title = "Looking for devices..."; ObjectID = "NaJ-Wx-Pim"; */
|
||||
"NaJ-Wx-Pim.title" = "Ищу устройства...";
|
||||
|
||||
/* Class = "NSTextFieldCell"; title = "Scan this QR code with an Android device. The transfer will begin automatically."; ObjectID = "d3J-ot-h5d"; */
|
||||
"d3J-ot-h5d.title" = "Отсканируйте этот QR-код на Android-устройстве. Передача начнётся автоматически.";
|
||||
|
||||
/* Class = "NSTextFieldCell"; title = "If this doesn't work, make sure that the device and your Mac are on the same network, and that the router isn't blocking LAN communication."; ObjectID = "uuF-4K-rMR"; */
|
||||
"uuF-4K-rMR.title" = "Если соединиться не удаётся, убедитесь, что устройство и Mac находятся в одной сети, и что роутер не блокирует передачу данных по локальной сети.";
|
||||
|
||||
/* Class = "NSTextFieldCell"; title = "If you don't see your device, open \"Files by Google\" app and tap \"Receive\" on the Nearby Share tab."; ObjectID = "vla-gF-eJo"; */
|
||||
"vla-gF-eJo.title" = "Если Вы не видите своё устройство, откройте приложение \"Google Files\" и нажмите \"Получить\" на вкладке Обмен.";
|
||||
|
||||
Reference in New Issue
Block a user