mirror of
https://github.com/grishka/NearDrop.git
synced 2026-04-03 01:36:15 +02:00
An experimental share extension to send files and too much refactoring
closes #4
This commit is contained in:
6
ShareExtension/Assets.xcassets/Contents.json
Normal file
6
ShareExtension/Assets.xcassets/Contents.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
ShareExtension/Assets.xcassets/NearDropIcon.imageset/16.png
vendored
Normal file
BIN
ShareExtension/Assets.xcassets/NearDropIcon.imageset/16.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1005 B |
BIN
ShareExtension/Assets.xcassets/NearDropIcon.imageset/32.png
vendored
Normal file
BIN
ShareExtension/Assets.xcassets/NearDropIcon.imageset/32.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.0 KiB |
22
ShareExtension/Assets.xcassets/NearDropIcon.imageset/Contents.json
vendored
Normal file
22
ShareExtension/Assets.xcassets/NearDropIcon.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "16.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "32.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
ShareExtension/Base.lproj/Localizable.strings
Normal file
BIN
ShareExtension/Base.lproj/Localizable.strings
Normal file
Binary file not shown.
22
ShareExtension/Base.lproj/Localizable.stringsdict
Normal file
22
ShareExtension/Base.lproj/Localizable.stringsdict
Normal file
@@ -0,0 +1,22 @@
|
||||
<?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>NFiles</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@files@</string>
|
||||
<key>files</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>%d file</string>
|
||||
<key>other</key>
|
||||
<string>%d files</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
264
ShareExtension/Base.lproj/ShareViewController.xib
Normal file
264
ShareExtension/Base.lproj/ShareViewController.xib
Normal file
@@ -0,0 +1,264 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="21701" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="21701"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="ShareViewController" customModule="ShareExtension" customModuleProvider="target">
|
||||
<connections>
|
||||
<outlet property="contentWrap" destination="ACO-U2-AZj" id="PAE-Pw-Vyx"/>
|
||||
<outlet property="filesIcon" destination="afM-Om-nLQ" id="I58-a3-SBZ"/>
|
||||
<outlet property="filesLabel" destination="OEz-QK-nem" id="his-3f-6kx"/>
|
||||
<outlet property="largeProgress" destination="fCj-wF-rEj" id="jEg-Uc-Ur7"/>
|
||||
<outlet property="listView" destination="gZI-Zb-Blx" id="VOC-3j-Pwy"/>
|
||||
<outlet property="listViewWrapper" destination="A4d-Qt-PsT" id="8g5-VW-MIb"/>
|
||||
<outlet property="loadingOverlay" destination="fLZ-IA-bPS" id="84g-Ef-GzW"/>
|
||||
<outlet property="progressDeviceIcon" destination="84U-lB-SRB" id="LEL-BY-2FY"/>
|
||||
<outlet property="progressDeviceIconWrap" destination="jBg-Ih-Gac" id="69x-6y-z0c"/>
|
||||
<outlet property="progressDeviceName" destination="dJc-gw-4ux" id="ZE4-Kx-5hv"/>
|
||||
<outlet property="progressDeviceSecondaryIcon" destination="BEO-kU-a2Q" id="iks-QR-2Od"/>
|
||||
<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="view" destination="1" id="2"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||
<customView translatesAutoresizingMaskIntoConstraints="NO" id="1">
|
||||
<rect key="frame" x="0.0" y="0.0" width="404" height="248"/>
|
||||
<subviews>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="NVE-vN-dkz">
|
||||
<rect key="frame" x="325" y="3" width="76" height="32"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="60" id="cP1-hK-9ZX"/>
|
||||
</constraints>
|
||||
<buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="6Up-t3-mwm">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
<string key="keyEquivalent" base64-UTF8="YES">
|
||||
Gw
|
||||
</string>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="cancel:" target="-2" id="Qav-AK-DGt"/>
|
||||
</connections>
|
||||
</button>
|
||||
<stackView distribution="fill" orientation="horizontal" alignment="top" spacing="5" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="1xF-vr-5sH">
|
||||
<rect key="frame" x="160" y="222" width="84" height="16"/>
|
||||
<subviews>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="4M6-D5-WIf">
|
||||
<rect key="frame" x="0.0" y="0.0" width="16" height="16"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="16" id="BOe-aZ-Njc"/>
|
||||
<constraint firstAttribute="height" constant="16" id="zLg-1a-wlZ"/>
|
||||
</constraints>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="NearDropIcon" id="q3u-Am-ZIA"/>
|
||||
</imageView>
|
||||
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="aNc-0i-CWK">
|
||||
<rect key="frame" x="19" y="0.0" width="67" height="16"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="left" title="NearDrop" allowsEditingTextAttributes="YES" id="0xp-rC-2gr">
|
||||
<font key="font" metaFont="systemBold"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
</subviews>
|
||||
<visibilityPriorities>
|
||||
<integer value="1000"/>
|
||||
<integer value="1000"/>
|
||||
</visibilityPriorities>
|
||||
<customSpacing>
|
||||
<real value="3.4028234663852886e+38"/>
|
||||
<real value="3.4028234663852886e+38"/>
|
||||
</customSpacing>
|
||||
</stackView>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="afM-Om-nLQ">
|
||||
<rect key="frame" x="10" y="196" width="16" height="16"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="16" id="3NE-mW-Jk0"/>
|
||||
<constraint firstAttribute="height" constant="16" id="koV-ob-gSn"/>
|
||||
</constraints>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" id="jOq-9r-V1W"/>
|
||||
</imageView>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" setsMaxLayoutWidthAtFirstLayout="YES" translatesAutoresizingMaskIntoConstraints="NO" id="OEz-QK-nem">
|
||||
<rect key="frame" x="29" y="196" width="367" height="16"/>
|
||||
<textFieldCell key="cell" lineBreakMode="truncatingMiddle" truncatesLastVisibleLine="YES" id="opy-Bj-x6u">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<customView translatesAutoresizingMaskIntoConstraints="NO" id="ACO-U2-AZj">
|
||||
<rect key="frame" x="0.0" y="40" width="404" height="146"/>
|
||||
</customView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="OEz-QK-nem" firstAttribute="top" secondItem="1xF-vr-5sH" secondAttribute="bottom" constant="10" id="852-oh-vM0"/>
|
||||
<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="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"/>
|
||||
<constraint firstAttribute="trailing" secondItem="NVE-vN-dkz" secondAttribute="trailing" constant="10" id="Z6U-4n-4tO"/>
|
||||
<constraint firstItem="afM-Om-nLQ" firstAttribute="top" secondItem="1" secondAttribute="top" constant="36" id="fUG-kT-wb0"/>
|
||||
<constraint firstItem="1xF-vr-5sH" firstAttribute="centerX" secondItem="1" secondAttribute="centerX" id="sCA-yf-S9L"/>
|
||||
<constraint firstItem="1xF-vr-5sH" firstAttribute="top" secondItem="1" secondAttribute="top" constant="10" id="tFn-vk-9Cq"/>
|
||||
<constraint firstAttribute="trailing" secondItem="OEz-QK-nem" secondAttribute="trailing" constant="10" id="vyd-BI-oDH"/>
|
||||
<constraint firstItem="ACO-U2-AZj" firstAttribute="top" secondItem="OEz-QK-nem" secondAttribute="bottom" constant="10" id="x5r-wc-s4x"/>
|
||||
</constraints>
|
||||
<point key="canvasLocation" x="140" y="-36"/>
|
||||
</customView>
|
||||
<stackView wantsLayer="YES" distribution="equalSpacing" orientation="vertical" alignment="centerX" spacing="0.0" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" id="fLZ-IA-bPS">
|
||||
<rect key="frame" x="0.0" y="0.0" width="521" height="100"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<subviews>
|
||||
<progressIndicator maxValue="100" indeterminate="YES" style="spinning" translatesAutoresizingMaskIntoConstraints="NO" id="fCj-wF-rEj">
|
||||
<rect key="frame" x="245" y="68" width="32" height="32"/>
|
||||
</progressIndicator>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="27P-yf-gUd">
|
||||
<rect key="frame" x="189" y="42" width="144" height="16"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" title="Looking for devices..." id="NaJ-Wx-Pim">
|
||||
<font key="font" textStyle="headline" name=".SFNS-Bold"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="V5W-Rm-YVM">
|
||||
<rect key="frame" x="-2" y="0.0" width="525" height="32"/>
|
||||
<textFieldCell key="cell" alignment="center" title="If you don't see your device, open "Files by Google" app and tap "Receive" on the Nearby Share tab." id="vla-gF-eJo">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="27P-yf-gUd" firstAttribute="top" secondItem="fCj-wF-rEj" secondAttribute="bottom" constant="10" id="87W-ec-fMh"/>
|
||||
<constraint firstItem="V5W-Rm-YVM" firstAttribute="top" secondItem="27P-yf-gUd" secondAttribute="bottom" constant="10" id="OSI-wI-LcY"/>
|
||||
</constraints>
|
||||
<visibilityPriorities>
|
||||
<integer value="1000"/>
|
||||
<integer value="1000"/>
|
||||
<integer value="1000"/>
|
||||
</visibilityPriorities>
|
||||
<customSpacing>
|
||||
<real value="3.4028234663852886e+38"/>
|
||||
<real value="3.4028234663852886e+38"/>
|
||||
<real value="3.4028234663852886e+38"/>
|
||||
</customSpacing>
|
||||
<point key="canvasLocation" x="660.5" y="-1.5"/>
|
||||
</stackView>
|
||||
<stackView wantsLayer="YES" distribution="equalSpacing" orientation="vertical" alignment="centerX" spacing="1" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" id="Q9K-dc-THx">
|
||||
<rect key="frame" x="0.0" y="0.0" width="384" height="130"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<customView translatesAutoresizingMaskIntoConstraints="NO" id="jBg-Ih-Gac">
|
||||
<rect key="frame" x="168" y="82" width="48" height="48"/>
|
||||
<subviews>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="84U-lB-SRB">
|
||||
<rect key="frame" x="0.0" y="0.0" width="48" height="48"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="48" id="9ld-k4-EkL"/>
|
||||
<constraint firstAttribute="height" constant="48" id="XA4-2k-hqR"/>
|
||||
</constraints>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" id="rb3-78-PXe"/>
|
||||
</imageView>
|
||||
<imageView hidden="YES" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="BEO-kU-a2Q">
|
||||
<rect key="frame" x="24" y="-8" width="32" height="32"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="32" id="05I-Ef-84Z"/>
|
||||
<constraint firstAttribute="width" constant="32" id="V0g-Fz-HWH"/>
|
||||
</constraints>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="NSCaution" id="k1c-Xl-fTQ"/>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" secondItem="BEO-kU-a2Q" secondAttribute="trailing" constant="-8" id="59U-Zi-ESa"/>
|
||||
<constraint firstAttribute="bottom" secondItem="BEO-kU-a2Q" secondAttribute="bottom" constant="-8" id="8ty-pq-miR"/>
|
||||
<constraint firstItem="84U-lB-SRB" firstAttribute="top" secondItem="jBg-Ih-Gac" secondAttribute="top" id="MB9-UI-2mb"/>
|
||||
<constraint firstItem="84U-lB-SRB" firstAttribute="leading" secondItem="jBg-Ih-Gac" secondAttribute="leading" id="b23-hJ-aWT"/>
|
||||
<constraint firstAttribute="trailing" secondItem="84U-lB-SRB" secondAttribute="trailing" id="eKl-3V-K49"/>
|
||||
<constraint firstAttribute="bottom" secondItem="84U-lB-SRB" secondAttribute="bottom" id="uh8-T1-Vd8"/>
|
||||
</constraints>
|
||||
</customView>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" setsMaxLayoutWidthAtFirstLayout="YES" translatesAutoresizingMaskIntoConstraints="NO" id="dJc-gw-4ux">
|
||||
<rect key="frame" x="-2" y="56" width="388" height="16"/>
|
||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" alignment="center" id="QzI-qQ-OBb">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<progressIndicator maxValue="100" doubleValue="50" indeterminate="YES" style="bar" translatesAutoresizingMaskIntoConstraints="NO" id="J5x-hu-Kn5">
|
||||
<rect key="frame" x="92" y="25" width="200" height="22"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="200" id="bM2-Ih-2UC"/>
|
||||
</constraints>
|
||||
</progressIndicator>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="y8I-D3-scQ">
|
||||
<rect key="frame" x="165" y="0.0" width="54" height="16"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" id="Iin-UY-IE5">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="secondaryLabelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="y8I-D3-scQ" firstAttribute="top" secondItem="J5x-hu-Kn5" secondAttribute="bottom" constant="10" id="4EB-xc-Qni"/>
|
||||
<constraint firstItem="dJc-gw-4ux" firstAttribute="leading" secondItem="Q9K-dc-THx" secondAttribute="leading" id="IXP-am-A8h"/>
|
||||
<constraint firstItem="J5x-hu-Kn5" firstAttribute="top" secondItem="dJc-gw-4ux" secondAttribute="bottom" constant="10" id="Zav-Ho-QEJ"/>
|
||||
<constraint firstItem="dJc-gw-4ux" firstAttribute="top" secondItem="jBg-Ih-Gac" secondAttribute="bottom" constant="10" id="bIE-Es-ZbK"/>
|
||||
<constraint firstAttribute="trailing" secondItem="dJc-gw-4ux" secondAttribute="trailing" id="bKd-Vz-YA1"/>
|
||||
</constraints>
|
||||
<visibilityPriorities>
|
||||
<integer value="1000"/>
|
||||
<integer value="1000"/>
|
||||
<integer value="1000"/>
|
||||
<integer value="1000"/>
|
||||
</visibilityPriorities>
|
||||
<customSpacing>
|
||||
<real value="3.4028234663852886e+38"/>
|
||||
<real value="3.4028234663852886e+38"/>
|
||||
<real value="3.4028234663852886e+38"/>
|
||||
<real value="3.4028234663852886e+38"/>
|
||||
</customSpacing>
|
||||
<point key="canvasLocation" x="4" y="-288"/>
|
||||
</stackView>
|
||||
<scrollView wantsLayer="YES" autohidesScrollers="YES" horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" id="A4d-Qt-PsT">
|
||||
<rect key="frame" x="0.0" y="0.0" width="271" height="172"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<clipView key="contentView" id="cCr-8P-Lya">
|
||||
<rect key="frame" x="1" y="1" width="269" height="170"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<collectionView id="gZI-Zb-Blx">
|
||||
<rect key="frame" x="0.0" y="0.0" width="269" height="170"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES"/>
|
||||
<collectionViewFlowLayout key="collectionViewLayout" minimumInteritemSpacing="10" minimumLineSpacing="10" id="ATS-Jd-odC">
|
||||
<size key="itemSize" width="50" height="50"/>
|
||||
</collectionViewFlowLayout>
|
||||
<color key="primaryBackgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</collectionView>
|
||||
</subviews>
|
||||
</clipView>
|
||||
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="3j2-z3-G1e">
|
||||
<rect key="frame" x="-100" y="-100" width="402" height="16"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
<scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="wty-KV-JAg">
|
||||
<rect key="frame" x="380" y="1" width="16" height="142"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
<point key="canvasLocation" x="-397.5" y="30"/>
|
||||
</scrollView>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="NSCaution" width="32" height="32"/>
|
||||
<image name="NearDropIcon" width="16" height="16"/>
|
||||
</resources>
|
||||
</document>
|
||||
26
ShareExtension/DeviceListCell.swift
Normal file
26
ShareExtension/DeviceListCell.swift
Normal file
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// DeviceListCell.swift
|
||||
// ShareExtension
|
||||
//
|
||||
// Created by Grishka on 20.09.2023.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
|
||||
class DeviceListCell:NSCollectionViewItem {
|
||||
public var clickHandler:(()->Void)?
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
let btn:NSButton=view as! NSButton
|
||||
btn.isEnabled=true
|
||||
btn.setButtonType(.momentaryPushIn)
|
||||
btn.action=#selector(onClick)
|
||||
btn.target=self
|
||||
}
|
||||
|
||||
@IBAction func onClick(_ sender:Any?){
|
||||
guard let handler=clickHandler else {return}
|
||||
handler()
|
||||
}
|
||||
}
|
||||
61
ShareExtension/DeviceListCell.xib
Normal file
61
ShareExtension/DeviceListCell.xib
Normal file
@@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="21701" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="21701"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="DeviceListCell" customModule="ShareExtension" customModuleProvider="target">
|
||||
<connections>
|
||||
<outlet property="view" destination="Hz6-mo-xeY" id="gtq-ca-SBh"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||
<customView misplaced="YES" id="Hz6-mo-xeY" customClass="NSButton">
|
||||
<rect key="frame" x="0.0" y="0.0" width="206" height="82"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<subviews>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" setsMaxLayoutWidthAtFirstLayout="YES" translatesAutoresizingMaskIntoConstraints="NO" id="QPM-sE-maP">
|
||||
<rect key="frame" x="-2" y="0.0" width="210" height="32"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="32" id="TBS-IE-2DT"/>
|
||||
</constraints>
|
||||
<textFieldCell key="cell" truncatesLastVisibleLine="YES" alignment="center" title="Label" id="cXi-mf-qP0">
|
||||
<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>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="O1J-am-CoK">
|
||||
<rect key="frame" x="79" y="42" width="48" height="48"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="48" id="KYr-2E-wCO"/>
|
||||
<constraint firstAttribute="height" constant="48" id="nik-I6-YgB"/>
|
||||
</constraints>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" id="QGU-rR-rJQ"/>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="O1J-am-CoK" firstAttribute="centerX" secondItem="Hz6-mo-xeY" secondAttribute="centerX" id="R76-2L-pXb"/>
|
||||
<constraint firstAttribute="bottom" secondItem="QPM-sE-maP" secondAttribute="bottom" id="Ryn-nY-yZp"/>
|
||||
<constraint firstItem="O1J-am-CoK" firstAttribute="top" secondItem="Hz6-mo-xeY" secondAttribute="top" id="ZFA-S9-fpT"/>
|
||||
<constraint firstAttribute="trailing" secondItem="QPM-sE-maP" secondAttribute="trailing" id="eOl-Va-HXq"/>
|
||||
<constraint firstItem="QPM-sE-maP" firstAttribute="top" secondItem="O1J-am-CoK" secondAttribute="bottom" constant="10" id="leg-nD-mHB"/>
|
||||
<constraint firstItem="QPM-sE-maP" firstAttribute="leading" secondItem="Hz6-mo-xeY" secondAttribute="leading" id="vvH-Hq-iUk"/>
|
||||
</constraints>
|
||||
<connections>
|
||||
<action selector="onClick:" target="-2" id="mve-gp-q4i"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="-60" y="150"/>
|
||||
</customView>
|
||||
<collectionViewItem id="1Lb-iJ-Nar" customClass="DeviceListCell" customModule="ShareExtension" customModuleProvider="target">
|
||||
<connections>
|
||||
<outlet property="imageView" destination="O1J-am-CoK" id="zQn-mV-bRy"/>
|
||||
<outlet property="textField" destination="QPM-sE-maP" id="s0j-Qq-7iA"/>
|
||||
<outlet property="view" destination="Hz6-mo-xeY" id="gZn-20-o77"/>
|
||||
</connections>
|
||||
</collectionViewItem>
|
||||
</objects>
|
||||
</document>
|
||||
27
ShareExtension/Info.plist
Normal file
27
ShareExtension/Info.plist
Normal file
@@ -0,0 +1,27 @@
|
||||
<?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>NSExtension</key>
|
||||
<dict>
|
||||
<key>NSExtensionAttributes</key>
|
||||
<dict>
|
||||
<key>NSExtensionActivationRule</key>
|
||||
<string>SUBQUERY (
|
||||
extensionItems,
|
||||
$extensionItem,
|
||||
SUBQUERY (
|
||||
$extensionItem.attachments,
|
||||
$attachment,
|
||||
ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.file-url"
|
||||
AND NOT (ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.folder")
|
||||
).@count == $extensionItem.attachments.@count
|
||||
).@count > 0</string>
|
||||
</dict>
|
||||
<key>NSExtensionPointIdentifier</key>
|
||||
<string>com.apple.share-services</string>
|
||||
<key>NSExtensionPrincipalClass</key>
|
||||
<string>$(PRODUCT_MODULE_NAME).ShareViewController</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
14
ShareExtension/ShareExtension.entitlements
Normal file
14
ShareExtension/ShareExtension.entitlements
Normal file
@@ -0,0 +1,14 @@
|
||||
<?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>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
<key>com.apple.security.files.user-selected.read-only</key>
|
||||
<true/>
|
||||
<key>com.apple.security.network.client</key>
|
||||
<true/>
|
||||
<key>com.apple.security.network.server</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
271
ShareExtension/ShareViewController.swift
Normal file
271
ShareExtension/ShareViewController.swift
Normal file
@@ -0,0 +1,271 @@
|
||||
//
|
||||
// ShareViewController.swift
|
||||
// ShareExtension
|
||||
//
|
||||
// Created by Grishka on 12.09.2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Cocoa
|
||||
import NearbyShare
|
||||
|
||||
class ShareViewController: NSViewController, ShareExtensionDelegate{
|
||||
|
||||
private var urls:[URL]=[]
|
||||
private var foundDevices:[RemoteDeviceInfo]=[]
|
||||
private var chosenDevice:RemoteDeviceInfo?
|
||||
private var lastError:Error?
|
||||
|
||||
@IBOutlet var filesIcon:NSImageView?
|
||||
@IBOutlet var filesLabel:NSTextField?
|
||||
@IBOutlet var loadingOverlay:NSStackView?
|
||||
@IBOutlet var largeProgress:NSProgressIndicator?
|
||||
@IBOutlet var listView:NSCollectionView?
|
||||
@IBOutlet var listViewWrapper:NSView?
|
||||
@IBOutlet var contentWrap:NSView?
|
||||
@IBOutlet var progressView:NSView?
|
||||
@IBOutlet var progressDeviceIcon:NSImageView?
|
||||
@IBOutlet var progressDeviceName:NSTextField?
|
||||
@IBOutlet var progressProgressBar:NSProgressIndicator?
|
||||
@IBOutlet var progressState:NSTextField?
|
||||
@IBOutlet var progressDeviceIconWrap:NSView?
|
||||
@IBOutlet var progressDeviceSecondaryIcon:NSImageView?
|
||||
|
||||
override var nibName: NSNib.Name? {
|
||||
return NSNib.Name("ShareViewController")
|
||||
}
|
||||
|
||||
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{
|
||||
let provider=attachment as! NSItemProvider
|
||||
provider.loadItem(forTypeIdentifier: kUTTypeURL as String) { data, err in
|
||||
if let url=URL(dataRepresentation: data as! Data, relativeTo: nil, isAbsolute: false){
|
||||
self.urls.append(url)
|
||||
if self.urls.count==attachments.count{
|
||||
DispatchQueue.main.async {
|
||||
self.urlsReady()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let cancelError = NSError(domain: NSCocoaErrorDomain, code: NSUserCancelledError, userInfo: nil)
|
||||
self.extensionContext!.cancelRequest(withError: cancelError)
|
||||
return
|
||||
}
|
||||
|
||||
contentWrap!.addSubview(listViewWrapper!)
|
||||
contentWrap!.addSubview(loadingOverlay!)
|
||||
contentWrap!.addSubview(progressView!)
|
||||
progressView!.isHidden=true
|
||||
|
||||
listViewWrapper!.translatesAutoresizingMaskIntoConstraints=false
|
||||
loadingOverlay!.translatesAutoresizingMaskIntoConstraints=false
|
||||
progressView!.translatesAutoresizingMaskIntoConstraints=false
|
||||
NSLayoutConstraint.activate([
|
||||
NSLayoutConstraint(item: listViewWrapper!, attribute: .width, relatedBy: .equal, toItem: contentWrap, attribute: .width, multiplier: 1, constant: 0),
|
||||
NSLayoutConstraint(item: listViewWrapper!, attribute: .height, relatedBy: .equal, toItem: contentWrap, attribute: .height, multiplier: 1, constant: 0),
|
||||
|
||||
NSLayoutConstraint(item: loadingOverlay!, attribute: .width, relatedBy: .equal, toItem: contentWrap, attribute: .width, multiplier: 1, constant: 0),
|
||||
NSLayoutConstraint(item: loadingOverlay!, attribute: .centerY, relatedBy: .equal, toItem: contentWrap, attribute: .centerY, multiplier: 1, constant: 0),
|
||||
|
||||
NSLayoutConstraint(item: progressView!, attribute: .width, relatedBy: .equal, toItem: contentWrap, attribute: .width, multiplier: 1, constant: 0),
|
||||
NSLayoutConstraint(item: progressView!, attribute: .centerY, relatedBy: .equal, toItem: contentWrap, attribute: .centerY, multiplier: 1, constant: 0)
|
||||
])
|
||||
|
||||
largeProgress!.startAnimation(nil)
|
||||
let flowLayout=NSCollectionViewFlowLayout()
|
||||
flowLayout.itemSize=NSSize(width: 75, height: 90)
|
||||
flowLayout.sectionInset=NSEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
|
||||
flowLayout.minimumInteritemSpacing=10
|
||||
flowLayout.minimumLineSpacing=10
|
||||
listView!.collectionViewLayout=flowLayout
|
||||
listView!.dataSource=self
|
||||
|
||||
progressDeviceIconWrap!.wantsLayer=true
|
||||
progressDeviceIconWrap!.layer!.masksToBounds=false
|
||||
}
|
||||
|
||||
override func viewDidLoad(){
|
||||
super.viewDidLoad()
|
||||
NearbyConnectionManager.shared.startDeviceDiscovery()
|
||||
NearbyConnectionManager.shared.addShareExtensionDelegate(self)
|
||||
}
|
||||
|
||||
override func viewWillDisappear() {
|
||||
if chosenDevice==nil{
|
||||
NearbyConnectionManager.shared.stopDeviceDiscovery()
|
||||
}
|
||||
NearbyConnectionManager.shared.removeShareExtensionDelegate(self)
|
||||
}
|
||||
|
||||
@IBAction func cancel(_ sender: AnyObject?) {
|
||||
if let device=chosenDevice{
|
||||
NearbyConnectionManager.shared.cancelOutgoingTransfer(id: device.id!)
|
||||
}
|
||||
let cancelError = NSError(domain: NSCocoaErrorDomain, code: NSUserCancelledError, userInfo: nil)
|
||||
self.extensionContext!.cancelRequest(withError: cancelError)
|
||||
}
|
||||
|
||||
private func urlsReady(){
|
||||
for url in urls{
|
||||
if url.isFileURL{
|
||||
var isDirectory=UnsafeMutablePointer<ObjCBool>.allocate(capacity: 1)
|
||||
if FileManager.default.fileExists(atPath: url.path, isDirectory: isDirectory) && isDirectory.pointee.boolValue{
|
||||
print("Canceling share request because URL \(url) is a directory")
|
||||
let cancelError = NSError(domain: NSCocoaErrorDomain, code: NSUserCancelledError, userInfo: nil)
|
||||
self.extensionContext!.cancelRequest(withError: cancelError)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
if urls.count==1{
|
||||
if urls[0].isFileURL{
|
||||
filesLabel!.stringValue=urls[0].lastPathComponent
|
||||
filesIcon!.image=NSWorkspace.shared.icon(forFile: urls[0].path)
|
||||
}else if urls[0].scheme=="http" || urls[0].scheme=="https"{
|
||||
filesLabel!.stringValue=urls[0].absoluteString
|
||||
filesIcon!.image=NSImage(named: NSImage.networkName)
|
||||
}
|
||||
}else{
|
||||
filesLabel!.stringValue=String.localizedStringWithFormat(NSLocalizedString("NFiles", value: "%d files", comment: ""), urls.count)
|
||||
filesIcon!.image=NSImage(named: NSImage.multipleDocumentsName)
|
||||
}
|
||||
}
|
||||
|
||||
func addDevice(device: RemoteDeviceInfo) {
|
||||
if foundDevices.isEmpty{
|
||||
loadingOverlay?.animator().isHidden=true
|
||||
}
|
||||
foundDevices.append(device)
|
||||
listView?.animator().insertItems(at: [[0, foundDevices.count-1]])
|
||||
}
|
||||
|
||||
func removeDevice(id: String){
|
||||
if chosenDevice != nil{
|
||||
return
|
||||
}
|
||||
for i in foundDevices.indices{
|
||||
if foundDevices[i].id==id{
|
||||
foundDevices.remove(at: i)
|
||||
listView?.animator().deleteItems(at: [[0, i]])
|
||||
break
|
||||
}
|
||||
}
|
||||
if foundDevices.isEmpty{
|
||||
loadingOverlay?.animator().isHidden=false
|
||||
}
|
||||
}
|
||||
|
||||
func connectionWasEstablished(pinCode: String) {
|
||||
progressState?.stringValue=String(format:NSLocalizedString("PinCode", value: "PIN: %@", comment: ""), arguments: [pinCode])
|
||||
progressProgressBar?.isIndeterminate=false
|
||||
progressProgressBar?.maxValue=1000
|
||||
progressProgressBar?.doubleValue=0
|
||||
}
|
||||
|
||||
func connectionFailed(with error: Error) {
|
||||
progressProgressBar?.isIndeterminate=false
|
||||
progressProgressBar?.maxValue=1000
|
||||
progressProgressBar?.doubleValue=0
|
||||
lastError=error
|
||||
if let ne=(error as? NearbyError), case let .canceled(reason)=ne{
|
||||
switch reason{
|
||||
case .userRejected:
|
||||
progressState?.stringValue=NSLocalizedString("TransferDeclined", value: "Declined", comment: "")
|
||||
case .userCanceled:
|
||||
progressState?.stringValue=NSLocalizedString("TransferCanceled", value: "Canceled", comment: "")
|
||||
case .notEnoughSpace:
|
||||
progressState?.stringValue=NSLocalizedString("NotEnoughSpace", value: "Not enough disk space", comment: "")
|
||||
case .unsupportedType:
|
||||
progressState?.stringValue=NSLocalizedString("UnsupportedType", value: "Attachment type not supported", comment: "")
|
||||
case .timedOut:
|
||||
progressState?.stringValue=NSLocalizedString("TransferTimedOut", value: "Timed out", comment: "")
|
||||
}
|
||||
progressDeviceSecondaryIcon?.isHidden=false
|
||||
dismissDelayed()
|
||||
}else{
|
||||
let alert=NSAlert(error: error)
|
||||
alert.beginSheetModal(for: view.window!) { resp in
|
||||
self.extensionContext!.cancelRequest(withError: error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func transferAccepted() {
|
||||
progressState?.stringValue=NSLocalizedString("Sending", value: "Sending...", comment: "")
|
||||
}
|
||||
|
||||
func transferProgress(progress: Double) {
|
||||
progressProgressBar!.doubleValue=progress*progressProgressBar!.maxValue
|
||||
}
|
||||
|
||||
func transferFinished() {
|
||||
progressState?.stringValue=NSLocalizedString("TransferFinished", value: "Transfer finished", comment: "")
|
||||
dismissDelayed()
|
||||
}
|
||||
|
||||
func selectDevice(device:RemoteDeviceInfo){
|
||||
NearbyConnectionManager.shared.stopDeviceDiscovery()
|
||||
listViewWrapper?.animator().isHidden=true
|
||||
progressView?.animator().isHidden=false
|
||||
progressDeviceName?.stringValue=device.name
|
||||
progressDeviceIcon?.image=imageForDeviceType(type: device.type)
|
||||
progressProgressBar?.startAnimation(nil)
|
||||
progressState?.stringValue=NSLocalizedString("Connecting", value: "Connecting...", comment: "")
|
||||
chosenDevice=device
|
||||
NearbyConnectionManager.shared.startOutgoingTransfer(deviceID: device.id!, delegate: self, urls: urls)
|
||||
}
|
||||
|
||||
private func dismissDelayed(){
|
||||
DispatchQueue.main.asyncAfter(deadline: .now()+2.0){
|
||||
if let error=self.lastError{
|
||||
self.extensionContext!.cancelRequest(withError: error)
|
||||
}else{
|
||||
self.extensionContext!.completeRequest(returningItems: nil, completionHandler: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate func imageForDeviceType(type:RemoteDeviceInfo.DeviceType)->NSImage{
|
||||
let imageName:String
|
||||
switch type{
|
||||
case .tablet:
|
||||
imageName="com.apple.ipad"
|
||||
case .computer:
|
||||
imageName="com.apple.macbookpro-13-unibody"
|
||||
default: // also .phone
|
||||
imageName="com.apple.iphone"
|
||||
}
|
||||
return NSImage(contentsOfFile: "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/\(imageName).icns")!
|
||||
}
|
||||
|
||||
extension ShareViewController:NSCollectionViewDataSource{
|
||||
func numberOfSections(in collectionView: NSCollectionView) -> Int {
|
||||
return 1
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||
return foundDevices.count
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem {
|
||||
let item=collectionView.makeItem(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "DeviceListCell"), for: indexPath)
|
||||
guard let collectionViewItem = item as? DeviceListCell else {return item}
|
||||
let device=foundDevices[indexPath[1]]
|
||||
collectionViewItem.textField?.stringValue=device.name
|
||||
collectionViewItem.imageView?.image=imageForDeviceType(type: device.type)
|
||||
// TODO maybe there's a better way to handle clicks on collection view items? I'm still new to Apple's way of doing UIs so I may do dumb shit occasionally
|
||||
collectionViewItem.clickHandler={
|
||||
self.selectDevice(device: device)
|
||||
}
|
||||
return collectionViewItem
|
||||
}
|
||||
}
|
||||
BIN
ShareExtension/ru.lproj/Localizable.strings
Normal file
BIN
ShareExtension/ru.lproj/Localizable.strings
Normal file
Binary file not shown.
26
ShareExtension/ru.lproj/Localizable.stringsdict
Normal file
26
ShareExtension/ru.lproj/Localizable.stringsdict
Normal file
@@ -0,0 +1,26 @@
|
||||
<?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>NFiles</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@files@</string>
|
||||
<key>files</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>%d файл</string>
|
||||
<key>few</key>
|
||||
<string>%d файла</string>
|
||||
<key>many</key>
|
||||
<string>%d файлов</string>
|
||||
<key>other</key>
|
||||
<string>%d файлов</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
12
ShareExtension/ru.lproj/ShareViewController.strings
Normal file
12
ShareExtension/ru.lproj/ShareViewController.strings
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
/* Class = "NSTextFieldCell"; title = "NearDrop"; ObjectID = "0xp-rC-2gr"; */
|
||||
"0xp-rC-2gr.title" = "NearDrop";
|
||||
|
||||
/* Class = "NSButtonCell"; title = "Cancel"; ObjectID = "6Up-t3-mwm"; */
|
||||
"6Up-t3-mwm.title" = "Отменить";
|
||||
|
||||
/* Class = "NSTextFieldCell"; title = "Looking for devices..."; ObjectID = "NaJ-Wx-Pim"; */
|
||||
"NaJ-Wx-Pim.title" = "Ищу устройства...";
|
||||
|
||||
/* 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