refactor profileSelector view
This commit is contained in:
@@ -47,7 +47,7 @@
|
||||
2AC1E3832F507D80004F76C0 /* GenericUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AC1E3822F507D80004F76C0 /* GenericUtils.swift */; };
|
||||
2AC1EAFB2F92260F004EDA80 /* UIStackExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AC1EAFA2F922602004EDA80 /* UIStackExtension.swift */; };
|
||||
2AC1EAFC2F922889004EDA80 /* UIStackExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AC1EAFA2F922602004EDA80 /* UIStackExtension.swift */; };
|
||||
3A4A3A112F0C000100000001 /* OSCProfilesTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A4A3A102F0C000100000001 /* OSCProfilesTableViewController.swift */; };
|
||||
3A4A3A112F0C000100000001 /* ProfileSelectorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A4A3A102F0C000100000001 /* ProfileSelectorViewController.swift */; };
|
||||
3A4A3A132F0C000100000003 /* LayoutOnScreenControlsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A4A3A122F0C000100000002 /* LayoutOnScreenControlsViewController.swift */; };
|
||||
840751B32BF49C050096B657 /* CustomTapGestureRecognizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 840751B22BF49C050096B657 /* CustomTapGestureRecognizer.m */; };
|
||||
84203F232C5F24C00032EEED /* OnScreenWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84203F222C5F24C00032EEED /* OnScreenWidgetView.swift */; };
|
||||
@@ -56,7 +56,6 @@
|
||||
84351B102C29ACCB00A77989 /* OSCProfile.m in Sources */ = {isa = PBXBuildFile; fileRef = 84351B0A2C29ACCA00A77989 /* OSCProfile.m */; };
|
||||
84351B112C29ACCB00A77989 /* OSCProfilesManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1D4E0A22FBBBBCC00112233 /* OSCProfilesManager.swift */; };
|
||||
84351B2D2C29AD6100A77989 /* ToolBarContainerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 84351B292C29AD6000A77989 /* ToolBarContainerView.m */; };
|
||||
84351B5D2C29ADBE00A77989 /* ProfileTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 84351B5B2C29ADBE00A77989 /* ProfileTableViewCell.xib */; };
|
||||
843667F02D9D7173004A7D7F /* widgetTemplates.bin in Resources */ = {isa = PBXBuildFile; fileRef = 843667EF2D9D7173004A7D7F /* widgetTemplates.bin */; };
|
||||
843CC7F02C1E757D00BBC475 /* NativeTouchPointer.m in Sources */ = {isa = PBXBuildFile; fileRef = 843CC7EF2C1E757D00BBC475 /* NativeTouchPointer.m */; };
|
||||
843CC7F62C1E7A1700BBC475 /* NativeTouchHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 843CC7F52C1E7A1700BBC475 /* NativeTouchHandler.m */; };
|
||||
@@ -219,7 +218,7 @@
|
||||
2A7114002F5A6C65001D852D /* GamepadNavigationIllustrationHud.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GamepadNavigationIllustrationHud.swift; sourceTree = "<group>"; };
|
||||
2AC1E3822F507D80004F76C0 /* GenericUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenericUtils.swift; sourceTree = "<group>"; };
|
||||
2AC1EAFA2F922602004EDA80 /* UIStackExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIStackExtension.swift; sourceTree = "<group>"; };
|
||||
3A4A3A102F0C000100000001 /* OSCProfilesTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OSCProfilesTableViewController.swift; sourceTree = "<group>"; };
|
||||
3A4A3A102F0C000100000001 /* ProfileSelectorViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileSelectorViewController.swift; sourceTree = "<group>"; };
|
||||
3A4A3A122F0C000100000002 /* LayoutOnScreenControlsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LayoutOnScreenControlsViewController.swift; sourceTree = "<group>"; };
|
||||
693B3A9A218638CD00982F7B /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = Settings.bundle; sourceTree = "<group>"; };
|
||||
840751B12BF49B5A0096B657 /* CustomTapGestureRecognizer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CustomTapGestureRecognizer.h; sourceTree = "<group>"; };
|
||||
@@ -233,7 +232,6 @@
|
||||
84351B0D2C29ACCB00A77989 /* OSCProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OSCProfile.h; sourceTree = "<group>"; };
|
||||
84351B292C29AD6000A77989 /* ToolBarContainerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ToolBarContainerView.m; sourceTree = "<group>"; };
|
||||
84351B2A2C29AD6000A77989 /* ToolBarContainerView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ToolBarContainerView.h; sourceTree = "<group>"; };
|
||||
84351B5B2C29ADBE00A77989 /* ProfileTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ProfileTableViewCell.xib; sourceTree = "<group>"; };
|
||||
843667EF2D9D7173004A7D7F /* widgetTemplates.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; name = widgetTemplates.bin; path = PresetConfigs/widgetTemplates.bin; sourceTree = "<group>"; };
|
||||
843CC7EE2C1E757D00BBC475 /* NativeTouchPointer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NativeTouchPointer.h; sourceTree = "<group>"; };
|
||||
843CC7EF2C1E757D00BBC475 /* NativeTouchPointer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NativeTouchPointer.m; sourceTree = "<group>"; };
|
||||
@@ -522,8 +520,7 @@
|
||||
84351B2E2C29AD6600A77989 /* Table */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
84351B5B2C29ADBE00A77989 /* ProfileTableViewCell.xib */,
|
||||
3A4A3A102F0C000100000001 /* OSCProfilesTableViewController.swift */,
|
||||
3A4A3A102F0C000100000001 /* ProfileSelectorViewController.swift */,
|
||||
);
|
||||
path = Table;
|
||||
sourceTree = "<group>";
|
||||
@@ -1112,7 +1109,6 @@
|
||||
8454AC6A2C319BDA00F0A302 /* iPhone.storyboard in Resources */,
|
||||
843667F02D9D7173004A7D7F /* widgetTemplates.bin in Resources */,
|
||||
84FD0B542C3134A6006B5BE5 /* Localizable.xcstrings in Resources */,
|
||||
84351B5D2C29ADBE00A77989 /* ProfileTableViewCell.xib in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -1218,7 +1214,7 @@
|
||||
97E20DD02E21647A000D5DCA /* MetalViewController.m in Sources */,
|
||||
97E20DD12E21647A000D5DCA /* MetalView.m in Sources */,
|
||||
97E20DD22E21647A000D5DCA /* MetalVideoRenderer.m in Sources */,
|
||||
3A4A3A112F0C000100000001 /* OSCProfilesTableViewController.swift in Sources */,
|
||||
3A4A3A112F0C000100000001 /* ProfileSelectorViewController.swift in Sources */,
|
||||
98D585701C0ED0E800F6CC00 /* TemporarySettings.m in Sources */,
|
||||
1829CE3F2E2154DF0074A99A /* SceneDelegate.m in Sources */,
|
||||
18729EDE2E8BD68800101194 /* UUIDHelper.swift in Sources */,
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="24506" targetRuntime="iOS.CocoaTouch.iPad" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES" initialViewController="EVd-wq-ego">
|
||||
<device id="ipad11_0rounded" orientation="portrait" layout="fullscreen" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="24504"/>
|
||||
<capability name="Image references" minToolsVersion="12.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
@@ -13,7 +12,7 @@
|
||||
<objects>
|
||||
<viewController id="wb7-af-jn8" customClass="MainFrameViewController" sceneMemberID="viewController">
|
||||
<collectionView key="view" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" indicatorStyle="black" dataMode="prototypes" id="TZj-Lc-M9d" customClass="AppCollectionView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="834" height="1124"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="834" height="1210"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="20" minimumInteritemSpacing="20" id="f7l-kG-hJc">
|
||||
@@ -3879,10 +3878,10 @@
|
||||
</objects>
|
||||
<point key="canvasLocation" x="2529.4964028776981" y="957.52066115702485"/>
|
||||
</scene>
|
||||
<!--Profiles Table View Controller-->
|
||||
<!--Profile Selector View Controller-->
|
||||
<scene sceneID="W0E-wz-n2b">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="OSCProfilesTableViewController" id="Atv-Nj-0qv" customClass="OSCProfilesTableViewController" customModule="VoidLink" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<viewController storyboardIdentifier="ProfileSelectorViewController" id="Atv-Nj-0qv" customClass="ProfileSelectorViewController" customModule="VoidLink" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="osA-Uy-SE1"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="8ja-wQ-jbJ"/>
|
||||
@@ -3890,83 +3889,11 @@
|
||||
<view key="view" opaque="NO" contentMode="scaleToFill" id="PlJ-LJ-d1p">
|
||||
<rect key="frame" x="0.0" y="0.0" width="1133" height="744"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<navigationBar clipsSubviews="YES" alpha="0.77500000000000002" contentMode="scaleToFill" translucent="NO" translatesAutoresizingMaskIntoConstraints="NO" id="62V-DN-FUk">
|
||||
<rect key="frame" x="226.5" y="61" width="680" height="44"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="44" id="lQr-5u-g05"/>
|
||||
</constraints>
|
||||
<color key="barTintColor" red="0.81960784310000001" green="0.81960784310000001" blue="0.83921568629999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<textAttributes key="titleTextAttributes">
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleTitle3"/>
|
||||
<color key="textColor" systemColor="systemGray5Color"/>
|
||||
</textAttributes>
|
||||
<textAttributes key="largeTitleTextAttributes">
|
||||
<color key="textColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</textAttributes>
|
||||
<items>
|
||||
<navigationItem id="Q2V-XF-4jq">
|
||||
<leftBarButtonItems>
|
||||
<barButtonItem title="ExportAll" width="70" style="plain" id="Bhn-IO-Wlt" userLabel="Export Data">
|
||||
<color key="tintColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<connections>
|
||||
<action selector="exportDataTapped:" destination="Atv-Nj-0qv" id="pwG-sO-9he"/>
|
||||
</connections>
|
||||
</barButtonItem>
|
||||
<barButtonItem title="Import" width="48" style="plain" id="CpY-Sb-BDc" userLabel="Import Data">
|
||||
<color key="tintColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<connections>
|
||||
<action selector="importDataTapped:" destination="Atv-Nj-0qv" id="Uq0-Ct-LbS"/>
|
||||
</connections>
|
||||
</barButtonItem>
|
||||
<barButtonItem title="Restore" width="45" style="plain" id="czn-mj-8d1">
|
||||
<color key="tintColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<connections>
|
||||
<action selector="restoreTapped:" destination="Atv-Nj-0qv" id="IvQ-c3-bmW"/>
|
||||
</connections>
|
||||
</barButtonItem>
|
||||
</leftBarButtonItems>
|
||||
<rightBarButtonItems>
|
||||
<barButtonItem title="Duplicate" width="80" style="plain" id="P34-hO-6cX">
|
||||
<color key="tintColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<connections>
|
||||
<action selector="duplicateTapped:" destination="Atv-Nj-0qv" id="Ymg-8q-iIc"/>
|
||||
</connections>
|
||||
</barButtonItem>
|
||||
<barButtonItem title="Delete" width="80" style="plain" id="egC-9E-zS4" userLabel="Delete">
|
||||
<color key="tintColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<connections>
|
||||
<action selector="deleteTapped:" destination="Atv-Nj-0qv" id="UpR-VB-qez"/>
|
||||
</connections>
|
||||
</barButtonItem>
|
||||
</rightBarButtonItems>
|
||||
</navigationItem>
|
||||
</items>
|
||||
</navigationBar>
|
||||
<tableView opaque="NO" clearsContextBeforeDrawing="NO" alpha="0.5" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="-1" estimatedSectionHeaderHeight="-1" sectionFooterHeight="-1" estimatedSectionFooterHeight="-1" translatesAutoresizingMaskIntoConstraints="NO" id="BA3-hd-bDp">
|
||||
<rect key="frame" x="226.5" y="105" width="680" height="589"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</tableView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="62V-DN-FUk" firstAttribute="bottom" secondItem="BA3-hd-bDp" secondAttribute="top" id="600-lH-rte"/>
|
||||
<constraint firstItem="62V-DN-FUk" firstAttribute="width" secondItem="PlJ-LJ-d1p" secondAttribute="width" multiplier="0.6" id="OWL-Yd-KfG"/>
|
||||
<constraint firstItem="BA3-hd-bDp" firstAttribute="centerX" secondItem="PlJ-LJ-d1p" secondAttribute="centerX" id="Xte-bA-pFb"/>
|
||||
<constraint firstItem="BA3-hd-bDp" firstAttribute="width" secondItem="PlJ-LJ-d1p" secondAttribute="width" multiplier="0.6" id="eQf-gF-6kX"/>
|
||||
<constraint firstItem="BA3-hd-bDp" firstAttribute="top" secondItem="PlJ-LJ-d1p" secondAttribute="top" constant="105" id="eje-7O-RaF"/>
|
||||
<constraint firstItem="BA3-hd-bDp" firstAttribute="bottom" secondItem="PlJ-LJ-d1p" secondAttribute="bottom" constant="-50" id="j96-Mz-xiG"/>
|
||||
<constraint firstItem="62V-DN-FUk" firstAttribute="centerX" secondItem="PlJ-LJ-d1p" secondAttribute="centerX" id="qmh-Pp-B9S"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<toolbarItems/>
|
||||
<simulatedToolbarMetrics key="simulatedBottomBarMetrics"/>
|
||||
<size key="freeformSize" width="1133" height="744"/>
|
||||
<connections>
|
||||
<outlet property="profileTableViewNavigationBar" destination="62V-DN-FUk" id="c3i-qa-4ix"/>
|
||||
<outlet property="profileTableViewNavigationItem" destination="Q2V-XF-4jq" id="TmF-ZM-NKC"/>
|
||||
<outlet property="tableView" destination="BA3-hd-bDp" id="Jzl-sP-ANp"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="K4u-Tz-tXU" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="24506" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="DL0-L5-LOv">
|
||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="24504"/>
|
||||
<capability name="Image references" minToolsVersion="12.0"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
@@ -15,7 +14,7 @@
|
||||
<objects>
|
||||
<viewController id="dgh-JZ-Q7z" customClass="MainFrameViewController" sceneMemberID="viewController">
|
||||
<collectionView key="view" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" id="Rtu-AT-Alw" customClass="AppCollectionView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="746"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" red="0.3333333432674408" green="0.3333333432674408" blue="0.3333333432674408" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="15" minimumInteritemSpacing="15" id="YcZ-cR-3tK">
|
||||
@@ -1507,83 +1506,17 @@
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-96" y="1822"/>
|
||||
</scene>
|
||||
<!--Profiles Table View Controller-->
|
||||
<!--Profile Selector View Controller-->
|
||||
<scene sceneID="C7c-yg-gQK">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="OSCProfilesTableViewController" id="0K8-kQ-xlN" customClass="OSCProfilesTableViewController" customModule="VoidLink" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<viewController storyboardIdentifier="ProfileSelectorViewController" id="0K8-kQ-xlN" customClass="ProfileSelectorViewController" customModule="VoidLink" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="bTO-bs-q93">
|
||||
<rect key="frame" x="0.0" y="0.0" width="852" height="393"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<tableView opaque="NO" clearsContextBeforeDrawing="NO" alpha="0.5" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="-1" estimatedSectionHeaderHeight="-1" sectionFooterHeight="-1" estimatedSectionFooterHeight="-1" translatesAutoresizingMaskIntoConstraints="NO" id="kTH-ez-aKD">
|
||||
<rect key="frame" x="80" y="156" width="692" height="217"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<color key="sectionIndexBackgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</tableView>
|
||||
<navigationBar alpha="0.77500000000000002" contentMode="scaleToFill" translucent="NO" translatesAutoresizingMaskIntoConstraints="NO" id="zsA-6X-Qc5">
|
||||
<rect key="frame" x="80" y="112" width="692" height="44"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="44" id="R90-2b-UrU"/>
|
||||
</constraints>
|
||||
<color key="barTintColor" red="0.81960784310000001" green="0.81960784310000001" blue="0.83921568629999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<items>
|
||||
<navigationItem style="editor" id="5pN-Sn-SCN">
|
||||
<leftBarButtonItems>
|
||||
<barButtonItem title="ExportAll" id="D9X-7p-9oc">
|
||||
<color key="tintColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<connections>
|
||||
<action selector="exportDataTapped:" destination="0K8-kQ-xlN" id="Sam-Ct-kqC"/>
|
||||
</connections>
|
||||
</barButtonItem>
|
||||
<barButtonItem title="Import" id="Z9M-yq-an2">
|
||||
<color key="tintColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<connections>
|
||||
<action selector="importDataTapped:" destination="0K8-kQ-xlN" id="OaF-8j-7Wy"/>
|
||||
</connections>
|
||||
</barButtonItem>
|
||||
<barButtonItem title="Restore" id="sUC-Ur-7eI">
|
||||
<color key="tintColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<connections>
|
||||
<action selector="restoreTapped:" destination="0K8-kQ-xlN" id="lAJ-eO-ez7"/>
|
||||
</connections>
|
||||
</barButtonItem>
|
||||
</leftBarButtonItems>
|
||||
<rightBarButtonItems>
|
||||
<barButtonItem title="Duplicate" width="80" style="plain" id="bue-hp-CWD">
|
||||
<color key="tintColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<connections>
|
||||
<action selector="duplicateTapped:" destination="0K8-kQ-xlN" id="Gb7-bx-nxp"/>
|
||||
</connections>
|
||||
</barButtonItem>
|
||||
<barButtonItem title="Delete" width="80" style="plain" id="ghM-zc-sr6">
|
||||
<color key="tintColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<connections>
|
||||
<action selector="deleteTapped:" destination="0K8-kQ-xlN" id="h6N-Gl-oiW"/>
|
||||
</connections>
|
||||
</barButtonItem>
|
||||
</rightBarButtonItems>
|
||||
</navigationItem>
|
||||
</items>
|
||||
</navigationBar>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="tvP-w4-JSG"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="zsA-6X-Qc5" firstAttribute="leading" secondItem="tvP-w4-JSG" secondAttribute="leading" constant="80" id="0Fi-vo-M6P"/>
|
||||
<constraint firstAttribute="bottom" secondItem="kTH-ez-aKD" secondAttribute="bottom" constant="20" symbolic="YES" id="1FM-gO-6PR"/>
|
||||
<constraint firstItem="tvP-w4-JSG" firstAttribute="trailing" secondItem="kTH-ez-aKD" secondAttribute="trailing" constant="80" id="ArS-pG-QUR"/>
|
||||
<constraint firstItem="kTH-ez-aKD" firstAttribute="leading" secondItem="tvP-w4-JSG" secondAttribute="leading" constant="80" id="Ujg-Sw-4hq"/>
|
||||
<constraint firstItem="tvP-w4-JSG" firstAttribute="trailing" secondItem="zsA-6X-Qc5" secondAttribute="trailing" constant="80" id="YKK-qs-mZR"/>
|
||||
<constraint firstItem="zsA-6X-Qc5" firstAttribute="top" secondItem="bTO-bs-q93" secondAttribute="topMargin" constant="16" id="gZg-eJ-rnP"/>
|
||||
<constraint firstItem="kTH-ez-aKD" firstAttribute="top" secondItem="zsA-6X-Qc5" secondAttribute="bottom" id="txs-Df-ANQ"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<size key="freeformSize" width="852" height="393"/>
|
||||
<connections>
|
||||
<outlet property="profileTableViewNavigationBar" destination="zsA-6X-Qc5" id="13u-ks-fVC"/>
|
||||
<outlet property="profileTableViewNavigationItem" destination="5pN-Sn-SCN" id="Ybc-XZ-vcP"/>
|
||||
<outlet property="tableView" destination="kTH-ez-aKD" id="pqR-CC-Kfh"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="Sod-EL-V75" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
@@ -3796,19 +3729,19 @@
|
||||
<image name="trash.fill" catalog="system" width="117" height="128"/>
|
||||
<image name="tray.full.fill" catalog="system" width="128" height="88"/>
|
||||
<systemColor name="linkColor">
|
||||
<color red="0.0" green="0.47843137254901963" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color red="0.0" green="0.47843137250000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</systemColor>
|
||||
<systemColor name="systemBrownColor">
|
||||
<color red="0.67450980392156867" green="0.49803921568627452" blue="0.36862745098039218" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color red="0.63529411759999999" green="0.51764705879999995" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</systemColor>
|
||||
<systemColor name="systemGray2Color">
|
||||
<color red="0.68235294117647061" green="0.68235294117647061" blue="0.69803921568627447" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color red="0.68235294120000001" green="0.68235294120000001" blue="0.69803921570000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</systemColor>
|
||||
<systemColor name="systemGray3Color">
|
||||
<color red="0.7803921568627451" green="0.7803921568627451" blue="0.80000000000000004" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color red="0.78039215689999997" green="0.78039215689999997" blue="0.80000000000000004" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</systemColor>
|
||||
<systemColor name="systemTealColor">
|
||||
<color red="0.0" green="0.76470588235294112" blue="0.81568627450980391" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color red="0.18823529410000001" green="0.69019607839999997" blue="0.78039215689999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</systemColor>
|
||||
</resources>
|
||||
</document>
|
||||
|
||||
@@ -696,7 +696,7 @@ final class ControllerNavigator: NSObject {
|
||||
|
||||
|
||||
|
||||
if let uiNavigationDelegate = uiNavigationDelegate, !mainFrameVC.isStreaming() || mainFrameVC.settingsExpandedInStreamView || uiNavigationDelegate is ToolboxViewController {
|
||||
if let uiNavigationDelegate = uiNavigationDelegate, !mainFrameVC.isStreaming() || mainFrameVC.settingsExpandedInStreamView || uiNavigationDelegate is ToolboxViewController || uiNavigationDelegate is ProfileSelectorViewController {
|
||||
let verticalNavigationAxis: ControllerElement = ControllerNavigator.radialMenuButtonPosition == .right ? .leftStickY : .rightStickY
|
||||
ControllerUtil.listenPrimaryControllerStickAxis(verticalNavigationAxis, threshold: 0.6) {state in
|
||||
GamepadNavigationIllustrationHud.updateActionState(for: verticalNavigationAxis, isInAction: state != .orderedSame)
|
||||
@@ -726,7 +726,7 @@ final class ControllerNavigator: NSObject {
|
||||
}
|
||||
}
|
||||
|
||||
if let uiNavigationDelegate = uiNavigationDelegate, !mainFrameVC.isStreaming() || uiNavigationDelegate is ToolboxViewController{
|
||||
if let uiNavigationDelegate = uiNavigationDelegate, !mainFrameVC.isStreaming() || uiNavigationDelegate is ToolboxViewController || uiNavigationDelegate is ProfileSelectorViewController {
|
||||
let horizontalNavigationAxis: ControllerElement = ControllerNavigator.radialMenuButtonPosition == .right ? .leftStickX : .rightStickX
|
||||
ControllerUtil.listenPrimaryControllerStickAxis(horizontalNavigationAxis, threshold: 0.6) {state in
|
||||
GamepadNavigationIllustrationHud.updateActionState(for: horizontalNavigationAxis, isInAction: state != .orderedSame)
|
||||
@@ -750,7 +750,7 @@ final class ControllerNavigator: NSObject {
|
||||
}
|
||||
}
|
||||
|
||||
if let uiNavigationDelegate = uiNavigationDelegate, !mainFrameVC.isStreaming() || mainFrameVC.settingsExpandedInStreamView || uiNavigationDelegate is UIAlertController || uiNavigationDelegate is OSCProfilesTableViewController || uiNavigationDelegate is ToolboxViewController {
|
||||
if let uiNavigationDelegate = uiNavigationDelegate, !mainFrameVC.isStreaming() || mainFrameVC.settingsExpandedInStreamView || uiNavigationDelegate is UIAlertController || uiNavigationDelegate is ProfileSelectorViewController || uiNavigationDelegate is ToolboxViewController {
|
||||
let navigations = uiNavigationDelegate.getNavigationElements()
|
||||
let buttonNavigations = navigations.filter({$0.control.type == .button})
|
||||
// let stickNavigations = navigations.filter({$0.control.type == .stick || $0.control.type == .stickAxis})
|
||||
@@ -1494,6 +1494,9 @@ extension ControllerCollectionNavigationDelegate {
|
||||
}
|
||||
|
||||
func applyControllerNavigationHighlight(to cell: UICollectionViewCell, highlighted: Bool) {
|
||||
if self is ProfileSelectorViewController {
|
||||
return
|
||||
}
|
||||
clearControllerNavigationHighlightBorder(in: cell)
|
||||
guard highlighted else { return }
|
||||
let highlightedView = controllerNavigationHighlightTargetView(for: cell)
|
||||
|
||||
@@ -86,6 +86,10 @@ class OSCProfilesManager: NSObject {
|
||||
persistEncodedProfiles(profilesEncoded)
|
||||
}
|
||||
|
||||
func persistProfileOrder(_ orderedProfiles: NSMutableArray) {
|
||||
persistProfiles(orderedProfiles)
|
||||
}
|
||||
|
||||
private func persistEncodedProfiles(_ profilesEncoded: NSMutableArray) {
|
||||
guard let data = try? NSKeyedArchiver.archivedData(withRootObject: profilesEncoded, requiringSecureCoding: true) else {
|
||||
return
|
||||
@@ -172,13 +176,19 @@ class OSCProfilesManager: NSObject {
|
||||
|
||||
func importEncodedProfiles(_ profilesEncoded: NSMutableArray) {
|
||||
let localProfiles = currentProfiles.mutableCopy() as? NSMutableArray ?? NSMutableArray()
|
||||
let profilesDecoded = decodeProfiles(from: profilesEncoded)
|
||||
let importedIncludesDefault = (profilesDecoded.firstObject as? OSCProfile)?.name == "Default"
|
||||
let isSingleProfile = profilesEncoded.count == 1
|
||||
|
||||
if localProfiles.count > 0 {
|
||||
if importedIncludesDefault && localProfiles.count > 0 {
|
||||
localProfiles.removeObject(at: 0)
|
||||
} else if !importedIncludesDefault,
|
||||
let localDefaultProfile = localProfiles.firstObject as? OSCProfile,
|
||||
localDefaultProfile.name == "Default" {
|
||||
profilesDecoded.insert(localDefaultProfile, at: 0)
|
||||
localProfiles.removeObject(at: 0)
|
||||
}
|
||||
|
||||
let profilesDecoded = decodeProfiles(from: profilesEncoded)
|
||||
|
||||
|
||||
let localProfileNames = Set(
|
||||
localProfiles.compactMap { ($0 as? OSCProfile)?.name }
|
||||
)
|
||||
@@ -202,13 +212,24 @@ class OSCProfilesManager: NSObject {
|
||||
for case let profile as Any in localProfilesToRemove {
|
||||
localProfiles.remove(profile)
|
||||
}
|
||||
|
||||
var indexOffset = 0
|
||||
|
||||
var indexOffset = importedIncludesDefault ? 0: 0
|
||||
for profile in localProfiles {
|
||||
profilesDecoded.insert(profile, at: 1+indexOffset)
|
||||
indexOffset += 1
|
||||
}
|
||||
|
||||
|
||||
if isSingleProfile, !importedIncludesDefault {
|
||||
for profile in profilesDecoded {
|
||||
if let profile = profile as? OSCProfile {
|
||||
profile.isSelected = false
|
||||
}
|
||||
}
|
||||
if let profile = profilesDecoded[profilesDecoded.count-1] as? OSCProfile {
|
||||
profile.isSelected = true
|
||||
}
|
||||
}
|
||||
|
||||
persistEncodedProfiles(encodedProfiles(from: profilesDecoded))
|
||||
}
|
||||
|
||||
|
||||
@@ -4592,6 +4592,29 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"All Profiles" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"zh-Hans" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "全部配置"
|
||||
}
|
||||
},
|
||||
"zh-Hant" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "全部設定檔"
|
||||
}
|
||||
},
|
||||
"zh-HK" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "全部設定檔"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Alpha" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
@@ -6511,6 +6534,29 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"Current Profile" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"zh-Hans" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "当前配置"
|
||||
}
|
||||
},
|
||||
"zh-Hant" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "目前設定檔"
|
||||
}
|
||||
},
|
||||
"zh-HK" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "目前設定檔"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Del" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
@@ -6586,6 +6632,29 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"Duplicate" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"zh-Hans" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "复制"
|
||||
}
|
||||
},
|
||||
"zh-Hant" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "複製"
|
||||
}
|
||||
},
|
||||
"zh-HK" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "複製"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Delete Buttons Here" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
@@ -8142,6 +8211,29 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"Export" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"zh-Hans" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "导出"
|
||||
}
|
||||
},
|
||||
"zh-Hant" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "匯出"
|
||||
}
|
||||
},
|
||||
"zh-HK" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "匯出"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Expands setting menu during streaming" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
@@ -14837,6 +14929,29 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"Restore" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"zh-Hans" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "恢复"
|
||||
}
|
||||
},
|
||||
"zh-Hant" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "還原"
|
||||
}
|
||||
},
|
||||
"zh-HK" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "還原"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Restore Purchase" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
@@ -18862,4 +18977,4 @@
|
||||
}
|
||||
},
|
||||
"version" : "1.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,17 +33,44 @@ class ThemeManager: NSObject {
|
||||
_ = setPublicUIStyle()
|
||||
return _userInterfaceStyle
|
||||
}
|
||||
|
||||
@objc class func overrideUserInterfaceStyle() -> UIUserInterfaceStyle {
|
||||
return _privateUserInterfaceStyle
|
||||
}
|
||||
|
||||
@objc class func setUserInterfaceStyle(_ style: UIUserInterfaceStyle) {
|
||||
let oldUserInterfaceStyle = _userInterfaceStyle
|
||||
_privateUserInterfaceStyle = style
|
||||
applyUserInterfaceStyleOverride(style)
|
||||
|
||||
if _userInterfaceStyle == style {
|
||||
_ = setPublicUIStyle()
|
||||
|
||||
if oldUserInterfaceStyle == _userInterfaceStyle {
|
||||
return
|
||||
}
|
||||
|
||||
_ = setPublicUIStyle()
|
||||
|
||||
NotificationCenter.default.post(
|
||||
name: Notification.Name(ThemeDidChangeNotification),
|
||||
object: nil
|
||||
)
|
||||
}
|
||||
|
||||
@objc class func systemUserInterfaceStyleDidChange(_ style: UIUserInterfaceStyle) {
|
||||
guard #available(iOS 13.0, *) else { return }
|
||||
|
||||
if _privateUserInterfaceStyle != .unspecified {
|
||||
applyUserInterfaceStyleOverride(_privateUserInterfaceStyle)
|
||||
return
|
||||
}
|
||||
|
||||
let oldUserInterfaceStyle = _userInterfaceStyle
|
||||
_userInterfaceStyle = style
|
||||
applyUserInterfaceStyleOverride(.unspecified)
|
||||
|
||||
if oldUserInterfaceStyle == _userInterfaceStyle {
|
||||
return
|
||||
}
|
||||
|
||||
NotificationCenter.default.post(
|
||||
name: Notification.Name(ThemeDidChangeNotification),
|
||||
object: nil
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
- (void)profileRefresh;
|
||||
- (void)reloadOnScreenWidgetViews;
|
||||
- (void)presentProfilesTableViewWithLoadingMode:(NSInteger)loadingMode;
|
||||
- (void)presentProfileSelectorWithLoadingMode:(NSInteger)loadingMode;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
+24
-42
@@ -322,14 +322,14 @@ typedef NS_ENUM(NSUInteger, DecelerationRateSliderMode) {
|
||||
object:nil];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(handleProfileTablViewDismiss)
|
||||
name:@"OscLayoutTableViewCloseNotification"
|
||||
selector:@selector(handleProfileSelectorDismiss)
|
||||
name:@"ProfileSelectorCloseNotification"
|
||||
object:nil];
|
||||
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(dummytest)
|
||||
name:@"OscLayoutProfileSelctedInTableView" // This is a special notification for reloading the on screen keyboard buttons. which can't be executed by _oscProfilesTableViewController.needToUpdateOscLayoutTVC code block, and has to be triggered by a notification
|
||||
name:@"OscLayoutProfileSelectedNotification" // This is a special notification for reloading the on screen keyboard buttons. It has to be triggered by a notification because it cannot be handled by the profile selector dismiss block.
|
||||
object:nil];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
@@ -364,7 +364,7 @@ typedef NS_ENUM(NSUInteger, DecelerationRateSliderMode) {
|
||||
selectedWidgetView = nil;
|
||||
selectedControllerLayer = nil;
|
||||
|
||||
_oscProfilesTableViewController.layoutViewBounds = self.view.bounds;
|
||||
_profileSelectorViewController.layoutViewBounds = self.view.bounds;
|
||||
[OSCProfilesManager setLayoutViewBounds:self.view.bounds];
|
||||
[OSCProfilesManager setOnScreenWidgetViewsSet:self.onScreenWidgetViews]; // pass the keyboard button dict to profiles manager
|
||||
|
||||
@@ -1029,7 +1029,7 @@ typedef NS_ENUM(NSUInteger, DecelerationRateSliderMode) {
|
||||
else{
|
||||
UIAlertController * savedAlertController = [UIAlertController alertControllerWithTitle: [NSString stringWithFormat:@""] message: [LocalizationHelper localizedStringForKey:@"Profile Default can not be overwritten"] preferredStyle:UIAlertControllerStyleAlert];
|
||||
[savedAlertController addAction:[UIAlertAction actionWithTitle:[LocalizationHelper localizedStringForKey:@"Ok"] style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
||||
[self.oscProfilesTableViewController profileViewRefresh]; // execute this will reset layout in OSC tool!
|
||||
[self.profileSelectorViewController profileViewRefresh]; // execute this will reset layout in OSC tool!
|
||||
}]];
|
||||
if(sender) [self presentViewController:savedAlertController animated:YES completion:nil];
|
||||
}
|
||||
@@ -1863,7 +1863,7 @@ typedef NS_ENUM(NSUInteger, DecelerationRateSliderMode) {
|
||||
return ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone);
|
||||
}
|
||||
|
||||
- (void)handleProfileTablViewDismiss{
|
||||
- (void)handleProfileSelectorDismiss{
|
||||
if(_quickSwitchEnabled){
|
||||
[self clearOnScreenWidgets];
|
||||
[self dismissViewControllerAnimated:NO completion:^{
|
||||
@@ -1876,28 +1876,19 @@ typedef NS_ENUM(NSUInteger, DecelerationRateSliderMode) {
|
||||
/* Basically the same method as loadTapped, without parameter*/
|
||||
// Make sure whenever self view controller load the selected profile and layout its buttons.
|
||||
- (void)profileRefresh{
|
||||
UIStoryboard *storyboard;
|
||||
BOOL isIPhone = ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone);
|
||||
if (isIPhone) {
|
||||
storyboard = [UIStoryboard storyboardWithName:@"iPhone" bundle:nil];
|
||||
}
|
||||
else {
|
||||
storyboard = [UIStoryboard storyboardWithName:@"iPad" bundle:nil];
|
||||
}
|
||||
|
||||
//initialiaze _oscProfilesTableViewController
|
||||
self->_oscProfilesTableViewController = [storyboard instantiateViewControllerWithIdentifier:@"OSCProfilesTableViewController"];
|
||||
// initialiaze _profileSelectorViewController
|
||||
self->_profileSelectorViewController = [[ProfileSelectorViewController alloc] init];
|
||||
self->_profileSelectorViewController.layoutViewBounds = self.view.bounds;
|
||||
|
||||
//this part is just for registration, will not be immediately executed.
|
||||
__weak typeof(self) weakSelf = self;
|
||||
self->_oscProfilesTableViewController.needToUpdateOscLayoutTVC = ^() { // a block that will be called when the modally presented 'OSCProfilesTableViewController' VC is dismissed. By the time the 'OSCProfilesTableViewController' VC is dismissed the user would have potentially selected a different OSC profile with a different layout and they want to see this layout on this 'LayoutOnScreenControlsViewController.' This block of code will load the profile and then hide/show and move each OSC button to their appropriate position
|
||||
self->_profileSelectorViewController.needToUpdateOscLayoutTVC = ^() { // a block that will be called when the modally presented 'ProfileSelectorViewController' VC is dismissed. By the time it is dismissed the user would have potentially selected a different OSC profile with a different layout and they want to see this layout on this 'LayoutOnScreenControlsViewController.' This block of code will load the profile and then hide/show and move each OSC button to their appropriate position
|
||||
__strong typeof(weakSelf) strongSelf = weakSelf;
|
||||
if (!strongSelf) return;
|
||||
[weakSelf reloadOnScreenWidgetViews];
|
||||
strongSelf->_oscProfilesTableViewController.currentOSCButtonLayers = weakSelf.layoutOSC.OSCButtonLayerPool; //pass updated OSCLayout to OSCProfileTableView again
|
||||
strongSelf->_profileSelectorViewController.currentOSCButtonLayers = weakSelf.layoutOSC.OSCButtonLayerPool; // pass updated OSCLayout to profile selector again
|
||||
};
|
||||
|
||||
[self.oscProfilesTableViewController.tableView reloadData];
|
||||
[self reloadOnScreenWidgetViews];
|
||||
|
||||
NSLog(@"profileRefresh %f", CACurrentMediaTime());
|
||||
@@ -1906,43 +1897,34 @@ typedef NS_ENUM(NSUInteger, DecelerationRateSliderMode) {
|
||||
// [self presentViewController:vc animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void) presentProfilesTableViewWithPickProfile:(bool)pickProfile{
|
||||
- (void) presentProfileSelectorWithPickProfile:(bool)pickProfile{
|
||||
[self hideStickIndicators];
|
||||
selectedWidgetView = nil;
|
||||
// if(pickProfile) [self clearOnScreenWidgets];
|
||||
|
||||
UIStoryboard *storyboard;
|
||||
BOOL isIPhone = ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone);
|
||||
if (isIPhone) {
|
||||
storyboard = [UIStoryboard storyboardWithName:@"iPhone" bundle:nil];
|
||||
}
|
||||
else {
|
||||
storyboard = [UIStoryboard storyboardWithName:@"iPad" bundle:nil];
|
||||
}
|
||||
|
||||
_oscProfilesTableViewController = [storyboard instantiateViewControllerWithIdentifier:@"OSCProfilesTableViewController"];
|
||||
_oscProfilesTableViewController.layoutViewBounds = self.view.bounds;
|
||||
|
||||
_profileSelectorViewController = [[ProfileSelectorViewController alloc] init];
|
||||
_profileSelectorViewController.layoutViewBounds = self.view.bounds;
|
||||
|
||||
__weak typeof(self) weakSelf = self;
|
||||
_oscProfilesTableViewController.needToUpdateOscLayoutTVC = ^() { // a block that will be called when the modally presented 'OSCProfilesTableViewController' VC is dismissed. By the time the 'OSCProfilesTableViewController' VC is dismissed the user would have potentially selected a different OSC ofile with a different layout and they want to see this layout on this 'LayoutOnScreenControlsViewController.' This block of code will load the proffile and then hide/show and move each OSC button to their appropriate position
|
||||
_profileSelectorViewController.needToUpdateOscLayoutTVC = ^() { // a block that will be called when the modally presented 'ProfileSelectorViewController' VC is dismissed. By the time it is dismissed the user would have potentially selected a different OSC profile with a different layout and they want to see this layout on this 'LayoutOnScreenControlsViewController.' This block of code will load the profile and then hide/show and move each OSC button to their appropriate position
|
||||
if(!pickProfile) [weakSelf reloadOnScreenWidgetViews];
|
||||
};
|
||||
|
||||
self.widgetPanelStack.hidden = YES;
|
||||
|
||||
_oscProfilesTableViewController.currentOSCButtonLayers = self.layoutOSC.OSCButtonLayerPool;
|
||||
_profileSelectorViewController.currentOSCButtonLayers = self.layoutOSC.OSCButtonLayerPool;
|
||||
|
||||
// _oscProfilesTableViewController.modalPresentationStyle = UIModalPresentationCurrentContext;
|
||||
_oscProfilesTableViewController.modalPresentationStyle = UIModalPresentationOverCurrentContext;
|
||||
// _oscProfilesTableViewController.modalPresentationStyle = UIModalPresentationPageSheet;
|
||||
_oscProfilesTableViewController.pickProfileEnabled = pickProfile;
|
||||
[self presentViewController:_oscProfilesTableViewController animated:NO completion:nil];
|
||||
// _profileSelectorViewController.modalPresentationStyle = UIModalPresentationCurrentContext;
|
||||
_profileSelectorViewController.modalPresentationStyle = UIModalPresentationOverCurrentContext;
|
||||
// _profileSelectorViewController.modalPresentationStyle = UIModalPresentationPageSheet;
|
||||
_profileSelectorViewController.pickProfileEnabled = pickProfile;
|
||||
[self presentViewController:_profileSelectorViewController animated:NO completion:nil];
|
||||
}
|
||||
|
||||
/* Presents the view controller that lists all OSC profiles the user can choose from */
|
||||
- (IBAction) loadTapped:(id)sender {
|
||||
[self saveTapped:nil];
|
||||
[self presentProfilesTableViewWithPickProfile:false];
|
||||
[self presentProfileSelectorWithPickProfile:false];
|
||||
}
|
||||
|
||||
|
||||
@@ -2081,7 +2063,7 @@ typedef NS_ENUM(NSUInteger, DecelerationRateSliderMode) {
|
||||
if([profilesManager getIndexOfSelectedProfile] == 0 && [self.layoutOSC.layoutChanges count] > 0){
|
||||
UIAlertController * movedAlertController = [UIAlertController alertControllerWithTitle: [NSString stringWithFormat:@""] message: [LocalizationHelper localizedStringForKey:@"Layout of the Default profile can not be changed"] preferredStyle:UIAlertControllerStyleAlert];
|
||||
[movedAlertController addAction:[UIAlertAction actionWithTitle:[LocalizationHelper localizedStringForKey:@"Ok"] style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
||||
[self.oscProfilesTableViewController profileViewRefresh];
|
||||
[self.profileSelectorViewController profileViewRefresh];
|
||||
}]];
|
||||
[self presentViewController:movedAlertController animated:YES completion:nil];
|
||||
}
|
||||
|
||||
+44
-54
@@ -188,7 +188,7 @@ final class LayoutOnScreenControlsViewController: UIViewController, OnScreenWidg
|
||||
@IBOutlet private weak var toolbarTopConstraintiPhone: NSLayoutConstraint!
|
||||
@IBOutlet private weak var toolbarTopConstraintiPad: NSLayoutConstraint!
|
||||
|
||||
var oscProfilesTableViewController: OSCProfilesTableViewController?
|
||||
var profileSelectorViewController: ProfileSelectorViewController?
|
||||
private var profilesManager: OSCProfilesManager!
|
||||
private var bulkEditEnabled: Bool = false
|
||||
private var selectedWidget: OnScreenWidgetView?
|
||||
@@ -286,7 +286,7 @@ final class LayoutOnScreenControlsViewController: UIViewController, OnScreenWidg
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(legacyOscLayerTapped(_:)), name: Notification.Name("LegacyOscCALayerSelectedNotification"), object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(handleProfileTablViewDismiss), name: Notification.Name("OscLayoutTableViewCloseNotification"), object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(handleProfileSelectorDismiss), name: Notification.Name("ProfileSelectorCloseNotification"), object: nil)
|
||||
// NotificationCenter.default.addObserver(self, selector: #selector(dummytest), name: Notification.Name("GameProfileSelectedNotification"), object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(widgetViewTapped(_:)), name: Notification.Name("OnScreenWidgetViewSelected"), object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(OSCLayoutChanged), name: Notification.Name("OSCLayoutChanged"), object: nil)
|
||||
@@ -358,7 +358,7 @@ final class LayoutOnScreenControlsViewController: UIViewController, OnScreenWidg
|
||||
}
|
||||
|
||||
@objc func reloadOnScreenWidgetViews() {
|
||||
if self.profileTableLoadingMode == .selectProfileFromMainFrame { return }
|
||||
if self.profileSelectorLoadingMode == .selectProfileFromMainFrame { return }
|
||||
|
||||
OnScreenWidgetView.isTweakingHighlight = false
|
||||
OnScreenWidgetView.editMode = true
|
||||
@@ -369,7 +369,7 @@ final class LayoutOnScreenControlsViewController: UIViewController, OnScreenWidg
|
||||
|
||||
guard let oscProfile = self.profilesManager?.getSelectedProfile() else { return }
|
||||
|
||||
if self.profileTableLoadingMode == .selectProfileFromStreamView {
|
||||
if self.profileSelectorLoadingMode == .selectProfileFromStreamView || self.profileSelectorLoadingMode == .pickProfile {
|
||||
NotificationCenter.default.post(name: Notification.Name("GameProfileSelectedNotification"), object: oscProfile)
|
||||
}
|
||||
|
||||
@@ -525,66 +525,68 @@ final class LayoutOnScreenControlsViewController: UIViewController, OnScreenWidg
|
||||
}
|
||||
|
||||
@objc func profileRefresh() {
|
||||
let storyboardName = UIDevice.current.userInterfaceIdiom == .phone ? "iPhone" : "iPad"
|
||||
let storyboard = UIStoryboard(name: storyboardName, bundle: nil)
|
||||
oscProfilesTableViewController = storyboard.instantiateViewController(withIdentifier: "OSCProfilesTableViewController") as? OSCProfilesTableViewController
|
||||
oscProfilesTableViewController?.needToUpdateOscLayoutTVC = { [weak self] in
|
||||
profileSelectorViewController = ProfileSelectorViewController()
|
||||
profileSelectorViewController?.layoutViewBounds = view.bounds
|
||||
profileSelectorViewController?.needToUpdateOscLayoutTVC = { [weak self] in
|
||||
guard let self else { return }
|
||||
if !loadJustTapped {
|
||||
self.reloadOnScreenWidgetViews()
|
||||
}
|
||||
loadJustTapped = false
|
||||
self.oscProfilesTableViewController?.currentOSCButtonLayers = self.layoutOSC.oscButtonLayerPool
|
||||
self.profileSelectorViewController?.currentOSCButtonLayers = self.layoutOSC.oscButtonLayerPool
|
||||
}
|
||||
oscProfilesTableViewController?.tableView?.reloadData()
|
||||
reloadOnScreenWidgetViews()
|
||||
}
|
||||
|
||||
@objc var profileTableLoadingMode: OSCProfilesTableViewLoadingMode = .selectProfile
|
||||
@objc(presentProfilesTableViewWithLoadingMode: animated:)
|
||||
func presentProfilesTableView(with loadingMode: OSCProfilesTableViewLoadingMode, animated: Bool = false) {
|
||||
profileTableLoadingMode = loadingMode
|
||||
presentProfilesTableView(with: loadingMode, pickedProfileDataHandler: nil, animated:animated)
|
||||
@objc var profileSelectorLoadingMode: ProfileSelectorLoadingMode = .selectProfile
|
||||
|
||||
@objc(presentProfileSelectorWithLoadingMode:)
|
||||
func presentProfileSelector(with loadingModeRawValue: Int) {
|
||||
guard let loadingMode = ProfileSelectorLoadingMode(rawValue: loadingModeRawValue) else {
|
||||
return
|
||||
}
|
||||
presentProfileSelector(with: loadingMode)
|
||||
}
|
||||
|
||||
private func presentProfilesTableView(
|
||||
with loadingMode: OSCProfilesTableViewLoadingMode,
|
||||
@objc func presentProfileSelector(with loadingMode: ProfileSelectorLoadingMode, animated: Bool = false) {
|
||||
profileSelectorLoadingMode = loadingMode
|
||||
presentProfileSelector(with: loadingMode, pickedProfileDataHandler: nil, animated:animated)
|
||||
}
|
||||
|
||||
private func presentProfileSelector(
|
||||
with loadingMode: ProfileSelectorLoadingMode,
|
||||
pickedProfileDataHandler: ((OSCProfile) -> Void)? = nil,
|
||||
animated: Bool = false
|
||||
) {
|
||||
hideStickIndicators()
|
||||
if loadingMode != .pickProfileData {selectedWidget = nil}
|
||||
let storyboardName = UIDevice.current.userInterfaceIdiom == .phone ? "iPhone" : "iPad"
|
||||
let storyboard = UIStoryboard(name: storyboardName, bundle: nil)
|
||||
let controller = storyboard.instantiateViewController(withIdentifier: "OSCProfilesTableViewController") as? OSCProfilesTableViewController
|
||||
controller?.layoutViewBounds = view.bounds
|
||||
controller?.needToUpdateOscLayoutTVC = { [weak self] in
|
||||
let controller = ProfileSelectorViewController()
|
||||
controller.layoutViewBounds = view.bounds
|
||||
controller.needToUpdateOscLayoutTVC = { [weak self] in
|
||||
guard let self else { return }
|
||||
if loadingMode == .selectProfile || loadingMode == .selectProfileFromStreamView {
|
||||
if loadingMode == .selectProfile || loadingMode == .selectProfileFromStreamView || loadingMode == .pickProfile {
|
||||
self.reloadOnScreenWidgetViews()
|
||||
}
|
||||
}
|
||||
controller?.currentOSCButtonLayers = layoutOSC.oscButtonLayerPool
|
||||
controller?.modalPresentationStyle = .overCurrentContext
|
||||
controller?.loadingMode = loadingMode
|
||||
controller?.pickedProfileDataHandler = pickedProfileDataHandler
|
||||
controller.currentOSCButtonLayers = layoutOSC.oscButtonLayerPool
|
||||
controller.modalPresentationStyle = .overCurrentContext
|
||||
controller.loadingMode = loadingMode
|
||||
controller.pickedProfileDataHandler = pickedProfileDataHandler
|
||||
widgetPanelStack.isHidden = true
|
||||
oscProfilesTableViewController = controller
|
||||
if let controller {
|
||||
present(controller, animated: animated)
|
||||
}
|
||||
profileSelectorViewController = controller
|
||||
present(controller, animated: animated)
|
||||
}
|
||||
|
||||
private var loadJustTapped:Bool = false
|
||||
@IBAction func loadTapped(_ sender: Any?) {
|
||||
// saveTapped(nil)
|
||||
loadJustTapped = true
|
||||
presentProfilesTableView(with: .selectProfile)
|
||||
presentProfileSelector(with: .selectProfile)
|
||||
}
|
||||
|
||||
@IBAction func importFromOtherButtonTapped(_ sender: Any?) {
|
||||
// importFromOtherButton.setTitle(LocalizationHelper.localizedString(forKey: "Import"), for: .normal)
|
||||
presentProfilesTableView(with: .pickProfileData) { [weak self] profile in
|
||||
presentProfileSelector(with: .pickProfileData) { [weak self] profile in
|
||||
if profile.name == self?.profilesManager.getSelectedProfile().name {return}
|
||||
self?.loadWidgets(from: profile, to: self?.selectedWidget)
|
||||
}
|
||||
@@ -647,8 +649,8 @@ final class LayoutOnScreenControlsViewController: UIViewController, OnScreenWidg
|
||||
*/
|
||||
|
||||
@objc private func handleReturnToForeground() {
|
||||
if (self.profileTableLoadingMode != .selectProfileFromMainFrame
|
||||
&& self.profileTableLoadingMode != .selectProfileFromMainFrame)
|
||||
if (self.profileSelectorLoadingMode != .selectProfileFromMainFrame
|
||||
&& self.profileSelectorLoadingMode != .selectProfileFromMainFrame)
|
||||
{setupWidgetPanel()}
|
||||
updateViewBounds()
|
||||
}
|
||||
@@ -657,7 +659,7 @@ final class LayoutOnScreenControlsViewController: UIViewController, OnScreenWidg
|
||||
super.viewWillTransition(to: size, with: coordinator)
|
||||
viewWillBeResized = true
|
||||
hideStickIndicators()
|
||||
if self.profileTableLoadingMode == .selectProfile {
|
||||
if self.profileSelectorLoadingMode == .selectProfile {
|
||||
|
||||
let oldSize = view.bounds.size
|
||||
let scaleX = size.width / oldSize.width
|
||||
@@ -710,7 +712,7 @@ final class LayoutOnScreenControlsViewController: UIViewController, OnScreenWidg
|
||||
viewWillBeResized = false
|
||||
selectedWidget = nil
|
||||
selectedControllerLayer = nil
|
||||
oscProfilesTableViewController?.layoutViewBounds = view.bounds
|
||||
profileSelectorViewController?.layoutViewBounds = view.bounds
|
||||
OSCProfilesManager.setLayoutViewBounds(view.bounds)
|
||||
OSCProfilesManager.setOnScreenWidgetViewsSet(onScreenWidgetViews)
|
||||
// reloadOnScreenWidgetViews()
|
||||
@@ -1560,7 +1562,6 @@ final class LayoutOnScreenControlsViewController: UIViewController, OnScreenWidg
|
||||
let alert = UIAlertController(title: success ? LocalizationHelper.localizedString(forKey: "Profile updated successfully") : "", message: message, preferredStyle: .alert)
|
||||
alert.addAction(UIAlertAction(title: LocalizationHelper.localizedString(forKey: "Ok"), style: .default) { _ in
|
||||
if !success {
|
||||
// self.oscProfilesTableViewController?.profileViewRefresh()
|
||||
}
|
||||
})
|
||||
present(alert, animated: true)
|
||||
@@ -1628,11 +1629,11 @@ final class LayoutOnScreenControlsViewController: UIViewController, OnScreenWidg
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func handleProfileTablViewDismiss() {
|
||||
@objc private func handleProfileSelectorDismiss() {
|
||||
|
||||
switch profileTableLoadingMode {
|
||||
switch profileSelectorLoadingMode {
|
||||
case .selectProfile:
|
||||
if oscProfilesTableViewController?.loadingMode != .pickProfileData {
|
||||
if profileSelectorViewController?.loadingMode != .pickProfileData {
|
||||
setupWidgetPanel()
|
||||
}
|
||||
else {
|
||||
@@ -1647,17 +1648,6 @@ final class LayoutOnScreenControlsViewController: UIViewController, OnScreenWidg
|
||||
case .pickProfileData:
|
||||
widgetPanelStack.isHidden = false
|
||||
}
|
||||
|
||||
/*
|
||||
if quickSwitchEnabled {
|
||||
clearOnScreenWidgets()
|
||||
dismiss(animated: false)
|
||||
} else {
|
||||
if oscProfilesTableViewController?.loadingMode != .pickProfileData {
|
||||
setupWidgetPanel()
|
||||
}
|
||||
else {widgetPanelStack.isHidden = false}
|
||||
}*/
|
||||
}
|
||||
|
||||
private func addInnerAnalogSticksToOuterAnalogLayers() {
|
||||
@@ -1731,7 +1721,7 @@ final class LayoutOnScreenControlsViewController: UIViewController, OnScreenWidg
|
||||
}
|
||||
|
||||
private func setupWidgetPanel() {
|
||||
widgetPanelStack.isHidden = profileTableLoadingMode != .selectProfile
|
||||
widgetPanelStack.isHidden = profileSelectorLoadingMode != .selectProfile
|
||||
tipTitleLabel.textAlignment = .left
|
||||
tipTitleLabel.contentMode = .top
|
||||
tipTitleLabel.lineBreakMode = .byWordWrapping
|
||||
@@ -2590,7 +2580,7 @@ final class LayoutOnScreenControlsViewController: UIViewController, OnScreenWidg
|
||||
if profilesManager.getIndexOfSelectedProfile() == 0, layoutOSC.layoutChanges.count > 0 {
|
||||
let alert = UIAlertController(title: "", message: LocalizationHelper.localizedString(forKey: "Layout of the Default profile can not be changed"), preferredStyle: .alert)
|
||||
alert.addAction(UIAlertAction(title: LocalizationHelper.localizedString(forKey: "Ok"), style: .default) { _ in
|
||||
self.oscProfilesTableViewController?.profileViewRefresh()
|
||||
self.profileSelectorViewController?.profileViewRefresh()
|
||||
})
|
||||
present(alert, animated: true)
|
||||
}
|
||||
|
||||
-662
@@ -1,662 +0,0 @@
|
||||
//
|
||||
// OSCProfilesTableViewController.m -> OSCProfilesTableViewController.swift
|
||||
// Moonlight
|
||||
//
|
||||
// Created by Long Le on 11/28/22.
|
||||
// Copyright © 2022 Moonlight Game Streaming Project. All rights reserved.
|
||||
//
|
||||
// Modified by True砖家 since 2024.6.24
|
||||
// Copyright © 2024 True砖家 on Bilibili. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
final class ProfileTableViewCell: UITableViewCell {
|
||||
@IBOutlet weak var name: UILabel!
|
||||
}
|
||||
|
||||
@objc(FileOperation)
|
||||
enum FileOperation: Int {
|
||||
case importOperation = 0
|
||||
case exportOperation = 1
|
||||
}
|
||||
|
||||
@objc enum OSCProfilesTableViewLoadingMode: Int {
|
||||
case selectProfile
|
||||
case selectProfileFromStreamView
|
||||
case selectProfileFromMainFrame
|
||||
case pickProfile
|
||||
case pickProfileData
|
||||
}
|
||||
|
||||
@objcMembers
|
||||
final class OSCProfilesTableViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UIDocumentPickerDelegate, UIGestureRecognizerDelegate, ControllerUINavigationDelegate {
|
||||
|
||||
@IBOutlet weak var tableView: UITableView!
|
||||
@IBOutlet weak var profileTableViewNavigationBar: UINavigationBar!
|
||||
@IBOutlet private weak var profileTableViewNavigationItem: UINavigationItem!
|
||||
|
||||
var currentFileOperation: FileOperation = .importOperation
|
||||
var needToUpdateOscLayoutTVC: (() -> Void)?
|
||||
var loadingMode: OSCProfilesTableViewLoadingMode = .selectProfile
|
||||
@nonobjc var pickedProfileDataHandler: ((OSCProfile) -> Void)?
|
||||
weak var currentOSCButtonLayers: NSMutableSet?
|
||||
var layoutViewBounds: CGRect = .zero
|
||||
|
||||
private var profilesManager: OSCProfilesManager!
|
||||
private var horizontalConstraintsConfigured = false
|
||||
private var profiles: NSMutableArray = []
|
||||
private var selectedProfileIndex = 0
|
||||
private var profilesLoadGeneration = 0
|
||||
|
||||
private func contentWidthMultiplier() -> CGFloat {
|
||||
PublicUtils.viewIsLandscape(view) ? (PublicUtils.isIPhone ? 0.8 : 0.65) : (PublicUtils.isIPhone ? 0.83 : 0.85)
|
||||
}
|
||||
|
||||
private func updateHorizontalLayoutConstraints() {
|
||||
let horizontalConstraints = view.constraints.filter { constraint in
|
||||
let firstItem = constraint.firstItem as? UIView
|
||||
let secondItem = constraint.secondItem as? UIView
|
||||
let involvesManagedView = firstItem == tableView ||
|
||||
firstItem == profileTableViewNavigationBar ||
|
||||
secondItem == tableView ||
|
||||
secondItem == profileTableViewNavigationBar
|
||||
let isHorizontalConstraint: Bool = {
|
||||
switch (constraint.firstAttribute, constraint.secondAttribute) {
|
||||
case (.leading, _), (.trailing, _), (.left, _), (.right, _), (.width, _), (.centerX, _),
|
||||
(_, .leading), (_, .trailing), (_, .left), (_, .right), (_, .width), (_, .centerX):
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}()
|
||||
|
||||
return involvesManagedView && isHorizontalConstraint
|
||||
}
|
||||
|
||||
NSLayoutConstraint.deactivate(horizontalConstraints)
|
||||
|
||||
[tableView, profileTableViewNavigationBar].forEach { controlledView in
|
||||
controlledView?.translatesAutoresizingMaskIntoConstraints = false
|
||||
}
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
profileTableViewNavigationBar.centerXAnchor.constraint(equalTo: view.centerXAnchor),
|
||||
profileTableViewNavigationBar.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: contentWidthMultiplier()),
|
||||
tableView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
|
||||
tableView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: contentWidthMultiplier()),
|
||||
])
|
||||
}
|
||||
|
||||
private func getCurrentOrientation() -> UIInterfaceOrientationMask {
|
||||
let bounds = UIScreen.main.bounds
|
||||
if bounds.width > bounds.height {
|
||||
return .landscape
|
||||
} else {
|
||||
return [.portrait, .portraitUpsideDown]
|
||||
}
|
||||
}
|
||||
|
||||
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
|
||||
getCurrentOrientation()
|
||||
}
|
||||
|
||||
override func viewWillDisappear(_ animated: Bool) {
|
||||
super.viewWillDisappear(animated)
|
||||
NotificationCenter.default.post(name: Notification.Name("OscLayoutTableViewCloseNotification"), object: self)
|
||||
}
|
||||
|
||||
override func viewDidDisappear(_ animated: Bool) {
|
||||
super.viewDidDisappear(animated)
|
||||
if #available(iOS 13.0, *) {
|
||||
ControllerNavigator.restorePreviousUINavigationDelegate(ifCurrentDelegateIs: self)
|
||||
}
|
||||
}
|
||||
|
||||
override func viewDidLayoutSubviews() {
|
||||
super.viewDidLayoutSubviews()
|
||||
|
||||
profileTableViewNavigationBar.layer.cornerRadius = 15
|
||||
profileTableViewNavigationBar.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
|
||||
profileTableViewNavigationBar.layer.masksToBounds = true
|
||||
|
||||
tableView.layer.cornerRadius = 15
|
||||
tableView.layer.maskedCorners = [.layerMinXMaxYCorner, .layerMaxXMaxYCorner]
|
||||
tableView.layer.masksToBounds = true
|
||||
|
||||
tableView.separatorStyle = .singleLine
|
||||
tableView.separatorInset = UIEdgeInsets(top: 0, left: 15, bottom: 0, right: 15)
|
||||
|
||||
if PublicUtils.liquidGlassEnabled {
|
||||
tableView.separatorColor = UIColor.white.withAlphaComponent(PublicUtils.isIPhone ? 0.28 : 0.165)
|
||||
} else {
|
||||
tableView.separatorColor = UIColor.white.withAlphaComponent(0.3)
|
||||
}
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
profilesManager = OSCProfilesManager.sharedManager(layoutViewBounds)
|
||||
configureTableView()
|
||||
updateHorizontalLayoutConstraints()
|
||||
horizontalConstraintsConfigured = true
|
||||
tableView.alpha = 1
|
||||
tableView.backgroundColor = UIColor.black.withAlphaComponent(self.loadingMode == .selectProfileFromMainFrame ? (
|
||||
ThemeManager.userInterfaceStyle() == .dark ? 0.83 : 0.6
|
||||
) : 0.43)
|
||||
|
||||
let tap = UITapGestureRecognizer(target: self, action: #selector(dismissSelf))
|
||||
tap.cancelsTouchesInView = false
|
||||
tap.delegate = self
|
||||
view.addGestureRecognizer(tap)
|
||||
|
||||
if PublicUtils.liquidGlassEnabled, #available(iOS 26.0, *) {
|
||||
profileTableViewNavigationItem.leftBarButtonItems?.forEach { $0.hidesSharedBackground = true }
|
||||
profileTableViewNavigationItem.rightBarButtonItems?.forEach { $0.hidesSharedBackground = true }
|
||||
}
|
||||
|
||||
reloadProfilesAsync(scrollToSelected: true)
|
||||
}
|
||||
|
||||
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
|
||||
super.viewWillTransition(to: size, with: coordinator)
|
||||
|
||||
coordinator.animate(alongsideTransition: { _ in
|
||||
self.updateHorizontalLayoutConstraints()
|
||||
self.view.layoutIfNeeded()
|
||||
})
|
||||
}
|
||||
|
||||
@objc private func dismissSelf() {
|
||||
dismiss(animated: false)
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
|
||||
if !horizontalConstraintsConfigured {
|
||||
updateHorizontalLayoutConstraints()
|
||||
horizontalConstraintsConfigured = true
|
||||
}
|
||||
configureTableView()
|
||||
if profiles.count > 0 {
|
||||
scrollToSelectedProfile(animated: true)
|
||||
} else {
|
||||
reloadProfilesAsync(scrollToSelected: true)
|
||||
}
|
||||
|
||||
if (loadingMode == .selectProfileFromMainFrame || loadingMode == .selectProfileFromStreamView)
|
||||
&& ControllerUtil.primaryGCController != nil {
|
||||
if #available(iOS 13.0, *) {
|
||||
ControllerNavigator.setUINavigationDelegate(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func configureTableView() {
|
||||
tableView.tableHeaderView = UIView(frame: .zero)
|
||||
tableView.delegate = self
|
||||
tableView.dataSource = self
|
||||
tableView.register(UINib(nibName: "ProfileTableViewCell", bundle: nil), forCellReuseIdentifier: "Cell")
|
||||
}
|
||||
|
||||
private func reloadProfilesAsync(scrollToSelected: Bool = false, notify: Bool = false) {
|
||||
profilesLoadGeneration += 1
|
||||
let generation = profilesLoadGeneration
|
||||
let manager = profilesManager
|
||||
|
||||
DispatchQueue.global(qos: .userInitiated).async { [weak self] in
|
||||
guard let manager else { return }
|
||||
|
||||
let loadedProfiles = manager.getAllProfiles()
|
||||
let loadedSelectedIndex = Self.selectedProfileIndex(in: loadedProfiles)
|
||||
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
guard let self, generation == self.profilesLoadGeneration else { return }
|
||||
|
||||
self.profiles = loadedProfiles
|
||||
self.selectedProfileIndex = loadedSelectedIndex
|
||||
self.tableView.reloadData()
|
||||
|
||||
if scrollToSelected {
|
||||
self.scrollToSelectedProfile(animated: true)
|
||||
}
|
||||
|
||||
if notify {
|
||||
self.notifyProfileViewDidRefresh()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func scrollToSelectedProfile(animated: Bool) {
|
||||
guard let selectedProfileIndex = validProfileIndex(selectedProfileIndex) else {
|
||||
return
|
||||
}
|
||||
|
||||
let indexPath = IndexPath(row: selectedProfileIndex, section: 0)
|
||||
tableView.scrollToRow(at: indexPath, at: .middle, animated: animated)
|
||||
}
|
||||
|
||||
private func moveSelectedProfile(by offset: Int) {
|
||||
PublicUtils.runOnMain { [weak self] in
|
||||
guard let self,
|
||||
self.profiles.count > 0,
|
||||
self.tableView.numberOfSections > 0,
|
||||
self.tableView.numberOfRows(inSection: 0) > 0 else {
|
||||
return
|
||||
}
|
||||
|
||||
let maxIndex = min(self.profiles.count, self.tableView.numberOfRows(inSection: 0)) - 1
|
||||
let currentIndex = min(max(self.selectedProfileIndex, 0), maxIndex)
|
||||
let nextIndex = min(max(currentIndex + offset, 0), maxIndex)
|
||||
let nextIndexPath = IndexPath(row: nextIndex, section: 0)
|
||||
|
||||
self.tableView.selectRow(at: nextIndexPath, animated: true, scrollPosition: .middle)
|
||||
self.tableView(self.tableView, didSelectRowAt: nextIndexPath)
|
||||
}
|
||||
}
|
||||
|
||||
private func validProfileIndex(_ index: Int) -> Int? {
|
||||
guard profiles.count > 0 else { return nil }
|
||||
return min(max(index, 0), profiles.count - 1)
|
||||
}
|
||||
|
||||
private func notifyProfileViewDidRefresh() {
|
||||
needToUpdateOscLayoutTVC?()
|
||||
if loadingMode != .selectProfileFromStreamView
|
||||
&& loadingMode != .pickProfile
|
||||
&& loadingMode != .pickProfileData
|
||||
&& loadingMode != .selectProfile
|
||||
{
|
||||
guard let selectedProfileIndex = validProfileIndex(selectedProfileIndex) else { return }
|
||||
NotificationCenter.default.post(name: Notification.Name("GameProfileSelectedNotification"), object: self.profiles[selectedProfileIndex])
|
||||
}
|
||||
}
|
||||
|
||||
private static func selectedProfileIndex(in profiles: NSMutableArray) -> Int {
|
||||
for index in 0..<profiles.count {
|
||||
guard let profile = profiles.object(at: index) as? OSCProfile else {
|
||||
continue
|
||||
}
|
||||
|
||||
if profile.isSelected {
|
||||
return index
|
||||
}
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
@IBAction func duplicateTapped(_ sender: Any?) {
|
||||
let inputAlert = UIAlertController(
|
||||
title: LocalizationHelper.localizedString(forKey: "Enter the name you want to save this profile as"),
|
||||
message: "",
|
||||
preferredStyle: .alert
|
||||
)
|
||||
inputAlert.addTextField { textField in
|
||||
textField.placeholder = LocalizationHelper.localizedString(forKey: "name")
|
||||
if #available(iOS 13.0, *) {
|
||||
// textField.textColor = .label
|
||||
}
|
||||
textField.clearButtonMode = .whileEditing
|
||||
textField.borderStyle = .none
|
||||
}
|
||||
inputAlert.addAction(UIAlertAction(title: LocalizationHelper.localizedString(forKey: "Cancel"), style: .default) { _ in
|
||||
inputAlert.dismiss(animated: false)
|
||||
})
|
||||
inputAlert.addAction(UIAlertAction(title: LocalizationHelper.localizedString(forKey: "Save"), style: .default) { [weak self] _ in
|
||||
guard let self else { return }
|
||||
let enteredProfileName = inputAlert.textFields?.first?.text ?? ""
|
||||
|
||||
if enteredProfileName == "Default" {
|
||||
let alert = UIAlertController(
|
||||
title: "",
|
||||
message: LocalizationHelper.localizedString(forKey: "Saving over the 'Default' profile is not allowed"),
|
||||
preferredStyle: .alert
|
||||
)
|
||||
alert.addAction(UIAlertAction(title: LocalizationHelper.localizedString(forKey: "Ok"), style: .default) { _ in
|
||||
alert.dismiss(animated: false) {
|
||||
self.present(inputAlert, animated: true)
|
||||
}
|
||||
})
|
||||
self.present(alert, animated: true)
|
||||
} else if enteredProfileName.isEmpty {
|
||||
let alert = UIAlertController(
|
||||
title: "",
|
||||
message: LocalizationHelper.localizedString(forKey: "Profile name cannot be blank!"),
|
||||
preferredStyle: .alert
|
||||
)
|
||||
alert.addAction(UIAlertAction(title: LocalizationHelper.localizedString(forKey: "Ok"), style: .default) { _ in
|
||||
alert.dismiss(animated: false) {
|
||||
self.present(inputAlert, animated: true)
|
||||
}
|
||||
})
|
||||
self.present(alert, animated: true)
|
||||
} else if self.profilesManager.profileNameAlreadyExist(enteredProfileName) {
|
||||
let alert = UIAlertController(
|
||||
title: "",
|
||||
message: LocalizationHelper.localizedString(forKey: "Profile name already exists"),
|
||||
preferredStyle: .alert
|
||||
)
|
||||
alert.addAction(UIAlertAction(title: LocalizationHelper.localizedString(forKey: "Ok"), style: .default))
|
||||
self.present(alert, animated: true)
|
||||
} else {
|
||||
self.profilesManager.duplicateSelectedProfile(withName: enteredProfileName)
|
||||
let alert = UIAlertController(
|
||||
title: "",
|
||||
message: LocalizationHelper.localizedString(forKey: "Profile %@ duplicated from current layout", enteredProfileName),
|
||||
preferredStyle: .alert
|
||||
)
|
||||
alert.addAction(UIAlertAction(title: LocalizationHelper.localizedString(forKey: "Ok"), style: .default) { _ in
|
||||
alert.dismiss(animated: false)
|
||||
self.profileViewRefresh()
|
||||
})
|
||||
self.present(alert, animated: true)
|
||||
}
|
||||
})
|
||||
|
||||
present(inputAlert, animated: true)
|
||||
}
|
||||
|
||||
func profileViewRefresh() {
|
||||
reloadProfilesAsync(notify: true)
|
||||
}
|
||||
|
||||
@IBAction func deleteTapped(_ sender: Any?) {
|
||||
profilesManager.deleteCurrentSelectedProfile()
|
||||
profileViewRefresh()
|
||||
}
|
||||
|
||||
@IBAction func exportDataTapped(_ sender: Any?) {
|
||||
currentFileOperation = .exportOperation
|
||||
let tempPath = NSTemporaryDirectory().appending("profiles.bin")
|
||||
try? Data().write(to: URL(fileURLWithPath: tempPath), options: .atomic)
|
||||
|
||||
let picker = UIDocumentPickerViewController(url: URL(fileURLWithPath: tempPath), in: .exportToService)
|
||||
picker.delegate = self
|
||||
present(picker, animated: true)
|
||||
}
|
||||
|
||||
@IBAction func importDataTapped(_ sender: Any?) {
|
||||
currentFileOperation = .importOperation
|
||||
let picker = UIDocumentPickerViewController(documentTypes: ["public.item"], in: .open)
|
||||
picker.delegate = self
|
||||
picker.allowsMultipleSelection = false
|
||||
present(picker, animated: true)
|
||||
}
|
||||
|
||||
@IBAction func restoreTapped(_ sender: Any?) {
|
||||
profilesManager.importDefaultTemplates()
|
||||
profileViewRefresh()
|
||||
}
|
||||
|
||||
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
|
||||
guard let url = urls.first else { return }
|
||||
switch currentFileOperation {
|
||||
case .exportOperation:
|
||||
profilesToFile(url)
|
||||
case .importOperation:
|
||||
fileToProfiles(url)
|
||||
}
|
||||
}
|
||||
|
||||
private func profilesToFile(_ destinationURL: URL) {
|
||||
do {
|
||||
let data = try NSKeyedArchiver.archivedData(withRootObject: profilesManager.getEncodedProfiles(), requiringSecureCoding: true)
|
||||
let accessed = destinationURL.startAccessingSecurityScopedResource()
|
||||
defer {
|
||||
if accessed {
|
||||
destinationURL.stopAccessingSecurityScopedResource()
|
||||
}
|
||||
}
|
||||
try data.write(to: destinationURL, options: .atomic)
|
||||
} catch {
|
||||
// NSLog("写入失败: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
private func fileToProfiles(_ sourceURL: URL) {
|
||||
var restoreFailed = false
|
||||
let accessed = sourceURL.startAccessingSecurityScopedResource()
|
||||
if !accessed {
|
||||
restoreFailed = true
|
||||
}
|
||||
|
||||
defer {
|
||||
if accessed {
|
||||
sourceURL.stopAccessingSecurityScopedResource()
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
let fileData = try Data(contentsOf: sourceURL)
|
||||
// NSLog("profile file read: \(UInt32(fileData.count))")
|
||||
let classes: [AnyClass] = [NSMutableData.self, NSMutableArray.self]
|
||||
let profilesEncoded = try NSKeyedUnarchiver.unarchivedObject(ofClasses: classes, from: fileData) as? NSMutableArray
|
||||
|
||||
let restoredAlert = UIAlertController(
|
||||
title: LocalizationHelper.localizedString(forKey: ""),
|
||||
message: LocalizationHelper.localizedString(forKey: "Pofiles imported"),
|
||||
preferredStyle: .alert
|
||||
)
|
||||
let failedAlert = UIAlertController(
|
||||
title: LocalizationHelper.localizedString(forKey: ""),
|
||||
message: LocalizationHelper.localizedString(forKey: "Failed to import profiles"),
|
||||
preferredStyle: .alert
|
||||
)
|
||||
let okAction = UIAlertAction(title: LocalizationHelper.localizedString(forKey: "OK"), style: .default)
|
||||
|
||||
if restoreFailed || profilesEncoded == nil {
|
||||
failedAlert.addAction(okAction)
|
||||
present(failedAlert, animated: true)
|
||||
} else {
|
||||
profilesManager.importEncodedProfiles(profilesEncoded!)
|
||||
restoredAlert.addAction(okAction)
|
||||
present(restoredAlert, animated: true)
|
||||
}
|
||||
|
||||
profileViewRefresh()
|
||||
// NSLog("profile test: \(UInt32(profilesEncoded?.count ?? 0))")
|
||||
} catch {
|
||||
restoreFailed = true
|
||||
let failedAlert = UIAlertController(
|
||||
title: LocalizationHelper.localizedString(forKey: ""),
|
||||
message: LocalizationHelper.localizedString(forKey: "Failed to import profiles"),
|
||||
preferredStyle: .alert
|
||||
)
|
||||
failedAlert.addAction(UIAlertAction(title: LocalizationHelper.localizedString(forKey: "OK"), style: .default))
|
||||
present(failedAlert, animated: true)
|
||||
profileViewRefresh()
|
||||
// NSLog("解码失败: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
profiles.count
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
guard let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as? ProfileTableViewCell,
|
||||
indexPath.row < profiles.count,
|
||||
let profile = profiles.object(at: indexPath.row) as? OSCProfile,
|
||||
let nameLabel = cell.name else {
|
||||
return UITableViewCell()
|
||||
}
|
||||
|
||||
nameLabel.text = profile.name.localizedProfileName
|
||||
nameLabel.backgroundColor = UIColor.clear
|
||||
nameLabel.alpha = 1.0
|
||||
nameLabel.textColor = UIColor.white.withAlphaComponent(0.9)
|
||||
nameLabel.font = UIFont.systemFont(ofSize: 18.5, weight: .medium)
|
||||
nameLabel.shadowColor = UIColor.black
|
||||
nameLabel.shadowOffset = CGSize(width: 0.5, height: 0.5)
|
||||
|
||||
cell.backgroundColor = UIColor.clear
|
||||
cell.contentView.backgroundColor = UIColor.clear
|
||||
|
||||
if loadingMode != .pickProfileData,
|
||||
indexPath.row == selectedProfileIndex {
|
||||
cell.accessoryType = UITableViewCell.AccessoryType.checkmark
|
||||
let checkmarkLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 20, height: 20))
|
||||
checkmarkLabel.text = "✓"
|
||||
checkmarkLabel.font = .systemFont(ofSize: 25)
|
||||
checkmarkLabel.textAlignment = .center
|
||||
checkmarkLabel.textColor = .green
|
||||
checkmarkLabel.layer.zPosition = 0
|
||||
cell.accessoryView = checkmarkLabel
|
||||
} else {
|
||||
cell.accessoryType = UITableViewCell.AccessoryType.none
|
||||
cell.accessoryView = nil
|
||||
}
|
||||
|
||||
return cell
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
|
||||
true
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
|
||||
60.0
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
|
||||
guard indexPath.row < profiles.count else { return }
|
||||
|
||||
if let profile = profiles.object(at: indexPath.row) as? OSCProfile, profile.name == "Default" {
|
||||
let alert = UIAlertController(title: "", message: "Deleting the 'Default' profile is not allowed", preferredStyle: .alert)
|
||||
alert.addAction(UIAlertAction(title: LocalizationHelper.localizedString(forKey: "Ok"), style: .default) { _ in
|
||||
alert.dismiss(animated: false)
|
||||
})
|
||||
present(alert, animated: true)
|
||||
return
|
||||
}
|
||||
|
||||
if editingStyle == .delete {
|
||||
if let profile = profiles.object(at: indexPath.row) as? OSCProfile, profile.isSelected, indexPath.row > 0,
|
||||
let previousProfile = profiles.object(at: indexPath.row - 1) as? OSCProfile {
|
||||
previousProfile.isSelected = true
|
||||
}
|
||||
|
||||
profiles.removeObject(at: indexPath.row)
|
||||
|
||||
let profilesEncoded = NSMutableArray()
|
||||
for case let profileDecoded as OSCProfile in profiles {
|
||||
if let profileEncoded = try? NSKeyedArchiver.archivedData(withRootObject: profileDecoded, requiringSecureCoding: true) {
|
||||
profilesEncoded.add(profileEncoded)
|
||||
}
|
||||
}
|
||||
if let data = try? NSKeyedArchiver.archivedData(withRootObject: profilesEncoded, requiringSecureCoding: true) {
|
||||
UserDefaults.standard.set(data, forKey: "OSCProfiles")
|
||||
UserDefaults.standard.synchronize()
|
||||
}
|
||||
|
||||
reloadProfilesAsync()
|
||||
}
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
guard indexPath.section == 0,
|
||||
indexPath.row >= 0,
|
||||
indexPath.row < profiles.count else {
|
||||
return
|
||||
}
|
||||
|
||||
if loadingMode == .pickProfileData,
|
||||
let pickedProfile = profiles.object(at: indexPath.row) as? OSCProfile {
|
||||
pickedProfileDataHandler?(pickedProfile)
|
||||
dismiss(animated: false)
|
||||
return
|
||||
}
|
||||
|
||||
let selectedIndexPath = IndexPath(row: indexPath.row, section: 0)
|
||||
let lastSelectedIndex = validProfileIndex(selectedProfileIndex)
|
||||
let lastSelectedIndexPath = lastSelectedIndex.map { IndexPath(row: $0, section: 0) }
|
||||
|
||||
if selectedIndexPath != lastSelectedIndexPath {
|
||||
if let lastSelectedIndexPath {
|
||||
let previousCell = tableView.cellForRow(at: lastSelectedIndexPath)
|
||||
previousCell?.accessoryType = .none
|
||||
previousCell?.accessoryView = nil
|
||||
}
|
||||
|
||||
profilesManager.setProfileToSelected(UInt32(indexPath.row))
|
||||
selectedProfileIndex = indexPath.row
|
||||
|
||||
let selectedCell = tableView.cellForRow(at: selectedIndexPath)
|
||||
selectedCell?.accessoryType = .checkmark
|
||||
let checkmarkLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 20, height: 20))
|
||||
checkmarkLabel.text = "✓"
|
||||
checkmarkLabel.font = .systemFont(ofSize: 25)
|
||||
checkmarkLabel.textAlignment = .center
|
||||
checkmarkLabel.textColor = .green
|
||||
checkmarkLabel.layer.zPosition = 0
|
||||
selectedCell?.accessoryView = checkmarkLabel
|
||||
|
||||
let rowsToReload = [lastSelectedIndexPath, selectedIndexPath]
|
||||
.compactMap { $0 }
|
||||
.filter {
|
||||
$0.section < tableView.numberOfSections &&
|
||||
$0.row >= 0 &&
|
||||
$0.row < tableView.numberOfRows(inSection: $0.section)
|
||||
}
|
||||
if !rowsToReload.isEmpty {
|
||||
tableView.reloadRows(at: rowsToReload, with: .none)
|
||||
}
|
||||
}
|
||||
profileViewRefresh()
|
||||
}
|
||||
|
||||
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
|
||||
if (loadingMode != .selectProfile
|
||||
&& loadingMode != .selectProfileFromMainFrame
|
||||
&& loadingMode != .selectProfileFromStreamView
|
||||
),
|
||||
let touchView = touch.view,
|
||||
touchView.isDescendant(of: tableView) {
|
||||
return true
|
||||
}
|
||||
return touch.view == view
|
||||
}
|
||||
|
||||
@available(iOS 13.0, *)
|
||||
func getNavigationElements() -> [ControllerNavigationElement] {
|
||||
var elements: [ControllerNavigationElement] = []
|
||||
elements.append(ControllerNavigationElement(control:ControllerNavigator.radialMenuButtonPosition == .left ? .dpadUp : .y, action: "previousItem"))
|
||||
elements.append(ControllerNavigationElement(control:ControllerNavigator.radialMenuButtonPosition == .left ? .dpadDown : .a, action: "nextItem"))
|
||||
elements.append(ControllerNavigationElement(control:ControllerNavigator.radialMenuButtonPosition == .left ? .dpadRight : .x, action: "exit"))
|
||||
return elements
|
||||
}
|
||||
|
||||
func navigateByController(forward: Bool) {
|
||||
}
|
||||
|
||||
func navigateByController(downward: Bool) {
|
||||
|
||||
}
|
||||
|
||||
func persistControllerNavigationHighlight() {}
|
||||
func restoreControllerNavigationHighlight() {}
|
||||
func restoreControllerNavigationHighlightAfterSettingsModeSwitch() {}
|
||||
|
||||
func uiWidgetActionForControllerNavigator(forward: Bool, from navigation: ControllerNavigationElement) {
|
||||
}
|
||||
|
||||
func uiButtonActionForControllerNavigator(pressed: Bool, from navigation: ControllerNavigationElement) {
|
||||
guard pressed else { return }
|
||||
PublicUtils.runOnMain { [weak self] in
|
||||
switch navigation.action {
|
||||
case "previousItem":
|
||||
self?.moveSelectedProfile(by: -1)
|
||||
case "nextItem":
|
||||
self?.moveSelectedProfile(by: 1)
|
||||
case "exit":
|
||||
self?.dismiss(animated: false)
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1622
File diff suppressed because it is too large
Load Diff
@@ -1,42 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="none" accessoryType="checkmark" indentationWidth="10" reuseIdentifier="Cell" id="KGk-i7-Jjw" customClass="ProfileTableViewCell" customModule="VoidLink" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
|
||||
<rect key="frame" x="0.0" y="0.0" width="280" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Profile Name" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="b1d-b4-TCK">
|
||||
<rect key="frame" x="16.000000000000007" y="11.666666666666664" width="97.666666666666686" height="21"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="0.95294117647058818" green="0.97647058823529409" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="0.1215686275" green="0.12941176469999999" blue="0.14117647059999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="b1d-b4-TCK" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="16" id="pxI-vz-oR6"/>
|
||||
<constraint firstItem="b1d-b4-TCK" firstAttribute="centerY" secondItem="H2p-sc-9uM" secondAttribute="centerY" id="xCR-Og-ne7"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
<viewLayoutGuide key="safeArea" id="aW0-zy-SZf"/>
|
||||
<color key="backgroundColor" red="0.1215686275" green="0.12941176469999999" blue="0.14117647059999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="tintColor" red="0.6705882353" green="0.61568627450000002" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<connections>
|
||||
<outlet property="name" destination="b1d-b4-TCK" id="CX8-IC-jlM"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="108" y="39"/>
|
||||
</tableViewCell>
|
||||
</objects>
|
||||
</document>
|
||||
@@ -1288,13 +1288,13 @@ static NSMutableSet* hostList;
|
||||
layoutToolVC.modalPresentationStyle = UIModalPresentationOverCurrentContext;
|
||||
|
||||
|
||||
layoutToolVC.profileTableLoadingMode = OSCProfilesTableViewLoadingModeSelectProfileFromMainFrame;
|
||||
layoutToolVC.profileSelectorLoadingMode = ProfileSelectorLoadingModeSelectProfileFromMainFrame;
|
||||
layoutToolVC.toolbarStackView.hidden = true;
|
||||
layoutToolVC.toolbarRootView.hidden = true;
|
||||
|
||||
self.gameProfileSelectorVC = layoutToolVC;
|
||||
[self presentViewController:layoutToolVC animated:false completion:^{
|
||||
[layoutToolVC presentProfilesTableViewWithLoadingMode:OSCProfilesTableViewLoadingModeSelectProfileFromMainFrame animated:animated];
|
||||
[layoutToolVC presentProfileSelectorWith:ProfileSelectorLoadingModeSelectProfileFromMainFrame animated:animated];
|
||||
}];
|
||||
}
|
||||
|
||||
@@ -1663,7 +1663,7 @@ static NSMutableSet* hostList;
|
||||
barButtonItem.tintColor = ThemeManager.appPrimaryColor;
|
||||
|
||||
if (@available(iOS 13.0, *)) {
|
||||
UIUserInterfaceStyle style = ThemeManager.userInterfaceStyle;
|
||||
UIUserInterfaceStyle style = ThemeManager.overrideUserInterfaceStyle;
|
||||
UIView *customView = barButtonItem.customView;
|
||||
customView.overrideUserInterfaceStyle = style;
|
||||
|
||||
@@ -1685,7 +1685,7 @@ static NSMutableSet* hostList;
|
||||
|
||||
- (void)applyThemeToNavigationControls {
|
||||
if (@available(iOS 13.0, *)) {
|
||||
UIUserInterfaceStyle style = ThemeManager.userInterfaceStyle;
|
||||
UIUserInterfaceStyle style = ThemeManager.overrideUserInterfaceStyle;
|
||||
self.overrideUserInterfaceStyle = style;
|
||||
self.view.overrideUserInterfaceStyle = style;
|
||||
self.navigationController.overrideUserInterfaceStyle = style;
|
||||
@@ -1856,7 +1856,7 @@ static NSMutableSet* hostList;
|
||||
TemporarySettings* tempSettings = [dataMan getSettings];
|
||||
if(tempSettings.appTheme.intValue != UIUserInterfaceStyleUnspecified) return;
|
||||
if ([self.traitCollection hasDifferentColorAppearanceComparedToTraitCollection:previousTraitCollection]) {
|
||||
[ThemeManager setUserInterfaceStyle:self.traitCollection.userInterfaceStyle];
|
||||
[ThemeManager systemUserInterfaceStyleDidChange:self.traitCollection.userInterfaceStyle];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2806,8 +2806,8 @@ static NSMutableSet* hostList;
|
||||
}];
|
||||
}
|
||||
else if(!self.gameProfileSelectorVC && !self.settingsViewController.layoutOnScreenControlsVC) [self openGameProfileSeletorWithAnimated:true];
|
||||
else if (self.gameProfileSelectorVC) [self.gameProfileSelectorVC.oscProfilesTableViewController dismissViewControllerAnimated:true completion:^{}];
|
||||
else if (self.settingsViewController.layoutOnScreenControlsVC) [self.settingsViewController.layoutOnScreenControlsVC.oscProfilesTableViewController dismissViewControllerAnimated:true completion:^{}];
|
||||
else if (self.gameProfileSelectorVC) [self.gameProfileSelectorVC.profileSelectorViewController dismissViewControllerAnimated:true completion:^{}];
|
||||
else if (self.settingsViewController.layoutOnScreenControlsVC) [self.settingsViewController.layoutOnScreenControlsVC.profileSelectorViewController dismissViewControllerAnimated:true completion:^{}];
|
||||
break;
|
||||
case RadialMenuItemHostView:
|
||||
[self switchToHostView];
|
||||
@@ -2833,8 +2833,8 @@ static NSMutableSet* hostList;
|
||||
- (void)controllerNavigatorDidSelectGameProfiles {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if(!self.gameProfileSelectorVC && !self.settingsViewController.layoutOnScreenControlsVC) [self openGameProfileSeletorWithAnimated:true];
|
||||
else if (self.gameProfileSelectorVC) [self.gameProfileSelectorVC.oscProfilesTableViewController dismissViewControllerAnimated:true completion:^{}];
|
||||
else if (self.settingsViewController.layoutOnScreenControlsVC) [self.settingsViewController.layoutOnScreenControlsVC.oscProfilesTableViewController dismissViewControllerAnimated:true completion:^{}];
|
||||
else if (self.gameProfileSelectorVC) [self.gameProfileSelectorVC.profileSelectorViewController dismissViewControllerAnimated:true completion:^{}];
|
||||
else if (self.settingsViewController.layoutOnScreenControlsVC) [self.settingsViewController.layoutOnScreenControlsVC.profileSelectorViewController dismissViewControllerAnimated:true completion:^{}];
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -3226,9 +3226,9 @@ BOOL isCustomResolution(int resolutionSelected) {
|
||||
// self.layoutOnScreenControlsVC.view.backgroundColor = [UIColor colorWithWhite:0.55 alpha:1.0];
|
||||
self.layoutOnScreenControlsVC.view.backgroundColor = UIColor.clearColor;
|
||||
self.layoutOnScreenControlsVC.modalPresentationStyle = UIModalPresentationOverCurrentContext;
|
||||
self.layoutOnScreenControlsVC.profileTableLoadingMode = OSCProfilesTableViewLoadingModeSelectProfileFromMainFrame;
|
||||
self.layoutOnScreenControlsVC.profileSelectorLoadingMode = ProfileSelectorLoadingModeSelectProfileFromMainFrame;
|
||||
[self presentViewController:self.layoutOnScreenControlsVC animated:NO completion:^{
|
||||
[self->_layoutOnScreenControlsVC presentProfilesTableViewWithLoadingMode:OSCProfilesTableViewLoadingModeSelectProfileFromMainFrame animated:animated];
|
||||
[self->_layoutOnScreenControlsVC presentProfileSelectorWith:ProfileSelectorLoadingModeSelectProfileFromMainFrame animated:animated];
|
||||
}];
|
||||
_layoutOnScreenControlsVC.toolbarStackView.hidden = true;
|
||||
_layoutOnScreenControlsVC.toolbarRootView.hidden = true;
|
||||
|
||||
@@ -1064,9 +1064,9 @@ static __weak StreamFrameViewController *VLSharedStreamFrameViewController = nil
|
||||
_layoutOnScreenControlsVC.quickSwitchEnabled = true;
|
||||
_layoutOnScreenControlsVC.toolbarStackView.hidden = true;
|
||||
_layoutOnScreenControlsVC.toolbarRootView.hidden = true;
|
||||
OSCProfilesTableViewLoadingMode loadingMode = pickProfile ? OSCProfilesTableViewLoadingModePickProfile : OSCProfilesTableViewLoadingModeSelectProfileFromStreamView;
|
||||
ProfileSelectorLoadingMode loadingMode = pickProfile ? ProfileSelectorLoadingModePickProfile : ProfileSelectorLoadingModeSelectProfileFromStreamView;
|
||||
[self presentViewController:_layoutOnScreenControlsVC animated:NO completion:^{
|
||||
[self->_layoutOnScreenControlsVC presentProfilesTableViewWithLoadingMode:loadingMode animated:false];
|
||||
[self->_layoutOnScreenControlsVC presentProfileSelectorWith:loadingMode animated:false];
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
@@ -295,11 +295,8 @@ import UIKit
|
||||
contentView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: contentWidthMultiplier()),
|
||||
contentView.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: PublicUtils.isIPhone ? 0.93 : 0.93),
|
||||
contentView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
|
||||
// contentView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
|
||||
|
||||
|
||||
contentView.topAnchor.constraint(greaterThanOrEqualTo: view.safeAreaLayoutGuide.topAnchor, constant: 8),
|
||||
contentView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: PublicUtils.isIPhone ? 3 : -5),
|
||||
|
||||
toolbarView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: sideInset),
|
||||
toolbarView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -sideInset),
|
||||
@@ -316,6 +313,14 @@ import UIKit
|
||||
collectionView.topAnchor.constraint(equalTo: contentView.safeAreaLayoutGuide.topAnchor, constant: topInset),
|
||||
collectionView.bottomAnchor.constraint(equalTo: toolbarView.topAnchor, constant: -toolbarVerticalInset),
|
||||
]
|
||||
|
||||
if PublicUtils.isIPhone {
|
||||
layoutConstraints.append(contentView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: 3))
|
||||
}
|
||||
else {
|
||||
layoutConstraints.append(contentView.centerYAnchor.constraint(equalTo: view.centerYAnchor))
|
||||
}
|
||||
|
||||
NSLayoutConstraint.activate(layoutConstraints)
|
||||
|
||||
setupToolbarConstraints()
|
||||
|
||||
@@ -1647,7 +1647,7 @@
|
||||
},
|
||||
"Bhn-IO-Wlt.title" : {
|
||||
"comment" : "Class = \"UIBarButtonItem\"; title = \"ExportAll\"; ObjectID = \"Bhn-IO-Wlt\";",
|
||||
"extractionState" : "extracted_with_value",
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
@@ -2409,7 +2409,7 @@
|
||||
},
|
||||
"CpY-Sb-BDc.title" : {
|
||||
"comment" : "Class = \"UIBarButtonItem\"; title = \"Import\"; ObjectID = \"CpY-Sb-BDc\";",
|
||||
"extractionState" : "extracted_with_value",
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
@@ -2517,7 +2517,7 @@
|
||||
},
|
||||
"czn-mj-8d1.title" : {
|
||||
"comment" : "Class = \"UIBarButtonItem\"; title = \"Restore\"; ObjectID = \"czn-mj-8d1\";",
|
||||
"extractionState" : "extracted_with_value",
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
@@ -2848,7 +2848,7 @@
|
||||
},
|
||||
"egC-9E-zS4.title" : {
|
||||
"comment" : "Class = \"UIBarButtonItem\"; title = \"Delete\"; ObjectID = \"egC-9E-zS4\";",
|
||||
"extractionState" : "extracted_with_value",
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
@@ -5374,7 +5374,7 @@
|
||||
},
|
||||
"P34-hO-6cX.title" : {
|
||||
"comment" : "Class = \"UIBarButtonItem\"; title = \"Duplicate\"; ObjectID = \"P34-hO-6cX\";",
|
||||
"extractionState" : "extracted_with_value",
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
|
||||
@@ -1713,7 +1713,7 @@
|
||||
},
|
||||
"bue-hp-CWD.title" : {
|
||||
"comment" : "Class = \"UIBarButtonItem\"; title = \"Duplicate\"; ObjectID = \"bue-hp-CWD\";",
|
||||
"extractionState" : "extracted_with_value",
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
@@ -2079,7 +2079,7 @@
|
||||
},
|
||||
"D9X-7p-9oc.title" : {
|
||||
"comment" : "Class = \"UIBarButtonItem\"; title = \"ExportAll\"; ObjectID = \"D9X-7p-9oc\";",
|
||||
"extractionState" : "extracted_with_value",
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
@@ -2649,7 +2649,7 @@
|
||||
},
|
||||
"ghM-zc-sr6.title" : {
|
||||
"comment" : "Class = \"UIBarButtonItem\"; title = \"Delete\"; ObjectID = \"ghM-zc-sr6\";",
|
||||
"extractionState" : "extracted_with_value",
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
@@ -5601,7 +5601,7 @@
|
||||
},
|
||||
"sUC-Ur-7eI.title" : {
|
||||
"comment" : "Class = \"UIBarButtonItem\"; title = \"Restore\"; ObjectID = \"sUC-Ur-7eI\";",
|
||||
"extractionState" : "extracted_with_value",
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
@@ -6663,7 +6663,7 @@
|
||||
},
|
||||
"Z9M-yq-an2.title" : {
|
||||
"comment" : "Class = \"UIBarButtonItem\"; title = \"Import\"; ObjectID = \"Z9M-yq-an2\";",
|
||||
"extractionState" : "extracted_with_value",
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
|
||||
Reference in New Issue
Block a user