Adds support for syncing with Dropbox
This commit is contained in:
parent
8f6b8d763a
commit
483ad69678
@ -33,6 +33,8 @@
|
||||
BF1173501DA32CF600047DF8 /* ControllersSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF11734F1DA32CF600047DF8 /* ControllersSettingsViewController.swift */; };
|
||||
BF13A7561D5D29B0000BB055 /* PreviewGameViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF13A7551D5D29B0000BB055 /* PreviewGameViewController.swift */; };
|
||||
BF13A7581D5D2FD9000BB055 /* EmulatorCore+Cheats.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF13A7571D5D2FD9000BB055 /* EmulatorCore+Cheats.swift */; };
|
||||
BF144C642238511400C387E1 /* Harmony_Dropbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BFDE2CC6222DF345008038E0 /* Harmony_Dropbox.framework */; };
|
||||
BF144C652238511400C387E1 /* Harmony_Dropbox.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = BFDE2CC6222DF345008038E0 /* Harmony_Dropbox.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
BF15AF841F54B43B009B6AAB /* ActionInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF15AF831F54B43B009B6AAB /* ActionInput.swift */; };
|
||||
BF18B61F1E2985F900F70067 /* UIAlertController+Importing.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF18B61E1E2985F900F70067 /* UIAlertController+Importing.swift */; };
|
||||
BF1DAD5D1D9F576000E752A7 /* SystemControllerSkinsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF1DAD5C1D9F576000E752A7 /* SystemControllerSkinsViewController.swift */; };
|
||||
@ -132,6 +134,10 @@
|
||||
BFD097211D3A01B8005A44C2 /* SaveStatesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF3540041C5DA70400C1184C /* SaveStatesViewController.swift */; };
|
||||
BFDB3418219E4B1700595A62 /* SyncStatusViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFDB3417219E4B1700595A62 /* SyncStatusViewController.swift */; };
|
||||
BFDD04F11D5E2C27002D450E /* GameCollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFDD04F01D5E2C27002D450E /* GameCollectionViewController.swift */; };
|
||||
BFDE2CD1222DF36A008038E0 /* SwiftyDropbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BFDE2CC8222DF345008038E0 /* SwiftyDropbox.framework */; };
|
||||
BFDE2CD2222DF36A008038E0 /* SwiftyDropbox.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = BFDE2CC8222DF345008038E0 /* SwiftyDropbox.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
BFDE2CD3222DF36A008038E0 /* Alamofire.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BFDE2CC7222DF345008038E0 /* Alamofire.framework */; };
|
||||
BFDE2CD4222DF36A008038E0 /* Alamofire.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = BFDE2CC7222DF345008038E0 /* Alamofire.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
BFE022A01F5B57FF0052D888 /* PopoverMenuButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFE0229F1F5B577D0052D888 /* PopoverMenuButton.swift */; };
|
||||
BFE4269E1D9C68E600DC913F /* SaveStatesStoryboardSegue.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFE4269D1D9C68E600DC913F /* SaveStatesStoryboardSegue.swift */; };
|
||||
BFE593CA21F3F8B7003412A6 /* GameSave.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFE593C921F3F8B7003412A6 /* GameSave.swift */; };
|
||||
@ -161,11 +167,14 @@
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
BF9F4FD01AAD7B87004C9500 /* DeltaCore.framework in Embed Frameworks */,
|
||||
BFDE2CD2222DF36A008038E0 /* SwiftyDropbox.framework in Embed Frameworks */,
|
||||
BF48F75C219A1F8A00BC2FC1 /* Harmony_Drive.framework in Embed Frameworks */,
|
||||
BF48F756219A1EF000BC2FC1 /* Harmony.framework in Embed Frameworks */,
|
||||
BFF0742D1E9DC17500ACDF4A /* GBCDeltaCore.framework in Embed Frameworks */,
|
||||
BFEC732E1AAECC4A00650035 /* Roxas.framework in Embed Frameworks */,
|
||||
BF0418151D01E93400E85BCF /* GBADeltaCore.framework in Embed Frameworks */,
|
||||
BFDE2CD4222DF36A008038E0 /* Alamofire.framework in Embed Frameworks */,
|
||||
BF144C652238511400C387E1 /* Harmony_Dropbox.framework in Embed Frameworks */,
|
||||
BF98C9832204D9AB006B95AC /* NESDeltaCore.framework in Embed Frameworks */,
|
||||
BF99C6951D0A9AA600BA92BC /* SNESDeltaCore.framework in Embed Frameworks */,
|
||||
BF072011219A3A9D00F05DA4 /* ZIPFoundation.framework in Embed Frameworks */,
|
||||
@ -293,6 +302,9 @@
|
||||
BFCEA67D1D56FF640061A534 /* UIViewControllerContextTransitioning+Conveniences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIViewControllerContextTransitioning+Conveniences.swift"; sourceTree = "<group>"; };
|
||||
BFDB3417219E4B1700595A62 /* SyncStatusViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncStatusViewController.swift; sourceTree = "<group>"; };
|
||||
BFDD04F01D5E2C27002D450E /* GameCollectionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GameCollectionViewController.swift; sourceTree = "<group>"; };
|
||||
BFDE2CC6222DF345008038E0 /* Harmony_Dropbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Harmony_Dropbox.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
BFDE2CC7222DF345008038E0 /* Alamofire.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Alamofire.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
BFDE2CC8222DF345008038E0 /* SwiftyDropbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = SwiftyDropbox.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
BFE0229F1F5B577D0052D888 /* PopoverMenuButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PopoverMenuButton.swift; sourceTree = "<group>"; };
|
||||
BFE4269D1D9C68E600DC913F /* SaveStatesStoryboardSegue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SaveStatesStoryboardSegue.swift; sourceTree = "<group>"; };
|
||||
BFE593C921F3F8B7003412A6 /* GameSave.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GameSave.swift; sourceTree = "<group>"; };
|
||||
@ -321,11 +333,14 @@
|
||||
files = (
|
||||
BF9F4FCF1AAD7B87004C9500 /* DeltaCore.framework in Frameworks */,
|
||||
BFEC732D1AAECC4A00650035 /* Roxas.framework in Frameworks */,
|
||||
BFDE2CD3222DF36A008038E0 /* Alamofire.framework in Frameworks */,
|
||||
BF48F75B219A1F8A00BC2FC1 /* Harmony_Drive.framework in Frameworks */,
|
||||
BF99C6941D0A9AA600BA92BC /* SNESDeltaCore.framework in Frameworks */,
|
||||
BF98C9822204D9AB006B95AC /* NESDeltaCore.framework in Frameworks */,
|
||||
BF0418141D01E93400E85BCF /* GBADeltaCore.framework in Frameworks */,
|
||||
BF072010219A3A9D00F05DA4 /* ZIPFoundation.framework in Frameworks */,
|
||||
BFDE2CD1222DF36A008038E0 /* SwiftyDropbox.framework in Frameworks */,
|
||||
BF144C642238511400C387E1 /* Harmony_Dropbox.framework in Frameworks */,
|
||||
BFF0742C1E9DC17500ACDF4A /* GBCDeltaCore.framework in Frameworks */,
|
||||
BF48F755219A1EF000BC2FC1 /* Harmony.framework in Frameworks */,
|
||||
4FE8465FD28810191C3E5212 /* Pods_Delta.framework in Frameworks */,
|
||||
@ -617,6 +632,9 @@
|
||||
BF9F4FCD1AAD7B25004C9500 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
BFDE2CC6222DF345008038E0 /* Harmony_Dropbox.framework */,
|
||||
BFDE2CC8222DF345008038E0 /* SwiftyDropbox.framework */,
|
||||
BFDE2CC7222DF345008038E0 /* Alamofire.framework */,
|
||||
BF98C9812204D9A1006B95AC /* NESDeltaCore.framework */,
|
||||
BF07200E219A3A9500F05DA4 /* ZIPFoundation.framework */,
|
||||
BF48F754219A1EEB00BC2FC1 /* Harmony.framework */,
|
||||
|
||||
@ -192,6 +192,10 @@
|
||||
argument = "-com.apple.CoreData.MigrationDebug 1"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = "-com.rileytestut.Harmony.Debug 1"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = "-com.apple.CoreData.ConcurrencyDebug 1"
|
||||
isEnabled = "YES">
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
import UIKit
|
||||
|
||||
import DeltaCore
|
||||
import Harmony_Dropbox
|
||||
|
||||
import Fabric
|
||||
import Crashlytics
|
||||
@ -112,6 +113,10 @@ extension AppDelegate
|
||||
return self.importControllerSkin(at: url)
|
||||
}
|
||||
}
|
||||
else if DropboxService.shared.handleDropboxURL(url)
|
||||
{
|
||||
return true
|
||||
}
|
||||
else
|
||||
{
|
||||
return self.deepLinkController.handle(.url(url))
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="ssH-mM-uG6">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14490.64" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="ssH-mM-uG6">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.47"/>
|
||||
<capability name="Named colors" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
@ -18,7 +18,7 @@
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<label key="tableFooterView" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Delta 0.6.0" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Str-BY-agW">
|
||||
<rect key="frame" x="0.0" y="817" width="375" height="44"/>
|
||||
<rect key="frame" x="0.0" y="861" width="375" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
|
||||
@ -241,14 +241,14 @@
|
||||
<tableViewSection headerTitle="Syncing" id="y6U-7a-bnX" userLabel="Syncing">
|
||||
<cells>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="DetailCell" textLabel="4U1-fe-PIb" detailTextLabel="kLY-5g-v8n" style="IBUITableViewCellStyleValue1" id="bwW-PG-BcV">
|
||||
<rect key="frame" x="0.0" y="611" width="375" height="44"/>
|
||||
<rect key="frame" x="0.0" y="655" width="375" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="bwW-PG-BcV" id="RNA-99-evH">
|
||||
<rect key="frame" x="0.0" y="0.0" width="341" height="43.5"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="349" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Service" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="4U1-fe-PIb">
|
||||
<rect key="frame" x="16" y="12" width="54" height="19.5"/>
|
||||
<rect key="frame" x="15" y="12" width="54" height="19.5"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="16"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
@ -268,14 +268,14 @@
|
||||
</connections>
|
||||
</tableViewCell>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="BadgeCell" textLabel="1u0-gh-zP7" style="IBUITableViewCellStyleDefault" id="JPg-6O-DRe" customClass="BadgedTableViewCell" customModule="Delta" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="655" width="375" height="44"/>
|
||||
<rect key="frame" x="0.0" y="699" width="375" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="JPg-6O-DRe" id="zcZ-QR-Nno">
|
||||
<rect key="frame" x="0.0" y="0.0" width="341" height="43.5"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="349" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Status" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="1u0-gh-zP7">
|
||||
<rect key="frame" x="16" y="0.0" width="324" height="43.5"/>
|
||||
<rect key="frame" x="15" y="0.0" width="325" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
@ -292,14 +292,14 @@
|
||||
<tableViewSection headerTitle="3D Touch" id="fdp-8c-oOc">
|
||||
<cells>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="Cell" textLabel="c5i-qG-ir9" style="IBUITableViewCellStyleDefault" id="SSL-t4-QZj">
|
||||
<rect key="frame" x="0.0" y="755" width="375" height="44"/>
|
||||
<rect key="frame" x="0.0" y="799" width="375" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="SSL-t4-QZj" id="hQB-Iy-bzy">
|
||||
<rect key="frame" x="0.0" y="0.0" width="341" height="43.5"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="349" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="App Icon Shortcuts" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="c5i-qG-ir9">
|
||||
<rect key="frame" x="16" y="0.0" width="324" height="43.5"/>
|
||||
<rect key="frame" x="15" y="0.0" width="325" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
@ -715,36 +715,47 @@
|
||||
</objects>
|
||||
<point key="canvasLocation" x="3270" y="-244"/>
|
||||
</scene>
|
||||
<!--Syncing Service-->
|
||||
<!--Syncing-->
|
||||
<scene sceneID="8nM-uV-t0b">
|
||||
<objects>
|
||||
<tableViewController title="Syncing Service" id="R9m-rV-VgV" customClass="SyncingServicesViewController" customModule="Delta" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<tableViewController title="Syncing" id="R9m-rV-VgV" customClass="SyncingServicesViewController" customModule="Delta" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="18" sectionFooterHeight="18" id="Zsb-6q-tLe">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
|
||||
<sections>
|
||||
<tableViewSection headerTitle="Service" id="mIB-Au-dYz">
|
||||
<tableViewSection id="m5I-He-R1D">
|
||||
<cells>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="Cell" textLabel="QAp-WA-1g3" style="IBUITableViewCellStyleDefault" id="vkb-8K-t7E">
|
||||
<rect key="frame" x="0.0" y="55.5" width="375" height="44"/>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="none" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="SwitchCell" rowHeight="44" id="fIu-zg-60Y" customClass="SwitchTableViewCell">
|
||||
<rect key="frame" x="0.0" y="35" width="375" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="vkb-8K-t7E" id="YcK-vq-ABN">
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="fIu-zg-60Y" id="e2H-i1-YQc">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="None" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="QAp-WA-1g3">
|
||||
<rect key="frame" x="16" y="0.0" width="343" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="vXS-JG-YrF">
|
||||
<rect key="frame" x="310" y="6.5" width="51" height="31"/>
|
||||
<connections>
|
||||
<action selector="toggleSyncing:" destination="R9m-rV-VgV" eventType="primaryActionTriggered" id="KNw-Wb-hIW"/>
|
||||
</connections>
|
||||
</switch>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstItem="vXS-JG-YrF" firstAttribute="trailing" secondItem="e2H-i1-YQc" secondAttribute="trailingMargin" id="G2g-ka-Gds"/>
|
||||
<constraint firstItem="vXS-JG-YrF" firstAttribute="centerY" secondItem="e2H-i1-YQc" secondAttribute="centerY" id="RDW-mS-nrf"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
<connections>
|
||||
<outlet property="switchView" destination="vXS-JG-YrF" id="RaC-P2-WCJ"/>
|
||||
</connections>
|
||||
</tableViewCell>
|
||||
</cells>
|
||||
</tableViewSection>
|
||||
<tableViewSection headerTitle="Service" id="mIB-Au-dYz">
|
||||
<cells>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="Cell" textLabel="4fb-TC-FrG" style="IBUITableViewCellStyleDefault" id="hBZ-Fp-9Kh">
|
||||
<rect key="frame" x="0.0" y="99.5" width="375" height="44"/>
|
||||
<rect key="frame" x="0.0" y="135" width="375" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="hBZ-Fp-9Kh" id="rfN-2N-L43">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
|
||||
@ -760,12 +771,29 @@
|
||||
</subviews>
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="Cell" textLabel="qR3-zd-gmV" style="IBUITableViewCellStyleDefault" id="Kfm-x4-Gub">
|
||||
<rect key="frame" x="0.0" y="179" width="375" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Kfm-x4-Gub" id="IAV-o1-LfP">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Dropbox" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="qR3-zd-gmV">
|
||||
<rect key="frame" x="16" y="0.0" width="343" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
</cells>
|
||||
</tableViewSection>
|
||||
<tableViewSection headerTitle="Account" id="1Wk-cG-HDE">
|
||||
<cells>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" textLabel="AYq-XK-j5L" style="IBUITableViewCellStyleDefault" id="nrN-mu-0HX">
|
||||
<rect key="frame" x="0.0" y="199.5" width="375" height="44"/>
|
||||
<rect key="frame" x="0.0" y="279" width="375" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="nrN-mu-0HX" id="lHU-qJ-uhj">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
|
||||
@ -786,7 +814,7 @@
|
||||
<tableViewSection headerTitle="" id="Jnq-12-IOu">
|
||||
<cells>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" textLabel="4TQ-cm-2sN" style="IBUITableViewCellStyleDefault" id="wRv-En-k1Y">
|
||||
<rect key="frame" x="0.0" y="279.5" width="375" height="44"/>
|
||||
<rect key="frame" x="0.0" y="359" width="375" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="wRv-En-k1Y" id="7QF-ID-Gu2">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
|
||||
@ -810,6 +838,9 @@
|
||||
<outlet property="delegate" destination="R9m-rV-VgV" id="qqu-iI-H9F"/>
|
||||
</connections>
|
||||
</tableView>
|
||||
<connections>
|
||||
<outlet property="syncingEnabledSwitch" destination="vXS-JG-YrF" id="xf0-Jg-iRi"/>
|
||||
</connections>
|
||||
</tableViewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="uqz-XU-aTr" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
|
||||
@ -346,13 +346,13 @@ private extension GameCollectionViewController
|
||||
guard game.fileURL != self.activeEmulatorCore?.game.fileURL else { throw LaunchError.alreadyRunning }
|
||||
}
|
||||
|
||||
if SyncManager.shared.syncCoordinator.isSyncing
|
||||
if let coordinator = SyncManager.shared.coordinator, coordinator.isSyncing
|
||||
{
|
||||
if let gameSave = game.gameSave
|
||||
{
|
||||
do
|
||||
{
|
||||
if let record = try SyncManager.shared.recordController.fetchRecords(for: [gameSave]).first
|
||||
if let record = try coordinator.recordController.fetchRecords(for: [gameSave]).first
|
||||
{
|
||||
if record.isSyncingEnabled && !record.isConflicted && (record.localStatus == nil || record.remoteStatus == .updated)
|
||||
{
|
||||
@ -535,7 +535,7 @@ private extension GameCollectionViewController
|
||||
context.saveWithErrorLogging()
|
||||
|
||||
// Local image URLs may not change despite being a different image, so manually mark record as updated.
|
||||
SyncManager.shared.recordController.updateRecord(for: temporaryGame)
|
||||
SyncManager.shared.recordController?.updateRecord(for: temporaryGame)
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.presentedViewController?.dismiss(animated: true, completion: nil)
|
||||
@ -625,7 +625,7 @@ private extension GameCollectionViewController
|
||||
|
||||
if let gameSave = game.gameSave
|
||||
{
|
||||
SyncManager.shared.recordController.updateRecord(for: gameSave)
|
||||
SyncManager.shared.recordController?.updateRecord(for: gameSave)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -382,7 +382,7 @@ private extension GamesViewController
|
||||
|
||||
func showSyncingToastViewIfNeeded()
|
||||
{
|
||||
guard SyncManager.shared.syncCoordinator.isSyncing && self.syncingToastView == nil else { return }
|
||||
guard let coordinator = SyncManager.shared.coordinator, coordinator.isSyncing && self.syncingToastView == nil else { return }
|
||||
|
||||
let toastView = RSTToastView(text: NSLocalizedString("Syncing...", comment: ""), detailText: nil)
|
||||
toastView.activityIndicatorView.startAnimating()
|
||||
|
||||
@ -59,14 +59,9 @@ extension LaunchViewController
|
||||
}
|
||||
|
||||
let isSyncingManagerStarted = RSTLaunchCondition(condition: { self.didAttemptStartingSyncManager }) { (completionHandler) in
|
||||
SyncManager.shared.syncCoordinator.start { (error) in
|
||||
self.didAttemptStartingSyncManager = true
|
||||
completionHandler(nil)
|
||||
}
|
||||
}
|
||||
|
||||
let isRecordControllerSeeded = RSTLaunchCondition(condition: { SyncManager.shared.syncCoordinator.recordController.isSeeded }) { (completionHandler) in
|
||||
SyncManager.shared.syncCoordinator.recordController.seedFromPersistentContainer() { (result) in
|
||||
self.didAttemptStartingSyncManager = true
|
||||
|
||||
SyncManager.shared.start(service: Settings.syncingService) { (result) in
|
||||
switch result
|
||||
{
|
||||
case .success: completionHandler(nil)
|
||||
@ -75,7 +70,7 @@ extension LaunchViewController
|
||||
}
|
||||
}
|
||||
|
||||
return [isDatabaseManagerStarted, isSyncingManagerStarted, isRecordControllerSeeded]
|
||||
return [isDatabaseManagerStarted, isSyncingManagerStarted]
|
||||
}
|
||||
|
||||
override func handleLaunchError(_ error: Error)
|
||||
|
||||
@ -130,10 +130,13 @@ extension Settings
|
||||
}
|
||||
}
|
||||
|
||||
static var syncingService: SyncingService {
|
||||
get { return SyncingService(rawValue: UserDefaults.standard.syncingService) ?? .none }
|
||||
static var syncingService: SyncManager.Service? {
|
||||
get {
|
||||
guard let syncingService = UserDefaults.standard.syncingService else { return nil }
|
||||
return SyncManager.Service(rawValue: syncingService)
|
||||
}
|
||||
set {
|
||||
UserDefaults.standard.syncingService = newValue.rawValue
|
||||
UserDefaults.standard.syncingService = newValue?.rawValue
|
||||
NotificationCenter.default.post(name: .settingsDidChange, object: nil, userInfo: [NotificationUserInfoKey.name: Name.syncingService])
|
||||
}
|
||||
}
|
||||
@ -234,5 +237,5 @@ private extension UserDefaults
|
||||
@NSManaged var gameShortcutsMode: String
|
||||
@NSManaged var gameShortcutIdentifiers: [String]
|
||||
|
||||
@NSManaged var syncingService: String
|
||||
@NSManaged var syncingService: String?
|
||||
}
|
||||
|
||||
@ -131,11 +131,11 @@ private extension SettingsViewController
|
||||
self.controllerOpacitySlider.value = Float(Settings.translucentControllerSkinOpacity)
|
||||
self.updateControllerOpacityLabel()
|
||||
|
||||
self.syncingServiceLabel.text = Settings.syncingService.localizedName
|
||||
self.syncingServiceLabel.text = Settings.syncingService?.localizedName
|
||||
|
||||
do
|
||||
{
|
||||
let records = try SyncManager.shared.recordController.fetchConflictedRecords()
|
||||
let records = try SyncManager.shared.recordController?.fetchConflictedRecords() ?? []
|
||||
self.syncingConflictsCount = records.count
|
||||
}
|
||||
catch
|
||||
@ -233,7 +233,7 @@ extension SettingsViewController
|
||||
{
|
||||
case .controllers: return 1 // Temporarily hide other controller indexes until controller logic is finalized
|
||||
case .controllerSkins: return System.allCases.count
|
||||
case .syncing: return Settings.syncingService == .none ? 1 : super.tableView(tableView, numberOfRowsInSection: sectionIndex)
|
||||
case .syncing: return SyncManager.shared.coordinator?.account == nil ? 1 : super.tableView(tableView, numberOfRowsInSection: sectionIndex)
|
||||
default:
|
||||
if isSectionHidden(section)
|
||||
{
|
||||
|
||||
@ -57,7 +57,7 @@ class GameSyncStatusViewController: UITableViewController
|
||||
|
||||
do
|
||||
{
|
||||
let records = try SyncManager.shared.recordController.fetchRecords(for: [recordedObject])
|
||||
let records = try SyncManager.shared.recordController?.fetchRecords(for: [recordedObject]) ?? []
|
||||
|
||||
let recordSyncStatusViewController = segue.destination as! RecordSyncStatusViewController
|
||||
recordSyncStatusViewController.record = records.first
|
||||
@ -132,12 +132,14 @@ private extension GameSyncStatusViewController
|
||||
|
||||
func fetchRecords()
|
||||
{
|
||||
guard let recordController = SyncManager.shared.recordController else { return }
|
||||
|
||||
var recordsByObjectURI = [URL: Record<NSManagedObject>]()
|
||||
|
||||
do
|
||||
{
|
||||
let recordedObjects = ([self.game, self.game.gameSave].compactMap { $0 } + Array(self.game.saveStates) + Array(self.game.cheats)) as! [Syncable]
|
||||
let records = try SyncManager.shared.recordController.fetchRecords(for: recordedObjects)
|
||||
let records = try recordController.fetchRecords(for: recordedObjects)
|
||||
|
||||
for record in records
|
||||
{
|
||||
|
||||
@ -196,7 +196,7 @@ private extension RecordVersionsViewController
|
||||
|
||||
func fetchVersions()
|
||||
{
|
||||
SyncManager.shared.syncCoordinator.fetchVersions(for: self.record) { (result) in
|
||||
SyncManager.shared.coordinator?.fetchVersions(for: self.record) { (result) in
|
||||
do
|
||||
{
|
||||
let versions = try result.get().map(Version.init)
|
||||
@ -242,6 +242,8 @@ private extension RecordVersionsViewController
|
||||
|
||||
guard let indexPath = self._selectedVersionIndexPath else { return }
|
||||
|
||||
guard let coordinator = SyncManager.shared.coordinator else { return }
|
||||
|
||||
func finish<T: Error>(_ result: Result<AnyRecord, T>)
|
||||
{
|
||||
DispatchQueue.main.async {
|
||||
@ -298,19 +300,19 @@ private extension RecordVersionsViewController
|
||||
case (.restoreVersion, _):
|
||||
let version = self.dataSource.item(at: indexPath)
|
||||
|
||||
progress = SyncManager.shared.syncCoordinator.restore(self.record, to: version.version) { (result) in
|
||||
progress = coordinator.restore(self.record, to: version.version) { (result) in
|
||||
finish(result)
|
||||
}
|
||||
|
||||
case (.resolveConflict, .local):
|
||||
progress = SyncManager.shared.syncCoordinator.resolveConflictedRecord(self.record, resolution: .local) { (result) in
|
||||
progress = coordinator.resolveConflictedRecord(self.record, resolution: .local) { (result) in
|
||||
finish(result)
|
||||
}
|
||||
|
||||
case (.resolveConflict, .remote):
|
||||
let version = self.dataSource.item(at: indexPath)
|
||||
|
||||
progress = SyncManager.shared.syncCoordinator.resolveConflictedRecord(self.record, resolution: .remote(version.version)) { (result) in
|
||||
progress = coordinator.resolveConflictedRecord(self.record, resolution: .remote(version.version)) { (result) in
|
||||
finish(result)
|
||||
}
|
||||
|
||||
|
||||
@ -116,12 +116,14 @@ private extension SyncStatusViewController
|
||||
|
||||
func fetchConflictedRecords()
|
||||
{
|
||||
guard let recordController = SyncManager.shared.recordController else { return }
|
||||
|
||||
DispatchQueue.global().async {
|
||||
do
|
||||
{
|
||||
var gameConflictsCount = [URL: Int]()
|
||||
|
||||
let records = try SyncManager.shared.recordController.fetchConflictedRecords()
|
||||
let records = try recordController.fetchConflictedRecords()
|
||||
|
||||
for record in records
|
||||
{
|
||||
|
||||
@ -13,24 +13,11 @@ import Harmony_Drive
|
||||
|
||||
import Roxas
|
||||
|
||||
enum SyncingService: String, CaseIterable
|
||||
{
|
||||
case none
|
||||
case googleDrive
|
||||
|
||||
var localizedName: String {
|
||||
switch self
|
||||
{
|
||||
case .none: return NSLocalizedString("None", comment: "")
|
||||
case .googleDrive: return NSLocalizedString("Google Drive", comment: "")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension SyncingServicesViewController
|
||||
{
|
||||
enum Section: Int, CaseIterable
|
||||
{
|
||||
case syncing
|
||||
case service
|
||||
case account
|
||||
case authenticate
|
||||
@ -38,12 +25,88 @@ extension SyncingServicesViewController
|
||||
}
|
||||
|
||||
class SyncingServicesViewController: UITableViewController
|
||||
{
|
||||
@IBOutlet private var syncingEnabledSwitch: UISwitch!
|
||||
|
||||
private var selectedSyncingService = Settings.syncingService
|
||||
|
||||
override func viewDidLoad()
|
||||
{
|
||||
super.viewDidLoad()
|
||||
|
||||
self.syncingEnabledSwitch.onTintColor = .deltaPurple
|
||||
self.syncingEnabledSwitch.isOn = (self.selectedSyncingService != nil)
|
||||
}
|
||||
}
|
||||
|
||||
private extension SyncingServicesViewController
|
||||
{
|
||||
@IBAction func toggleSyncing(_ sender: UISwitch)
|
||||
{
|
||||
if sender.isOn
|
||||
{
|
||||
self.changeService(to: SyncManager.Service.allCases.first)
|
||||
}
|
||||
else
|
||||
{
|
||||
if SyncManager.shared.coordinator?.account != nil
|
||||
{
|
||||
let alertController = UIAlertController(title: NSLocalizedString("Disable Syncing?", comment: ""), message: NSLocalizedString("Enabling syncing again later may result in conflicts that must be resolved manually.", comment: ""), preferredStyle: .alert)
|
||||
alertController.addAction(.cancel)
|
||||
alertController.addAction(UIAlertAction(title: NSLocalizedString("Disable", comment: ""), style: .default) { (action) in
|
||||
self.changeService(to: nil)
|
||||
})
|
||||
self.present(alertController, animated: true, completion: nil)
|
||||
}
|
||||
else
|
||||
{
|
||||
self.changeService(to: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func changeService(to service: SyncManager.Service?)
|
||||
{
|
||||
SyncManager.shared.reset(for: service) { (result) in
|
||||
DispatchQueue.main.async {
|
||||
do
|
||||
{
|
||||
try result.get()
|
||||
|
||||
let previousService = self.selectedSyncingService
|
||||
self.selectedSyncingService = service
|
||||
|
||||
// Set to non-nil if we later authenticate.
|
||||
Settings.syncingService = nil
|
||||
|
||||
if (previousService == nil && service != nil) || (previousService != nil && service == nil)
|
||||
{
|
||||
self.tableView.reloadSections(IndexSet(integersIn: Section.service.rawValue ... Section.authenticate.rawValue), with: .fade)
|
||||
}
|
||||
else
|
||||
{
|
||||
self.tableView.reloadData()
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
let alertController = UIAlertController(title: NSLocalizedString("Unable to Change Syncing Service", comment: ""), error: error)
|
||||
self.present(alertController, animated: true, completion: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension SyncingServicesViewController
|
||||
{
|
||||
func isSectionHidden(_ section: Section) -> Bool
|
||||
{
|
||||
switch section
|
||||
{
|
||||
case .account: return SyncManager.shared.syncCoordinator.account == nil
|
||||
case .service: return !self.syncingEnabledSwitch.isOn
|
||||
case .account: return !self.syncingEnabledSwitch.isOn || SyncManager.shared.coordinator?.account == nil
|
||||
case .authenticate: return !self.syncingEnabledSwitch.isOn
|
||||
default: return false
|
||||
}
|
||||
}
|
||||
@ -51,28 +114,24 @@ class SyncingServicesViewController: UITableViewController
|
||||
|
||||
extension SyncingServicesViewController
|
||||
{
|
||||
override func numberOfSections(in tableView: UITableView) -> Int
|
||||
{
|
||||
guard Settings.syncingService != .none else { return 1 }
|
||||
|
||||
return super.numberOfSections(in: tableView)
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
|
||||
{
|
||||
let cell = super.tableView(tableView, cellForRowAt: indexPath)
|
||||
|
||||
switch Section.allCases[indexPath.section]
|
||||
{
|
||||
case .syncing:
|
||||
cell.textLabel?.text = NSLocalizedString("Syncing", comment: "")
|
||||
|
||||
case .service:
|
||||
let service = SyncingService.allCases[indexPath.row]
|
||||
cell.accessoryType = (service == Settings.syncingService) ? .checkmark : .none
|
||||
let service = SyncManager.Service.allCases[indexPath.row]
|
||||
cell.accessoryType = (service == self.selectedSyncingService) ? .checkmark : .none
|
||||
|
||||
case .account:
|
||||
cell.textLabel?.text = SyncManager.shared.syncCoordinator.account?.name ?? NSLocalizedString("Unknown Account", comment: "")
|
||||
cell.textLabel?.text = SyncManager.shared.coordinator?.account?.name ?? NSLocalizedString("Unknown Account", comment: "")
|
||||
|
||||
case .authenticate:
|
||||
if SyncManager.shared.syncCoordinator.isAuthenticated
|
||||
if SyncManager.shared.coordinator?.account != nil
|
||||
{
|
||||
cell.textLabel?.textColor = .red
|
||||
cell.textLabel?.text = NSLocalizedString("Sign Out", comment: "")
|
||||
@ -91,31 +150,40 @@ extension SyncingServicesViewController
|
||||
{
|
||||
switch Section.allCases[indexPath.section]
|
||||
{
|
||||
case .syncing: break
|
||||
|
||||
case .service:
|
||||
Settings.syncingService = SyncingService.allCases[indexPath.row]
|
||||
let syncingService = SyncManager.Service.allCases[indexPath.row]
|
||||
guard syncingService != self.selectedSyncingService else { return }
|
||||
|
||||
if Settings.syncingService == .none && self.tableView.numberOfSections > 1
|
||||
if SyncManager.shared.coordinator?.account != nil
|
||||
{
|
||||
self.tableView.deleteSections(IndexSet(integersIn: Section.account.rawValue ... Section.authenticate.rawValue), with: .fade)
|
||||
let alertController = UIAlertController(title: NSLocalizedString("Are you sure you want to change sync services?", comment: ""), message: NSLocalizedString("Switching back later may result in conflicts that must be resolved manually.", comment: ""), preferredStyle: .actionSheet)
|
||||
alertController.addAction(.cancel)
|
||||
alertController.addAction(UIAlertAction(title: NSLocalizedString("Change Sync Service", comment: ""), style: .destructive, handler: { (action) in
|
||||
self.changeService(to: syncingService)
|
||||
}))
|
||||
|
||||
self.present(alertController, animated: true, completion: nil)
|
||||
}
|
||||
else if Settings.syncingService != .none && self.tableView.numberOfSections == 1
|
||||
else
|
||||
{
|
||||
self.tableView.insertSections(IndexSet(integersIn: Section.account.rawValue ... Section.authenticate.rawValue), with: .fade)
|
||||
self.changeService(to: syncingService)
|
||||
}
|
||||
|
||||
self.tableView.reloadSections(IndexSet(integer: Section.service.rawValue), with: .none)
|
||||
|
||||
case .account: break
|
||||
|
||||
case .authenticate:
|
||||
if SyncManager.shared.syncCoordinator.isAuthenticated
|
||||
case .authenticate:
|
||||
if SyncManager.shared.coordinator?.account != nil
|
||||
{
|
||||
SyncManager.shared.syncCoordinator.deauthenticate { (result) in
|
||||
SyncManager.shared.deauthenticate { (result) in
|
||||
DispatchQueue.main.async {
|
||||
do
|
||||
{
|
||||
try result.get()
|
||||
self.tableView.reloadData()
|
||||
|
||||
Settings.syncingService = nil
|
||||
}
|
||||
catch
|
||||
{
|
||||
@ -127,16 +195,21 @@ extension SyncingServicesViewController
|
||||
}
|
||||
else
|
||||
{
|
||||
SyncManager.shared.syncCoordinator.authenticate(presentingViewController: self) { (result) in
|
||||
SyncManager.shared.authenticate(presentingViewController: self) { (result) in
|
||||
DispatchQueue.main.async {
|
||||
do
|
||||
{
|
||||
_ = try result.get()
|
||||
self.tableView.reloadData()
|
||||
|
||||
Settings.syncingService = self.selectedSyncingService
|
||||
}
|
||||
catch GeneralError.cancelled.self
|
||||
{
|
||||
// Ignore
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
let alertController = UIAlertController(title: NSLocalizedString("Failed to Sign In", comment: ""), error: error)
|
||||
self.present(alertController, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
@ -113,6 +113,14 @@
|
||||
<string>com.googleusercontent.apps.457607414709-7oc45nq59frd7rre6okq22fafftd55g1</string>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>db-f5btgysf9ma9bb6</string>
|
||||
</array>
|
||||
<key>CFBundleURLName</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>7</string>
|
||||
@ -150,7 +158,7 @@
|
||||
</dict>
|
||||
</dict>
|
||||
<key>NSPhotoLibraryUsageDescription</key>
|
||||
<string>Press "OK" to allow Delta to use images from your Photo Library as game artwork.</string>
|
||||
<string>Press "OK" to allow Delta to use images from your Photo Library as game artwork.</string>
|
||||
<key>UIFileSharingEnabled</key>
|
||||
<true/>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
@ -272,5 +280,10 @@
|
||||
</dict>
|
||||
</dict>
|
||||
</array>
|
||||
<key>LSApplicationQueriesSchemes</key>
|
||||
<array>
|
||||
<string>dbapi-8-emm</string>
|
||||
<string>dbapi-2</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
|
||||
import Harmony
|
||||
import Harmony_Drive
|
||||
import Harmony_Dropbox
|
||||
|
||||
extension SyncManager
|
||||
{
|
||||
@ -34,6 +35,40 @@ extension SyncManager
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum Service: String, CaseIterable
|
||||
{
|
||||
case googleDrive = "com.rileytestut.Harmony.Drive"
|
||||
case dropbox = "com.rileytestut.Harmony.Dropbox"
|
||||
|
||||
var localizedName: String {
|
||||
switch self
|
||||
{
|
||||
case .googleDrive: return NSLocalizedString("Google Drive", comment: "")
|
||||
case .dropbox: return NSLocalizedString("Dropbox", comment: "")
|
||||
}
|
||||
}
|
||||
|
||||
var service: Harmony.Service {
|
||||
switch self
|
||||
{
|
||||
case .googleDrive: return DriveService.shared
|
||||
case .dropbox: return DropboxService.shared
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum Error: LocalizedError
|
||||
{
|
||||
case nilService
|
||||
|
||||
var errorDescription: String? {
|
||||
switch self
|
||||
{
|
||||
case .nilService: return NSLocalizedString("There is no chosen service for syncing.", comment: "")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension Syncable where Self: NSManagedObject
|
||||
@ -48,22 +83,26 @@ final class SyncManager
|
||||
{
|
||||
static let shared = SyncManager()
|
||||
|
||||
var service: Service {
|
||||
return self.syncCoordinator.service
|
||||
var service: Service? {
|
||||
guard let service = self.coordinator?.service else { return nil }
|
||||
return Service(rawValue: service.identifier)
|
||||
}
|
||||
|
||||
var recordController: RecordController {
|
||||
return self.syncCoordinator.recordController
|
||||
var recordController: RecordController? {
|
||||
return self.coordinator?.recordController
|
||||
}
|
||||
|
||||
private(set) var previousSyncResult: SyncResult?
|
||||
|
||||
let syncCoordinator = SyncCoordinator(service: DriveService.shared, persistentContainer: DatabaseManager.shared)
|
||||
private(set) var coordinator: SyncCoordinator?
|
||||
|
||||
private init()
|
||||
{
|
||||
DriveService.shared.clientID = "457607414709-7oc45nq59frd7rre6okq22fafftd55g1.apps.googleusercontent.com"
|
||||
|
||||
DropboxService.shared.clientID = "f5btgysf9ma9bb6"
|
||||
DropboxService.shared.preferredDirectoryName = "Delta Emulator"
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(SyncManager.syncingDidFinish(_:)), name: SyncCoordinator.didFinishSyncingNotification, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(SyncManager.didEnterBackground(_:)), name: UIApplication.didEnterBackgroundNotification, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(SyncManager.willEnterForeground(_:)), name: UIApplication.willEnterForegroundNotification, object: nil)
|
||||
@ -72,11 +111,83 @@ final class SyncManager
|
||||
|
||||
extension SyncManager
|
||||
{
|
||||
func start(service: Service?, completionHandler: @escaping (Result<Void, Swift.Error>) -> Void)
|
||||
{
|
||||
guard let service = service else { return completionHandler(.success) }
|
||||
|
||||
let coordinator = SyncCoordinator(service: service.service, persistentContainer: DatabaseManager.shared)
|
||||
coordinator.start { (result) in
|
||||
do
|
||||
{
|
||||
_ = try result.get()
|
||||
|
||||
self.coordinator = coordinator
|
||||
|
||||
completionHandler(.success)
|
||||
}
|
||||
catch
|
||||
{
|
||||
completionHandler(.failure(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func reset(for service: Service?, completionHandler: @escaping (Result<Void, Swift.Error>) -> Void)
|
||||
{
|
||||
if let coordinator = self.coordinator
|
||||
{
|
||||
coordinator.deauthenticate { (result) in
|
||||
self.coordinator = nil
|
||||
self.start(service: service, completionHandler: completionHandler)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self.start(service: service, completionHandler: completionHandler)
|
||||
}
|
||||
}
|
||||
|
||||
func authenticate(presentingViewController: UIViewController? = nil, completionHandler: @escaping (Result<Account, AuthenticationError>) -> Void)
|
||||
{
|
||||
guard let coordinator = self.coordinator else { return completionHandler(.failure(AuthenticationError(Error.nilService))) }
|
||||
|
||||
coordinator.authenticate(presentingViewController: presentingViewController) { (result) in
|
||||
do
|
||||
{
|
||||
let account = try result.get()
|
||||
|
||||
if !coordinator.recordController.isSeeded
|
||||
{
|
||||
coordinator.recordController.seedFromPersistentContainer { (result) in
|
||||
switch result
|
||||
{
|
||||
case .success: completionHandler(.success(account))
|
||||
case .failure(let error): completionHandler(.failure(AuthenticationError(error)))
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
completionHandler(.success(account))
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
completionHandler(.failure(AuthenticationError(error)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func deauthenticate(completionHandler: @escaping (Result<Void, DeauthenticationError>) -> Void)
|
||||
{
|
||||
guard let coordinator = self.coordinator else { return completionHandler(.success) }
|
||||
|
||||
coordinator.deauthenticate(completionHandler: completionHandler)
|
||||
}
|
||||
|
||||
func sync()
|
||||
{
|
||||
guard Settings.syncingService != .none else { return }
|
||||
|
||||
self.syncCoordinator.sync()
|
||||
self.coordinator?.sync()
|
||||
}
|
||||
}
|
||||
|
||||
@ -86,6 +197,8 @@ private extension SyncManager
|
||||
{
|
||||
guard let result = notification.userInfo?[SyncCoordinator.syncResultKey] as? SyncResult else { return }
|
||||
self.previousSyncResult = result
|
||||
|
||||
print("Finished syncing!")
|
||||
}
|
||||
|
||||
@objc func didEnterBackground(_ notification: Notification)
|
||||
|
||||
2
External/Harmony
vendored
2
External/Harmony
vendored
@ -1 +1 @@
|
||||
Subproject commit 2cfca813e9e4d0ecbc824050ab0336cb9b7c6b37
|
||||
Subproject commit 39311d36660c98bc6f240d7134c39f8361fc7b3e
|
||||
2
External/Roxas
vendored
2
External/Roxas
vendored
@ -1 +1 @@
|
||||
Subproject commit 1945d97204d113c635ec959f7777e7200d40cdee
|
||||
Subproject commit ffd65b85417db90895361446ea848d68a8ef9e4c
|
||||
Loading…
Reference in New Issue
Block a user