Compare commits

..

11 Commits

Author SHA1 Message Date
spidy123222
625389ab96 Add Exit Shortcut 2025-04-08 15:19:33 -07:00
spidy123222
f7e34cbbe9 Rewrite SendAppOperation execution to allow to wait for shortcut execution. 2025-04-08 15:19:33 -07:00
spidy123222
0fe8d7fed9 Move to SendAppOperation 2025-04-08 15:19:33 -07:00
spidy123222
1a1aa42e02 move it behind pendiungunitcount 60 2025-04-08 15:19:33 -07:00
spidy123222
7ff4b48223 Move attempt to a higher Stage. 2025-04-08 15:19:33 -07:00
spidy123222
4801f6e8f2 Attempt a million 2025-04-08 15:19:33 -07:00
Spidy123222
ff28f6fa8f Add files via upload
Signed-off-by: Spidy123222 <64176728+Spidy123222@users.noreply.github.com>
2025-04-08 15:19:33 -07:00
Spidy123222
2d141afbaf remove from install apps
Signed-off-by: Spidy123222 <64176728+Spidy123222@users.noreply.github.com>
2025-04-08 15:19:33 -07:00
Spidy123222
06e38aae00 Hopefully fix problem
Signed-off-by: Spidy123222 <64176728+Spidy123222@users.noreply.github.com>
2025-04-08 15:19:33 -07:00
Spidy123222
d8783230a7 fix error for open link
Signed-off-by: Spidy123222 <64176728+Spidy123222@users.noreply.github.com>
2025-04-08 15:19:33 -07:00
Spidy123222
6c479bfede test open URL
Signed-off-by: Spidy123222 <64176728+Spidy123222@users.noreply.github.com>
2025-04-08 15:19:33 -07:00
59 changed files with 2232 additions and 2049 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -54,12 +54,57 @@ jobs:
swiftpm-cache-restore-keys: | swiftpm-cache-restore-keys: |
xcode-cache-sourcedata- xcode-cache-sourcedata-
- name: Restore Pods from Cache (Exact match)
id: pods-restore
uses: actions/cache/restore@v3
with:
path: |
./Podfile.lock
./Pods/
./AltStore.xcworkspace/
key: pods-cache-${{ hashFiles('Podfile') }}
# restore-keys: | # commented out to strictly check cache for this particular podfile
# pods-cache-
- name: Restore Pods from Cache (Last Available)
if: ${{ steps.pods-restore.outputs.cache-hit != 'true' }}
id: pods-restore-recent
uses: actions/cache/restore@v3
with:
path: |
./Podfile.lock
./Pods/
./AltStore.xcworkspace/
key: pods-cache-
- name: Install CocoaPods
# if: ${{ steps.pods-restore.outputs.cache-hit != 'true'}}
id: pods-install
run: |
pod install
- name: Save Pods to Cache
id: save-pods
if: ${{ steps.pods-restore.outputs.cache-hit != 'true' }}
uses: actions/cache/save@v3
with:
path: |
./Podfile.lock
./Pods/
./AltStore.xcworkspace/
key: pods-cache-${{ hashFiles('Podfile') }}
- name: List Files and derived data - name: List Files and derived data
run: | run: |
echo ">>>>>>>>> Workdir <<<<<<<<<<" echo ">>>>>>>>> Workdir <<<<<<<<<<"
ls -la . ls -la .
echo "" echo ""
echo ">>>>>>>>> Pods <<<<<<<<<<"
find Pods -maxdepth 2 -exec ls -ld {} + || true # List contents if directory exists
echo ""
echo ">>>>>>>>> SideStore <<<<<<<<<<" echo ">>>>>>>>> SideStore <<<<<<<<<<"
find SideStore -maxdepth 2 -exec ls -ld {} + || true # List contents if directory exists find SideStore -maxdepth 2 -exec ls -ld {} + || true # List contents if directory exists
echo "" echo ""

View File

@@ -35,8 +35,8 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
include: include:
- os: 'macos-26' - os: 'macos-15'
version: '26.0' version: '16.2'
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
outputs: outputs:
version: ${{ steps.version.outputs.version }} version: ${{ steps.version.outputs.version }}
@@ -173,6 +173,45 @@ jobs:
# swiftpm-cache-restore-keys: | # swiftpm-cache-restore-keys: |
# xcode-cache-sourcedata-build-${{ github.ref_name }}- # xcode-cache-sourcedata-build-${{ github.ref_name }}-
- name: (Build) Restore Pods from Cache (Exact match)
id: pods-restore
uses: actions/cache/restore@v3
with:
path: |
./Podfile.lock
./Pods/
./AltStore.xcworkspace/
key: pods-cache-build-${{ github.ref_name }}-${{ hashFiles('Podfile') }}
# restore-keys: | # commented out to strictly check cache for this particular podfile
# pods-cache-
- name: (Build) Restore Pods from Cache (Last Available)
if: ${{ steps.pods-restore.outputs.cache-hit != 'true' }}
id: pods-restore-recent
uses: actions/cache/restore@v3
with:
path: |
./Podfile.lock
./Pods/
./AltStore.xcworkspace/
key: pods-cache-build-${{ github.ref_name }}-
- name: (Build) Install CocoaPods
run: pod install
shell: bash
- name: (Build) Save Pods to Cache
id: save-pods
if: ${{ steps.pods-restore.outputs.cache-hit != 'true' }}
uses: actions/cache/save@v3
with:
path: |
./Podfile.lock
./Pods/
./AltStore.xcworkspace/
key: pods-cache-build-${{ github.ref_name }}-${{ hashFiles('Podfile') }}
- name: (Build) Clean previous build artifacts - name: (Build) Clean previous build artifacts
# using 'tee' to intercept stdout and log for detailed build-log # using 'tee' to intercept stdout and log for detailed build-log
run: | run: |
@@ -188,6 +227,10 @@ jobs:
ls -la . ls -la .
echo "" echo ""
echo ">>>>>>>>> Pods <<<<<<<<<<"
find Pods -maxdepth 2 -exec ls -ld {} + || true # List contents if directory exists
echo ""
echo ">>>>>>>>> SideStore <<<<<<<<<<" echo ">>>>>>>>> SideStore <<<<<<<<<<"
find SideStore -maxdepth 2 -exec ls -ld {} + || true # List contents if directory exists find SideStore -maxdepth 2 -exec ls -ld {} + || true # List contents if directory exists
echo "" echo ""

View File

@@ -116,35 +116,6 @@ jobs:
run: echo "date=$(date -u +'%Y-%m-%d')" >> $GITHUB_OUTPUT run: echo "date=$(date -u +'%Y-%m-%d')" >> $GITHUB_OUTPUT
shell: bash shell: bash
- name: List files to upload
id: list_uploads
run: |
echo ">>>>>>>>> Workdir <<<<<<<<<<"
find . -maxdepth 4 -exec ls -ld {} + || true # List contents if directory exists
echo ""
FILES="SideStore.ipa SideStore.dSYMs.zip encrypted-build-logs.zip"
if [[ "${{ vars.ENABLE_TESTS }}" == "1" && "${{ vars.ENABLE_TESTS_BUILD }}" == "1" ]]; then
FILES="$FILES encrypted-tests-build-logs.zip"
fi
if [[ "${{ vars.ENABLE_TESTS }}" == "1" && "${{ vars.ENABLE_TESTS_RUN }}" == "1" ]]; then
FILES="$FILES encrypted-tests-run-logs.zip test-results.zip tests-recording.mp4"
fi
echo "Final upload list:"
for f in $FILES; do
if [[ -f "$f" ]]; then
echo " ✓ $f"
else
echo " - $f (missing)"
fi
done
echo "files=$FILES" >> $GITHUB_OUTPUT
- name: Upload to releases - name: Upload to releases
uses: IsaacShelton/update-existing-release@v1.3.1 uses: IsaacShelton/update-existing-release@v1.3.1
with: with:
@@ -152,7 +123,7 @@ jobs:
release: ${{ inputs.release_name }} release: ${{ inputs.release_name }}
tag: ${{ inputs.release_tag }} tag: ${{ inputs.release_tag }}
prerelease: ${{ inputs.is_beta }} prerelease: ${{ inputs.is_beta }}
files: ${{ steps.list_uploads.outputs.files }} files: SideStore.ipa SideStore.dSYMs.zip encrypted-build-logs.zip encrypted-tests-build-logs.zip encrypted-tests-run-logs.zip test-results.zip tests-recording.mp4
body: | body: |
This is an ⚠️ **EXPERIMENTAL** ⚠️ ${{ inputs.release_name }} build for commit [${{ github.sha }}](https://github.com/${{ github.repository }}/commit/${{ github.sha }}). This is an ⚠️ **EXPERIMENTAL** ⚠️ ${{ inputs.release_name }} build for commit [${{ github.sha }}](https://github.com/${{ github.repository }}/commit/${{ github.sha }}).

View File

@@ -19,8 +19,8 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
include: include:
- os: 'macos-26' - os: 'macos-15'
version: '26.0' version: '16.2'
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
@@ -37,7 +37,7 @@ jobs:
- name: Setup Xcode - name: Setup Xcode
uses: maxim-lobanov/setup-xcode@v1.6.0 uses: maxim-lobanov/setup-xcode@v1.6.0
with: with:
xcode-version: '26.0' xcode-version: '16.2'
# - name: (Tests-Build) Cache Build # - name: (Tests-Build) Cache Build
# uses: irgaly/xcode-cache@v1.8.1 # uses: irgaly/xcode-cache@v1.8.1
@@ -68,6 +68,41 @@ jobs:
~/Library/Caches/org.swift.swiftpm ~/Library/Caches/org.swift.swiftpm
key: xcode-cache-tests-${{ github.ref_name }}- key: xcode-cache-tests-${{ github.ref_name }}-
- name: (Tests-Build) Restore Pods from Cache (Exact match)
id: pods-restore
uses: actions/cache/restore@v3
with:
path: |
./Podfile.lock
./Pods/
./AltStore.xcworkspace/
key: pods-cache-test-${{ github.ref_name }}-${{ hashFiles('Podfile') }}
- name: (Tests-Build) Restore Pods from Cache (Last Available)
if: ${{ steps.pods-restore.outputs.cache-hit != 'true' }}
id: pods-restore-recent
uses: actions/cache/restore@v3
with:
path: |
./Podfile.lock
./Pods/
./AltStore.xcworkspace/
key: pods-cache-test-${{ github.ref_name }}-
- name: (Tests-Build) Install CocoaPods
run: pod install
shell: bash
- name: (Tests-Build) Save Pods to Cache
if: ${{ steps.pods-restore.outputs.cache-hit != 'true' }}
uses: actions/cache/save@v3
with:
path: |
./Podfile.lock
./Pods/
./AltStore.xcworkspace/
key: pods-cache-test-${{ github.ref_name }}-${{ hashFiles('Podfile') }}
- name: Clean Derived Data (if required) - name: Clean Derived Data (if required)
if: ${{ vars.PERFORM_CLEAN_TESTS_BUILD == '1' }} if: ${{ vars.PERFORM_CLEAN_TESTS_BUILD == '1' }}
run: | run: |
@@ -89,6 +124,10 @@ jobs:
ls -la . ls -la .
echo "" echo ""
echo ">>>>>>>>> Pods <<<<<<<<<<"
find Pods -maxdepth 2 -exec ls -ld {} + || true # List contents if directory exists
echo ""
echo ">>>>>>>>> SideStore <<<<<<<<<<" echo ">>>>>>>>> SideStore <<<<<<<<<<"
find SideStore -maxdepth 2 -exec ls -ld {} + || true # List contents if directory exists find SideStore -maxdepth 2 -exec ls -ld {} + || true # List contents if directory exists
echo "" echo ""

View File

@@ -19,8 +19,8 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
include: include:
- os: 'macos-26' - os: 'macos-15'
version: '26.0' version: '16.2'
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
@@ -38,7 +38,7 @@ jobs:
- name: Setup Xcode - name: Setup Xcode
uses: maxim-lobanov/setup-xcode@v1.6.0 uses: maxim-lobanov/setup-xcode@v1.6.0
with: with:
xcode-version: '26.0' xcode-version: '16.2'
# - name: (Tests-Run) Cache Build # - name: (Tests-Run) Cache Build
# uses: irgaly/xcode-cache@v1.8.1 # uses: irgaly/xcode-cache@v1.8.1
@@ -56,6 +56,41 @@ jobs:
~/Library/Caches/org.swift.swiftpm ~/Library/Caches/org.swift.swiftpm
key: xcode-cache-tests-${{ github.ref_name }}-${{ github.sha }} key: xcode-cache-tests-${{ github.ref_name }}-${{ github.sha }}
- name: (Tests-Run) Restore Pods from Cache (Exact match)
id: pods-restore
uses: actions/cache/restore@v3
with:
path: |
./Podfile.lock
./Pods/
./AltStore.xcworkspace/
key: pods-cache-test-${{ github.ref_name }}-${{ hashFiles('Podfile') }}
- name: (Tests-Run) Restore Pods from Cache (Last Available)
if: ${{ steps.pods-restore.outputs.cache-hit != 'true' }}
id: pods-restore-recent
uses: actions/cache/restore@v3
with:
path: |
./Podfile.lock
./Pods/
./AltStore.xcworkspace/
key: pods-cache-test-${{ github.ref_name }}-
- name: (Tests-Run) Install CocoaPods
run: pod install
shell: bash
- name: (Tests-Run) Save Pods to Cache
if: ${{ steps.pods-restore.outputs.cache-hit != 'true' }}
uses: actions/cache/save@v3
with:
path: |
./Podfile.lock
./Pods/
./AltStore.xcworkspace/
key: pods-cache-test-${{ github.ref_name }}-${{ hashFiles('Podfile') }}
- name: (Tests-Run) Clean previous build artifacts - name: (Tests-Run) Clean previous build artifacts
run: | run: |
make clean make clean
@@ -69,6 +104,10 @@ jobs:
ls -la . ls -la .
echo "" echo ""
echo ">>>>>>>>> Pods <<<<<<<<<<"
find Pods -maxdepth 2 -exec ls -ld {} + || true # List contents if directory exists
echo ""
echo ">>>>>>>>> SideStore <<<<<<<<<<" echo ">>>>>>>>> SideStore <<<<<<<<<<"
find SideStore -maxdepth 2 -exec ls -ld {} + || true # List contents if directory exists find SideStore -maxdepth 2 -exec ls -ld {} + || true # List contents if directory exists
echo "" echo ""

View File

@@ -12,8 +12,8 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
include: include:
- os: 'macos-26' - os: 'macos-15'
version: '26.0' version: '16.2'
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
@@ -89,6 +89,43 @@ jobs:
~/Library/Caches/org.swift.swiftpm ~/Library/Caches/org.swift.swiftpm
key: xcode-cache-build-stable- key: xcode-cache-build-stable-
- name: (Build) Restore Pods from Cache (Exact match)
id: pods-restore
uses: actions/cache/restore@v3
with:
path: |
./Podfile.lock
./Pods/
./AltStore.xcworkspace/
key: pods-cache-build-stable-${{ hashFiles('Podfile') }}
- name: (Build) Restore Pods from Cache (Last Available)
if: ${{ steps.pods-restore.outputs.cache-hit != 'true' }}
id: pods-restore-recent
uses: actions/cache/restore@v3
with:
path: |
./Podfile.lock
./Pods/
./AltStore.xcworkspace/
key: pods-cache-build-stable-
- name: (Build) Install CocoaPods
run: pod install
shell: bash
- name: (Build) Save Pods to Cache
id: save-pods
if: ${{ steps.pods-restore.outputs.cache-hit != 'true' }}
uses: actions/cache/save@v3
with:
path: |
./Podfile.lock
./Pods/
./AltStore.xcworkspace/
key: pods-cache-build-stable-${{ hashFiles('Podfile') }}
- name: (Build) Clean previous build artifacts - name: (Build) Clean previous build artifacts
run: | run: |
make clean make clean
@@ -103,6 +140,10 @@ jobs:
ls -la . ls -la .
echo "" echo ""
echo ">>>>>>>>> Pods <<<<<<<<<<"
find Pods -maxdepth 2 -exec ls -ld {} + || true # List contents if directory exists
echo ""
echo ">>>>>>>>> SideStore <<<<<<<<<<" echo ">>>>>>>>> SideStore <<<<<<<<<<"
find SideStore -maxdepth 2 -exec ls -ld {} + || true # List contents if directory exists find SideStore -maxdepth 2 -exec ls -ld {} + || true # List contents if directory exists
echo "" echo ""

2
.gitmodules vendored
View File

@@ -30,7 +30,7 @@
url = https://github.com/rileytestut/Roxas.git url = https://github.com/rileytestut/Roxas.git
[submodule "Dependencies/libimobiledevice"] [submodule "Dependencies/libimobiledevice"]
path = Dependencies/libimobiledevice path = Dependencies/libimobiledevice
url = https://github.com/SideStore/libimobiledevice url = https://github.com/libimobiledevice/libimobiledevice
[submodule "Dependencies/libusbmuxd"] [submodule "Dependencies/libusbmuxd"]
path = Dependencies/libusbmuxd path = Dependencies/libusbmuxd
url = https://github.com/libimobiledevice/libusbmuxd.git url = https://github.com/libimobiledevice/libusbmuxd.git

View File

@@ -4,7 +4,7 @@
<dict> <dict>
<key>com.apple.security.application-groups</key> <key>com.apple.security.application-groups</key>
<array> <array>
<string>group.$(GROUP_ID)</string> <string>group.$(APP_GROUP_IDENTIFIER)</string>
</array> </array>
</dict> </dict>
</plist> </plist>

File diff suppressed because it is too large Load Diff

View File

@@ -10,4 +10,7 @@
<FileRef <FileRef
location = "group:Dependencies/Roxas/Roxas.xcodeproj"> location = "group:Dependencies/Roxas/Roxas.xcodeproj">
</FileRef> </FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace> </Workspace>

View File

@@ -2,14 +2,24 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>aps-environment</key> <!-- <key>com.apple.security.files.user-selected.read-write</key>
<string>development</string> <array>
<string></string>
</array>
<key>com.apple.developer.applesignin</key>
<array>
<string></string>
</array> -->
<key>com.apple.developer.kernel.extended-virtual-addressing</key> <key>com.apple.developer.kernel.extended-virtual-addressing</key>
<true/> <true/>
<key>com.apple.developer.kernel.increased-debugging-memory-limit</key> <key>com.apple.developer.kernel.increased-debugging-memory-limit</key>
<true/> <true/>
<key>com.apple.developer.kernel.increased-memory-limit</key> <key>com.apple.developer.kernel.increased-memory-limit</key>
<true/> <true/>
<key>aps-environment</key>
<string>development</string>
<key>com.apple.developer.siri</key>
<true/>
<key>com.apple.security.application-groups</key> <key>com.apple.security.application-groups</key>
<array> <array>
<string>group.$(APP_GROUP_IDENTIFIER)</string> <string>group.$(APP_GROUP_IDENTIFIER)</string>

View File

@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.application-groups</key>
<array>
<string>group.$(APP_GROUP_IDENTIFIER)</string>
</array>
</dict>
</plist>

View File

@@ -27,12 +27,10 @@ extension AppDelegate
static let addSourceDeepLinkNotification = Notification.Name(Bundle.Info.appbundleIdentifier + ".AddSourceDeepLinkNotification") static let addSourceDeepLinkNotification = Notification.Name(Bundle.Info.appbundleIdentifier + ".AddSourceDeepLinkNotification")
static let appBackupDidFinish = Notification.Name(Bundle.Info.appbundleIdentifier + ".AppBackupDidFinish") static let appBackupDidFinish = Notification.Name(Bundle.Info.appbundleIdentifier + ".AppBackupDidFinish")
static let exportCertificateNotification = Notification.Name(Bundle.Info.appbundleIdentifier + ".ExportCertificateNotification")
static let importAppDeepLinkURLKey = "fileURL" static let importAppDeepLinkURLKey = "fileURL"
static let appBackupResultKey = "result" static let appBackupResultKey = "result"
static let addSourceDeepLinkURLKey = "sourceURL" static let addSourceDeepLinkURLKey = "sourceURL"
static let exportCertificateCallbackTemplateKey = "callback"
} }
@UIApplicationMain @UIApplicationMain
@@ -99,9 +97,7 @@ final class AppDelegate: UIResponder, UIApplicationDelegate {
self.prepareImageCache() self.prepareImageCache()
// TODO: @mahee96: find if we need to start em_proxy as in altstore? // TODO: @mahee96: find if we need to start em_proxy as in altstore?
if UserDefaults.standard.enableEMPforWireguard { // start_em_proxy(bind_addr: Consts.Proxy.serverURL)
start_em_proxy(bind_addr: Consts.Proxy.serverURL)
}
SecureValueTransformer.register() SecureValueTransformer.register()
@@ -126,9 +122,7 @@ final class AppDelegate: UIResponder, UIApplicationDelegate {
{ {
// Make sure to update SceneDelegate.sceneDidEnterBackground() as well. // Make sure to update SceneDelegate.sceneDidEnterBackground() as well.
// TODO: @mahee96: find if we need to stop em_proxy as in altstore? // TODO: @mahee96: find if we need to stop em_proxy as in altstore?
if UserDefaults.standard.enableEMPforWireguard { // stop_em_proxy()
stop_em_proxy()
}
guard let oneMonthAgo = Calendar.current.date(byAdding: .month, value: -1, to: Date()) else { return } guard let oneMonthAgo = Calendar.current.date(byAdding: .month, value: -1, to: Date()) else { return }
let midnightOneMonthAgo = Calendar.current.startOfDay(for: oneMonthAgo) let midnightOneMonthAgo = Calendar.current.startOfDay(for: oneMonthAgo)
@@ -145,9 +139,7 @@ final class AppDelegate: UIResponder, UIApplicationDelegate {
func applicationWillEnterForeground(_ application: UIApplication) func applicationWillEnterForeground(_ application: UIApplication)
{ {
AppManager.shared.update() AppManager.shared.update()
if UserDefaults.standard.enableEMPforWireguard {
start_em_proxy(bind_addr: Consts.Proxy.serverURL) start_em_proxy(bind_addr: Consts.Proxy.serverURL)
}
PatreonAPI.shared.refreshPatreonAccount() PatreonAPI.shared.refreshPatreonAccount()
} }
@@ -300,26 +292,6 @@ private extension AppDelegate
return true return true
case "pairing":
let queryItems = components.queryItems?.reduce(into: [String: String]()) { $0[$1.name.lowercased()] = $1.value } ?? [:]
guard let callbackTemplate = queryItems["urlName"]?.removingPercentEncoding else { return false }
DispatchQueue.main.async {
exportPairingFile(callbackTemplate)
}
return true
case "certificate":
let queryItems = components.queryItems?.reduce(into: [String: String]()) { $0[$1.name.lowercased()] = $1.value } ?? [:]
guard let callbackTemplate = queryItems["callback_template"]?.removingPercentEncoding else { return false }
DispatchQueue.main.async {
NotificationCenter.default.post(name: AppDelegate.exportCertificateNotification, object: nil, userInfo: [AppDelegate.exportCertificateCallbackTemplateKey: callbackTemplate])
}
return true
default: return false default: return false
} }
} }

View File

@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait" appearance="light"/> <device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies> <dependencies>
<deployment identifier="iOS"/> <deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22684"/>
<capability name="Named colors" minToolsVersion="9.0"/> <capability name="Named colors" minToolsVersion="9.0"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/> <capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
@@ -14,7 +14,7 @@
<objects> <objects>
<navigationController storyboardIdentifier="navigationController" id="ZTo-53-dSL" sceneMemberID="viewController"> <navigationController storyboardIdentifier="navigationController" id="ZTo-53-dSL" sceneMemberID="viewController">
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" barStyle="black" largeTitles="YES" id="Aej-RF-PfV" customClass="NavigationBar" customModule="SideStore" customModuleProvider="target"> <navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" barStyle="black" largeTitles="YES" id="Aej-RF-PfV" customClass="NavigationBar" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="20" width="375" height="96"/> <rect key="frame" x="0.0" y="0.0" width="375" height="96"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> <color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="barTintColor" name="SettingsBackground"/> <color key="barTintColor" name="SettingsBackground"/>
@@ -42,13 +42,13 @@
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews> <subviews>
<view hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="oyW-Fd-ojD" userLabel="Sizing View"> <view hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="oyW-Fd-ojD" userLabel="Sizing View">
<rect key="frame" x="0.0" y="64" width="375" height="603"/> <rect key="frame" x="0.0" y="44" width="375" height="623"/>
</view> </view>
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" alwaysBounceVertical="YES" indicatorStyle="white" keyboardDismissMode="onDrag" translatesAutoresizingMaskIntoConstraints="NO" id="WXx-hX-AXv"> <scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" alwaysBounceVertical="YES" indicatorStyle="white" keyboardDismissMode="onDrag" translatesAutoresizingMaskIntoConstraints="NO" id="WXx-hX-AXv">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/> <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<subviews> <subviews>
<view contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" translatesAutoresizingMaskIntoConstraints="NO" id="2wp-qG-f0Z"> <view contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" translatesAutoresizingMaskIntoConstraints="NO" id="2wp-qG-f0Z">
<rect key="frame" x="0.0" y="0.0" width="375" height="603"/> <rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
<subviews> <subviews>
<stackView opaque="NO" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" axis="vertical" spacing="50" translatesAutoresizingMaskIntoConstraints="NO" id="YmX-7v-pxh"> <stackView opaque="NO" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" axis="vertical" spacing="50" translatesAutoresizingMaskIntoConstraints="NO" id="YmX-7v-pxh">
<rect key="frame" x="16" y="6" width="343" height="359.5"/> <rect key="frame" x="16" y="6" width="343" height="359.5"/>
@@ -57,13 +57,13 @@
<rect key="frame" x="0.0" y="0.0" width="343" height="67.5"/> <rect key="frame" x="0.0" y="0.0" width="343" height="67.5"/>
<subviews> <subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Welcome to SideStore." textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="EI2-V3-zQZ"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Welcome to SideStore." textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="EI2-V3-zQZ">
<rect key="frame" x="0.0" y="0.0" width="343" height="41"/> <rect key="frame" x="0.0" y="0.0" width="333.5" height="41"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="34"/> <fontDescription key="fontDescription" type="boldSystem" pointSize="34"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Sign in with your Apple ID to get started." textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="SNU-tv-8Au"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Sign in with your Apple ID to get started." textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="SNU-tv-8Au">
<rect key="frame" x="0.0" y="47" width="306.5" height="20.5"/> <rect key="frame" x="0.0" y="47" width="308.5" height="20.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/> <fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" white="1" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> <color key="textColor" white="1" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
@@ -160,7 +160,7 @@
</stackView> </stackView>
</subviews> </subviews>
</stackView> </stackView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="2N5-zd-fUj"> <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="2N5-zd-fUj">
<rect key="frame" x="0.0" y="191" width="343" height="51"/> <rect key="frame" x="0.0" y="191" width="343" height="51"/>
<color key="backgroundColor" name="SettingsHighlighted"/> <color key="backgroundColor" name="SettingsHighlighted"/>
<constraints> <constraints>
@@ -179,7 +179,7 @@
</subviews> </subviews>
</stackView> </stackView>
<stackView opaque="NO" contentMode="scaleToFill" verticalCompressionResistancePriority="250" axis="vertical" spacing="4" translatesAutoresizingMaskIntoConstraints="NO" id="DBk-rT-ZE8"> <stackView opaque="NO" contentMode="scaleToFill" verticalCompressionResistancePriority="250" axis="vertical" spacing="4" translatesAutoresizingMaskIntoConstraints="NO" id="DBk-rT-ZE8">
<rect key="frame" x="16" y="498.5" width="343" height="96.5"/> <rect key="frame" x="16" y="518.5" width="343" height="96.5"/>
<subviews> <subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Why do we need this?" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="p9U-0q-Kn8"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Why do we need this?" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="p9U-0q-Kn8">
<rect key="frame" x="0.0" y="0.0" width="343" height="20.5"/> <rect key="frame" x="0.0" y="0.0" width="343" height="20.5"/>
@@ -198,10 +198,6 @@
</stackView> </stackView>
</subviews> </subviews>
<constraints> <constraints>
<constraint firstItem="DBk-rT-ZE8" firstAttribute="leading" secondItem="2wp-qG-f0Z" secondAttribute="leadingMargin" id="5AT-nV-ZP9"/>
<constraint firstAttribute="bottomMargin" secondItem="DBk-rT-ZE8" secondAttribute="bottom" id="HgY-oY-8KM"/>
<constraint firstAttribute="trailingMargin" secondItem="DBk-rT-ZE8" secondAttribute="trailing" id="VCf-bW-2K4"/>
<constraint firstItem="YmX-7v-pxh" firstAttribute="top" secondItem="2wp-qG-f0Z" secondAttribute="top" constant="6" id="iUr-Nd-tkt"/>
<constraint firstItem="DBk-rT-ZE8" firstAttribute="top" relation="greaterThanOrEqual" secondItem="YmX-7v-pxh" secondAttribute="bottom" constant="8" symbolic="YES" id="zTU-eY-DWd"/> <constraint firstItem="DBk-rT-ZE8" firstAttribute="top" relation="greaterThanOrEqual" secondItem="YmX-7v-pxh" secondAttribute="bottom" constant="8" symbolic="YES" id="zTU-eY-DWd"/>
</constraints> </constraints>
</view> </view>
@@ -219,15 +215,19 @@
<constraints> <constraints>
<constraint firstAttribute="bottom" secondItem="WXx-hX-AXv" secondAttribute="bottom" id="0jL-Ky-ju6"/> <constraint firstAttribute="bottom" secondItem="WXx-hX-AXv" secondAttribute="bottom" id="0jL-Ky-ju6"/>
<constraint firstAttribute="leadingMargin" secondItem="YmX-7v-pxh" secondAttribute="leading" id="2PO-lG-dmB"/> <constraint firstAttribute="leadingMargin" secondItem="YmX-7v-pxh" secondAttribute="leading" id="2PO-lG-dmB"/>
<constraint firstItem="DBk-rT-ZE8" firstAttribute="leading" secondItem="2wp-qG-f0Z" secondAttribute="leadingMargin" id="5AT-nV-ZP9"/>
<constraint firstItem="oyW-Fd-ojD" firstAttribute="top" secondItem="zMn-DV-fpy" secondAttribute="top" id="730-db-ukB"/> <constraint firstItem="oyW-Fd-ojD" firstAttribute="top" secondItem="zMn-DV-fpy" secondAttribute="top" id="730-db-ukB"/>
<constraint firstItem="2wp-qG-f0Z" firstAttribute="bottomMargin" secondItem="DBk-rT-ZE8" secondAttribute="bottom" id="HgY-oY-8KM"/>
<constraint firstItem="zMn-DV-fpy" firstAttribute="trailing" secondItem="oyW-Fd-ojD" secondAttribute="trailing" id="KGE-CN-SWf"/> <constraint firstItem="zMn-DV-fpy" firstAttribute="trailing" secondItem="oyW-Fd-ojD" secondAttribute="trailing" id="KGE-CN-SWf"/>
<constraint firstItem="WXx-hX-AXv" firstAttribute="top" secondItem="mjy-4S-hyH" secondAttribute="top" id="LPQ-bF-ic0"/> <constraint firstItem="WXx-hX-AXv" firstAttribute="top" secondItem="mjy-4S-hyH" secondAttribute="top" id="LPQ-bF-ic0"/>
<constraint firstItem="zMn-DV-fpy" firstAttribute="trailing" secondItem="WXx-hX-AXv" secondAttribute="trailing" id="MG7-A6-pKp"/> <constraint firstItem="zMn-DV-fpy" firstAttribute="trailing" secondItem="WXx-hX-AXv" secondAttribute="trailing" id="MG7-A6-pKp"/>
<constraint firstAttribute="trailingMargin" secondItem="YmX-7v-pxh" secondAttribute="trailing" id="O4T-nu-o3e"/> <constraint firstAttribute="trailingMargin" secondItem="YmX-7v-pxh" secondAttribute="trailing" id="O4T-nu-o3e"/>
<constraint firstItem="zMn-DV-fpy" firstAttribute="bottom" secondItem="oyW-Fd-ojD" secondAttribute="bottom" id="PuX-ab-cEq"/> <constraint firstItem="zMn-DV-fpy" firstAttribute="bottom" secondItem="oyW-Fd-ojD" secondAttribute="bottom" id="PuX-ab-cEq"/>
<constraint firstItem="oyW-Fd-ojD" firstAttribute="leading" secondItem="zMn-DV-fpy" secondAttribute="leading" id="SzC-gC-Nvi"/> <constraint firstItem="oyW-Fd-ojD" firstAttribute="leading" secondItem="zMn-DV-fpy" secondAttribute="leading" id="SzC-gC-Nvi"/>
<constraint firstItem="2wp-qG-f0Z" firstAttribute="trailingMargin" secondItem="DBk-rT-ZE8" secondAttribute="trailing" id="VCf-bW-2K4"/>
<constraint firstItem="WXx-hX-AXv" firstAttribute="leading" secondItem="zMn-DV-fpy" secondAttribute="leading" id="d08-zF-5X6"/> <constraint firstItem="WXx-hX-AXv" firstAttribute="leading" secondItem="zMn-DV-fpy" secondAttribute="leading" id="d08-zF-5X6"/>
<constraint firstItem="2wp-qG-f0Z" firstAttribute="height" secondItem="oyW-Fd-ojD" secondAttribute="height" id="dFN-pw-TWt"/> <constraint firstItem="2wp-qG-f0Z" firstAttribute="height" secondItem="oyW-Fd-ojD" secondAttribute="height" id="dFN-pw-TWt"/>
<constraint firstItem="YmX-7v-pxh" firstAttribute="top" secondItem="2wp-qG-f0Z" secondAttribute="top" constant="6" id="iUr-Nd-tkt"/>
<constraint firstItem="2wp-qG-f0Z" firstAttribute="width" secondItem="oyW-Fd-ojD" secondAttribute="width" id="rYO-GN-0Lk"/> <constraint firstItem="2wp-qG-f0Z" firstAttribute="width" secondItem="oyW-Fd-ojD" secondAttribute="width" id="rYO-GN-0Lk"/>
</constraints> </constraints>
</view> </view>
@@ -264,7 +264,7 @@
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews> <subviews>
<stackView opaque="NO" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" axis="vertical" distribution="equalSpacing" translatesAutoresizingMaskIntoConstraints="NO" id="bp6-55-IG2"> <stackView opaque="NO" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" axis="vertical" distribution="equalSpacing" translatesAutoresizingMaskIntoConstraints="NO" id="bp6-55-IG2">
<rect key="frame" x="0.0" y="64" width="375" height="544"/> <rect key="frame" x="0.0" y="44" width="375" height="564"/>
<subviews> <subviews>
<stackView opaque="NO" contentMode="scaleToFill" alignment="center" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="FjP-tm-w7K"> <stackView opaque="NO" contentMode="scaleToFill" alignment="center" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="FjP-tm-w7K">
<rect key="frame" x="16" y="35" width="343" height="95.5"/> <rect key="frame" x="16" y="35" width="343" height="95.5"/>
@@ -298,7 +298,7 @@
</subviews> </subviews>
</stackView> </stackView>
<stackView opaque="NO" contentMode="scaleToFill" alignment="center" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="LpI-Jt-SzX"> <stackView opaque="NO" contentMode="scaleToFill" alignment="center" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="LpI-Jt-SzX">
<rect key="frame" x="16" y="161" width="343" height="95.5"/> <rect key="frame" x="16" y="168" width="343" height="95.5"/>
<subviews> <subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="2" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="0LW-eE-qHa"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="2" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="0LW-eE-qHa">
<rect key="frame" x="0.0" y="0.0" width="59" height="95.5"/> <rect key="frame" x="0.0" y="0.0" width="59" height="95.5"/>
@@ -310,7 +310,7 @@
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="5" translatesAutoresizingMaskIntoConstraints="NO" id="dMu-eg-gIO"> <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="5" translatesAutoresizingMaskIntoConstraints="NO" id="dMu-eg-gIO">
<rect key="frame" x="79" y="16" width="264" height="64"/> <rect key="frame" x="79" y="15.5" width="264" height="64"/>
<subviews> <subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Connect to Wi-Fi and VPN" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="esj-pD-D4A"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Connect to Wi-Fi and VPN" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="esj-pD-D4A">
<rect key="frame" x="0.0" y="0.0" width="264" height="20.5"/> <rect key="frame" x="0.0" y="0.0" width="264" height="20.5"/>
@@ -318,7 +318,7 @@
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Enable LocalDevVPN and use Sidestore on the go." textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="4rk-ge-FSj"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Enable SideStore VPN in Wireguard and be able to use Sidestore on the go." textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="4rk-ge-FSj">
<rect key="frame" x="0.0" y="25.5" width="264" height="38.5"/> <rect key="frame" x="0.0" y="25.5" width="264" height="38.5"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/> <fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" white="1" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> <color key="textColor" white="1" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
@@ -329,7 +329,7 @@
</subviews> </subviews>
</stackView> </stackView>
<stackView opaque="NO" contentMode="scaleToFill" alignment="center" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="tfb-ja-9UC"> <stackView opaque="NO" contentMode="scaleToFill" alignment="center" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="tfb-ja-9UC">
<rect key="frame" x="16" y="287.5" width="343" height="95.5"/> <rect key="frame" x="16" y="300.5" width="343" height="95.5"/>
<subviews> <subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="3" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="nVr-El-Csi"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="3" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="nVr-El-Csi">
<rect key="frame" x="0.0" y="0.0" width="59" height="95.5"/> <rect key="frame" x="0.0" y="0.0" width="59" height="95.5"/>
@@ -341,7 +341,7 @@
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="5" translatesAutoresizingMaskIntoConstraints="NO" id="z6Y-zi-teL"> <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="5" translatesAutoresizingMaskIntoConstraints="NO" id="z6Y-zi-teL">
<rect key="frame" x="79" y="15.5" width="264" height="64"/> <rect key="frame" x="79" y="16" width="264" height="64"/>
<subviews> <subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Download Apps" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="JeJ-bk-UCA"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Download Apps" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="JeJ-bk-UCA">
<rect key="frame" x="0.0" y="0.0" width="264" height="20.5"/> <rect key="frame" x="0.0" y="0.0" width="264" height="20.5"/>
@@ -360,7 +360,7 @@
</subviews> </subviews>
</stackView> </stackView>
<stackView opaque="NO" contentMode="scaleToFill" alignment="center" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="X3r-G1-vf2"> <stackView opaque="NO" contentMode="scaleToFill" alignment="center" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="X3r-G1-vf2">
<rect key="frame" x="16" y="413.5" width="343" height="95.5"/> <rect key="frame" x="16" y="433.5" width="343" height="95.5"/>
<subviews> <subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="4" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="i2U-NL-plG"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="4" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="i2U-NL-plG">
<rect key="frame" x="0.0" y="0.0" width="59" height="95.5"/> <rect key="frame" x="0.0" y="0.0" width="59" height="95.5"/>
@@ -372,7 +372,7 @@
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="5" translatesAutoresizingMaskIntoConstraints="NO" id="Xs6-pJ-PUz"> <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="5" translatesAutoresizingMaskIntoConstraints="NO" id="Xs6-pJ-PUz">
<rect key="frame" x="79" y="17" width="264" height="62"/> <rect key="frame" x="79" y="16" width="264" height="64"/>
<subviews> <subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Apps Refresh Automatically" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="nvb-Aq-sYa"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Apps Refresh Automatically" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="nvb-Aq-sYa">
<rect key="frame" x="0.0" y="0.0" width="264" height="20.5"/> <rect key="frame" x="0.0" y="0.0" width="264" height="20.5"/>
@@ -381,7 +381,7 @@
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Apps are refreshed in the background while you are on SideStore VPN!" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="HU5-Hv-E3d"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Apps are refreshed in the background while you are on SideStore VPN!" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="HU5-Hv-E3d">
<rect key="frame" x="0.0" y="25.5" width="264" height="36.5"/> <rect key="frame" x="0.0" y="25.5" width="264" height="38.5"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/> <fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" white="1" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> <color key="textColor" white="1" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
@@ -431,7 +431,7 @@
</objects> </objects>
<point key="canvasLocation" x="1353" y="736"/> <point key="canvasLocation" x="1353" y="736"/>
</scene> </scene>
<!--Refresh SideStore--> <!--Refresh AltStore-->
<scene sceneID="9Vh-dM-OqX"> <scene sceneID="9Vh-dM-OqX">
<objects> <objects>
<viewController storyboardIdentifier="refreshAltStoreViewController" id="aoK-yE-UVT" customClass="RefreshAltStoreViewController" customModule="SideStore" customModuleProvider="target" sceneMemberID="viewController"> <viewController storyboardIdentifier="refreshAltStoreViewController" id="aoK-yE-UVT" customClass="RefreshAltStoreViewController" customModule="SideStore" customModuleProvider="target" sceneMemberID="viewController">
@@ -485,7 +485,7 @@
<constraint firstItem="tDQ-ao-1Jg" firstAttribute="leading" secondItem="R83-kV-365" secondAttribute="leadingMargin" id="zEt-Xr-kJx"/> <constraint firstItem="tDQ-ao-1Jg" firstAttribute="leading" secondItem="R83-kV-365" secondAttribute="leadingMargin" id="zEt-Xr-kJx"/>
</constraints> </constraints>
</view> </view>
<navigationItem key="navigationItem" title="Refresh SideStore" largeTitleDisplayMode="always" id="5nk-NR-jtV"/> <navigationItem key="navigationItem" title="Refresh AltStore" largeTitleDisplayMode="always" id="5nk-NR-jtV"/>
<simulatedNavigationBarMetrics key="simulatedTopBarMetrics" prompted="NO"/> <simulatedNavigationBarMetrics key="simulatedTopBarMetrics" prompted="NO"/>
<connections> <connections>
<outlet property="placeholderView" destination="fpO-Bf-gFY" id="q7d-au-d94"/> <outlet property="placeholderView" destination="fpO-Bf-gFY" id="q7d-au-d94"/>

View File

@@ -532,7 +532,6 @@
<rect key="frame" x="0.0" y="20" width="375" height="96"/> <rect key="frame" x="0.0" y="20" width="375" height="96"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<color key="tintColor" name="Primary"/> <color key="tintColor" name="Primary"/>
<edgeInsets key="layoutMargins" top="8" left="20" bottom="8" right="8"/>
</navigationBar> </navigationBar>
<nil name="viewControllers"/> <nil name="viewControllers"/>
<connections> <connections>
@@ -562,7 +561,6 @@
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" largeTitles="YES" id="CzO-Kt-BlZ" customClass="NavigationBar" customModule="SideStore" customModuleProvider="target"> <navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" largeTitles="YES" id="CzO-Kt-BlZ" customClass="NavigationBar" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="20" width="375" height="96"/> <rect key="frame" x="0.0" y="20" width="375" height="96"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<edgeInsets key="layoutMargins" top="8" left="20" bottom="8" right="8"/>
</navigationBar> </navigationBar>
<nil name="viewControllers"/> <nil name="viewControllers"/>
<connections> <connections>
@@ -915,7 +913,6 @@
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" largeTitles="YES" id="9sB-f3-Fnk"> <navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" largeTitles="YES" id="9sB-f3-Fnk">
<rect key="frame" x="0.0" y="0.0" width="375" height="108"/> <rect key="frame" x="0.0" y="0.0" width="375" height="108"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<edgeInsets key="layoutMargins" top="8" left="20" bottom="8" right="8"/>
</navigationBar> </navigationBar>
<nil name="viewControllers"/> <nil name="viewControllers"/>
<connections> <connections>

View File

@@ -12,73 +12,84 @@ import EmotionalDamage
import minimuxer import minimuxer
import WidgetKit import WidgetKit
import AltSign
import AltStoreCore import AltStoreCore
import UniformTypeIdentifiers import UniformTypeIdentifiers
let pairingFileName = "ALTPairingFile.mobiledevicepairing" let pairingFileName = "ALTPairingFile.mobiledevicepairing"
final class LaunchViewController: UIViewController, UIDocumentPickerDelegate { final class LaunchViewController: RSTLaunchViewController, UIDocumentPickerDelegate
{
private var didFinishLaunching = false private var didFinishLaunching = false
private var retries = 0
private var maxRetries = 3
private var splashView: SplashView!
private var destinationViewController: TabBarController?
private var startTime: Date!
override func viewDidLoad() { private var destinationViewController: TabBarController!
override var launchConditions: [RSTLaunchCondition] {
let isDatabaseStarted = RSTLaunchCondition(condition: { DatabaseManager.shared.isStarted }) { (completionHandler) in
DatabaseManager.shared.start(completionHandler: completionHandler)
}
return [isDatabaseStarted]
}
override var childForStatusBarStyle: UIViewController? {
return self.children.first
}
override var childForStatusBarHidden: UIViewController? {
return self.children.first
}
override func viewDidLoad()
{
defer {
// Create destinationViewController now so view controllers can register for receiving Notifications.
self.destinationViewController = self.storyboard!.instantiateViewController(withIdentifier: "tabBarController") as! TabBarController
}
super.viewDidLoad() super.viewDidLoad()
splashView = SplashView(frame: view.bounds, appName: "SideStore")
destinationViewController = storyboard!.instantiateViewController(withIdentifier: "tabBarController") as? TabBarController
view.addSubview(splashView)
} }
override func viewDidAppear(_ animated: Bool) { override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated) super.viewDidAppear(true)
guard !didFinishLaunching else { return } if #available(iOS 17, *), !UserDefaults.standard.sidejitenable {
Task { DispatchQueue.global().async {
startTime = Date() self.isSideJITServerDetected() { result in
await runLaunchSequence() DispatchQueue.main.async {
doPostLaunch() switch result {
case .success():
let dialogMessage = UIAlertController(title: "SideJITServer Detected", message: "Would you like to enable SideJITServer", preferredStyle: .alert)
// Create OK button with action handler
let ok = UIAlertAction(title: "OK", style: .default, handler: { (action) -> Void in
UserDefaults.standard.sidejitenable = true
})
let cancel = UIAlertAction(title: "Cancel", style: .cancel)
//Add OK button to a dialog message
dialogMessage.addAction(ok)
dialogMessage.addAction(cancel)
// Present Alert to
self.present(dialogMessage, animated: true, completion: nil)
case .failure(_):
print("Cannot find sideJITServer")
}
}
}
} }
} }
private func runLaunchSequence() async {
guard retries < maxRetries else { return }
retries += 1
await Task.detached {
if !DatabaseManager.shared.isStarted {
await withCheckedContinuation { continuation in
DatabaseManager.shared.start { error in
if let error {
Task { await self.handleLaunchError(error, retryCallback: self.runLaunchSequence) }
} else {
Task { await self.finishLaunching() }
}
continuation.resume(returning: ())
}
}
} else {
await self.finishLaunching()
}
}.value
}
private func doPostLaunch() {
SideJITManager.shared.checkAndPromptIfNeeded(presentingVC: self)
if #available(iOS 17, *), UserDefaults.standard.sidejitenable { if #available(iOS 17, *), UserDefaults.standard.sidejitenable {
DispatchQueue.global().async { SideJITManager.shared.askForNetwork() } DispatchQueue.global().async {
self.askfornetwork()
}
print("SideJITServer Enabled") print("SideJITServer Enabled")
} }
#if !targetEnvironment(simulator) #if !targetEnvironment(simulator)
detectAndImportAccountFile()
if UserDefaults.standard.enableEMPforWireguard {
start_em_proxy(bind_addr: Consts.Proxy.serverURL) start_em_proxy(bind_addr: Consts.Proxy.serverURL)
}
guard let pf = fetchPairingFile() else { guard let pf = fetchPairingFile() else {
displayError("Device pairing file not found.") displayError("Device pairing file not found.")
return return
@@ -87,48 +98,145 @@ final class LaunchViewController: UIViewController, UIDocumentPickerDelegate {
#endif #endif
} }
func start_minimuxer_threads(_ pairing_file: String) { func askfornetwork() {
target_minimuxer_address() let address = UserDefaults.standard.textInputSideJITServerurl ?? ""
let documentsDirectory = FileManager.default.documentsDirectory.absoluteString
do { var SJSURL = address
let loggingEnabled = UserDefaults.standard.isMinimuxerConsoleLoggingEnabled
try minimuxer.startWithLogger(pairing_file, documentsDirectory, loggingEnabled) if (UserDefaults.standard.textInputSideJITServerurl ?? "").isEmpty {
} catch { SJSURL = "http://sidejitserver._http._tcp.local:8080"
try! FileManager.default.removeItem(at: FileManager.default.documentsDirectory.appendingPathComponent(pairingFileName))
displayError("minimuxer failed to start, please restart SideStore. \((error as? LocalizedError)?.failureReason ?? "UNKNOWN ERROR")")
}
start_auto_mounter(documentsDirectory)
} }
func fetchPairingFile() -> String? { PairingFileManager.shared.fetchPairingFile(presentingVC: self) } // Create a network operation at launch to Refresh SideJITServer
let url = URL(string: "\(SJSURL)/re/")!
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
print(data)
}
task.resume()
}
func isSideJITServerDetected(completion: @escaping (Result<Void, Error>) -> Void) {
let address = UserDefaults.standard.textInputSideJITServerurl ?? ""
var SJSURL = address
if (UserDefaults.standard.textInputSideJITServerurl ?? "").isEmpty {
SJSURL = "http://sidejitserver._http._tcp.local:8080"
}
// Create a network operation at launch to Refresh SideJITServer
let url = URL(string: SJSURL)!
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
if let error = error {
print("No SideJITServer on Network")
completion(.failure(error))
return
}
completion(.success(()))
}
task.resume()
return
}
func fetchPairingFile() -> String? {
let filename = "ALTPairingFile.mobiledevicepairing"
let fm = FileManager.default
let documentsPath = fm.documentsDirectory.appendingPathComponent("/\(filename)")
if fm.fileExists(atPath: documentsPath.path), let contents = try? String(contentsOf: documentsPath), !contents.isEmpty {
print("Loaded ALTPairingFile from \(documentsPath.path)")
return contents
} else if
let appResourcePath = Bundle.main.url(forResource: "ALTPairingFile", withExtension: "mobiledevicepairing"),
fm.fileExists(atPath: appResourcePath.path),
let data = fm.contents(atPath: appResourcePath.path),
let contents = String(data: data, encoding: .utf8),
!contents.isEmpty,
!UserDefaults.standard.isPairingReset {
print("Loaded ALTPairingFile from \(appResourcePath.path)")
return contents
} else if let plistString = Bundle.main.object(forInfoDictionaryKey: "ALTPairingFile") as? String, !plistString.isEmpty, !plistString.contains("insert pairing file here"), !UserDefaults.standard.isPairingReset{
print("Loaded ALTPairingFile from Info.plist")
return plistString
} else {
// Show an alert explaining the pairing file
// Create new Alert
let dialogMessage = UIAlertController(title: "Pairing File", message: "Select the pairing file or select \"Help\" for help.", preferredStyle: .alert)
// Create OK button with action handler
let ok = UIAlertAction(title: "OK", style: .default, handler: { (action) -> Void in
// Try to load it from a file picker
var types = UTType.types(tag: "plist", tagClass: UTTagClass.filenameExtension, conformingTo: nil)
types.append(contentsOf: UTType.types(tag: "mobiledevicepairing", tagClass: UTTagClass.filenameExtension, conformingTo: UTType.data))
types.append(.xml)
let documentPickerController = UIDocumentPickerViewController(forOpeningContentTypes: types)
documentPickerController.shouldShowFileExtensions = true
documentPickerController.delegate = self
self.present(documentPickerController, animated: true, completion: nil)
UserDefaults.standard.isPairingReset = false
})
//Add "help" button to take user to wiki
let wikiOption = UIAlertAction(title: "Help", style: .default) { (action) in
let wikiURL: String = "https://docs.sidestore.io/docs/getting-started/pairing-file"
if let url = URL(string: wikiURL) {
UIApplication.shared.open(url)
}
sleep(2)
exit(0)
}
//Add buttons to dialog message
dialogMessage.addAction(wikiOption)
dialogMessage.addAction(ok)
// Present Alert to
self.present(dialogMessage, animated: true, completion: nil)
let dialogMessage2 = UIAlertController(title: "Analytics", message: "This app contains anonymous analytics for research and project development. By continuing to use this app, you are consenting to this data collection", preferredStyle: .alert)
let ok2 = UIAlertAction(title: "OK", style: .default, handler: { (action) -> Void in})
dialogMessage2.addAction(ok2)
self.present(dialogMessage2, animated: true, completion: nil)
return nil
}
}
func displayError(_ msg: String) { func displayError(_ msg: String) {
print(msg) print(msg)
let alert = UIAlertController(title: "Error launching SideStore", message: msg, preferredStyle: .alert) // Create a new alert
self.present(alert, animated: true) let dialogMessage = UIAlertController(title: "Error launching SideStore", message: msg, preferredStyle: .alert)
// Present alert to user
self.present(dialogMessage, animated: true, completion: nil)
} }
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
let url = urls[0] let url = urls[0]
let isSecuredURL = url.startAccessingSecurityScopedResource() == true let isSecuredURL = url.startAccessingSecurityScopedResource() == true
defer {
if (isSecuredURL) {
url.stopAccessingSecurityScopedResource()
}
}
do { do {
let data = try Data(contentsOf: url) // Read to a string
guard let pairingString = String(data: data, encoding: .utf8) else { let data1 = try Data(contentsOf: urls[0])
let pairing_string = String(bytes: data1, encoding: .utf8)
if pairing_string == nil {
displayError("Unable to read pairing file") displayError("Unable to read pairing file")
return
} }
try pairingString.write(to: FileManager.default.documentsDirectory.appendingPathComponent(pairingFileName), atomically: true, encoding: .utf8)
start_minimuxer_threads(pairingString) // Save to a file for next launch
let pairingFile = FileManager.default.documentsDirectory.appendingPathComponent("\(pairingFileName)")
try pairing_string?.write(to: pairingFile, atomically: true, encoding: String.Encoding.utf8)
// Start minimuxer now that we have a file
start_minimuxer_threads(pairing_string!)
} catch { } catch {
displayError("Unable to read pairing file") displayError("Unable to read pairing file")
} }
if (isSecuredURL) {
url.stopAccessingSecurityScopedResource()
}
controller.dismiss(animated: true, completion: nil) controller.dismiss(animated: true, completion: nil)
} }
@@ -136,78 +244,75 @@ final class LaunchViewController: UIViewController, UIDocumentPickerDelegate {
displayError("Choosing a pairing file was cancelled. Please re-open the app and try again.") displayError("Choosing a pairing file was cancelled. Please re-open the app and try again.")
} }
func importAccountAtFile(_ file: URL, remove: Bool = false) { func start_minimuxer_threads(_ pairing_file: String) {
_ = file.startAccessingSecurityScopedResource() target_minimuxer_address()
defer { file.stopAccessingSecurityScopedResource() } let documentsDirectory = FileManager.default.documentsDirectory.absoluteString
guard let accountD = try? Data(contentsOf: file) else { do {
let toastView = ToastView(text: NSLocalizedString("Could not read data from file!", comment: ""), detailText: "\(file)") // enable minimuxer console logging only if enabled in settings
return toastView.show(in: self) let isMinimuxerConsoleLoggingEnabled = UserDefaults.standard.isMinimuxerConsoleLoggingEnabled
try minimuxer.startWithLogger(pairing_file, documentsDirectory, isMinimuxerConsoleLoggingEnabled)
} catch {
try! FileManager.default.removeItem(at: FileManager.default.documentsDirectory.appendingPathComponent("\(pairingFileName)"))
displayError("minimuxer failed to start, please restart SideStore. \((error as? LocalizedError)?.failureReason ?? "UNKNOWN ERROR!!!!!! REPORT TO GITHUB ISSUES!")")
} }
guard let account = try? Foundation.JSONDecoder().decode(ImportedAccount.self, from: accountD) else { if #available(iOS 17, *) {
let toastView = ToastView(text: NSLocalizedString("Could not parse data from file!", comment: ""), detailText: "\(file)") // TODO: iOS 17 and above have a new JIT implementation that is completely broken in SideStore :(
return toastView.show(in: self)
} }
print("We want to import this account probably: \(account)") else {
if remove { start_auto_mounter(documentsDirectory)
try? FileManager.default.removeItem(at: file)
} }
Keychain.shared.appleIDEmailAddress = account.email
Keychain.shared.appleIDPassword = account.password // Create destinationViewController now so view controllers can register for receiving Notifications.
Keychain.shared.adiPb = account.adiPB self.destinationViewController = self.storyboard!.instantiateViewController(withIdentifier: "tabBarController") as? TabBarController
Keychain.shared.identifier = account.local_user
if let altCert = ALTCertificate(p12Data: account.cert, password: account.certpass) {
Keychain.shared.signingCertificate = altCert.encryptedP12Data(withPassword: "")!
Keychain.shared.signingCertificatePassword = account.certpass
let toastView = ToastView(text: NSLocalizedString("Successfully imported '\(account.email)'!", comment: ""), detailText: "SideStore should be fully operational!")
return toastView.show(in: self)
} else {
let toastView = ToastView(text: NSLocalizedString("Failed to import account certificate!", comment: ""), detailText: "Failed to create ALTCertificate. Check if the password is correct. Still imported account/adi.pb details!")
return toastView.show(in: self)
} }
} }
func detectAndImportAccountFile() { extension LaunchViewController
let accountFileURL = FileManager.default.documentsDirectory.appendingPathComponent("Account.sideconf") {
#if !DEBUG override func handleLaunchError(_ error: Error)
importAccountAtFile(accountFileURL, remove: true) {
#else do
importAccountAtFile(accountFileURL) {
#endif throw error
} }
} catch let error as NSError
{
extension LaunchViewController {
@MainActor
func handleLaunchError(_ error: Error, retryCallback: (() async -> Void)? = nil) {
do { throw error } catch let error as NSError {
let title = error.userInfo[NSLocalizedFailureErrorKey] as? String ?? NSLocalizedString("Unable to Launch SideStore", comment: "") let title = error.userInfo[NSLocalizedFailureErrorKey] as? String ?? NSLocalizedString("Unable to Launch SideStore", comment: "")
let desc: String
if #available(iOS 14.5, *) { let errorDescription: String
desc = ([error.debugDescription] + error.underlyingErrors.map { ($0 as NSError).debugDescription }).joined(separator: "\n\n")
} else { if #available(iOS 14.5, *)
desc = error.debugDescription {
let errorMessages = [error.debugDescription] + error.underlyingErrors.map { ($0 as NSError).debugDescription }
errorDescription = errorMessages.joined(separator: "\n\n")
} }
let alert = UIAlertController(title: title, message: desc, preferredStyle: .alert) else
alert.addAction(UIAlertAction(title: NSLocalizedString("Retry", comment: ""), style: .default) { _ in {
Task { await retryCallback?() } errorDescription = error.debugDescription
}) }
present(alert, animated: true)
let alertController = UIAlertController(title: title, message: errorDescription, preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: NSLocalizedString("Retry", comment: ""), style: .default, handler: { (action) in
self.handleLaunchConditions()
}))
self.present(alertController, animated: true, completion: nil)
} }
} }
@MainActor override func finishLaunching()
func finishLaunching() async { {
guard !didFinishLaunching else { return } super.finishLaunching()
didFinishLaunching = true
guard !self.didFinishLaunching else { return }
AppManager.shared.update() AppManager.shared.update()
AppManager.shared.updatePatronsIfNeeded() AppManager.shared.updatePatronsIfNeeded()
PatreonAPI.shared.refreshPatreonAccount() PatreonAPI.shared.refreshPatreonAccount()
AppManager.shared.updateAllSources { result in AppManager.shared.updateAllSources { result in
guard case .failure(let error) = result else { return } guard case .failure(let error) = result else { return }
Logger.main.error("Failed to update sources on launch. \(error.localizedDescription, privacy: .public)") Logger.main.error("Failed to update sources on launch. \(error.localizedDescription, privacy: .public)")
let errorDesc = ErrorProcessing(.fullError).getDescription(error: error as NSError) let errorDesc = ErrorProcessing(.fullError).getDescription(error: error as NSError)
print("Failed to update sources on launch. \(errorDesc)") print("Failed to update sources on launch. \(errorDesc)")
@@ -215,64 +320,63 @@ extension LaunchViewController {
if String(describing: error).contains("The Internet connection appears to be offline"){ if String(describing: error).contains("The Internet connection appears to be offline"){
mode = .localizedDescription // dont make noise! mode = .localizedDescription // dont make noise!
} }
let toastView = ToastView(error: error, mode: mode) let toastView = ToastView(error: error, mode: mode)
toastView.addTarget(self.destinationViewController, action: #selector(TabBarController.presentSources), for: .touchUpInside) toastView.addTarget(self.destinationViewController, action: #selector(TabBarController.presentSources), for: .touchUpInside)
toastView.show(in: self.destinationViewController!.selectedViewController ?? self.destinationViewController!) toastView.show(in: self.destinationViewController.selectedViewController ?? self.destinationViewController)
} }
updateKnownSources()
self.updateKnownSources()
// Ask widgets to be refreshed
WidgetCenter.shared.reloadAllTimelines() WidgetCenter.shared.reloadAllTimelines()
didFinishLaunching = true
let destinationVC = destinationViewController! // Add view controller as child (rather than presenting modally)
// so tint adjustment + card presentations works correctly.
self.destinationViewController.view.frame = CGRect(x: 0, y: 0, width: self.view.bounds.width, height: self.view.bounds.height)
self.destinationViewController.view.alpha = 0.0
self.addChild(self.destinationViewController)
self.view.addSubview(self.destinationViewController.view, pinningEdgesWith: .zero)
self.destinationViewController.didMove(toParent: self)
let elapsed = abs(startTime.timeIntervalSinceNow) UIView.animate(withDuration: 0.2) {
let remaining = elapsed >= 1 ? 0 : 1 - elapsed self.destinationViewController.view.alpha = 1.0
try? await Task.sleep(nanoseconds: UInt64(remaining * 1_000_000_000)) }
destinationVC.loadViewIfNeeded() self.didFinishLaunching = true
addChild(destinationVC)
destinationVC.view.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(destinationVC.view)
destinationVC.didMove(toParent: self)
// Pin edges BEFORE animation
NSLayoutConstraint.activate([
destinationVC.view.topAnchor.constraint(equalTo: view.topAnchor),
destinationVC.view.bottomAnchor.constraint(equalTo: view.bottomAnchor),
destinationVC.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
destinationVC.view.trailingAnchor.constraint(equalTo: view.trailingAnchor)
])
// Set initial alpha for fade-in
destinationVC.view.alpha = 0
UIView.transition(with: view, duration: 0.3, options: .transitionCrossDissolve) { [self] in
self.splashView.alpha = 0
destinationVC.view.alpha = 1
} completion: { _ in
self.splashView.removeFromSuperview()
self.destinationViewController = destinationVC
} }
} }
func updateKnownSources() { private extension LaunchViewController
{
func updateKnownSources()
{
AppManager.shared.updateKnownSources { result in AppManager.shared.updateKnownSources { result in
switch result { switch result
{
case .failure(let error): print("[ALTLog] Failed to update known sources:", error) case .failure(let error): print("[ALTLog] Failed to update known sources:", error)
case .success((_, let blockedSources)): case .success((_, let blockedSources)):
DatabaseManager.shared.persistentContainer.performBackgroundTask { context in DatabaseManager.shared.persistentContainer.performBackgroundTask { context in
let blockedSourceIDs = Set(blockedSources.lazy.map { $0.identifier }) let blockedSourceIDs = Set(blockedSources.lazy.map { $0.identifier })
let blockedSourceURLs = Set(blockedSources.lazy.compactMap { $0.sourceURL }) let blockedSourceURLs = Set(blockedSources.lazy.compactMap { $0.sourceURL })
let predicate = NSPredicate(format: "%K IN %@ OR %K IN %@", #keyPath(Source.identifier), blockedSourceIDs, #keyPath(Source.sourceURL), blockedSourceURLs)
let sourceErrors = Source.all(satisfying: predicate, in: context).map { source in let predicate = NSPredicate(format: "%K IN %@ OR %K IN %@",
let blocked = blockedSources.first { $0.identifier == source.identifier } #keyPath(Source.identifier), blockedSourceIDs,
return SourceError.blocked(source, bundleIDs: blocked?.bundleIDs, existingSource: source) #keyPath(Source.sourceURL), blockedSourceURLs)
let sourceErrors = Source.all(satisfying: predicate, in: context).map { (source) in
let blockedSource = blockedSources.first { $0.identifier == source.identifier }
return SourceError.blocked(source, bundleIDs: blockedSource?.bundleIDs, existingSource: source)
} }
guard !sourceErrors.isEmpty else { return } guard !sourceErrors.isEmpty else { return }
Task { Task {
for error in sourceErrors { for error in sourceErrors
{
let title = String(format: NSLocalizedString("“%@” Blocked", comment: ""), error.$source.name) let title = String(format: NSLocalizedString("“%@” Blocked", comment: ""), error.$source.name)
let message = [error.localizedDescription, error.recoverySuggestion].compactMap { $0 }.joined(separator: "\n\n") let message = [error.localizedDescription, error.recoverySuggestion].compactMap { $0 }.joined(separator: "\n\n")
await self.presentAlert(title: title, message: message) await self.presentAlert(title: title, message: message)
} }
} }
@@ -281,142 +385,3 @@ extension LaunchViewController {
} }
} }
} }
// MARK: - SplashView
final class SplashView: UIView {
let iconView = UIImageView()
let titleLabel = UILabel()
init(frame: CGRect, appName: String) {
super.init(frame: frame)
backgroundColor = .systemBackground
setupIcon()
setupTitle(appName: appName)
}
required init?(coder: NSCoder) { fatalError() }
private func setupIcon() {
let container = UIView()
container.translatesAutoresizingMaskIntoConstraints = false
container.layer.shadowColor = UIColor.black.cgColor
container.layer.shadowOpacity = 0.25
container.layer.shadowOffset = CGSize(width: 0, height: 4)
container.layer.shadowRadius = 8
addSubview(container)
iconView.image = UIImage(named: "AppIcon") ?? UIImage(named: "AppIcon60x60") ?? UIImage(systemName: "app.fill")
iconView.contentMode = .scaleAspectFit
iconView.translatesAutoresizingMaskIntoConstraints = false
iconView.layer.cornerRadius = 24
iconView.clipsToBounds = true
container.addSubview(iconView)
NSLayoutConstraint.activate([
container.centerXAnchor.constraint(equalTo: centerXAnchor),
container.centerYAnchor.constraint(equalTo: centerYAnchor, constant: -20),
container.widthAnchor.constraint(equalToConstant: 120),
container.heightAnchor.constraint(equalToConstant: 120),
iconView.topAnchor.constraint(equalTo: container.topAnchor),
iconView.bottomAnchor.constraint(equalTo: container.bottomAnchor),
iconView.leadingAnchor.constraint(equalTo: container.leadingAnchor),
iconView.trailingAnchor.constraint(equalTo: container.trailingAnchor)
])
}
private func setupTitle(appName: String) {
titleLabel.text = appName
titleLabel.font = .systemFont(ofSize: 24, weight: .bold)
titleLabel.textColor = .label
titleLabel.textAlignment = .center
titleLabel.translatesAutoresizingMaskIntoConstraints = false
addSubview(titleLabel)
NSLayoutConstraint.activate([
titleLabel.topAnchor.constraint(equalTo: iconView.bottomAnchor, constant: 12),
titleLabel.centerXAnchor.constraint(equalTo: centerXAnchor)
])
}
}
// MARK: - PairingFileManager
final class PairingFileManager {
static let shared = PairingFileManager()
func fetchPairingFile(presentingVC: UIViewController) -> String? {
let fm = FileManager.default
let filename = pairingFileName
let documentsPath = fm.documentsDirectory.appendingPathComponent("/\(filename)")
if fm.fileExists(atPath: documentsPath.path),
let contents = try? String(contentsOf: documentsPath), !contents.isEmpty {
return contents
}
if let url = Bundle.main.url(forResource: "ALTPairingFile", withExtension: "mobiledevicepairing"),
fm.fileExists(atPath: url.path),
let data = fm.contents(atPath: url.path),
let contents = String(data: data, encoding: .utf8),
!contents.isEmpty, !UserDefaults.standard.isPairingReset { return contents }
if let plistString = Bundle.main.object(forInfoDictionaryKey: "ALTPairingFile") as? String,
!plistString.isEmpty, !plistString.contains("insert pairing file here"), !UserDefaults.standard.isPairingReset { return plistString }
presentPairingFileAlert(on: presentingVC)
return nil
}
private func presentPairingFileAlert(on vc: UIViewController) {
let alert = UIAlertController(title: "Pairing File", message: "Select the pairing file or select \"Help\" for help.", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Help", style: .default) { _ in
if let url = URL(string: "https://docs.sidestore.io/docs/advanced/pairing-file") { UIApplication.shared.open(url) }
sleep(2); exit(0)
})
alert.addAction(UIAlertAction(title: "OK", style: .default) { _ in
var types = UTType.types(tag: "plist", tagClass: .filenameExtension, conformingTo: nil)
types.append(contentsOf: UTType.types(tag: "mobiledevicepairing", tagClass: .filenameExtension, conformingTo: .data))
types.append(.xml)
let picker = UIDocumentPickerViewController(forOpeningContentTypes: types)
picker.delegate = vc as? UIDocumentPickerDelegate
picker.shouldShowFileExtensions = true
vc.present(picker, animated: true)
UserDefaults.standard.isPairingReset = false
})
vc.present(alert, animated: true)
}
}
// MARK: - SideJITManager
final class SideJITManager {
static let shared = SideJITManager()
func checkAndPromptIfNeeded(presentingVC: UIViewController) {
guard #available(iOS 17, *), !UserDefaults.standard.sidejitenable else { return }
DispatchQueue.global().async {
self.isSideJITServerDetected { result in
DispatchQueue.main.async {
switch result {
case .success():
let alert = UIAlertController(title: "SideJITServer Detected", message: "Would you like to enable SideJITServer", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default) { _ in UserDefaults.standard.sidejitenable = true })
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))
presentingVC.present(alert, animated: true)
case .failure(_): print("Cannot find sideJITServer")
}
}
}
}
}
func askForNetwork() {
let address = UserDefaults.standard.textInputSideJITServerurl ?? ""
let SJSURL = address.isEmpty ? "http://sidejitserver._http._tcp.local:8080" : address
URLSession.shared.dataTask(with: URL(string: "\(SJSURL)/re/")!) { data, resp, err in
print("data: \(String(describing: data)), response: \(String(describing: resp)), error: \(String(describing: err))")
}.resume()
}
func isSideJITServerDetected(completion: @escaping (Result<Void, Error>) -> Void) {
let address = UserDefaults.standard.textInputSideJITServerurl ?? ""
let SJSURL = address.isEmpty ? "http://sidejitserver._http._tcp.local:8080" : address
guard let url = URL(string: SJSURL) else { return }
URLSession.shared.dataTask(with: url) { _, _, error in
if let error = error { completion(.failure(error)); return }
completion(.success(()))
}.resume()
}
}

View File

@@ -993,6 +993,7 @@ extension AppManager
case .failure(let error): completionHandler(.failure(error)) case .failure(let error): completionHandler(.failure(error))
case .success(let installedApp): completionHandler(.success(installedApp)) case .success(let installedApp): completionHandler(.success(installedApp))
} }
//UIApplication.shared.open(shortcutURLon, options: [:], completionHandler: nil)
} }
installOperation.addDependency(sendAppOperation) installOperation.addDependency(sendAppOperation)
@@ -1519,24 +1520,6 @@ private extension AppManager
patchAppOperation.addDependency(deactivateAppsOperation) patchAppOperation.addDependency(deactivateAppsOperation)
let modifyAppExBundleIdOperation = RSTAsyncBlockOperation { operation in
if !context.useMainProfile {
operation.finish()
return
}
if let app = context.app, let profile = context.provisioningProfiles?[app.bundleIdentifier] {
var appexBundleIds: [String: String] = [:]
for appex in app.appExtensions {
appexBundleIds[appex.bundleIdentifier] = appex.bundleIdentifier.replacingOccurrences(of: app.bundleIdentifier, with: profile.bundleIdentifier)
}
context.appexBundleIds = appexBundleIds
}
operation.finish()
}
modifyAppExBundleIdOperation.addDependency(fetchProvisioningProfilesOperation)
/* Resign */ /* Resign */
let resignAppOperation = ResignAppOperation(context: context) let resignAppOperation = ResignAppOperation(context: context)
resignAppOperation.resultHandler = { (result) in resignAppOperation.resultHandler = { (result) in
@@ -1551,7 +1534,6 @@ private extension AppManager
} }
} }
resignAppOperation.addDependency(patchAppOperation) resignAppOperation.addDependency(patchAppOperation)
resignAppOperation.addDependency(modifyAppExBundleIdOperation)
progress.addChild(resignAppOperation.progress, withPendingUnitCount: 20) progress.addChild(resignAppOperation.progress, withPendingUnitCount: 20)
@@ -1605,7 +1587,6 @@ private extension AppManager
patchAppOperation, patchAppOperation,
refreshAnisetteDataOperation, refreshAnisetteDataOperation,
fetchProvisioningProfilesOperation, fetchProvisioningProfilesOperation,
modifyAppExBundleIdOperation,
resignAppOperation, resignAppOperation,
sendAppOperation, sendAppOperation,
installOperation installOperation
@@ -1685,7 +1666,7 @@ private extension AppManager
let context = AppOperationContext(bundleIdentifier: app.bundleIdentifier, authenticatedContext: group.context) let context = AppOperationContext(bundleIdentifier: app.bundleIdentifier, authenticatedContext: group.context)
context.app = ALTApplication(fileURL: app.fileURL) context.app = ALTApplication(fileURL: app.fileURL)
context.useMainProfile = app.useMainProfile
// Since this doesn't involve modifying app bundle which will cause re-install, this is safe in refresh path // Since this doesn't involve modifying app bundle which will cause re-install, this is safe in refresh path
//App-Extensions: Ensure DB data and disk state must match //App-Extensions: Ensure DB data and disk state must match
let dbAppEx: Set<InstalledExtension> = Set(app.appExtensions) let dbAppEx: Set<InstalledExtension> = Set(app.appExtensions)

View File

@@ -166,11 +166,9 @@ class MyAppsViewController: UICollectionViewController, PeekPopPreviewing
@IBAction func unwindToMyAppsViewController(_ segue: UIStoryboardSegue) @IBAction func unwindToMyAppsViewController(_ segue: UIStoryboardSegue)
{ {
} }
var minimuxerStatus: Bool { var minimuxerStatus: Bool {
// added isMinimuxerStatusCheckEnabled to forcefully ignore minimuxer status if status check is disabled in settings guard minimuxer.ready() else {
guard !UserDefaults.standard.isMinimuxerStatusCheckEnabled || minimuxer.ready() else { ToastView(error: (OperationError.noWiFi as NSError).withLocalizedTitle("No WiFi or VPN!")).show(in: self)
ToastView(error: (OperationError.noWiFi as NSError).withLocalizedTitle("No Wi-Fi or VPN!")).show(in: self)
return false return false
} }
return true return true
@@ -1487,6 +1485,15 @@ private extension MyAppsViewController
guard minimuxerStatus else { return } guard minimuxerStatus else { return }
} }
if #available(iOS 17, *), !sidejitenabled {
let error = OperationError.tooNewError as NSError
let localizedError = error.withLocalizedTitle("No iOS 17 On Device JIT!")
ToastView(error: localizedError, opensLog: true).show(in: self)
AppManager.shared.log(error, operation: .enableJIT, app: installedApp)
return
}
AppManager.shared.enableJIT(for: installedApp) { result in AppManager.shared.enableJIT(for: installedApp) { result in
DispatchQueue.main.async { DispatchQueue.main.async {
switch result { switch result {

View File

@@ -99,10 +99,7 @@ final class BackgroundRefreshAppsOperation: ResultOperation<[String: Result<Inst
self.finish(.failure(RefreshError(.noInstalledApps))) self.finish(.failure(RefreshError(.noInstalledApps)))
return return
} }
if UserDefaults.standard.enableEMPforWireguard {
start_em_proxy(bind_addr: Consts.Proxy.serverURL) start_em_proxy(bind_addr: Consts.Proxy.serverURL)
}
target_minimuxer_address() target_minimuxer_address()
let documentsDirectory = FileManager.default.documentsDirectory.absoluteString let documentsDirectory = FileManager.default.documentsDirectory.absoluteString
do { do {

View File

@@ -201,7 +201,7 @@ struct OperationError: ALTLocalizedError {
case .unknownResult: return NSLocalizedString("The operation returned an unknown result.", comment: "") case .unknownResult: return NSLocalizedString("The operation returned an unknown result.", comment: "")
case .timedOut: return NSLocalizedString("The operation timed out.", comment: "") case .timedOut: return NSLocalizedString("The operation timed out.", comment: "")
case .notAuthenticated: return NSLocalizedString("You are not signed in.", comment: "") case .notAuthenticated: return NSLocalizedString("You are not signed in.", comment: "")
case .unknownUDID: return NSLocalizedString("SideStore could not determine this device's UDID. Please replace your pairing using iloader.", comment: "") case .unknownUDID: return NSLocalizedString("SideStore could not determine this device's UDID.", comment: "")
case .invalidApp: return NSLocalizedString("The app is in an invalid format.", comment: "") case .invalidApp: return NSLocalizedString("The app is in an invalid format.", comment: "")
case .maximumAppIDLimitReached: return NSLocalizedString("Cannot register more than 10 App IDs within a 7 day period.", comment: "") case .maximumAppIDLimitReached: return NSLocalizedString("Cannot register more than 10 App IDs within a 7 day period.", comment: "")
case .noSources: return NSLocalizedString("There are no SideStore sources.", comment: "") case .noSources: return NSLocalizedString("There are no SideStore sources.", comment: "")
@@ -220,16 +220,16 @@ struct OperationError: ALTLocalizedError {
case .openAppFailed: case .openAppFailed:
let appName = self.appName ?? NSLocalizedString("The app", comment: "") let appName = self.appName ?? NSLocalizedString("The app", comment: "")
return String(format: NSLocalizedString("SideStore was denied permission to launch %@.", comment: ""), appName) return String(format: NSLocalizedString("SideStore was denied permission to launch %@.", comment: ""), appName)
case .noWiFi: return NSLocalizedString("You do not appear to be connected to Wi-Fi and/or LocalDevVPN!\nSideStore cannot install or refresh applications without Wi-Fi and LocalDevVPN. If both are connected, replace your pairing with iloader.", comment: "") case .noWiFi: return NSLocalizedString("You do not appear to be connected to WiFi and/or the WireGuard VPN!\nSideStore will never be able to install or refresh applications without WiFi and the WireGuard VPN.", comment: "")
case .tooNewError: return NSLocalizedString("iOS 17.0-17.3.1 changed how JIT is enabled so SideStore cannot enable JIT without SideJITServer on these versions, sorry for any inconvenience.", comment: "") case .tooNewError: return NSLocalizedString("iOS 17 has changed how JIT is enabled therefore SideStore cannot enable it without SideJITServer at this time, sorry for any inconvenience.\nWe will let everyone know once we have a solution!", comment: "")
case .unableToConnectSideJIT: return NSLocalizedString("Unable to connect to SideJITServer. Please check that you are on the same Wi-Fi of and your Firewall has been set correctly on your server.", comment: "") case .unableToConnectSideJIT: return NSLocalizedString("Unable to connect to SideJITServer Please check that you are on the Same Wi-Fi and your Firewall has been set correctly", comment: "")
case .unableToRespondSideJITDevice: return NSLocalizedString("SideJITServer is unable to connect to your iDevice. Please make sure you have paired your iDevice by running 'SideJITServer -y', or try refreshing SideJITServer from Settings.", comment: "") case .unableToRespondSideJITDevice: return NSLocalizedString("SideJITServer is unable to connect to your iDevice Please make sure you have paired your Device by doing 'SideJITServer -y' or try Refreshing SideJITServer from Settings", comment: "")
case .wrongSideJITIP: return NSLocalizedString("Incorrect SideJITServer IP. Please make sure that you are on the same Wi-Fi as SideJITServer", comment: "") case .wrongSideJITIP: return NSLocalizedString("Incorrect SideJITServer IP Please make sure that you are on the Samw Wifi as SideJITServer", comment: "")
case .refreshsidejit: return NSLocalizedString("Unable to find app; Please try refreshing SideJITServer from Settings.", comment: "") case .refreshsidejit: return NSLocalizedString("Unable to find App Please try Refreshing SideJITServer from Settings", comment: "")
case .anisetteV1Error: return NSLocalizedString("An error occurred while getting anisette data from a V1 server: %@. Try using another anisette server.", comment: "") case .anisetteV1Error: return NSLocalizedString("An error occurred when getting anisette data from a V1 server: %@. Try using another anisette server.", comment: "")
case .provisioningError: return NSLocalizedString("An error occurred while provisioning: %@ %@. Please try again. If the issue persists, report it on GitHub Issues!", comment: "") case .provisioningError: return NSLocalizedString("An error occurred when provisioning: %@ %@. Please try again. If the issue persists, report it on GitHub Issues!", comment: "")
case .anisetteV3Error: return NSLocalizedString("An error occurred while getting anisette data from a V3 server: %@. Please try again. If the issue persists, report it on GitHub Issues!", comment: "") case .anisetteV3Error: return NSLocalizedString("An error occurred when getting anisette data from a V3 server: %@. Please try again. If the issue persists, report it on GitHub Issues!", comment: "")
case .cacheClearError: return NSLocalizedString("An error occurred while clearing the cache: %@", comment: "") case .cacheClearError: return NSLocalizedString("An error occurred while clearing cache: %@", comment: "")
case .SideJITIssue: return NSLocalizedString("An error occurred while using SideJIT: %@", comment: "") case .SideJITIssue: return NSLocalizedString("An error occurred while using SideJIT: %@", comment: "")
case .refreshAppFailed: case .refreshAppFailed:
@@ -260,7 +260,7 @@ struct OperationError: ALTLocalizedError {
var recoverySuggestion: String? { var recoverySuggestion: String? {
switch self.code switch self.code
{ {
case .noWiFi: return NSLocalizedString("Make sure LocalDevVPN is connected and that you are connected to any Wi-Fi network!", comment: "") case .noWiFi: return NSLocalizedString("Make sure the VPN is toggled on and you are connected to any WiFi network!", comment: "")
case .serverNotFound: return NSLocalizedString("Make sure you're on the same Wi-Fi network as a computer running AltServer, or try connecting this device to your computer via USB.", comment: "") case .serverNotFound: return NSLocalizedString("Make sure you're on the same Wi-Fi network as a computer running AltServer, or try connecting this device to your computer via USB.", comment: "")
case .maximumAppIDLimitReached: case .maximumAppIDLimitReached:
let baseMessage = NSLocalizedString("Delete sideloaded apps to free up App ID slots.", comment: "") let baseMessage = NSLocalizedString("Delete sideloaded apps to free up App ID slots.", comment: "")
@@ -308,9 +308,9 @@ extension MinimuxerError: LocalizedError {
case .NoDevice: case .NoDevice:
return NSLocalizedString("Cannot fetch the device from the muxer", comment: "") return NSLocalizedString("Cannot fetch the device from the muxer", comment: "")
case .NoConnection: case .NoConnection:
return NSLocalizedString("Unable to connect to the device, make sure LocalDevVPN is enabled and you're connected to Wi-Fi. This could mean an invalid pairing.", comment: "") return NSLocalizedString("Unable to connect to the device, make sure Wireguard is enabled and you're connected to WiFi. This could mean an invalid pairing.", comment: "")
case .PairingFile: case .PairingFile:
return NSLocalizedString("Invalid pairing file. Your pairing file either didn't have a UDID, or it wasn't a valid plist. Please use iloader to replace it.", comment: "") return NSLocalizedString("Invalid pairing file. Your pairing file either didn't have a UDID, or it wasn't a valid plist. Please use jitterbugpair to generate it", comment: "")
case .CreateDebug: case .CreateDebug:
return self.createService(name: "debug") return self.createService(name: "debug")
@@ -338,7 +338,7 @@ extension MinimuxerError: LocalizedError {
case .CreateAfc: case .CreateAfc:
return self.createService(name: "AFC") return self.createService(name: "AFC")
case .RwAfc: case .RwAfc:
return NSLocalizedString("AFC was unable to manage files on the device. Ensure Wi-Fi and LocalDevVPN are connected. If they both are, replace your pairing using iloader.", comment: "") return NSLocalizedString("AFC was unable to manage files on the device. This usually means an invalid pairing.", comment: "")
case .InstallApp(let message): case .InstallApp(let message):
return NSLocalizedString("Unable to install the app: \(message.toString())", comment: "") return NSLocalizedString("Unable to install the app: \(message.toString())", comment: "")
case .UninstallApp: case .UninstallApp:
@@ -350,38 +350,6 @@ extension MinimuxerError: LocalizedError {
return NSLocalizedString("Unable to manage profiles on the device", comment: "") return NSLocalizedString("Unable to manage profiles on the device", comment: "")
case .ProfileRemove: case .ProfileRemove:
return NSLocalizedString("Unable to manage profiles on the device", comment: "") return NSLocalizedString("Unable to manage profiles on the device", comment: "")
case .CreateLockdown:
return NSLocalizedString("Unable to connect to lockdown", comment: "")
case .CreateCoreDevice:
return NSLocalizedString("Unable to connect to core device proxy", comment: "")
case .CreateSoftwareTunnel:
return NSLocalizedString("Unable to create software tunnel", comment: "")
case .CreateRemoteServer:
return NSLocalizedString("Unable to connect to remote server", comment: "")
case .CreateProcessControl:
return NSLocalizedString("Unable to connect to process control", comment: "")
case .GetLockdownValue:
return NSLocalizedString("Unable to get value from lockdown", comment: "")
case .Connect:
return NSLocalizedString("Unable to connect to TCP port", comment: "")
case .Close:
return NSLocalizedString("Unable to close TCP port", comment: "")
case .XpcHandshake:
return NSLocalizedString("Unable to get services from XPC", comment: "")
case .NoService:
return NSLocalizedString("Device did not contain service", comment: "")
case .InvalidProductVersion:
return NSLocalizedString("Service version was in an unexpected format", comment: "")
case .CreateFolder:
return NSLocalizedString("Unable to create DDI folder", comment: "")
case .DownloadImage:
return NSLocalizedString("Unable to download DDI", comment: "")
case .ImageLookup:
return NSLocalizedString("Unable to lookup DDI images", comment: "")
case .ImageRead:
return NSLocalizedString("Unable to read images to memory", comment: "")
case .Mount:
return NSLocalizedString("Mount failed", comment: "")
} }
} }

View File

@@ -67,7 +67,6 @@ class FetchProvisioningProfilesOperation: ResultOperation<[String: ALTProvisioni
let dispatchGroup = DispatchGroup() let dispatchGroup = DispatchGroup()
if !self.context.useMainProfile {
for appExtension in app.appExtensions for appExtension in app.appExtensions
{ {
dispatchGroup.enter() dispatchGroup.enter()
@@ -84,7 +83,6 @@ class FetchProvisioningProfilesOperation: ResultOperation<[String: ALTProvisioni
self.progress.completedUnitCount += 1 self.progress.completedUnitCount += 1
} }
} }
}
dispatchGroup.notify(queue: .global()) { dispatchGroup.notify(queue: .global()) {
if let error = error if let error = error

View File

@@ -13,6 +13,8 @@ import AltSign
import Roxas import Roxas
import minimuxer import minimuxer
let shortcutURLonDelay = URL(string: "shortcuts://run-shortcut?name=TurnOnDataDelay")!
@objc(InstallAppOperation) @objc(InstallAppOperation)
final class InstallAppOperation: ResultOperation<InstalledApp> final class InstallAppOperation: ResultOperation<InstalledApp>
{ {
@@ -72,8 +74,6 @@ final class InstallAppOperation: ResultOperation<InstalledApp>
} }
installedApp.update(resignedApp: resignedApp, certificateSerialNumber: certificate.serialNumber, storeBuildVersion: storeBuildVersion) installedApp.update(resignedApp: resignedApp, certificateSerialNumber: certificate.serialNumber, storeBuildVersion: storeBuildVersion)
installedApp.useMainProfile = self.context.useMainProfile
installedApp.needsResign = false installedApp.needsResign = false
if let team = DatabaseManager.shared.activeTeam(in: backgroundContext) if let team = DatabaseManager.shared.activeTeam(in: backgroundContext)
@@ -206,6 +206,10 @@ final class InstallAppOperation: ResultOperation<InstalledApp>
let alert = UIAlertController(title: "Finish Refresh", message: "Please reopen SideStore after the process is finished.To finish refreshing, SideStore must be moved to the background. To do this, you can either go to the Home Screen manually or by hitting Continue. Please reopen SideStore after doing this.", preferredStyle: .alert) let alert = UIAlertController(title: "Finish Refresh", message: "Please reopen SideStore after the process is finished.To finish refreshing, SideStore must be moved to the background. To do this, you can either go to the Home Screen manually or by hitting Continue. Please reopen SideStore after doing this.", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: NSLocalizedString("Continue", comment: ""), style: .default, handler: { _ in alert.addAction(UIAlertAction(title: NSLocalizedString("Continue", comment: ""), style: .default, handler: { _ in
print("Going home") print("Going home")
// Cell Shortcut
UIApplication.shared.open(shortcutURLonDelay, options: [:]) { _ in
print("Cell OFF Shortcut finished execution.")}
UIApplication.shared.perform(#selector(NSXPCConnection.suspend)) UIApplication.shared.perform(#selector(NSXPCConnection.suspend))
})) }))
@@ -222,6 +226,8 @@ final class InstallAppOperation: ResultOperation<InstalledApp>
} }
} }
} }
// Cell Shortcut
UIApplication.shared.open(shortcutURLonDelay, options: [:]) { _ in print("Cell OFF Shortcut finished execution.")}
UIApplication.shared.perform(#selector(NSXPCConnection.suspend)) UIApplication.shared.perform(#selector(NSXPCConnection.suspend))
} }
} }

View File

@@ -66,8 +66,6 @@ class AppOperationContext
var app: ALTApplication? var app: ALTApplication?
var provisioningProfiles: [String: ALTProvisioningProfile]? var provisioningProfiles: [String: ALTProvisioningProfile]?
var appexBundleIds: [String: String]?
var useMainProfile = false
var isFinished = false var isFinished = false

View File

@@ -212,7 +212,6 @@ private extension PatchAppOperation
#if targetEnvironment(simulator) #if targetEnvironment(simulator)
throw PatchAppError.unsupportedOperatingSystemVersion(ProcessInfo.processInfo.operatingSystemVersion) throw PatchAppError.unsupportedOperatingSystemVersion(ProcessInfo.processInfo.operatingSystemVersion)
#else #else
let spotlightPath = "Applications/Spotlight.app/Spotlight" let spotlightPath = "Applications/Spotlight.app/Spotlight"
let spotlightFileURL = self.patchDirectory.appendingPathComponent(spotlightPath) let spotlightFileURL = self.patchDirectory.appendingPathComponent(spotlightPath)

View File

@@ -136,11 +136,7 @@ final class RemoveAppExtensionsOperation: ResultOperation<Void>
alertController.addAction(UIAlertAction(title: UIAlertAction.cancel.title, style: UIAlertAction.cancel.style, handler: { (action) in alertController.addAction(UIAlertAction(title: UIAlertAction.cancel.title, style: UIAlertAction.cancel.style, handler: { (action) in
self.finish(.failure(OperationError.cancelled)) self.finish(.failure(OperationError.cancelled))
})) }))
alertController.addAction(UIAlertAction(title: NSLocalizedString("Keep App Extensions (Use Main Profile)", comment: ""), style: .default) { (action) in alertController.addAction(UIAlertAction(title: NSLocalizedString("Keep App Extensions", comment: ""), style: .default) { (action) in
self.context.useMainProfile = true
self.finish(.success(()))
})
alertController.addAction(UIAlertAction(title: NSLocalizedString("Keep App Extensions (Register App ID for Each Extension)", comment: ""), style: .default) { (action) in
self.finish(.success(())) self.finish(.success(()))
}) })
alertController.addAction(UIAlertAction(title: NSLocalizedString("Remove App Extensions", comment: ""), style: .destructive) { (action) in alertController.addAction(UIAlertAction(title: NSLocalizedString("Remove App Extensions", comment: ""), style: .destructive) { (action) in

View File

@@ -55,7 +55,7 @@ final class ResignAppOperation: ResultOperation<ALTApplication>
let prepareAppProgress = Progress.discreteProgress(totalUnitCount: 2) let prepareAppProgress = Progress.discreteProgress(totalUnitCount: 2)
self.progress.addChild(prepareAppProgress, withPendingUnitCount: 3) self.progress.addChild(prepareAppProgress, withPendingUnitCount: 3)
let prepareAppBundleProgress = self.prepareAppBundle(for: app, profiles: profiles, appexBundleIds: context.appexBundleIds ?? [:]) { (result) in let prepareAppBundleProgress = self.prepareAppBundle(for: app, profiles: profiles) { (result) in
guard let appBundleURL = self.process(result) else { return } guard let appBundleURL = self.process(result) else { return }
// Resign app bundle // Resign app bundle
@@ -107,7 +107,7 @@ final class ResignAppOperation: ResultOperation<ALTApplication>
private extension ResignAppOperation private extension ResignAppOperation
{ {
func prepareAppBundle(for app: ALTApplication, profiles: [String: ALTProvisioningProfile], appexBundleIds: [String: String], completionHandler: @escaping (Result<URL, Error>) -> Void) -> Progress func prepareAppBundle(for app: ALTApplication, profiles: [String: ALTProvisioningProfile], completionHandler: @escaping (Result<URL, Error>) -> Void) -> Progress
{ {
let progress = Progress.discreteProgress(totalUnitCount: 1) let progress = Progress.discreteProgress(totalUnitCount: 1)
@@ -119,15 +119,10 @@ private extension ResignAppOperation
func prepare(_ bundle: Bundle, additionalInfoDictionaryValues: [String: Any] = [:]) throws func prepare(_ bundle: Bundle, additionalInfoDictionaryValues: [String: Any] = [:]) throws
{ {
guard let identifier = bundle.bundleIdentifier else { throw ALTError(.missingAppBundle) } guard let identifier = bundle.bundleIdentifier else { throw ALTError(.missingAppBundle) }
guard let profile = context.useMainProfile ? profiles.values.first : profiles[identifier] else { throw ALTError(.missingProvisioningProfile) } guard let profile = profiles[identifier] else { throw ALTError(.missingProvisioningProfile) }
guard var infoDictionary = bundle.completeInfoDictionary else { throw ALTError(.missingInfoPlist) } guard var infoDictionary = bundle.completeInfoDictionary else { throw ALTError(.missingInfoPlist) }
if let forcedBundleIdentifier = appexBundleIds[identifier] {
infoDictionary[kCFBundleIdentifierKey as String] = forcedBundleIdentifier
} else {
infoDictionary[kCFBundleIdentifierKey as String] = profile.bundleIdentifier infoDictionary[kCFBundleIdentifierKey as String] = profile.bundleIdentifier
}
infoDictionary[Bundle.Info.altBundleID] = identifier infoDictionary[Bundle.Info.altBundleID] = identifier
infoDictionary[Bundle.Info.devicePairingString] = "<insert pairing file here>" infoDictionary[Bundle.Info.devicePairingString] = "<insert pairing file here>"
infoDictionary.removeValue(forKey: "DTXcode") infoDictionary.removeValue(forKey: "DTXcode")

View File

@@ -27,12 +27,10 @@ final class SendAppOperation: ResultOperation<()>
self.progress.totalUnitCount = 1 self.progress.totalUnitCount = 1
} }
override func main() override func main() {
{
super.main() super.main()
if let error = self.context.error if let error = self.context.error {
{
return self.finish(.failure(error)) return self.finish(.failure(error))
} }
@@ -40,16 +38,31 @@ final class SendAppOperation: ResultOperation<()>
return self.finish(.failure(OperationError.invalidParameters("SendAppOperation.main: self.resignedApp is nil"))) return self.finish(.failure(OperationError.invalidParameters("SendAppOperation.main: self.resignedApp is nil")))
} }
// self.context.resignedApp.fileURL points to the app bundle, but we want the .ipa. let shortcutURLoff = URL(string: "shortcuts://run-shortcut?name=TurnOffData")!
let app = AnyApp(name: resignedApp.name, bundleIdentifier: self.context.bundleIdentifier, url: resignedApp.fileURL, storeApp: nil) let app = AnyApp(name: resignedApp.name, bundleIdentifier: self.context.bundleIdentifier, url: resignedApp.fileURL, storeApp: nil)
let fileURL = InstalledApp.refreshedIPAURL(for: app) let fileURL = InstalledApp.refreshedIPAURL(for: app)
print("AFC App `fileURL`: \(fileURL.absoluteString)") print("AFC App `fileURL`: \(fileURL.absoluteString)")
if let data = NSData(contentsOf: fileURL) { // Wait for Shortcut to Finish Before Proceeding
UIApplication.shared.open(shortcutURLoff, options: [:]) { _ in
print("Shortcut finished execution. Proceeding with file transfer.")
DispatchQueue.global().async {
self.processFile(at: fileURL, for: app.bundleIdentifier)
}
}
}
private func processFile(at fileURL: URL, for bundleIdentifier: String) {
guard let data = NSData(contentsOf: fileURL) else {
print("IPA doesn't exist????")
return self.finish(.failure(OperationError(.appNotFound(name: bundleIdentifier))))
}
do { do {
let bytes = Data(data).toRustByteSlice() let bytes = Data(data).toRustByteSlice()
try yeet_app_afc(app.bundleIdentifier, bytes.forRust()) try yeet_app_afc(bundleIdentifier, bytes.forRust())
self.progress.completedUnitCount += 1 self.progress.completedUnitCount += 1
self.finish(.success(())) self.finish(.success(()))
} catch { } catch {
@@ -57,9 +70,5 @@ final class SendAppOperation: ResultOperation<()>
self.progress.completedUnitCount += 1 self.progress.completedUnitCount += 1
self.finish(.success(())) self.finish(.success(()))
} }
} else {
print("IPA doesn't exist????")
self.finish(.failure(OperationError(.appNotFound(name: resignedApp.name))))
}
} }
} }

View File

@@ -40,9 +40,7 @@ final class SceneDelegate: UIResponder, UIWindowSceneDelegate
guard DatabaseManager.shared.isStarted else { return } guard DatabaseManager.shared.isStarted else { return }
AppManager.shared.update() AppManager.shared.update()
if UserDefaults.standard.enableEMPforWireguard {
start_em_proxy(bind_addr: Consts.Proxy.serverURL) start_em_proxy(bind_addr: Consts.Proxy.serverURL)
}
PatreonAPI.shared.refreshPatreonAccount() PatreonAPI.shared.refreshPatreonAccount()
} }
@@ -58,9 +56,7 @@ final class SceneDelegate: UIResponder, UIWindowSceneDelegate
// Make sure to update AppDelegate.applicationDidEnterBackground() as well. // Make sure to update AppDelegate.applicationDidEnterBackground() as well.
// TODO: @mahee96: find if we need to stop em_proxy as in altstore? // TODO: @mahee96: find if we need to stop em_proxy as in altstore?
if UserDefaults.standard.enableEMPforWireguard { // stop_em_proxy()
stop_em_proxy()
}
guard let oneMonthAgo = Calendar.current.date(byAdding: .month, value: -1, to: Date()) else { return } guard let oneMonthAgo = Calendar.current.date(byAdding: .month, value: -1, to: Date()) else { return }
@@ -146,61 +142,8 @@ private extension SceneDelegate
NotificationCenter.default.post(name: AppDelegate.addSourceDeepLinkNotification, object: nil, userInfo: [AppDelegate.addSourceDeepLinkURLKey: sourceURL]) NotificationCenter.default.post(name: AppDelegate.addSourceDeepLinkNotification, object: nil, userInfo: [AppDelegate.addSourceDeepLinkURLKey: sourceURL])
} }
case "pairing":
let queryItems = components.queryItems?.reduce(into: [String: String]()) { $0[$1.name.lowercased()] = $1.value } ?? [:]
Logger.main.info("queryItems \(queryItems)")
guard let callbackTemplate = queryItems["urlname"]?.removingPercentEncoding else { return }
DispatchQueue.main.async {
exportPairingFile(callbackTemplate)
}
case "certificate":
let queryItems = components.queryItems?.reduce(into: [String: String]()) { $0[$1.name.lowercased()] = $1.value } ?? [:]
guard let callbackTemplate = queryItems["callback_template"]?.removingPercentEncoding else { return }
DispatchQueue.main.async {
NotificationCenter.default.post(name: AppDelegate.exportCertificateNotification, object: nil, userInfo: [AppDelegate.exportCertificateCallbackTemplateKey: callbackTemplate])
}
default: break default: break
} }
} }
} }
} }
func exportPairingFile(_ urlname: String) {
if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
let window = windowScene.windows.first, let viewcontroller = window.rootViewController {
let fm = FileManager.default
let documentsPath = fm.documentsDirectory.appendingPathComponent("ALTPairingFile.mobiledevicepairing")
guard let data = try? Data(contentsOf: documentsPath) else {
let toastView = ToastView(text: NSLocalizedString("Failed to find Pairing File!", comment: ""), detailText: nil)
toastView.show(in: viewcontroller)
return
}
let base64encodedCert = data.base64EncodedString()
var allowedQueryParamAndKey = NSCharacterSet.urlQueryAllowed
allowedQueryParamAndKey.remove(charactersIn: ";/?:@&=+$, ")
guard let encodedCert = base64encodedCert.addingPercentEncoding(withAllowedCharacters: allowedQueryParamAndKey) else {
let toastView = ToastView(text: NSLocalizedString("Failed to encode pairingFile!", comment: ""), detailText: nil)
toastView.show(in: viewcontroller)
return
}
var urlStr = "\(urlname)://pairingFile?data=$(BASE64_PAIRING)"
let finished = urlStr.replacingOccurrences(of: "$(BASE64_PAIRING)", with: encodedCert, options: .literal, range: nil)
print(finished)
guard let callbackUrl = URL(string: finished) else {
let toastView = ToastView(text: NSLocalizedString("Failed to initialize callback URL!", comment: ""), detailText: nil)
toastView.show(in: viewcontroller)
return
}
UIApplication.shared.open(callbackUrl)
}
}

View File

@@ -380,8 +380,13 @@ private extension ErrorLogViewController
func searchFAQ(for loggedError: LoggedError) func searchFAQ(for loggedError: LoggedError)
{ {
let staticURL = URL(string: "https://docs.sidestore.io/docs/troubleshooting/error-codes")! let baseURL = URL(string: "https://faq.altstore.io/getting-started/error-codes")!
let safariViewController = SFSafariViewController(url: staticURL) var components = URLComponents(url: baseURL, resolvingAgainstBaseURL: false)!
let query = [loggedError.domain, "\(loggedError.error.displayCode)"].joined(separator: "+")
components.queryItems = [URLQueryItem(name: "q", value: query)]
let safariViewController = SFSafariViewController(url: components.url ?? baseURL)
safariViewController.preferredControlTintColor = .altPrimary safariViewController.preferredControlTintColor = .altPrimary
self.present(safariViewController, animated: true) self.present(safariViewController, animated: true)
} }

View File

@@ -82,7 +82,7 @@ final class AboutPatreonHeaderView: UICollectionReusableView
imageView.layer.cornerRadius = imageView.bounds.midY imageView.layer.cornerRadius = imageView.bounds.midY
} }
for button in [self.supportButton, self.accountButton, self.twitterButton, self.instagramButton].compactMap({$0}) for button in [self.supportButton, self.accountButton].compactMap({$0})
{ {
button.clipsToBounds = true button.clipsToBounds = true
button.layer.cornerRadius = 16 button.layer.cornerRadius = 16

View File

@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="24412" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="5Rz-4h-jJ8"> <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="5Rz-4h-jJ8">
<device id="retina6_3" orientation="portrait" appearance="light"/> <device id="retina6_3" orientation="portrait" appearance="light"/>
<dependencies> <dependencies>
<deployment identifier="iOS"/> <deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="24405"/> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
<capability name="Image references" minToolsVersion="12.0"/> <capability name="Image references" minToolsVersion="12.0"/>
<capability name="Named colors" minToolsVersion="9.0"/> <capability name="Named colors" minToolsVersion="9.0"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/> <capability name="Safe area layout guides" minToolsVersion="9.0"/>
@@ -22,7 +22,7 @@
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> <color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="separatorColor" white="1" alpha="0.25" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> <color key="separatorColor" white="1" alpha="0.25" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<stackView key="tableFooterView" opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="equalCentering" alignment="center" spacing="15" id="48g-cT-stR"> <stackView key="tableFooterView" opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="equalCentering" alignment="center" spacing="15" id="48g-cT-stR">
<rect key="frame" x="0.0" y="2352.3333301544189" width="402" height="125"/> <rect key="frame" x="0.0" y="1986.3333377838135" width="402" height="125"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews> <subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="900" text="Follow SideStore for updates" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="XFa-MY-7cV"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="900" text="Follow SideStore for updates" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="XFa-MY-7cV">
@@ -104,7 +104,7 @@
<tableViewSection headerTitle="" id="flW-d4-bco"> <tableViewSection headerTitle="" id="flW-d4-bco">
<cells> <cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" textLabel="7lu-Yk-87t" rowHeight="51" style="IBUITableViewCellStyleDefault" id="DzJ-TL-jvR" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" textLabel="7lu-Yk-87t" rowHeight="51" style="IBUITableViewCellStyleDefault" id="DzJ-TL-jvR" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="17.666666030883789" width="402" height="51"/> <rect key="frame" x="0.0" y="22.333333969116211" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="DzJ-TL-jvR" id="XnZ-bO-peM"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="DzJ-TL-jvR" id="XnZ-bO-peM">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/> <rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
@@ -134,7 +134,7 @@
<tableViewSection headerTitle="" id="CAI-9J-8fR"> <tableViewSection headerTitle="" id="CAI-9J-8fR">
<cells> <cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" textLabel="xvY-lN-Toz" detailTextLabel="CnN-M1-AYK" rowHeight="51" style="IBUITableViewCellStyleValue1" id="kCH-yh-bMk" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" textLabel="xvY-lN-Toz" detailTextLabel="CnN-M1-AYK" rowHeight="51" style="IBUITableViewCellStyleValue1" id="kCH-yh-bMk" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="104.33333206176758" width="402" height="51"/> <rect key="frame" x="0.0" y="113.66666793823242" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="kCH-yh-bMk" id="MQ9-Qn-bWg"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="kCH-yh-bMk" id="MQ9-Qn-bWg">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/> <rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
@@ -166,7 +166,7 @@
</userDefinedRuntimeAttributes> </userDefinedRuntimeAttributes>
</tableViewCell> </tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" textLabel="rAc-lQ-B1k" detailTextLabel="0uP-Cd-tNX" rowHeight="51" style="IBUITableViewCellStyleValue1" id="q11-3k-oIm" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" textLabel="rAc-lQ-B1k" detailTextLabel="0uP-Cd-tNX" rowHeight="51" style="IBUITableViewCellStyleValue1" id="q11-3k-oIm" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="155.33333206176758" width="402" height="51"/> <rect key="frame" x="0.0" y="164.66666793823242" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="q11-3k-oIm" id="QCY-a8-Lhx"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="q11-3k-oIm" id="QCY-a8-Lhx">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/> <rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
@@ -198,7 +198,7 @@
</userDefinedRuntimeAttributes> </userDefinedRuntimeAttributes>
</tableViewCell> </tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" textLabel="Sge-cM-Fw9" detailTextLabel="434-MW-Den" rowHeight="51" style="IBUITableViewCellStyleValue1" id="vuc-eX-w3f" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" textLabel="Sge-cM-Fw9" detailTextLabel="434-MW-Den" rowHeight="51" style="IBUITableViewCellStyleValue1" id="vuc-eX-w3f" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="206.33333206176758" width="402" height="51"/> <rect key="frame" x="0.0" y="215.66666793823242" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="vuc-eX-w3f" id="wpD-YB-mrf"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="vuc-eX-w3f" id="wpD-YB-mrf">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/> <rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
@@ -234,7 +234,7 @@
<tableViewSection id="YHi-gR-wed"> <tableViewSection id="YHi-gR-wed">
<cells> <cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="R1C-Gr-xD4" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="R1C-Gr-xD4" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="293.33333206176758" width="402" height="51"/> <rect key="frame" x="0.0" y="302.66666793823242" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="R1C-Gr-xD4" id="Ojx-7f-z7E"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="R1C-Gr-xD4" id="Ojx-7f-z7E">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/> <rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
@@ -275,7 +275,7 @@
<tableViewSection id="RpS-Hn-sQU"> <tableViewSection id="RpS-Hn-sQU">
<cells> <cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="9dU-Hl-NiJ" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="9dU-Hl-NiJ" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="380.33333206176758" width="402" height="51"/> <rect key="frame" x="0.0" y="389.66666793823242" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="9dU-Hl-NiJ" id="w62-f1-Ody"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="9dU-Hl-NiJ" id="w62-f1-Ody">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/> <rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
@@ -316,7 +316,7 @@
<tableViewSection headerTitle="" id="2dM-lg-cRI"> <tableViewSection headerTitle="" id="2dM-lg-cRI">
<cells> <cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="Rra-U5-kCd" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="Rra-U5-kCd" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="466.99999809265137" width="402" height="51"/> <rect key="frame" x="0.0" y="481.00000190734863" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Rra-U5-kCd" id="8gV-kx-lGe"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Rra-U5-kCd" id="8gV-kx-lGe">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/> <rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
@@ -329,7 +329,7 @@
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="DPu-zD-Als"> <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="DPu-zD-Als">
<rect key="frame" x="311" y="11.666666666666664" width="63" height="28"/> <rect key="frame" x="323" y="10" width="51" height="31"/>
<connections> <connections>
<action selector="toggleIsBackgroundRefreshEnabled:" destination="aMk-Xp-UL8" eventType="valueChanged" id="gK5-Wr-8Hh"/> <action selector="toggleIsBackgroundRefreshEnabled:" destination="aMk-Xp-UL8" eventType="valueChanged" id="gK5-Wr-8Hh"/>
</connections> </connections>
@@ -350,43 +350,8 @@
</userDefinedRuntimeAttribute> </userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes> </userDefinedRuntimeAttributes>
</tableViewCell> </tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="7rt-MT-kFH" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="517.99999809265137" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="7rt-MT-kFH" id="mZL-UA-6V0">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Enable EMP for wireguard" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ZH7-ZA-Epf" userLabel="Enable EMP for wireguard">
<rect key="frame" x="30" y="15.333333333333334" width="209" height="20.333333333333329"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="8qE-hE-Ujn">
<rect key="frame" x="311" y="11.666666666666664" width="63" height="28"/>
<connections>
<action selector="toggleEnableEMPforWireguard:" destination="aMk-Xp-UL8" eventType="valueChanged" id="B0Q-Jb-fox"/>
</connections>
</switch>
</subviews>
<constraints>
<constraint firstAttribute="trailingMargin" secondItem="8qE-hE-Ujn" secondAttribute="trailing" id="KgO-N1-7Bw"/>
<constraint firstItem="ZH7-ZA-Epf" firstAttribute="leading" secondItem="mZL-UA-6V0" secondAttribute="leadingMargin" id="MBP-lj-8f5"/>
<constraint firstItem="ZH7-ZA-Epf" firstAttribute="centerY" secondItem="mZL-UA-6V0" secondAttribute="centerY" id="Pht-1f-5K3"/>
<constraint firstItem="8qE-hE-Ujn" firstAttribute="centerY" secondItem="mZL-UA-6V0" secondAttribute="centerY" id="vhM-Am-Jpo"/>
</constraints>
</tableViewCellContentView>
<color key="backgroundColor" white="1" alpha="0.14999999999999999" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<edgeInsets key="layoutMargins" top="8" left="30" bottom="8" right="30"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="style">
<integer key="value" value="2"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="GYp-O0-pse" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="GYp-O0-pse" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="568.99999809265137" width="402" height="51"/> <rect key="frame" x="0.0" y="532.00000190734863" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="GYp-O0-pse" id="vDG-ZV-xRS"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="GYp-O0-pse" id="vDG-ZV-xRS">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/> <rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
@@ -399,7 +364,7 @@
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="iQA-wm-5ag"> <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="iQA-wm-5ag">
<rect key="frame" x="311" y="11.666666666666664" width="63" height="28"/> <rect key="frame" x="323" y="10" width="51" height="31"/>
<connections> <connections>
<action selector="toggleNoIdleTimeoutEnabled:" destination="aMk-Xp-UL8" eventType="valueChanged" id="WSl-Jc-g5J"/> <action selector="toggleNoIdleTimeoutEnabled:" destination="aMk-Xp-UL8" eventType="valueChanged" id="WSl-Jc-g5J"/>
</connections> </connections>
@@ -421,7 +386,7 @@
</userDefinedRuntimeAttributes> </userDefinedRuntimeAttributes>
</tableViewCell> </tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="amC-sE-8O0" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="amC-sE-8O0" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="619.99999809265137" width="402" height="51"/> <rect key="frame" x="0.0" y="583.00000190734863" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="amC-sE-8O0" id="GEO-2e-E4k"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="amC-sE-8O0" id="GEO-2e-E4k">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/> <rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
@@ -449,7 +414,7 @@
</userDefinedRuntimeAttributes> </userDefinedRuntimeAttributes>
</tableViewCell> </tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="7PQ-AW-GcV" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="7PQ-AW-GcV" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="670.99999809265137" width="402" height="51"/> <rect key="frame" x="0.0" y="634.00000190734863" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="7PQ-AW-GcV" id="wQ8-9w-iiw"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="7PQ-AW-GcV" id="wQ8-9w-iiw">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/> <rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
@@ -462,7 +427,7 @@
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="1aa-og-ZXD"> <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="1aa-og-ZXD">
<rect key="frame" x="311" y="11.666666666666664" width="63" height="28"/> <rect key="frame" x="323" y="10" width="51" height="31"/>
<connections> <connections>
<action selector="toggleDisableAppLimit:" destination="aMk-Xp-UL8" eventType="valueChanged" id="zYc-B2-JPg"/> <action selector="toggleDisableAppLimit:" destination="aMk-Xp-UL8" eventType="valueChanged" id="zYc-B2-JPg"/>
</connections> </connections>
@@ -488,7 +453,7 @@
<tableViewSection headerTitle="" id="eHy-qI-w5w"> <tableViewSection headerTitle="" id="eHy-qI-w5w">
<cells> <cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="30h-59-88f" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="30h-59-88f" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="757.66666412353516" width="402" height="51"/> <rect key="frame" x="0.0" y="725.33333587646484" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="30h-59-88f" id="7qD-DW-Jls"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="30h-59-88f" id="7qD-DW-Jls">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/> <rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
@@ -529,19 +494,19 @@
<tableViewSection id="1fc-f1-ALD"> <tableViewSection id="1fc-f1-ALD">
<cells> <cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="7Ek-Ls-QVO" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="7Ek-Ls-QVO" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="844.66666412353516" width="402" height="51"/> <rect key="frame" x="0.0" y="812.33333587646484" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="7Ek-Ls-QVO" id="KjD-M3-oNg"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="7Ek-Ls-QVO" id="KjD-M3-oNg">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/> <rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="View Error Log" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="vH6-7i-tCE"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="View Error Log" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="vH6-7i-tCE">
<rect key="frame" x="30" y="15.333333333333334" width="119" height="20.333333333333329"/> <rect key="frame" x="30" y="15.333333333333334" width="119" height="20.333333333333329"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/> <fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="AeT-qF-bwB"> <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="AeT-qF-bwB">
<rect key="frame" x="356.33333333333331" y="14.333333333333334" width="15.666666666666686" height="22.333333333333329"/> <rect key="frame" x="356.33333333333331" y="14.333333333333334" width="15.666666666666686" height="22.333333333333329"/>
<imageReference key="image" image="chevron.right" catalog="system" symbolScale="large"/> <imageReference key="image" image="chevron.right" catalog="system" symbolScale="large"/>
</imageView> </imageView>
@@ -566,13 +531,13 @@
</connections> </connections>
</tableViewCell> </tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="hFh-X1-ZAi" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="hFh-X1-ZAi" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="895.66666412353516" width="402" height="51"/> <rect key="frame" x="0.0" y="863.33333587646484" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="hFh-X1-ZAi" id="nCs-Ro-A6t"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="hFh-X1-ZAi" id="nCs-Ro-A6t">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/> <rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Clear Cache…" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="j4e-Mz-DlL"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Clear Cache…" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="j4e-Mz-DlL">
<rect key="frame" x="29.999999999999993" y="15.333333333333334" width="114.33333333333331" height="20.333333333333329"/> <rect key="frame" x="29.999999999999993" y="15.333333333333334" width="114.33333333333331" height="20.333333333333329"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/> <fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
@@ -598,28 +563,28 @@
<tableViewSection headerTitle="" id="J90-vn-u2O"> <tableViewSection headerTitle="" id="J90-vn-u2O">
<cells> <cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="i4T-2q-jF3" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="i4T-2q-jF3" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="982.33333015441895" width="402" height="51"/> <rect key="frame" x="0.0" y="954.66666984558105" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="i4T-2q-jF3" id="VTQ-H4-aCM"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="i4T-2q-jF3" id="VTQ-H4-aCM">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/> <rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Developers" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="hRA-OK-Vjw"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Developers" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="hRA-OK-Vjw">
<rect key="frame" x="30" y="15.333333333333334" width="86" height="20.333333333333329"/> <rect key="frame" x="30" y="15.333333333333334" width="86" height="20.333333333333329"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/> <fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" white="1" alpha="0.80000000000000004" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> <color key="textColor" white="1" alpha="0.80000000000000004" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<stackView opaque="NO" contentMode="scaleToFill" spacing="14" translatesAutoresizingMaskIntoConstraints="NO" id="lx9-35-OSk"> <stackView opaque="NO" contentMode="scaleToFill" ambiguous="YES" spacing="14" translatesAutoresizingMaskIntoConstraints="NO" id="lx9-35-OSk">
<rect key="frame" x="217" y="15.333333333333334" width="155" height="20.333333333333329"/> <rect key="frame" x="217" y="15.333333333333336" width="155" height="20.333333333333329"/>
<subviews> <subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="SideStore Team" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="JAA-iZ-VGb"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="SideStore Team" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="JAA-iZ-VGb">
<rect key="frame" x="0.0" y="0.0" width="125.33333333333333" height="20.333333333333332"/> <rect key="frame" x="0.0" y="0.0" width="125.33333333333333" height="20.333333333333332"/>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="17"/> <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Mmj-3V-fTb"> <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Mmj-3V-fTb">
<rect key="frame" x="139.33333333333331" y="-1" width="15.666666666666657" height="22.333333333333332"/> <rect key="frame" x="139.33333333333331" y="-1" width="15.666666666666657" height="22.333333333333332"/>
<imageReference key="image" image="chevron.right" catalog="system" symbolScale="large"/> <imageReference key="image" image="chevron.right" catalog="system" symbolScale="large"/>
</imageView> </imageView>
@@ -643,7 +608,7 @@
</userDefinedRuntimeAttributes> </userDefinedRuntimeAttributes>
</tableViewCell> </tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="oHX-oR-nwJ" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="oHX-oR-nwJ" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="1033.3333301544189" width="402" height="51"/> <rect key="frame" x="0.0" y="1005.6666698455811" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="oHX-oR-nwJ" id="hN4-i5-igu"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="oHX-oR-nwJ" id="hN4-i5-igu">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/> <rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
@@ -688,7 +653,7 @@
</userDefinedRuntimeAttributes> </userDefinedRuntimeAttributes>
</tableViewCell> </tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="0MT-ht-Sit" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="0MT-ht-Sit" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="1084.3333301544189" width="402" height="51"/> <rect key="frame" x="0.0" y="1056.6666698455811" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="0MT-ht-Sit" id="OZp-WM-5H7"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="0MT-ht-Sit" id="OZp-WM-5H7">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/> <rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
@@ -733,7 +698,7 @@
</userDefinedRuntimeAttributes> </userDefinedRuntimeAttributes>
</tableViewCell> </tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="O5R-Al-lGj" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="O5R-Al-lGj" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="1135.3333301544189" width="402" height="51"/> <rect key="frame" x="0.0" y="1071.6666698455811" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="O5R-Al-lGj" id="CrG-Mr-xQq"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="O5R-Al-lGj" id="CrG-Mr-xQq">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/> <rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
@@ -774,19 +739,19 @@
<tableViewSection headerTitle="" id="OMa-EK-hRI"> <tableViewSection headerTitle="" id="OMa-EK-hRI">
<cells> <cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="FMZ-as-Ljo" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="FMZ-as-Ljo" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="1221.9999961853027" width="402" height="51"/> <rect key="frame" x="0.0" y="1163.0000038146973" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="FMZ-as-Ljo" id="JzL-Of-A3T"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="FMZ-as-Ljo" id="JzL-Of-A3T">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/> <rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Send Feedback" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="pMI-Aj-nQF"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Send Feedback" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="pMI-Aj-nQF">
<rect key="frame" x="29.999999999999993" y="15.333333333333334" width="125.33333333333331" height="20.333333333333329"/> <rect key="frame" x="29.999999999999993" y="15.333333333333334" width="125.33333333333331" height="20.333333333333329"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/> <fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Jyy-x0-Owj"> <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Jyy-x0-Owj">
<rect key="frame" x="356.33333333333331" y="14.333333333333334" width="15.666666666666686" height="22.333333333333329"/> <rect key="frame" x="356.33333333333331" y="14.333333333333334" width="15.666666666666686" height="22.333333333333329"/>
<imageReference key="image" image="chevron.right" catalog="system" symbolScale="large"/> <imageReference key="image" image="chevron.right" catalog="system" symbolScale="large"/>
</imageView> </imageView>
@@ -808,19 +773,19 @@
</userDefinedRuntimeAttributes> </userDefinedRuntimeAttributes>
</tableViewCell> </tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="Qca-pU-sJh" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="Qca-pU-sJh" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="1272.9999961853027" width="402" height="51"/> <rect key="frame" x="0.0" y="1214.0000038146973" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Qca-pU-sJh" id="QtU-8J-VQN"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Qca-pU-sJh" id="QtU-8J-VQN">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/> <rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="View Refresh Attempts" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="sni-07-q0M"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="View Refresh Attempts" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="sni-07-q0M">
<rect key="frame" x="30" y="15.333333333333334" width="187.66666666666666" height="20.333333333333329"/> <rect key="frame" x="30" y="15.333333333333334" width="187.66666666666666" height="20.333333333333329"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/> <fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="4d3-me-Hqc"> <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="4d3-me-Hqc">
<rect key="frame" x="356.33333333333331" y="14.333333333333334" width="15.666666666666686" height="22.333333333333329"/> <rect key="frame" x="356.33333333333331" y="14.333333333333334" width="15.666666666666686" height="22.333333333333329"/>
<imageReference key="image" image="chevron.right" catalog="system" symbolScale="large"/> <imageReference key="image" image="chevron.right" catalog="system" symbolScale="large"/>
</imageView> </imageView>
@@ -845,19 +810,19 @@
</connections> </connections>
</tableViewCell> </tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="VrV-qI-zXF" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="VrV-qI-zXF" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="1323.9999961853027" width="402" height="51"/> <rect key="frame" x="0.0" y="1265.0000038146973" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="VrV-qI-zXF" id="w1r-uY-4pD"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="VrV-qI-zXF" id="w1r-uY-4pD">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/> <rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="SideJITServer" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="46q-DB-5nc"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="SideJITServer" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="46q-DB-5nc">
<rect key="frame" x="29.999999999999993" y="15.333333333333334" width="115.33333333333331" height="20.333333333333329"/> <rect key="frame" x="29.999999999999993" y="15.333333333333334" width="115.33333333333331" height="20.333333333333329"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/> <fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="wvD-eZ-nQI"> <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="wvD-eZ-nQI">
<rect key="frame" x="356.33333333333331" y="14.333333333333334" width="15.666666666666686" height="22.333333333333329"/> <rect key="frame" x="356.33333333333331" y="14.333333333333334" width="15.666666666666686" height="22.333333333333329"/>
<imageReference key="image" image="chevron.right" catalog="system" symbolScale="large"/> <imageReference key="image" image="chevron.right" catalog="system" symbolScale="large"/>
</imageView> </imageView>
@@ -879,19 +844,19 @@
</userDefinedRuntimeAttributes> </userDefinedRuntimeAttributes>
</tableViewCell> </tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="VNn-u4-cN8" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="VNn-u4-cN8" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="1374.9999961853027" width="402" height="51"/> <rect key="frame" x="0.0" y="1316.0000038146973" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="VNn-u4-cN8" id="4bh-qe-l2N"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="VNn-u4-cN8" id="4bh-qe-l2N">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/> <rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Reset Pairing File" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ysS-9s-dXm"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Reset Pairing File" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ysS-9s-dXm">
<rect key="frame" x="30" y="15.333333333333334" width="140" height="20.333333333333329"/> <rect key="frame" x="30" y="15.333333333333334" width="140" height="20.333333333333329"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/> <fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="r09-mH-pOD"> <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="r09-mH-pOD">
<rect key="frame" x="356.33333333333331" y="14.333333333333334" width="15.666666666666686" height="22.333333333333329"/> <rect key="frame" x="356.33333333333331" y="14.333333333333334" width="15.666666666666686" height="22.333333333333329"/>
<imageReference key="image" image="chevron.right" catalog="system" symbolScale="large"/> <imageReference key="image" image="chevron.right" catalog="system" symbolScale="large"/>
</imageView> </imageView>
@@ -913,19 +878,19 @@
</userDefinedRuntimeAttributes> </userDefinedRuntimeAttributes>
</tableViewCell> </tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="e7s-hL-kv9" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="e7s-hL-kv9" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="1425.9999961853027" width="402" height="51"/> <rect key="frame" x="0.0" y="1367.0000038146973" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="e7s-hL-kv9" id="yjL-Mu-HTk"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="e7s-hL-kv9" id="yjL-Mu-HTk">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/> <rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Anisette Servers" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="eds-Dj-36y"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Anisette Servers" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="eds-Dj-36y">
<rect key="frame" x="30" y="15.333333333333334" width="135.66666666666666" height="20.333333333333329"/> <rect key="frame" x="30" y="15.333333333333334" width="135.66666666666666" height="20.333333333333329"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/> <fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="0dh-yd-7i9"> <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="0dh-yd-7i9">
<rect key="frame" x="356.33333333333331" y="14.333333333333334" width="15.666666666666686" height="22.333333333333329"/> <rect key="frame" x="356.33333333333331" y="14.333333333333334" width="15.666666666666686" height="22.333333333333329"/>
<imageReference key="image" image="chevron.right" catalog="system" symbolScale="large"/> <imageReference key="image" image="chevron.right" catalog="system" symbolScale="large"/>
</imageView> </imageView>
@@ -947,20 +912,20 @@
</userDefinedRuntimeAttributes> </userDefinedRuntimeAttributes>
</tableViewCell> </tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="XW5-Zc-nXH" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="XW5-Zc-nXH" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="1476.9999961853027" width="402" height="51"/> <rect key="frame" x="0.0" y="1418.0000038146973" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="XW5-Zc-nXH" id="AtM-bL-8pS"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="XW5-Zc-nXH" id="AtM-bL-8pS">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/> <rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Enable Beta Updates" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="2px-HD-0UT"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Enable Beta Updates" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="2px-HD-0UT">
<rect key="frame" x="30" y="15.333333333333334" width="169" height="20.333333333333329"/> <rect key="frame" x="30" y="15.333333333333334" width="169" height="20.333333333333329"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/> <fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" ambiguous="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="e32-w4-5fk"> <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="e32-w4-5fk">
<rect key="frame" x="311" y="11.666666666666664" width="63" height="28"/> <rect key="frame" x="323" y="10" width="51" height="31"/>
<connections> <connections>
<action selector="toggleEnableBetaUpdates:" destination="aMk-Xp-UL8" eventType="valueChanged" id="uxG-df-7GK"/> <action selector="toggleEnableBetaUpdates:" destination="aMk-Xp-UL8" eventType="valueChanged" id="uxG-df-7GK"/>
</connections> </connections>
@@ -982,19 +947,19 @@
</userDefinedRuntimeAttributes> </userDefinedRuntimeAttributes>
</tableViewCell> </tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="qbY-8c-LYT" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="qbY-8c-LYT" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="1527.9999961853027" width="402" height="51"/> <rect key="frame" x="0.0" y="1469.0000038146973" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="qbY-8c-LYT" id="NxK-qB-w7Q"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="qbY-8c-LYT" id="NxK-qB-w7Q">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/> <rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Beta Updates Track" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="5J9-vR-vhX" userLabel="Beta Track Label"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Beta Updates Track" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="5J9-vR-vhX" userLabel="Beta Track Label">
<rect key="frame" x="30" y="15.333333333333334" width="159.66666666666666" height="20.333333333333329"/> <rect key="frame" x="30" y="15.333333333333334" width="159.66666666666666" height="20.333333333333329"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/> <fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<button opaque="NO" contentMode="scaleToFill" ambiguous="YES" showsMenuAsPrimaryAction="YES" contentHorizontalAlignment="right" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" changesSelectionAsPrimaryAction="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Oct-iT-NwP" userLabel="Beta Track Drop Down Button"> <button opaque="NO" contentMode="scaleToFill" showsMenuAsPrimaryAction="YES" contentHorizontalAlignment="right" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" changesSelectionAsPrimaryAction="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Oct-iT-NwP" userLabel="Beta Track Drop Down Button">
<rect key="frame" x="301.66666666666669" y="8.3333333333333321" width="70.333333333333314" height="34.333333333333343"/> <rect key="frame" x="301.66666666666669" y="8.3333333333333321" width="70.333333333333314" height="34.333333333333343"/>
<constraints> <constraints>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="50" id="new-width-constraint"/> <constraint firstAttribute="width" relation="greaterThanOrEqual" constant="50" id="new-width-constraint"/>
@@ -1020,139 +985,23 @@
</tableViewCell> </tableViewCell>
</cells> </cells>
</tableViewSection> </tableViewSection>
<tableViewSection id="ZhW-yK-wdJ">
<cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="qjD-UK-myl" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="1614.9999961853027" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="qjD-UK-myl" id="bcu-KT-Xee">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Import Account..." textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="jts-UA-M8d">
<rect key="frame" x="30" y="15.333333333333334" width="143" height="20.333333333333329"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<constraints>
<constraint firstItem="jts-UA-M8d" firstAttribute="centerY" secondItem="bcu-KT-Xee" secondAttribute="centerY" id="9Wq-8a-v4s"/>
<constraint firstItem="jts-UA-M8d" firstAttribute="leading" secondItem="bcu-KT-Xee" secondAttribute="leadingMargin" id="rTG-U2-MOH"/>
</constraints>
</tableViewCellContentView>
<color key="backgroundColor" white="1" alpha="0.14999999999999999" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<edgeInsets key="layoutMargins" top="8" left="30" bottom="8" right="30"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="style">
<integer key="value" value="1"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="boolean" keyPath="isSelectable" value="YES"/>
</userDefinedRuntimeAttributes>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="dNh-fp-vBs" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="1665.9999961853027" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="dNh-fp-vBs" id="Meb-tV-6br">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Export Account..." textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="uHg-iq-d36">
<rect key="frame" x="30" y="15.333333333333334" width="142.33333333333334" height="20.333333333333329"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<constraints>
<constraint firstItem="uHg-iq-d36" firstAttribute="leading" secondItem="Meb-tV-6br" secondAttribute="leadingMargin" id="P8L-Yt-APv"/>
<constraint firstItem="uHg-iq-d36" firstAttribute="centerY" secondItem="Meb-tV-6br" secondAttribute="centerY" id="bkY-rp-t3t"/>
</constraints>
</tableViewCellContentView>
<color key="backgroundColor" white="1" alpha="0.14999999999999999" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<edgeInsets key="layoutMargins" top="8" left="30" bottom="8" right="30"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="style">
<integer key="value" value="2"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="boolean" keyPath="isSelectable" value="YES"/>
</userDefinedRuntimeAttributes>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="Y6h-Bo-yec" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="1716.9999961853027" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Y6h-Bo-yec" id="4Jf-I6-v7z">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Import Signing Certificate..." textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="rv6-S1-2gw">
<rect key="frame" x="30.000000000000014" y="15.333333333333334" width="227.33333333333337" height="20.333333333333329"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<constraints>
<constraint firstItem="rv6-S1-2gw" firstAttribute="leading" secondItem="4Jf-I6-v7z" secondAttribute="leadingMargin" id="7zH-bg-kLS"/>
<constraint firstItem="rv6-S1-2gw" firstAttribute="centerY" secondItem="4Jf-I6-v7z" secondAttribute="centerY" id="Yls-DF-HHr"/>
</constraints>
</tableViewCellContentView>
<color key="backgroundColor" white="1" alpha="0.14999999999999999" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<edgeInsets key="layoutMargins" top="8" left="30" bottom="8" right="30"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="style">
<integer key="value" value="2"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="boolean" keyPath="isSelectable" value="YES"/>
</userDefinedRuntimeAttributes>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="dLk-d6-X4T" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="1767.9999961853027" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="dLk-d6-X4T" id="Okl-3m-rde">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Export Signing Certificate..." textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="WPe-mj-W7t">
<rect key="frame" x="29.999999999999986" y="15.333333333333334" width="226.66666666666663" height="20.333333333333329"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<constraints>
<constraint firstItem="WPe-mj-W7t" firstAttribute="leading" secondItem="Okl-3m-rde" secondAttribute="leadingMargin" id="9g7-9Z-ZZQ"/>
<constraint firstItem="WPe-mj-W7t" firstAttribute="centerY" secondItem="Okl-3m-rde" secondAttribute="centerY" id="RiS-WT-srl"/>
</constraints>
</tableViewCellContentView>
<color key="backgroundColor" white="1" alpha="0.14999999999999999" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<edgeInsets key="layoutMargins" top="8" left="30" bottom="8" right="30"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="style">
<integer key="value" value="3"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="boolean" keyPath="isSelectable" value="YES"/>
</userDefinedRuntimeAttributes>
</tableViewCell>
</cells>
</tableViewSection>
<tableViewSection headerTitle="" id="lLQ-K0-XSb"> <tableViewSection headerTitle="" id="lLQ-K0-XSb">
<cells> <cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="daQ-mk-yqC" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="daQ-mk-yqC" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="1854.6666622161865" width="402" height="51"/> <rect key="frame" x="0.0" y="1560.3333377838135" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="daQ-mk-yqC" id="ZkW-ZR-twy"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="daQ-mk-yqC" id="ZkW-ZR-twy">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/> <rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Disable Response Caching" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="jFh-36-AP2"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Disable Response Caching" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="jFh-36-AP2">
<rect key="frame" x="30.000000000000014" y="15.333333333333334" width="215.33333333333337" height="20.333333333333329"/> <rect key="frame" x="30.000000000000014" y="15.333333333333334" width="215.33333333333337" height="20.333333333333329"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/> <fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" ambiguous="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="AAh-cu-qw8"> <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="AAh-cu-qw8">
<rect key="frame" x="311" y="11.666666666666664" width="63" height="28"/> <rect key="frame" x="323" y="10" width="51" height="31"/>
<connections> <connections>
<action selector="toggleDisableResponseCaching:" destination="aMk-Xp-UL8" eventType="valueChanged" id="lCm-qi-piH"/> <action selector="toggleDisableResponseCaching:" destination="aMk-Xp-UL8" eventType="valueChanged" id="lCm-qi-piH"/>
</connections> </connections>
@@ -1174,20 +1023,20 @@
</userDefinedRuntimeAttributes> </userDefinedRuntimeAttributes>
</tableViewCell> </tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="hRP-jU-2hd" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="hRP-jU-2hd" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="1905.6666622161865" width="402" height="51"/> <rect key="frame" x="0.0" y="1611.3333377838135" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="hRP-jU-2hd" id="JhE-O4-pRg"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="hRP-jU-2hd" id="JhE-O4-pRg">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/> <rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Export Resigned Apps" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="d5F-bf-6kB"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Export Resigned Apps" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="d5F-bf-6kB">
<rect key="frame" x="30" y="15.333333333333334" width="180" height="20.333333333333329"/> <rect key="frame" x="30" y="15.333333333333334" width="180" height="20.333333333333329"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/> <fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" ambiguous="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="GYP-qn-wzh"> <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="GYP-qn-wzh">
<rect key="frame" x="311" y="11.666666666666664" width="63" height="28"/> <rect key="frame" x="323" y="10" width="51" height="31"/>
<connections> <connections>
<action selector="toggleResignedAppExport:" destination="aMk-Xp-UL8" eventType="valueChanged" id="Z1k-xh-sjD"/> <action selector="toggleResignedAppExport:" destination="aMk-Xp-UL8" eventType="valueChanged" id="Z1k-xh-sjD"/>
</connections> </connections>
@@ -1209,20 +1058,20 @@
</userDefinedRuntimeAttributes> </userDefinedRuntimeAttributes>
</tableViewCell> </tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="JoN-Aj-XtZ" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="JoN-Aj-XtZ" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="1956.6666622161865" width="402" height="51"/> <rect key="frame" x="0.0" y="1662.3333377838135" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="JoN-Aj-XtZ" id="v8Q-VQ-Q1h"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="JoN-Aj-XtZ" id="v8Q-VQ-Q1h">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/> <rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Enable Verbose Ops Logging" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="7bz-tI-tLY"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Enable Verbose Ops Logging" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="7bz-tI-tLY">
<rect key="frame" x="29.999999999999986" y="15.333333333333334" width="232.66666666666663" height="20.333333333333329"/> <rect key="frame" x="29.999999999999986" y="15.333333333333334" width="232.66666666666663" height="20.333333333333329"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/> <fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" ambiguous="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Q5X-Mo-KpE"> <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Q5X-Mo-KpE">
<rect key="frame" x="311" y="11.666666666666664" width="63" height="28"/> <rect key="frame" x="323" y="10" width="51" height="31"/>
<connections> <connections>
<action selector="toggleVerboseOperationsLogging:" destination="aMk-Xp-UL8" eventType="valueChanged" id="n9N-Gt-OY2"/> <action selector="toggleVerboseOperationsLogging:" destination="aMk-Xp-UL8" eventType="valueChanged" id="n9N-Gt-OY2"/>
</connections> </connections>
@@ -1244,13 +1093,13 @@
</userDefinedRuntimeAttributes> </userDefinedRuntimeAttributes>
</tableViewCell> </tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="QOO-bO-4M5" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="QOO-bO-4M5" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="2007.6666622161865" width="402" height="51"/> <rect key="frame" x="0.0" y="1713.3333377838135" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="QOO-bO-4M5" id="VTT-z5-C89"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="QOO-bO-4M5" id="VTT-z5-C89">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/> <rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Export Database..." textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Ho1-To-wve" userLabel="Export Database"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Export Database..." textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Ho1-To-wve" userLabel="Export Database">
<rect key="frame" x="30" y="15.333333333333334" width="151.66666666666666" height="20.333333333333329"/> <rect key="frame" x="30" y="15.333333333333334" width="151.66666666666666" height="20.333333333333329"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/> <fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
@@ -1272,13 +1121,13 @@
</userDefinedRuntimeAttributes> </userDefinedRuntimeAttributes>
</tableViewCell> </tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="ToB-H7-2lR" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="ToB-H7-2lR" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="2058.6666622161865" width="402" height="51"/> <rect key="frame" x="0.0" y="1764.3333377838135" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="ToB-H7-2lR" id="Acf-xV-Isn"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="ToB-H7-2lR" id="Acf-xV-Isn">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/> <rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Delete Database..." textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="CcF-9x-Eu8" userLabel="Delete Database Label"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Delete Database..." textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="CcF-9x-Eu8" userLabel="Delete Database Label">
<rect key="frame" x="30" y="15.333333333333334" width="150.33333333333334" height="20.333333333333329"/> <rect key="frame" x="30" y="15.333333333333334" width="150.33333333333334" height="20.333333333333329"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/> <fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
@@ -1300,19 +1149,19 @@
</userDefinedRuntimeAttributes> </userDefinedRuntimeAttributes>
</tableViewCell> </tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="xtI-eU-LFb" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="xtI-eU-LFb" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="2109.6666622161865" width="402" height="51"/> <rect key="frame" x="0.0" y="1815.3333377838135" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="xtI-eU-LFb" id="bc9-41-6mE"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="xtI-eU-LFb" id="bc9-41-6mE">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/> <rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Operations Logging Control" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="LW3-gm-lj5"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Operations Logging Control" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="LW3-gm-lj5">
<rect key="frame" x="30.000000000000014" y="15.333333333333334" width="224.33333333333337" height="20.333333333333329"/> <rect key="frame" x="30.000000000000014" y="15.333333333333334" width="224.33333333333337" height="20.333333333333329"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/> <fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="zl4-ti-HTW"> <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="zl4-ti-HTW">
<rect key="frame" x="356.33333333333331" y="14.333333333333334" width="15.666666666666686" height="22.333333333333329"/> <rect key="frame" x="356.33333333333331" y="14.333333333333334" width="15.666666666666686" height="22.333333333333329"/>
<imageReference key="image" image="chevron.right" catalog="system" symbolScale="large"/> <imageReference key="image" image="chevron.right" catalog="system" symbolScale="large"/>
</imageView> </imageView>
@@ -1334,19 +1183,19 @@
</userDefinedRuntimeAttributes> </userDefinedRuntimeAttributes>
</tableViewCell> </tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="pvu-IV-Poa" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="pvu-IV-Poa" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="2160.6666622161865" width="402" height="51"/> <rect key="frame" x="0.0" y="1866.3333377838135" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="pvu-IV-Poa" id="zck-an-8cK"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="pvu-IV-Poa" id="zck-an-8cK">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/> <rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Recreate Database on Next Start" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ZRk-8S-kBQ" userLabel="Recreate Database Label"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Recreate Database on Next Start" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ZRk-8S-kBQ" userLabel="Recreate Database Label">
<rect key="frame" x="30" y="15.333333333333334" width="265.33333333333331" height="20.333333333333329"/> <rect key="frame" x="30" y="15.333333333333334" width="265.33333333333331" height="20.333333333333329"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/> <fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" ambiguous="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="uGv-Lb-Ita" userLabel="Recreate DB switch"> <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="uGv-Lb-Ita" userLabel="Recreate DB switch">
<rect key="frame" x="323" y="10" width="51" height="31"/> <rect key="frame" x="323" y="10" width="51" height="31"/>
<connections> <connections>
<action selector="toggleRecreateDatabaseSwitch:" destination="aMk-Xp-UL8" eventType="valueChanged" id="vlf-Iz-kWr"/> <action selector="toggleRecreateDatabaseSwitch:" destination="aMk-Xp-UL8" eventType="valueChanged" id="vlf-Iz-kWr"/>
@@ -1369,19 +1218,19 @@
</userDefinedRuntimeAttributes> </userDefinedRuntimeAttributes>
</tableViewCell> </tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="9By-QW-Jw9" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="9By-QW-Jw9" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="2211.6666622161865" width="402" height="51"/> <rect key="frame" x="0.0" y="1917.3333377838135" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="9By-QW-Jw9" id="Dzq-gE-zyT"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="9By-QW-Jw9" id="Dzq-gE-zyT">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/> <rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Minimuxer Console Logging" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="jW6-pb-xdP"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Minimuxer Console Logging" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="jW6-pb-xdP">
<rect key="frame" x="30.000000000000014" y="15.333333333333334" width="225.33333333333337" height="20.333333333333329"/> <rect key="frame" x="30.000000000000014" y="15.333333333333334" width="225.33333333333337" height="20.333333333333329"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/> <fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" ambiguous="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="os8-7F-rSm" userLabel="Minimuxer logging Switch"> <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="os8-7F-rSm" userLabel="Minimuxer logging Switch">
<rect key="frame" x="323" y="10" width="51" height="31"/> <rect key="frame" x="323" y="10" width="51" height="31"/>
<connections> <connections>
<action selector="toggleMinimuxerConsoleLogging:" destination="aMk-Xp-UL8" eventType="valueChanged" id="d0C-kx-aFV"/> <action selector="toggleMinimuxerConsoleLogging:" destination="aMk-Xp-UL8" eventType="valueChanged" id="d0C-kx-aFV"/>
@@ -1397,41 +1246,6 @@
</tableViewCellContentView> </tableViewCellContentView>
<color key="backgroundColor" white="1" alpha="0.14999999999999999" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> <color key="backgroundColor" white="1" alpha="0.14999999999999999" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<edgeInsets key="layoutMargins" top="8" left="30" bottom="8" right="30"/> <edgeInsets key="layoutMargins" top="8" left="30" bottom="8" right="30"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="style">
<integer key="value" value="2"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="LzP-Qb-bmC" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="2262.6666622161865" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="LzP-Qb-bmC" id="3rE-h0-8kb">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Minimuxer Status Check" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="3BY-c1-QEV" userLabel="Minimuxer Status Check">
<rect key="frame" x="30.000000000000014" y="15.333333333333334" width="198.33333333333337" height="20.333333333333329"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" ambiguous="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="AB6-Ok-Faf" userLabel="Minimuxer Check Switch">
<rect key="frame" x="323" y="10" width="51" height="31"/>
<connections>
<action selector="toggleMinimuxerStatusCheck:" destination="aMk-Xp-UL8" eventType="valueChanged" id="Kwh-Km-aLj"/>
</connections>
</switch>
</subviews>
<constraints>
<constraint firstAttribute="trailingMargin" secondItem="AB6-Ok-Faf" secondAttribute="trailing" id="EtH-X0-plP"/>
<constraint firstItem="AB6-Ok-Faf" firstAttribute="centerY" secondItem="3rE-h0-8kb" secondAttribute="centerY" id="Tc3-56-q7s"/>
<constraint firstItem="3BY-c1-QEV" firstAttribute="centerY" secondItem="3rE-h0-8kb" secondAttribute="centerY" id="kIV-xS-Ava"/>
<constraint firstItem="3BY-c1-QEV" firstAttribute="leading" secondItem="3rE-h0-8kb" secondAttribute="leadingMargin" id="pJS-6V-6vh"/>
</constraints>
</tableViewCellContentView>
<color key="backgroundColor" white="1" alpha="0.14999999999999999" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<edgeInsets key="layoutMargins" top="8" left="30" bottom="8" right="30"/>
<userDefinedRuntimeAttributes> <userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="style"> <userDefinedRuntimeAttribute type="number" keyPath="style">
<integer key="value" value="3"/> <integer key="value" value="3"/>
@@ -1457,7 +1271,6 @@
<outlet property="betaUpdatesSwitch" destination="e32-w4-5fk" id="kdn-ZR-cNU"/> <outlet property="betaUpdatesSwitch" destination="e32-w4-5fk" id="kdn-ZR-cNU"/>
<outlet property="disableAppLimitSwitch" destination="1aa-og-ZXD" id="oVL-Md-yZ8"/> <outlet property="disableAppLimitSwitch" destination="1aa-og-ZXD" id="oVL-Md-yZ8"/>
<outlet property="disableResponseCachingSwitch" destination="AAh-cu-qw8" id="aVT-Md-yZ8"/> <outlet property="disableResponseCachingSwitch" destination="AAh-cu-qw8" id="aVT-Md-yZ8"/>
<outlet property="enableEMPforWireguard" destination="8qE-hE-Ujn" id="VC2-PV-cea"/>
<outlet property="exportResignedAppsSwitch" destination="GYP-qn-wzh" id="aVL-Md-yZ8"/> <outlet property="exportResignedAppsSwitch" destination="GYP-qn-wzh" id="aVL-Md-yZ8"/>
<outlet property="githubButton" destination="oqj-4S-I9l" id="sxB-LE-gA2"/> <outlet property="githubButton" destination="oqj-4S-I9l" id="sxB-LE-gA2"/>
<outlet property="mastodonButton" destination="B8Q-e7-beR" id="Kbe-Og-rsg"/> <outlet property="mastodonButton" destination="B8Q-e7-beR" id="Kbe-Og-rsg"/>
@@ -1482,9 +1295,8 @@
<toolbarItems/> <toolbarItems/>
<simulatedTabBarMetrics key="simulatedBottomBarMetrics"/> <simulatedTabBarMetrics key="simulatedBottomBarMetrics"/>
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" barStyle="black" largeTitles="YES" id="Jtn-cs-Tvp" customClass="NavigationBar" customModule="SideStore" customModuleProvider="target"> <navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" barStyle="black" largeTitles="YES" id="Jtn-cs-Tvp" customClass="NavigationBar" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="124" width="402" height="106"/> <rect key="frame" x="0.0" y="62" width="402" height="96"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<edgeInsets key="layoutMargins" top="8" left="20" bottom="8" right="8"/>
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> <color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="barTintColor" name="SettingsBackground"/> <color key="barTintColor" name="SettingsBackground"/>
<textAttributes key="titleTextAttributes"> <textAttributes key="titleTextAttributes">
@@ -1516,14 +1328,14 @@
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<prototypes> <prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="Cell" id="8Xf-RE-QJx" customClass="RefreshAttemptTableViewCell"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="Cell" id="8Xf-RE-QJx" customClass="RefreshAttemptTableViewCell">
<rect key="frame" x="0.0" y="50" width="402" height="73.333335876464844"/> <rect key="frame" x="0.0" y="50" width="402" height="64.666664123535156"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="8Xf-RE-QJx" id="r3G-oh-AyQ"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="8Xf-RE-QJx" id="r3G-oh-AyQ">
<rect key="frame" x="0.0" y="0.0" width="402" height="73.333335876464844"/> <rect key="frame" x="0.0" y="0.0" width="402" height="64.666664123535156"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="4" translatesAutoresizingMaskIntoConstraints="NO" id="SN9-pA-GDU"> <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="4" translatesAutoresizingMaskIntoConstraints="NO" id="SN9-pA-GDU">
<rect key="frame" x="20" y="15.000000000000004" width="362" height="43.333333333333343"/> <rect key="frame" x="20" y="10.999999999999996" width="362" height="42.666666666666657"/>
<subviews> <subviews>
<stackView opaque="NO" contentMode="scaleToFill" distribution="equalSpacing" translatesAutoresizingMaskIntoConstraints="NO" id="SqJ-wP-gO1"> <stackView opaque="NO" contentMode="scaleToFill" distribution="equalSpacing" translatesAutoresizingMaskIntoConstraints="NO" id="SqJ-wP-gO1">
<rect key="frame" x="0.0" y="0.0" width="362" height="20.333333333333332"/> <rect key="frame" x="0.0" y="0.0" width="362" height="20.333333333333332"/>
@@ -1543,7 +1355,7 @@
</subviews> </subviews>
</stackView> </stackView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Could not connect to SideStore." textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="7L1-AA-2yo"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Could not connect to SideStore." textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="7L1-AA-2yo">
<rect key="frame" x="0.0" y="24.333333333333336" width="362" height="19"/> <rect key="frame" x="0.0" y="24.333333333333336" width="362" height="18.333333333333336"/>
<fontDescription key="fontDescription" type="system" pointSize="15"/> <fontDescription key="fontDescription" type="system" pointSize="15"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
@@ -1584,7 +1396,7 @@
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews> <subviews>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" layoutMarginsFollowReadableWidth="YES" contentInsetAdjustmentBehavior="never" indicatorStyle="white" editable="NO" translatesAutoresizingMaskIntoConstraints="NO" id="oQQ-pR-oKc"> <textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" layoutMarginsFollowReadableWidth="YES" contentInsetAdjustmentBehavior="never" indicatorStyle="white" editable="NO" translatesAutoresizingMaskIntoConstraints="NO" id="oQQ-pR-oKc">
<rect key="frame" x="0.0" y="178" width="402" height="579"/> <rect key="frame" x="0.0" y="106" width="402" height="685"/>
<edgeInsets key="layoutMargins" top="8" left="30" bottom="8" right="30"/> <edgeInsets key="layoutMargins" top="8" left="30" bottom="8" right="30"/>
<string key="text">Jay Freeman (ldid) <string key="text">Jay Freeman (ldid)
Copyright (C) 2007-2012 Jay Freeman (saurik) Copyright (C) 2007-2012 Jay Freeman (saurik)
@@ -1783,17 +1595,17 @@ Settings by i cons from the Noun Project</string>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<prototypes> <prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="Cell" id="HAm-mA-O78" customClass="ErrorLogTableViewCell"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="Cell" id="HAm-mA-O78" customClass="ErrorLogTableViewCell">
<rect key="frame" x="20" y="55.333332061767578" width="362" height="116"/> <rect key="frame" x="20" y="55.333332061767578" width="362" height="107.33333587646484"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="HAm-mA-O78" id="swa-et-rfA"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="HAm-mA-O78" id="swa-et-rfA">
<rect key="frame" x="0.0" y="0.0" width="362" height="116"/> <rect key="frame" x="0.0" y="0.0" width="362" height="107.33333587646484"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="mtw-JM-T70"> <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="mtw-JM-T70">
<rect key="frame" x="16" y="15" width="330" height="86"/> <rect key="frame" x="20" y="11" width="322" height="85.333333333333329"/>
<subviews> <subviews>
<stackView opaque="NO" contentMode="scaleToFill" alignment="top" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="bjU-TX-4lm" userLabel="Compact"> <stackView opaque="NO" contentMode="scaleToFill" alignment="top" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="bjU-TX-4lm" userLabel="Compact">
<rect key="frame" x="0.0" y="0.0" width="330" height="44"/> <rect key="frame" x="0.0" y="0.0" width="322" height="43.333333333333336"/>
<subviews> <subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="sDZ-ZN-NT1" customClass="AppIconImageView" customModule="SideStore" customModuleProvider="target"> <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="sDZ-ZN-NT1" customClass="AppIconImageView" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="43" height="43"/> <rect key="frame" x="0.0" y="0.0" width="43" height="43"/>
@@ -1803,10 +1615,10 @@ Settings by i cons from the Noun Project</string>
</constraints> </constraints>
</imageView> </imageView>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="equalSpacing" spacing="4" translatesAutoresizingMaskIntoConstraints="NO" id="82d-v0-RCp"> <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="equalSpacing" spacing="4" translatesAutoresizingMaskIntoConstraints="NO" id="82d-v0-RCp">
<rect key="frame" x="51" y="0.0" width="279" height="39"/> <rect key="frame" x="51" y="0.0" width="271" height="39"/>
<subviews> <subviews>
<stackView opaque="NO" contentMode="scaleToFill" distribution="equalSpacing" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="Q2j-Tc-bp2"> <stackView opaque="NO" contentMode="scaleToFill" distribution="equalSpacing" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="Q2j-Tc-bp2">
<rect key="frame" x="0.0" y="0.0" width="279" height="18"/> <rect key="frame" x="0.0" y="0.0" width="271" height="18"/>
<subviews> <subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Success" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="Na7-uj-XYZ"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Success" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="Na7-uj-XYZ">
<rect key="frame" x="0.0" y="0.0" width="60" height="18"/> <rect key="frame" x="0.0" y="0.0" width="60" height="18"/>
@@ -1815,7 +1627,7 @@ Settings by i cons from the Noun Project</string>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="751" text="Date" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="SGf-pP-RL0"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="751" text="Date" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="SGf-pP-RL0">
<rect key="frame" x="248.66666666666671" y="0.0" width="30.333333333333343" height="18"/> <rect key="frame" x="240.66666666666669" y="0.0" width="30.333333333333314" height="18"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/> <fontDescription key="fontDescription" type="system" pointSize="14"/>
<color key="textColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> <color key="textColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
@@ -1823,7 +1635,7 @@ Settings by i cons from the Noun Project</string>
</subviews> </subviews>
</stackView> </stackView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Error Code" textAlignment="natural" lineBreakMode="headTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="R5a-wv-xHd"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Error Code" textAlignment="natural" lineBreakMode="headTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="R5a-wv-xHd">
<rect key="frame" x="0.0" y="22" width="279" height="17"/> <rect key="frame" x="0.0" y="22" width="271" height="17"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/> <fontDescription key="fontDescription" type="system" pointSize="14"/>
<color key="textColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> <color key="textColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
@@ -1833,7 +1645,7 @@ Settings by i cons from the Noun Project</string>
</subviews> </subviews>
</stackView> </stackView>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" scrollEnabled="NO" editable="NO" text="Error Description" textAlignment="natural" selectable="NO" layoutManager="textKit1" translatesAutoresizingMaskIntoConstraints="NO" id="1df-ri-hKN" customClass="CollapsingTextView" customModule="SideStore" customModuleProvider="target"> <textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" scrollEnabled="NO" editable="NO" text="Error Description" textAlignment="natural" selectable="NO" layoutManager="textKit1" translatesAutoresizingMaskIntoConstraints="NO" id="1df-ri-hKN" customClass="CollapsingTextView" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="52" width="330" height="34"/> <rect key="frame" x="0.0" y="51.333333333333343" width="322" height="34"/>
<accessibility key="accessibilityConfiguration"> <accessibility key="accessibilityConfiguration">
<accessibilityTraits key="traits" staticText="YES"/> <accessibilityTraits key="traits" staticText="YES"/>
<bool key="isElement" value="NO"/> <bool key="isElement" value="NO"/>
@@ -1845,7 +1657,7 @@ Settings by i cons from the Noun Project</string>
</subviews> </subviews>
</stackView> </stackView>
<button opaque="NO" contentMode="scaleToFill" showsMenuAsPrimaryAction="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ba2-EY-tf5" customClass="ErrorLogMenuButton"> <button opaque="NO" contentMode="scaleToFill" showsMenuAsPrimaryAction="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ba2-EY-tf5" customClass="ErrorLogMenuButton">
<rect key="frame" x="0.0" y="0.0" width="362" height="116"/> <rect key="frame" x="0.0" y="0.0" width="362" height="107.33333333333333"/>
<accessibility key="accessibilityConfiguration"> <accessibility key="accessibilityConfiguration">
<bool key="isElement" value="NO"/> <bool key="isElement" value="NO"/>
</accessibility> </accessibility>
@@ -1916,11 +1728,11 @@ Settings by i cons from the Noun Project</string>
<objects> <objects>
<viewController id="xB2-Se-VVg" customClass="ErrorDetailsViewController" customModule="SideStore" customModuleProvider="target" sceneMemberID="viewController"> <viewController id="xB2-Se-VVg" customClass="ErrorDetailsViewController" customModule="SideStore" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="eBQ-se-VIy"> <view key="view" contentMode="scaleToFill" id="eBQ-se-VIy">
<rect key="frame" x="0.0" y="0.0" width="402" height="812"/> <rect key="frame" x="0.0" y="0.0" width="402" height="864"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews> <subviews>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" scrollEnabled="NO" editable="NO" textAlignment="natural" translatesAutoresizingMaskIntoConstraints="NO" id="ctd-NB-4ov"> <textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" scrollEnabled="NO" editable="NO" textAlignment="natural" translatesAutoresizingMaskIntoConstraints="NO" id="ctd-NB-4ov">
<rect key="frame" x="0.0" y="0.0" width="402" height="812"/> <rect key="frame" x="0.0" y="0.0" width="402" height="864"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/> <color key="backgroundColor" systemColor="systemBackgroundColor"/>
<color key="textColor" systemColor="labelColor"/> <color key="textColor" systemColor="labelColor"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/> <fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
@@ -1958,9 +1770,8 @@ Settings by i cons from the Noun Project</string>
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="7gm-d1-zWK" sceneMemberID="viewController"> <navigationController automaticallyAdjustsScrollViewInsets="NO" id="7gm-d1-zWK" sceneMemberID="viewController">
<toolbarItems/> <toolbarItems/>
<navigationBar key="navigationBar" contentMode="scaleToFill" id="dI0-sh-yGf"> <navigationBar key="navigationBar" contentMode="scaleToFill" id="dI0-sh-yGf">
<rect key="frame" x="0.0" y="16" width="402" height="54"/> <rect key="frame" x="0.0" y="0.0" width="402" height="56"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<edgeInsets key="layoutMargins" top="8" left="20" bottom="8" right="8"/>
</navigationBar> </navigationBar>
<nil name="viewControllers"/> <nil name="viewControllers"/>
<connections> <connections>

View File

@@ -16,8 +16,6 @@ import IntentsUI
import SemanticVersion import SemanticVersion
import AltStoreCore import AltStoreCore
import CAltSign
import UniformTypeIdentifiers
extension SettingsViewController extension SettingsViewController
{ {
@@ -32,7 +30,6 @@ extension SettingsViewController
case techyThings case techyThings
case credits case credits
case advancedSettings case advancedSettings
case signing
// diagnostics section, will be enabled on release builds only on swipe down with 3 fingers 3 times // diagnostics section, will be enabled on release builds only on swipe down with 3 fingers 3 times
case diagnostics case diagnostics
// case macDirtyCow // case macDirtyCow
@@ -83,13 +80,6 @@ extension SettingsViewController
// case hiddenSettings // case hiddenSettings
} }
fileprivate enum SigningSettingsRow: Int, CaseIterable {
case importAccount
case exportAccount
case importCert
case exportCert
}
fileprivate enum DiagnosticsRow: Int, CaseIterable fileprivate enum DiagnosticsRow: Int, CaseIterable
{ {
case responseCaching case responseCaching
@@ -121,7 +111,6 @@ final class SettingsViewController: UITableViewController
@IBOutlet private var accountTypeLabel: UILabel! @IBOutlet private var accountTypeLabel: UILabel!
@IBOutlet private var backgroundRefreshSwitch: UISwitch! @IBOutlet private var backgroundRefreshSwitch: UISwitch!
@IBOutlet private var enableEMPforWireguard: UISwitch!
@IBOutlet private var noIdleTimeoutSwitch: UISwitch! @IBOutlet private var noIdleTimeoutSwitch: UISwitch!
@IBOutlet private var disableAppLimitSwitch: UISwitch! @IBOutlet private var disableAppLimitSwitch: UISwitch!
@IBOutlet private var betaUpdatesSwitch: UISwitch! @IBOutlet private var betaUpdatesSwitch: UISwitch!
@@ -154,7 +143,6 @@ final class SettingsViewController: UITableViewController
NotificationCenter.default.addObserver(self, selector: #selector(SettingsViewController.openPatreonSettings(_:)), name: AppDelegate.openPatreonSettingsDeepLinkNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(SettingsViewController.openPatreonSettings(_:)), name: AppDelegate.openPatreonSettingsDeepLinkNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(SettingsViewController.openErrorLog(_:)), name: ToastView.openErrorLogNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(SettingsViewController.openErrorLog(_:)), name: ToastView.openErrorLogNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(SettingsViewController.openExportCertificateConfirm(_:)), name: AppDelegate.exportCertificateNotification, object: nil)
} }
@@ -203,16 +191,6 @@ final class SettingsViewController: UITableViewController
{ {
super.viewDidLoad() super.viewDidLoad()
// --- iOS 26 fix ---
if #available(iOS 26.0, *) {
let appearance = UINavigationBarAppearance()
// appearance.configureWithOpaqueBackground() // or .defaultBackground if you want blur
// appearance.backgroundColor = UIColor(named: "SettingsBackground")
appearance.titleTextAttributes = [.foregroundColor: UIColor.white]
appearance.largeTitleTextAttributes = [.foregroundColor: UIColor.white]
navigationController?.navigationBar.standardAppearance = appearance
navigationController?.navigationBar.scrollEdgeAppearance = appearance // required for iOS 26, maybe enforce it in storyboard?
}
let nib = UINib(nibName: "SettingsHeaderFooterView", bundle: nil) let nib = UINib(nibName: "SettingsHeaderFooterView", bundle: nil)
self.prototypeHeaderFooterView = nib.instantiate(withOwner: nil, options: nil)[0] as? SettingsHeaderFooterView self.prototypeHeaderFooterView = nib.instantiate(withOwner: nil, options: nil)[0] as? SettingsHeaderFooterView
@@ -258,120 +236,6 @@ final class SettingsViewController: UITableViewController
} }
configureReleaseChannelButton() configureReleaseChannelButton()
#if !targetEnvironment(simulator)
detectAndImportAccountFile()
#endif
}
func importAccountAtFile(_ file: URL, remove: Bool = false) {
_ = file.startAccessingSecurityScopedResource()
defer { file.stopAccessingSecurityScopedResource() }
guard let accountD = try? Data(contentsOf: file) else {
let toastView = ToastView(text: NSLocalizedString("Could not read data from file!", comment: ""), detailText: "\(file)")
return toastView.show(in: self)
}
guard let account = try? Foundation.JSONDecoder().decode(ImportedAccount.self, from: accountD) else {
let toastView = ToastView(text: NSLocalizedString("Could not parse data from file!", comment: ""), detailText: "\(file)")
return toastView.show(in: self)
}
print("We want to import this account probably: \(account)")
if remove {
try? FileManager.default.removeItem(at: file)
}
Keychain.shared.appleIDEmailAddress = account.email
Keychain.shared.appleIDPassword = account.password
Keychain.shared.adiPb = account.adiPB
Keychain.shared.identifier = account.local_user
signIn()
update()
if let altCert = ALTCertificate(p12Data: account.cert, password: account.certpass) {
Keychain.shared.signingCertificate = altCert.encryptedP12Data(withPassword: "")!
Keychain.shared.signingCertificatePassword = account.certpass
let toastView = ToastView(text: NSLocalizedString("Successfully imported '\(account.email)'!", comment: ""), detailText: "SideStore should be fully operational!")
return toastView.show(in: self)
} else {
let toastView = ToastView(text: NSLocalizedString("Failed to import account certificate!", comment: ""), detailText: "Failed to create ALTCertificate. Check if the password is correct. Still imported account/adi.pb details!")
return toastView.show(in: self)
}
}
func detectAndImportAccountFile() {
let accountFileURL = FileManager.default.documentsDirectory.appendingPathComponent("Account.sideconf")
#if !DEBUG
importAccountAtFile(accountFileURL, remove: true)
#else
importAccountAtFile(accountFileURL)
#endif
}
func exportAccount(_ certpass: String) -> ImportedAccount? {
guard let email = Keychain.shared.appleIDEmailAddress,
let password = Keychain.shared.appleIDPassword,
let cert = Keychain.shared.signingCertificate,
let identifier = Keychain.shared.identifier,
let adiPB = Keychain.shared.adiPb else {
#if DEBUG
print(Keychain.shared.appleIDEmailAddress ?? "Empty email")
print(Keychain.shared.appleIDPassword ?? "Empty password")
print(Keychain.shared.signingCertificate ?? "Empty cert")
print(Keychain.shared.identifier ?? "Empty identifier")
print(Keychain.shared.adiPb ?? "Empty adiPb")
#endif
return nil
}
return ImportedAccount(email: email, password: password, cert: cert, certpass: certpass, local_user: identifier, adiPB: adiPB)
}
func showExportAccount() {
Task {
guard let password = await withUnsafeContinuation({ (c: UnsafeContinuation<String?,Never>) in
let alertController = UIAlertController(title: NSLocalizedString("Please enter the password for the certificate.", comment: ""), message: nil, preferredStyle: .alert)
alertController.addTextField { (textField) in
textField.autocorrectionType = .no
textField.autocapitalizationType = .none
}
let submitAction = UIAlertAction(title: NSLocalizedString("OK", comment: ""), style: .default) { (action) in
let textField = alertController.textFields?.first
let code = textField?.text ?? ""
c.resume(returning: code)
}
alertController.addAction(submitAction)
alertController.addAction(UIAlertAction(title: NSLocalizedString("Cancel", comment: ""), style: .cancel) { (action) in
c.resume(returning: nil)
})
self.present(alertController, animated: true)
}) else {
return
}
guard let account = exportAccount(password) else {
let toastView = ToastView(text: NSLocalizedString("Failed to export account!", comment: ""), detailText: "Account not found.")
return toastView.show(in: self)
}
guard let accountData = try? Foundation.JSONEncoder().encode(account) else {
let toastView = ToastView(text: NSLocalizedString("Failed to export account data!", comment: ""), detailText: "Account malformed.")
toastView.show(in: self)
return
}
let accountTmpPath = FileManager.default.temporaryDirectory.appendingPathComponent("\(account.email).sideconf")
do {
try accountData.write(to: accountTmpPath)
} catch {
let toastView = ToastView(text: NSLocalizedString("Failed to export account!", comment: ""), detailText: error.localizedDescription)
toastView.show(in: self)
return
}
let exportVC = UIDocumentPickerViewController(forExporting: [accountTmpPath], asCopy: false)
self.present(exportVC, animated: true)
}
} }
override func viewWillAppear(_ animated: Bool) override func viewWillAppear(_ animated: Bool)
@@ -471,7 +335,6 @@ private extension SettingsViewController
// AppRefreshRow // AppRefreshRow
self.backgroundRefreshSwitch.isOn = UserDefaults.standard.isBackgroundRefreshEnabled self.backgroundRefreshSwitch.isOn = UserDefaults.standard.isBackgroundRefreshEnabled
self.enableEMPforWireguard.isOn = UserDefaults.standard.enableEMPforWireguard
self.noIdleTimeoutSwitch.isOn = UserDefaults.standard.isIdleTimeoutDisableEnabled self.noIdleTimeoutSwitch.isOn = UserDefaults.standard.isIdleTimeoutDisableEnabled
self.disableAppLimitSwitch.isOn = UserDefaults.standard.isAppLimitDisabled self.disableAppLimitSwitch.isOn = UserDefaults.standard.isAppLimitDisabled
@@ -571,18 +434,6 @@ private extension SettingsViewController
case .advancedSettings: case .advancedSettings:
settingsHeaderFooterView.primaryLabel.text = NSLocalizedString("ADVANCED SETTINGS", comment: "") settingsHeaderFooterView.primaryLabel.text = NSLocalizedString("ADVANCED SETTINGS", comment: "")
case .signing:
// FIXME: Why "Enable Background Refresh ..." appear here if secondaryLabel is not specified???
if isHeader
{
settingsHeaderFooterView.primaryLabel.text = NSLocalizedString("SIGNING", comment: "")
}
else
{
settingsHeaderFooterView.secondaryLabel.text = NSLocalizedString("", comment: "")
}
case .diagnostics: case .diagnostics:
settingsHeaderFooterView.primaryLabel.text = NSLocalizedString("DIAGNOSTICS", comment: "") settingsHeaderFooterView.primaryLabel.text = NSLocalizedString("DIAGNOSTICS", comment: "")
@@ -702,11 +553,6 @@ private extension SettingsViewController
UserDefaults.standard.isMinimuxerConsoleLoggingEnabled = sender.isOn UserDefaults.standard.isMinimuxerConsoleLoggingEnabled = sender.isOn
} }
@IBAction func toggleMinimuxerStatusCheck(_ sender: UISwitch) {
// update it in database
UserDefaults.standard.isMinimuxerStatusCheckEnabled = sender.isOn
}
@IBAction func toggleRecreateDatabaseSwitch(_ sender: UISwitch) { @IBAction func toggleRecreateDatabaseSwitch(_ sender: UISwitch) {
// Update the setting in UserDefaults // Update the setting in UserDefaults
UserDefaults.standard.recreateDatabaseOnNextStart = sender.isOn UserDefaults.standard.recreateDatabaseOnNextStart = sender.isOn
@@ -749,11 +595,6 @@ private extension SettingsViewController
UserDefaults.standard.isBackgroundRefreshEnabled = sender.isOn UserDefaults.standard.isBackgroundRefreshEnabled = sender.isOn
} }
@IBAction func toggleEnableEMPforWireguard(_ sender: UISwitch)
{
UserDefaults.standard.enableEMPforWireguard = sender.isOn
}
@IBAction func toggleNoIdleTimeoutEnabled(_ sender: UISwitch) @IBAction func toggleNoIdleTimeoutEnabled(_ sender: UISwitch)
{ {
UserDefaults.standard.isIdleTimeoutDisableEnabled = sender.isOn UserDefaults.standard.isIdleTimeoutDisableEnabled = sender.isOn
@@ -915,48 +756,6 @@ private extension SettingsViewController
self.performSegue(withIdentifier: "showErrorLog", sender: nil) self.performSegue(withIdentifier: "showErrorLog", sender: nil)
} }
} }
@objc func openExportCertificateConfirm(_ notification: Notification)
{
func export()
{
guard let template = notification.userInfo?[AppDelegate.exportCertificateCallbackTemplateKey] as? String,
template.contains("$(BASE64_CERT)") else {
let toastView = ToastView(text: NSLocalizedString("No $(BASE64_CERT) placeholder found", comment: ""), detailText: nil)
toastView.show(in: self)
return
}
guard let data = Keychain.shared.signingCertificate,
let password = Keychain.shared.signingCertificatePassword else {
let toastView = ToastView(text: NSLocalizedString("Failed to find certificate or password", comment: ""), detailText: nil)
toastView.show(in: self)
return
}
let base64encodedCert = data.base64EncodedString()
var allowedQueryParamAndKey = NSCharacterSet.urlQueryAllowed
allowedQueryParamAndKey.remove(charactersIn: ";/?:@&=+$, ")
guard let encodedCert = base64encodedCert.addingPercentEncoding(withAllowedCharacters: allowedQueryParamAndKey) else {
let toastView = ToastView(text: NSLocalizedString("Failed to encode certificate!", comment: ""), detailText: nil)
toastView.show(in: self)
return
}
var urlStr = template.replacingOccurrences(of: "$(BASE64_CERT)", with: encodedCert, options: .literal, range: nil)
urlStr = urlStr.replacingOccurrences(of: "$(PASSWORD)", with: password, options: .literal, range: nil)
print(urlStr)
guard let callbackUrl = URL(string: urlStr) else {
let toastView = ToastView(text: NSLocalizedString("Failed to initialize callback URL!", comment: ""), detailText: nil)
toastView.show(in: self)
return
}
UIApplication.shared.open(callbackUrl)
}
let alertController = UIAlertController(title: NSLocalizedString("Export Certificate", comment: ""), message: NSLocalizedString("Do you want to export your certificate to an external app? That app will be able to sign apps using your certificate.", comment: ""), preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: NSLocalizedString("Export", comment: ""), style: .default) { _ in export() })
alertController.addAction(.cancel)
self.present(alertController, animated: true, completion: nil)
}
} }
extension SettingsViewController extension SettingsViewController
@@ -1028,7 +827,7 @@ extension SettingsViewController
case _ where isSectionHidden(section): return nil case _ where isSectionHidden(section): return nil
case .signIn where self.activeTeam != nil: return nil case .signIn where self.activeTeam != nil: return nil
case .account where self.activeTeam == nil: return nil case .account where self.activeTeam == nil: return nil
case .signIn, .account, .patreon, .display, .appRefresh, .techyThings, .credits, .advancedSettings, .signing ,.diagnostics /* ,.macDirtyCow */: case .signIn, .account, .patreon, .display, .appRefresh, .techyThings, .credits, .advancedSettings, .diagnostics /* ,.macDirtyCow */:
let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: "HeaderFooterView") as! SettingsHeaderFooterView let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: "HeaderFooterView") as! SettingsHeaderFooterView
self.prepare(headerView, for: section, isHeader: true) self.prepare(headerView, for: section, isHeader: true)
return headerView return headerView
@@ -1045,7 +844,7 @@ extension SettingsViewController
case _ where isSectionHidden(section): return nil case _ where isSectionHidden(section): return nil
case .signIn where self.activeTeam != nil: return nil case .signIn where self.activeTeam != nil: return nil
// case .signIn, .patreon, .display, .appRefresh, .techyThings, .macDirtyCow: // case .signIn, .patreon, .display, .appRefresh, .techyThings, .macDirtyCow:
case .signIn, .patreon, .display, .appRefresh, .techyThings, .signing: case .signIn, .patreon, .display, .appRefresh, .techyThings:
let footerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: "HeaderFooterView") as! SettingsHeaderFooterView let footerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: "HeaderFooterView") as! SettingsHeaderFooterView
self.prepare(footerView, for: section, isHeader: false) self.prepare(footerView, for: section, isHeader: false)
return footerView return footerView
@@ -1063,7 +862,7 @@ extension SettingsViewController
case .signIn where self.activeTeam != nil: return 1.0 case .signIn where self.activeTeam != nil: return 1.0
case .account where self.activeTeam == nil: return 1.0 case .account where self.activeTeam == nil: return 1.0
// case .signIn, .account, .patreon, .display, .appRefresh, .techyThings, .credits, .macDirtyCow, .advanced: // case .signIn, .account, .patreon, .display, .appRefresh, .techyThings, .credits, .macDirtyCow, .advanced:
case .signIn, .account, .patreon, .display, .appRefresh, .techyThings, .credits, .advancedSettings, .signing, .diagnostics: case .signIn, .account, .patreon, .display, .appRefresh, .techyThings, .credits, .advancedSettings, .diagnostics:
let height = self.preferredHeight(for: self.prototypeHeaderFooterView, in: section, isHeader: true) let height = self.preferredHeight(for: self.prototypeHeaderFooterView, in: section, isHeader: true)
return height return height
@@ -1080,7 +879,7 @@ extension SettingsViewController
case .signIn where self.activeTeam != nil: return 1.0 case .signIn where self.activeTeam != nil: return 1.0
case .account where self.activeTeam == nil: return 1.0 case .account where self.activeTeam == nil: return 1.0
// case .signIn, .patreon, .display, .appRefresh, .techyThings, .macDirtyCow: // case .signIn, .patreon, .display, .appRefresh, .techyThings, .macDirtyCow:
case .signIn, .patreon, .display, .appRefresh, .techyThings, .signing, .diagnostics: case .signIn, .patreon, .display, .appRefresh, .techyThings, .diagnostics:
let height = self.preferredHeight(for: self.prototypeHeaderFooterView, in: section, isHeader: false) let height = self.preferredHeight(for: self.prototypeHeaderFooterView, in: section, isHeader: false)
return height return height
@@ -1355,161 +1154,6 @@ extension SettingsViewController
case .refreshAttempts, .betaUpdates, .betaTrack: break case .refreshAttempts, .betaUpdates, .betaTrack: break
} }
case .signing:
let row = SigningSettingsRow.allCases[indexPath.row]
switch row {
case .exportAccount: showExportAccount()
case .importAccount:
Task {
let confUrl = await withUnsafeContinuation { c in
let importVc = UIDocumentPickerViewController(forOpeningContentTypes: [UTType(filenameExtension: "sideconf")!], asCopy: false)
ImportExport.documentPickerHandler = DocumentPickerHandler { url in
c.resume(returning: url)
}
importVc.delegate = ImportExport.documentPickerHandler
self.present(importVc, animated: true)
}
guard let confUrl else {
return
}
importAccountAtFile(confUrl)
}
case .importCert:
let importVc = UIDocumentPickerViewController(forOpeningContentTypes: [UTType(filenameExtension: "p12")!], asCopy: false)
ImportExport.documentPickerHandler = DocumentPickerHandler { url in
guard let url else {
return
}
importVc.delegate = ImportExport.documentPickerHandler
self.present(importVc, animated: true)
_ = url.startAccessingSecurityScopedResource()
defer { url.stopAccessingSecurityScopedResource() }
}
Task {
let certUrl = await withUnsafeContinuation { c in
let importVc = UIDocumentPickerViewController(forOpeningContentTypes: [UTType(filenameExtension: "p12")!], asCopy: false)
ImportExport.documentPickerHandler = DocumentPickerHandler { url in
_ = url?.startAccessingSecurityScopedResource()
defer { url?.stopAccessingSecurityScopedResource() }
c.resume(returning: url)
}
importVc.delegate = ImportExport.documentPickerHandler
self.present(importVc, animated: true)
}
guard let certUrl else {
return
}
let password = await withUnsafeContinuation { (c: UnsafeContinuation<String?,Never>) in
let alertController = UIAlertController(title: NSLocalizedString("Please enter the password for the certificate.", comment: ""), message: nil, preferredStyle: .alert)
alertController.addTextField { (textField) in
textField.autocorrectionType = .no
textField.autocapitalizationType = .none
}
let submitAction = UIAlertAction(title: NSLocalizedString("OK", comment: ""), style: .default) { (action) in
let textField = alertController.textFields?.first
let code = textField?.text ?? ""
c.resume(returning: code)
}
alertController.addAction(submitAction)
alertController.addAction(UIAlertAction(title: NSLocalizedString("Cancel", comment: ""), style: .cancel) { (action) in
c.resume(returning: nil)
})
self.present(alertController, animated: true)
}
guard let password else {
return
}
_ = certUrl.startAccessingSecurityScopedResource()
defer {
certUrl.stopAccessingSecurityScopedResource()
}
let certData : Data
do {
certData = try Data(contentsOf: certUrl)
} catch {
let toastView = ToastView(text: NSLocalizedString("Failed to import certificate!", comment: ""), detailText: error.localizedDescription)
toastView.show(in: self)
return
}
guard let altCert = ALTCertificate(p12Data: certData, password: password) else {
let toastView = ToastView(text: NSLocalizedString("Failed to import certificate!", comment: ""), detailText: "Failed to create ALTCertificate. Check if the password is correct.")
toastView.show(in: self)
return
}
Keychain.shared.signingCertificate = altCert.encryptedP12Data(withPassword: "")!
let toastView = ToastView(text: NSLocalizedString("Certificate imported successfully!", comment: ""), detailText: nil)
toastView.show(in: self)
}
case .exportCert:
Task {
guard let certData = Keychain.shared.signingCertificate else {
let toastView = ToastView(text: NSLocalizedString("Failed to export certificate!", comment: ""), detailText: "Certificate not found.")
toastView.show(in: self)
return
}
let password = await withUnsafeContinuation { (c: UnsafeContinuation<String?,Never>) in
let alertController = UIAlertController(title: NSLocalizedString("Please enter the password for the certificate.", comment: ""), message: nil, preferredStyle: .alert)
alertController.addTextField { (textField) in
textField.autocorrectionType = .no
textField.autocapitalizationType = .none
}
let submitAction = UIAlertAction(title: NSLocalizedString("OK", comment: ""), style: .default) { (action) in
let textField = alertController.textFields?.first
let code = textField?.text ?? ""
c.resume(returning: code)
}
alertController.addAction(submitAction)
alertController.addAction(UIAlertAction(title: NSLocalizedString("Cancel", comment: ""), style: .cancel) { (action) in
c.resume(returning: nil)
})
self.present(alertController, animated: true)
}
guard let password else {
return
}
guard let altCert = ALTCertificate(p12Data: certData, password: nil) else {
let toastView = ToastView(text: NSLocalizedString("Failed to export certificate!", comment: ""), detailText: "Failed to create ALTCertificate. Check if the password is correct.")
toastView.show(in: self)
return
}
guard let newCertData = altCert.encryptedP12Data(withPassword: password) else {
let toastView = ToastView(text: NSLocalizedString("Failed to export certificate!", comment: ""), detailText: "Failed to encrypt ALTCertificate.")
toastView.show(in: self)
return
}
let newCertTmpPath = FileManager.default.temporaryDirectory.appendingPathComponent("SideStoreSigningCertificate.p12")
do {
try newCertData.write(to: newCertTmpPath)
} catch {
let toastView = ToastView(text: NSLocalizedString("Failed to export certificate!", comment: ""), detailText: error.localizedDescription)
toastView.show(in: self)
return
}
let exportVC = UIDocumentPickerViewController(forExporting: [newCertTmpPath], asCopy: false)
self.present(exportVC, animated: true)
}
}
case .diagnostics: case .diagnostics:
let row = DiagnosticsRow.allCases[indexPath.row] let row = DiagnosticsRow.allCases[indexPath.row]

View File

@@ -20,7 +20,6 @@
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" largeTitles="YES" id="xWh-1U-u0q" customClass="NavigationBar" customModule="SideStore" customModuleProvider="target"> <navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" largeTitles="YES" id="xWh-1U-u0q" customClass="NavigationBar" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="59" width="393" height="96"/> <rect key="frame" x="0.0" y="59" width="393" height="96"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<edgeInsets key="layoutMargins" top="8" left="20" bottom="8" right="8"/>
</navigationBar> </navigationBar>
<nil name="viewControllers"/> <nil name="viewControllers"/>
<connections> <connections>
@@ -249,7 +248,6 @@
<navigationBar key="navigationBar" contentMode="scaleToFill" largeTitles="YES" id="HLe-3g-P8I" customClass="NavigationBar" customModule="SideStore" customModuleProvider="target"> <navigationBar key="navigationBar" contentMode="scaleToFill" largeTitles="YES" id="HLe-3g-P8I" customClass="NavigationBar" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="393" height="108"/> <rect key="frame" x="0.0" y="0.0" width="393" height="108"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<edgeInsets key="layoutMargins" top="8" left="20" bottom="8" right="8"/>
</navigationBar> </navigationBar>
<nil name="viewControllers"/> <nil name="viewControllers"/>
<connections> <connections>

View File

@@ -46,14 +46,6 @@ final class SourcesViewController: UICollectionViewController
{ {
super.viewDidLoad() super.viewDidLoad()
// Ensure large titles
navigationController?.navigationBar.prefersLargeTitles = true
navigationItem.largeTitleDisplayMode = .automatic
// Set title
navigationItem.title = "Sources"
navigationController?.navigationBar.layoutMargins.left = 20
let layout = self.makeLayout() let layout = self.makeLayout()
self.collectionView.collectionViewLayout = layout self.collectionView.collectionViewLayout = layout

View File

@@ -36,7 +36,6 @@ final class TabBarController: UITabBarController
NotificationCenter.default.addObserver(self, selector: #selector(TabBarController.openPatreonSettings(_:)), name: AppDelegate.openPatreonSettingsDeepLinkNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(TabBarController.openPatreonSettings(_:)), name: AppDelegate.openPatreonSettingsDeepLinkNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(TabBarController.importApp(_:)), name: AppDelegate.importAppDeepLinkNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(TabBarController.importApp(_:)), name: AppDelegate.importAppDeepLinkNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(TabBarController.presentSources(_:)), name: AppDelegate.addSourceDeepLinkNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(TabBarController.presentSources(_:)), name: AppDelegate.addSourceDeepLinkNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(TabBarController.exportFiles(_:)), name: AppDelegate.exportCertificateNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(TabBarController.openErrorLog(_:)), name: ToastView.openErrorLogNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(TabBarController.openErrorLog(_:)), name: ToastView.openErrorLogNotification, object: nil)
} }
@@ -142,9 +141,4 @@ private extension TabBarController
{ {
self.selectedIndex = Tab.settings.rawValue self.selectedIndex = Tab.settings.rawValue
} }
@objc func exportFiles(_ notification: Notification)
{
self.selectedIndex = Tab.settings.rawValue
}
} }

View File

@@ -1,18 +0,0 @@
//
// ImportedAccount.swift
// AltStore
//
// Created by ny on 9/7/25.
// Copyright © 2025 SideStore. All rights reserved.
//
import Foundation
struct ImportedAccount: Codable {
let email: String
let password: String
let cert: Data
let certpass: String
let local_user: String
let adiPB: String
}

View File

@@ -30,15 +30,12 @@ public extension UserDefaults
@NSManaged var preferredServerID: String? @NSManaged var preferredServerID: String?
@NSManaged var isBackgroundRefreshEnabled: Bool @NSManaged var isBackgroundRefreshEnabled: Bool
@NSManaged var enableEMPforWireguard: Bool
@NSManaged var isIdleTimeoutDisableEnabled: Bool @NSManaged var isIdleTimeoutDisableEnabled: Bool
@NSManaged var isAppLimitDisabled: Bool @NSManaged var isAppLimitDisabled: Bool
@NSManaged var isBetaUpdatesEnabled: Bool @NSManaged var isBetaUpdatesEnabled: Bool
@NSManaged var isExportResignedAppEnabled: Bool @NSManaged var isExportResignedAppEnabled: Bool
@NSManaged var isVerboseOperationsLoggingEnabled: Bool @NSManaged var isVerboseOperationsLoggingEnabled: Bool
@NSManaged var isMinimuxerConsoleLoggingEnabled: Bool @NSManaged var isMinimuxerConsoleLoggingEnabled: Bool
@NSManaged var isMinimuxerStatusCheckEnabled: Bool
@NSManaged var recreateDatabaseOnNextStart: Bool @NSManaged var recreateDatabaseOnNextStart: Bool
@NSManaged var isPairingReset: Bool @NSManaged var isPairingReset: Bool
@NSManaged var isDebugModeEnabled: Bool @NSManaged var isDebugModeEnabled: Bool
@@ -135,10 +132,8 @@ public extension UserDefaults
#keyPath(UserDefaults.isDebugModeEnabled): false, #keyPath(UserDefaults.isDebugModeEnabled): false,
#keyPath(UserDefaults.isVerboseOperationsLoggingEnabled): false, #keyPath(UserDefaults.isVerboseOperationsLoggingEnabled): false,
#keyPath(UserDefaults.isMinimuxerConsoleLoggingEnabled): false, // minimuxer logging is disabled by default for console loggin #keyPath(UserDefaults.isMinimuxerConsoleLoggingEnabled): false, // minimuxer logging is disabled by default for console loggin
#keyPath(UserDefaults.isMinimuxerStatusCheckEnabled): false, // minimuxer status check is disabled by default to support LocalDevVPN based cellular refresh
#keyPath(UserDefaults.recreateDatabaseOnNextStart): false, #keyPath(UserDefaults.recreateDatabaseOnNextStart): false,
#keyPath(UserDefaults.isBackgroundRefreshEnabled): true, #keyPath(UserDefaults.isBackgroundRefreshEnabled): true,
#keyPath(UserDefaults.enableEMPforWireguard): false,
#keyPath(UserDefaults.isIdleTimeoutDisableEnabled): true, #keyPath(UserDefaults.isIdleTimeoutDisableEnabled): true,
#keyPath(UserDefaults.isPairingReset): true, #keyPath(UserDefaults.isPairingReset): true,
#keyPath(UserDefaults.isLegacyDeactivationSupported): isLegacyDeactivationSupported, #keyPath(UserDefaults.isLegacyDeactivationSupported): isLegacyDeactivationSupported,

View File

@@ -98,7 +98,6 @@
<attribute name="refreshedDate" attributeType="Date" usesScalarValueType="NO"/> <attribute name="refreshedDate" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="resignedBundleIdentifier" attributeType="String"/> <attribute name="resignedBundleIdentifier" attributeType="String"/>
<attribute name="storeBuildVersion" optional="YES" attributeType="String"/> <attribute name="storeBuildVersion" optional="YES" attributeType="String"/>
<attribute name="useMainProfile" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="version" attributeType="String"/> <attribute name="version" attributeType="String"/>
<relationship name="appExtensions" toMany="YES" deletionRule="Cascade" destinationEntity="InstalledExtension" inverseName="parentApp" inverseEntity="InstalledExtension"/> <relationship name="appExtensions" toMany="YES" deletionRule="Cascade" destinationEntity="InstalledExtension" inverseName="parentApp" inverseEntity="InstalledExtension"/>
<relationship name="loggedErrors" toMany="YES" deletionRule="Nullify" destinationEntity="LoggedError" inverseName="installedApp" inverseEntity="LoggedError"/> <relationship name="loggedErrors" toMany="YES" deletionRule="Nullify" destinationEntity="LoggedError" inverseName="installedApp" inverseEntity="LoggedError"/>

View File

@@ -59,8 +59,6 @@ public class InstalledApp: BaseEntity, InstalledAppProtocol
@NSManaged public var needsResign: Bool @NSManaged public var needsResign: Bool
@NSManaged public var hasAlternateIcon: Bool @NSManaged public var hasAlternateIcon: Bool
@NSManaged public var useMainProfile: Bool
@NSManaged public var certificateSerialNumber: String? @NSManaged public var certificateSerialNumber: String?
@NSManaged public var storeBuildVersion: String? @NSManaged public var storeBuildVersion: String?

View File

@@ -25,7 +25,7 @@ struct TextLockScreenWidget: Widget
} }
.supportedFamilies([.accessoryCircular]) .supportedFamilies([.accessoryCircular])
.configurationDisplayName("AltWidget (Text)") .configurationDisplayName("AltWidget (Text)")
.description("View remaining days until SideStore expires.") .description("View remaining days until AltStore expires.")
} }
else else
{ {
@@ -48,7 +48,7 @@ struct IconLockScreenWidget: Widget
} }
.supportedFamilies([.accessoryCircular]) .supportedFamilies([.accessoryCircular])
.configurationDisplayName("AltWidget (Icon)") .configurationDisplayName("AltWidget (Icon)")
.description("View remaining days until SideStore expires.") .description("View remaining days until AltStore expires.")
} }
else else
{ {

View File

@@ -1,16 +1,13 @@
// Configuration settings file format documentation can be found at: // Configuration settings file format documentation can be found at:
// https://help.apple.com/xcode/#/dev745c5c974 // https://help.apple.com/xcode/#/dev745c5c974
MARKETING_VERSION = 0.6.3 MARKETING_VERSION = 0.6.1
CURRENT_PROJECT_VERSION = 0603 CURRENT_PROJECT_VERSION = 0601
// Vars to be overwritten by `CodeSigning.xcconfig` if exists // Vars to be overwritten by `CodeSigning.xcconfig` if exists
DEVELOPMENT_TEAM = S32Z3HMYVQ DEVELOPMENT_TEAM = S32Z3HMYVQ
ORG_IDENTIFIER = com.SideStore ORG_IDENTIFIER = com.SideStore
// Default is free for CI builds, override it using CodeSigning.xcconfig if required
CODE_SIGN_ENTITLEMENTS = ./AltStore/AltStoreFree.entitlements
// Codesigning settings defined optionally, see `CodeSigning.xcconfig.example` // Codesigning settings defined optionally, see `CodeSigning.xcconfig.example`
#include? "CodeSigning.xcconfig" #include? "CodeSigning.xcconfig"
@@ -23,10 +20,8 @@ PRODUCT_NAME = SideStore
//PRODUCT_BUNDLE_IDENTIFIER[config=Debug] = $(ORG_PREFIX).SideStore$(BUNDLE_ID_SUFFIX) //PRODUCT_BUNDLE_IDENTIFIER[config=Debug] = $(ORG_PREFIX).SideStore$(BUNDLE_ID_SUFFIX)
//PRODUCT_BUNDLE_IDENTIFIER[config=Release] = $(ORG_PREFIX).SideStore //PRODUCT_BUNDLE_IDENTIFIER[config=Release] = $(ORG_PREFIX).SideStore
// preserve unmodified bundle ID (without any extra suffixes) // preserve unmodified bundle ID (without any extra suffixes)
PRODUCT_BUNDLE_IDENTIFIER[config=Debug] = $(ORG_IDENTIFIER).SideStore.$(DEVELOPMENT_TEAM) GROUP_ID = $(ORG_PREFIX).SideStore$(BUNDLE_ID_SUFFIX)
PRODUCT_BUNDLE_IDENTIFIER[config=Release] = $(ORG_IDENTIFIER).SideStore PRODUCT_BUNDLE_IDENTIFIER = $(GROUP_ID)
GROUP_ID = $(ORG_IDENTIFIER).SideStore
GROUP_ID[config=Debug] = $(ORG_IDENTIFIER).SideStore.$(DEVELOPMENT_TEAM)
EXTENSION_PREFIX = $(PRODUCT_BUNDLE_IDENTIFIER) EXTENSION_PREFIX = $(PRODUCT_BUNDLE_IDENTIFIER)
APP_GROUP_IDENTIFIER = $(GROUP_ID) APP_GROUP_IDENTIFIER = $(GROUP_ID)

View File

@@ -3,11 +3,6 @@
// https://developer.apple.com/account/#/membership // https://developer.apple.com/account/#/membership
DEVELOPMENT_TEAM = XYZ0123456 DEVELOPMENT_TEAM = XYZ0123456
// If you have a free account use this following line
// CODE_SIGN_ENTITLEMENTS = ./AltStore/AltStoreFree.entitlements
// Paid accounts can use this following line
CODE_SIGN_ENTITLEMENTS = ./AltStore/AltStore.entitlements
// Set this for dev-local xcode builds // Set this for dev-local xcode builds
//MARKETING_VERSION_SUFFIX = -local //MARKETING_VERSION_SUFFIX = -local

View File

@@ -201,7 +201,7 @@ build-and-test:
@echo "" @echo ""
@echo "Performing a build and running tests..." @echo "Performing a build and running tests..."
@xcodebuild test \ @xcodebuild test \
-destination 'platform=iOS Simulator,name=iPhone 17 Pro,OS=26.0' \ -destination 'platform=iOS Simulator,name=iPhone 16 Pro,OS=18.2' \
-resultBundlePath build/tests/test-results.xcresult \ -resultBundlePath build/tests/test-results.xcresult \
-enableCodeCoverage YES \ -enableCodeCoverage YES \
$(COMMON_BUILD_SETTINGS) $(COMMON_BUILD_SETTINGS)
@@ -213,7 +213,7 @@ build-tests:
@echo "Performing a build-for-testing..." @echo "Performing a build-for-testing..."
@xcodebuild build-for-testing \ @xcodebuild build-for-testing \
-enableCodeCoverage YES \ -enableCodeCoverage YES \
-destination 'platform=iOS Simulator,name=iPhone 17 Pro,OS=26.0' \ -destination 'platform=iOS Simulator,name=iPhone 16 Pro,OS=18.2' \
$(COMMON_BUILD_SETTINGS) $(COMMON_BUILD_SETTINGS)
run-tests: run-tests:
@@ -224,22 +224,22 @@ run-tests:
@xcodebuild test-without-building \ @xcodebuild test-without-building \
-enableCodeCoverage YES \ -enableCodeCoverage YES \
-resultBundlePath build/tests/test-results.xcresult \ -resultBundlePath build/tests/test-results.xcresult \
-destination 'platform=iOS Simulator,name=iPhone 17 Pro,OS=26.0' \ -destination 'platform=iOS Simulator,name=iPhone 16 Pro,OS=18.2' \
$(COMMON_BUILD_SETTINGS) $(COMMON_BUILD_SETTINGS)
boot-sim-async: boot-sim-async:
@if xcrun simctl list devices "iPhone 17 Pro" | grep -q "Booted"; then \ @if xcrun simctl list devices "iPhone 16 Pro" | grep -q "Booted"; then \
echo "Simulator 'iPhone 17 Pro' is already booted."; \ echo "Simulator 'iPhone 16 Pro' is already booted."; \
else \ else \
echo "Booting simulator 'iPhone 17 Pro' asynchronously..."; \ echo "Booting simulator 'iPhone 16 Pro' asynchronously..."; \
xcrun simctl boot "iPhone 17 Pro" & \ xcrun simctl boot "iPhone 16 Pro" & \
echo "Simulator boot command dispatched."; \ echo "Simulator boot command dispatched."; \
fi fi
sim-boot-check: sim-boot-check:
@echo "Checking simulator boot status..." @echo "Checking simulator boot status..."
@if xcrun simctl list devices "iPhone 17 Pro" | grep -q "Booted"; then \ @if xcrun simctl list devices "iPhone 16 Pro" | grep -q "Booted"; then \
echo "Simulator 'iPhone 17 Pro' is booted."; \ echo "Simulator 'iPhone 16 Pro' is booted."; \
else \ else \
echo "Simulator bootup failed or is not booted yet."; \ echo "Simulator bootup failed or is not booted yet."; \
exit 1; \ exit 1; \

37
Podfile Normal file
View File

@@ -0,0 +1,37 @@
inhibit_all_warnings!
target 'SideStore' do
platform :ios, '15.0'
use_frameworks! :linkage => :static
# Pods for AltStore
pod 'Nuke', '~> 10.0'
pod 'AppCenter/Analytics', '~> 5.0'
pod 'AppCenter/Crashes', '~> 5.0'
pod 'Starscream', '~> 4.0.0'
end
target 'AltStoreCore' do
platform :ios, '15.0'
use_frameworks! :linkage => :static
# Pods for AltStoreCore
pod 'KeychainAccess', '~> 4.2.2'
# pod 'SemanticVersion', '~> 0.3.5'
# Add the Swift Package using the repository URL
# pod 'SemanticVersion', :git => 'https://github.com/SwiftPackageIndex/SemanticVersion.git', :tag => '0.4.0'
end
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '15.0'
config.build_settings['MACOSX_DEPLOYMENT_TARGET'] = '11.0'
end
end
end

33
Podfile.lock Normal file
View File

@@ -0,0 +1,33 @@
PODS:
- AppCenter/Analytics (5.0.5):
- AppCenter/Core
- AppCenter/Core (5.0.5)
- AppCenter/Crashes (5.0.5):
- AppCenter/Core
- KeychainAccess (4.2.2)
- Nuke (10.7.1)
- Starscream (4.0.8)
DEPENDENCIES:
- AppCenter/Analytics (~> 5.0)
- AppCenter/Crashes (~> 5.0)
- KeychainAccess (~> 4.2.2)
- Nuke (~> 10.0)
- Starscream (~> 4.0.0)
SPEC REPOS:
trunk:
- AppCenter
- KeychainAccess
- Nuke
- Starscream
SPEC CHECKSUMS:
AppCenter: 994875ea7941b9e168babb98299f900a94bcef13
KeychainAccess: c0c4f7f38f6fc7bbe58f5702e25f7bd2f65abf51
Nuke: 279f17a599fd1c83cf51de5e0e1f2db143a287b0
Starscream: 19b5533ddb925208db698f0ac508a100b884a1b9
PODFILE CHECKSUM: c0b9b55044ebe3d841c52647f4f74ad4169f97f1
COCOAPODS: 1.16.2

View File

@@ -6,7 +6,7 @@
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://makeapullrequest.com) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://makeapullrequest.com)
[![Nightly SideStore build](https://github.com/SideStore/SideStore/actions/workflows/nightly.yml/badge.svg)](https://github.com/SideStore/SideStore/actions/workflows/nightly.yml) [![Nightly SideStore build](https://github.com/SideStore/SideStore/actions/workflows/nightly.yml/badge.svg)](https://github.com/SideStore/SideStore/actions/workflows/nightly.yml)
[![.github/workflows/beta.yml](https://github.com/SideStore/SideStore/actions/workflows/beta.yml/badge.svg)](https://github.com/SideStore/SideStore/actions/workflows/beta.yml) [![.github/workflows/beta.yml](https://github.com/SideStore/SideStore/actions/workflows/beta.yml/badge.svg)](https://github.com/SideStore/SideStore/actions/workflows/beta.yml)
[![Discord](https://img.shields.io/discord/949183273383395328?label=Discord)](https://dis.sidestore.io) [![Discord](https://img.shields.io/discord/949183273383395328?label=Discord)](https://discord.gg/sidestore)
![Alt](https://repobeats.axiom.co/api/embed/3a329ce95955690b9a9366f8d5598626a847d96c.svg "Repobeats analytics image") ![Alt](https://repobeats.axiom.co/api/embed/3a329ce95955690b9a9366f8d5598626a847d96c.svg "Repobeats analytics image")
@@ -18,20 +18,20 @@ SideStore's goal is to provide an untethered sideloading experience. It's a comm
## Requirements ## Requirements
- Xcode 15 - Xcode 15
- iOS 14+ - iOS 15+
- Rustup (`brew install rustup`) - Rustup (`brew install rustup`)
Why iOS 14? Targeting such a recent version of iOS allows us to accelerate development, especially since not many developers have older devices to test on. This is corrobated by the fact that SwiftUI support is much better, allowing us to transistion to a more modern UI codebase. Why iOS 15? Targeting such a recent version of iOS allows us to accelerate development, especially since not many developers have older devices to test on. This is corrobated by the fact that SwiftUI support is much better, allowing us to transistion to a more modern UI codebase.
## Project Overview ## Project Overview
### SideStore ### SideStore
SideStore is a just regular, sandboxed iOS application. The AltStore app target contains the vast majority of SideStore's functionality, including all the logic for downloading and updating apps through SideStore. SideStore makes heavy use of standard iOS frameworks and technologies most iOS developers are familiar with. SideStore is a just regular, sandboxed iOS application. The AltStore app target contains the vast majority of SideStore's functionality, including all the logic for downloading and updating apps through SideStore. SideStore makes heavy use of standard iOS frameworks and technologies most iOS developers are familiar with.
### EM Proxy ### EM Proxy
[EM Proxy](https://github.com/jkcoxson/em_proxy) powers the defining feature of SideStore: untethered app installation. By leveraging a custom-built App Store app with additional entitlements ([LocalDevVPN](https://github.com/jkcoxson/LocalDevVPN)) to create the VPN tunnel for us, it allows SideStore to take advantage of [Jitterbug](https://github.com/osy/Jitterbug)'s loopback method without requiring a paid developer account. [SideServer mobile](https://github.com/jkcoxson/em_proxy) powers the defining feature of SideStore: untethered app installation. By leveraging an App Store app with additional entitlements (WireGuard or StosVPN) to create the VPN tunnel for us, it allows SideStore to take advantage of [Jitterbug](https://github.com/osy/Jitterbug)'s loopback method without requiring a paid developer account.
### Minimuxer ### Minimuxer
[Minimuxer](https://github.com/jkcoxson/minimuxer) is a lockdown muxer that can run inside iOSs sandbox. It replicates Apples usbmuxd protocol on macOS to “discover” devices to interface with LocalDevVPN on-device. [Minimuxer](https://github.com/jkcoxson/minimuxer) is a lockdown muxer that can run inside iOSs sandbox. It replicates Apples usbmuxd protocol on MacOS to “discover” devices to interface with wireguard On-Device.
### Roxas ### Roxas
[Roxas](https://github.com/rileytestut/roxas) is Riley Testut's internal framework from AltStore used across many of their iOS projects, developed to simplify a variety of common tasks used in iOS development. [Roxas](https://github.com/rileytestut/roxas) is Riley Testut's internal framework from AltStore used across many of their iOS projects, developed to simplify a variety of common tasks used in iOS development.

View File

@@ -19,41 +19,7 @@ final class UITests: XCTestCase {
private static let APP_NAME = "SideStore" private static let APP_NAME = "SideStore"
func printAllMethods(of className: String) {
guard let cls: AnyClass = objc_getClass(className) as? AnyClass else {
print("Class \(className) not found")
return
}
var methodCount: UInt32 = 0
if let methodList = class_copyMethodList(cls, &methodCount) {
for i in 0..<Int(methodCount) {
let method = methodList[i]
let sel = method_getName(method)
print(String(describing: sel))
}
free(methodList)
}
}
override func setUpWithError() throws { override func setUpWithError() throws {
// ensure the swizzle only happens once
if !Self.mockIdlingPrivateApiToNoOp {
let original = class_getInstanceMethod(
objc_getClass("XCUIApplicationProcess") as? AnyClass,
// this is the new method signature obtained via reflection
Selector(("waitForQuiescenceIncludingAnimationsIdle:isPreEvent:"))
)
let replaced = class_getInstanceMethod(type(of: self), #selector(Self.replace))
if let original, let replaced{
method_exchangeImplementations(original, replaced)
}
Self.mockIdlingPrivateApiToNoOp = true
}
/* UNCOMMENT below to enable the printing of private members of XCUIApplicationProcess */
// printAllMethods(of: "XCUIApplicationProcess")
// Put setup code here. This method is called before the invocation of each test method in the class. // Put setup code here. This method is called before the invocation of each test method in the class.
// Self.dismissSpotlight() // Self.dismissSpotlight()
// Self.deleteMyApp() // Self.deleteMyApp()
@@ -81,9 +47,7 @@ final class UITests: XCTestCase {
// if it exists keep going immediately else wait for upto 5 sec with polling every 1 sec for existence // if it exists keep going immediately else wait for upto 5 sec with polling every 1 sec for existence
XCTAssertTrue(systemAlert.exists || systemAlert.waitForExistence(timeout: 5), "Notifications alert did not appear") XCTAssertTrue(systemAlert.exists || systemAlert.waitForExistence(timeout: 5), "Notifications alert did not appear")
let allowButton = systemAlert.scrollViews.otherElements.buttons["Allow"] systemAlert.scrollViews.otherElements.buttons["Allow"].tap()
_ = allowButton.exists || allowButton.waitForExistence(timeout: 0.5)
allowButton.tap()
// Do the actual validation // Do the actual validation
try performBulkAddingRecommendedSources(for: app) try performBulkAddingRecommendedSources(for: app)
@@ -91,7 +55,6 @@ final class UITests: XCTestCase {
func testBulkAddInputSources() throws { func testBulkAddInputSources() throws {
// let app = XCUIApplication()
let app = XCUIApplication() let app = XCUIApplication()
app.launch() app.launch()
@@ -99,9 +62,7 @@ final class UITests: XCTestCase {
// if it exists keep going immediately else wait for upto 5 sec with polling every 1 sec for existence // if it exists keep going immediately else wait for upto 5 sec with polling every 1 sec for existence
XCTAssertTrue(systemAlert.exists || systemAlert.waitForExistence(timeout: 5), "Notifications alert did not appear") XCTAssertTrue(systemAlert.exists || systemAlert.waitForExistence(timeout: 5), "Notifications alert did not appear")
let allowButton = systemAlert.scrollViews.otherElements.buttons["Allow"] systemAlert.scrollViews.otherElements.buttons["Allow"].tap()
_ = allowButton.exists || allowButton.waitForExistence(timeout: 0.5)
allowButton.tap()
// Do the actual validation // Do the actual validation
try performBulkAddingInputSources(for: app) try performBulkAddingInputSources(for: app)
@@ -116,9 +77,7 @@ final class UITests: XCTestCase {
// if it exists keep going immediately else wait for upto 5 sec with polling every 1 sec for existence // if it exists keep going immediately else wait for upto 5 sec with polling every 1 sec for existence
XCTAssertTrue(systemAlert.exists || systemAlert.waitForExistence(timeout: 5), "Notifications alert did not appear") XCTAssertTrue(systemAlert.exists || systemAlert.waitForExistence(timeout: 5), "Notifications alert did not appear")
let allowButton = systemAlert.scrollViews.otherElements.buttons["Allow"] systemAlert.scrollViews.otherElements.buttons["Allow"].tap()
_ = allowButton.exists || allowButton.waitForExistence(timeout: 0.5)
allowButton.tap()
// Do the actual validation // Do the actual validation
try performRepeatabilityForStagingInputSources(for: app) try performRepeatabilityForStagingInputSources(for: app)
@@ -133,9 +92,7 @@ final class UITests: XCTestCase {
// if it exists keep going immediately else wait for upto 5 sec with polling every 1 sec for existence // if it exists keep going immediately else wait for upto 5 sec with polling every 1 sec for existence
XCTAssertTrue(systemAlert.exists || systemAlert.waitForExistence(timeout: 5), "Notifications alert did not appear") XCTAssertTrue(systemAlert.exists || systemAlert.waitForExistence(timeout: 5), "Notifications alert did not appear")
let allowButton = systemAlert.scrollViews.otherElements.buttons["Allow"] systemAlert.scrollViews.otherElements.buttons["Allow"].tap()
_ = allowButton.exists || allowButton.waitForExistence(timeout: 0.5)
allowButton.tap()
// Do the actual validation // Do the actual validation
try performRepeatabilityForStagingRecommendedSources(for: app) try performRepeatabilityForStagingRecommendedSources(for: app)
@@ -200,13 +157,6 @@ private extension UITests {
springboard_app.tap() springboard_app.tap()
} }
@objc func replace() {
return
}
static var mockIdlingPrivateApiToNoOp = false
class func deleteMyApp2() { class func deleteMyApp2() {
XCUIApplication().terminate() XCUIApplication().terminate()
dismissSpringboardAlerts() dismissSpringboardAlerts()
@@ -221,19 +171,16 @@ private extension UITests {
let button = springboard_app.buttons["Remove App"] let button = springboard_app.buttons["Remove App"]
_ = button.exists || button.waitForExistence(timeout: 5) _ = button.exists || button.waitForExistence(timeout: 5)
button.tap() button.tap()
_ = springboard_app.waitForExistence(timeout: 0.5)
} }
do { do {
let button = springboard_app.buttons["Delete App"] let button = springboard_app.buttons["Delete App"]
_ = button.waitForExistence(timeout: 0.5) _ = button.waitForExistence(timeout: 0.3)
button.tap() button.tap()
_ = springboard_app.waitForExistence(timeout: 0.5)
} }
do { do {
let button = springboard_app.buttons["Delete"] let button = springboard_app.buttons["Delete"]
_ = button.waitForExistence(timeout: 0.5) _ = button.waitForExistence(timeout: 0.3)
button.tap() button.tap()
_ = springboard_app.waitForExistence(timeout: 0.5)
} }
// // Press home once to make the icons stop wiggling // // Press home once to make the icons stop wiggling
@@ -283,49 +230,19 @@ private extension UITests {
try tapAddForThesePickedSources(app: app, sourceMappings: sourceMappings, cellsQuery: cellsQuery) try tapAddForThesePickedSources(app: app, sourceMappings: sourceMappings, cellsQuery: cellsQuery)
// Commit the changes by tapping "Done". // Commit the changes by tapping "Done".
let doneButton = app.navigationBars["Add Source"].buttons["Done"] app.navigationBars["Add Source"].buttons["Done"].tap()
_ = doneButton.waitForExistence(timeout: 0.5)
doneButton.tap()
// Accept each source addition via alert. // Accept each source addition via alert.
for source in sourceMappings { for source in sourceMappings {
let alertIdentifier = "Would you like to add the source “\(source.alertTitle)”?" let alertIdentifier = "Would you like to add the source “\(source.alertTitle)”?"
let addSourceButton = app.alerts[alertIdentifier] let addSourceButton = app.alerts[alertIdentifier]
.scrollViews.otherElements.buttons["Add Source"] .scrollViews.otherElements.buttons["Add Source"]
_ = addSourceButton.waitForExistence(timeout: 0.5) _ = addSourceButton.exists || addSourceButton.waitForExistence(timeout: 0.3)
addSourceButton.tap() addSourceButton.tap()
} }
} }
private func performBulkAddingRecommendedSources(for app: XCUIApplication) throws {
// Navigate to the Sources screen and open the Add Source view.
let srcTab = app.tabBars["Tab Bar"].buttons["Sources"]
_ = srcTab.waitForExistence(timeout: 0.5)
srcTab.tap()
let srcAdd = app.navigationBars["Sources"].buttons["Add"]
_ = srcAdd.waitForExistence(timeout: 0.5)
srcAdd.tap()
let cellsQuery = app.collectionViews.cells
// Data model for recommended sources. NOTE: This list order is required to be the same as that of "Add Source" Screen
let recommendedSources: [(identifier: String, alertTitle: String, requiresSwipe: Bool)] = [
("SideStore Team Picks\ncommunity-apps.sidestore.io/sidecommunity.json", "SideStore Team Picks", false),
("Provenance EMU\nprovenance-emu.com/apps.json", "Provenance EMU", false),
("Countdown Respository\nneoarz.github.io/Countdown-App/Countdown.json", "Countdown Respository", false),
("OatmealDome's AltStore Source\naltstore.oatmealdome.me", "OatmealDome's AltStore Source", true),
("UTM Repository\nVirtual machines for iOS", "UTM Repository", false),
("Flyinghead\nflyinghead.github.io/flycast-builds/altstore.json", "Flyinghead", false),
// ("PojavLauncher Repository\nalt.crystall1ne.dev", "PojavLauncher Repository", false), // not a stable source, sometimes becomes unreachable, so disabled
("PokeMMO\npokemmo.eu/altstore/", "PokeMMO", true),
("Odyssey\ntheodyssey.dev/altstore/odysseysource.json", "Odyssey", false),
("Yattee\nrepos.yattee.stream/alt/apps.json", "Yattee", false),
("ThatStella7922 Source\nThe home for all apps ThatStella7922", "ThatStella7922 Source", false)
]
try performBulkAdd(app: app, sourceMappings: recommendedSources, cellsQuery: cellsQuery)
}
private func performBulkAddingInputSources(for app: XCUIApplication) throws { private func performBulkAddingInputSources(for app: XCUIApplication) throws {
@@ -343,22 +260,16 @@ private extension UITests {
https://bit.ly/Quantumsource https://bit.ly/Quantumsource
""".trimmedIndentation """.trimmedIndentation
let srcTab = app.tabBars["Tab Bar"].buttons["Sources"] let app = XCUIApplication()
_ = srcTab.waitForExistence(timeout: 0.5) app.tabBars["Tab Bar"].buttons["Sources"].tap()
srcTab.tap() app.navigationBars["Sources"].buttons["Add"].tap()
let srcAdd = app.navigationBars["Sources"].buttons["Add"]
_ = srcAdd.waitForExistence(timeout: 0.5)
srcAdd.tap()
let collectionViewsQuery = app.collectionViews let collectionViewsQuery = app.collectionViews
let appsSidestoreIoTextField = collectionViewsQuery.textFields["apps.sidestore.io"] let appsSidestoreIoTextField = collectionViewsQuery.textFields["apps.sidestore.io"]
_ = appsSidestoreIoTextField.waitForExistence(timeout: 0.5) _ = appsSidestoreIoTextField.exists || appsSidestoreIoTextField.waitForExistence(timeout: 5)
appsSidestoreIoTextField.tap() appsSidestoreIoTextField.tap()
appsSidestoreIoTextField.tap() appsSidestoreIoTextField.tap()
_ = appsSidestoreIoTextField.waitForExistence(timeout: 0.5) collectionViewsQuery.staticTexts["Paste"].tap()
let pasteButton = collectionViewsQuery.staticTexts["Paste"]
_ = pasteButton.waitForExistence(timeout: 0.5)
pasteButton.tap()
// if app.keyboards.buttons["Return"].exists { // if app.keyboards.buttons["Return"].exists {
// app.keyboards.buttons["Return"].tap() // app.keyboards.buttons["Return"].tap()
@@ -371,7 +282,6 @@ private extension UITests {
if app.keyboards.count > 0 { if app.keyboards.count > 0 {
appsSidestoreIoTextField.typeText("\n") // Fallback to newline so that soft kb is dismissed appsSidestoreIoTextField.typeText("\n") // Fallback to newline so that soft kb is dismissed
_ = app.exists || app.waitForExistence(timeout: 0.5)
} }
let cellsQuery = collectionViewsQuery.cells let cellsQuery = collectionViewsQuery.cells
@@ -392,31 +302,6 @@ private extension UITests {
try performBulkAdd(app: app, sourceMappings: textInputSources, cellsQuery: cellsQuery) try performBulkAdd(app: app, sourceMappings: textInputSources, cellsQuery: cellsQuery)
} }
private func performRepeatabilityForStagingRecommendedSources(for app: XCUIApplication) throws {
// Navigate to the Sources screen and open the Add Source view.
let srcTab = app.tabBars["Tab Bar"].buttons["Sources"]
srcTab.tap()
_ = srcTab.waitForExistence(timeout: 0.5)
let srcAdd = app.navigationBars["Sources"].buttons["Add"]
srcAdd.tap()
_ = srcAdd.waitForExistence(timeout: 0.5)
let cellsQuery = app.collectionViews.cells
// Data model for recommended sources. NOTE: This list order is required to be the same as that of "Add Source" Screen
let recommendedSources: [(identifier: String, alertTitle: String, requiresSwipe: Bool)] = [
("SideStore Team Picks\ncommunity-apps.sidestore.io/sidecommunity.json", "SideStore Team Picks", false),
("Provenance EMU\nprovenance-emu.com/apps.json", "Provenance EMU", false),
("Countdown Respository\nneoarz.github.io/Countdown-App/Countdown.json", "Countdown Respository", false),
("OatmealDome's AltStore Source\naltstore.oatmealdome.me", "OatmealDome's AltStore Source", false),
("UTM Repository\nVirtual machines for iOS", "UTM Repository", false),
]
let repeatCount = 3 // number of times to run the entire sequence
let timeSeed = UInt64(Date().timeIntervalSince1970) // time is unique (upto microseconds) - uncomment this to use non-deterministic seed based RNG (random number generator)
try repeatabilityTest(app: app, sourceMappings: recommendedSources, cellsQuery: cellsQuery, repeatCount: repeatCount, seed: timeSeed)
}
private func performRepeatabilityForStagingInputSources(for app: XCUIApplication) throws { private func performRepeatabilityForStagingInputSources(for app: XCUIApplication) throws {
@@ -430,28 +315,20 @@ private extension UITests {
https://bit.ly/40Isul6 https://bit.ly/40Isul6
""".trimmedIndentation """.trimmedIndentation
let srcTab = app.tabBars["Tab Bar"].buttons["Sources"] let app = XCUIApplication()
_ = srcTab.waitForExistence(timeout: 0.5) app.tabBars["Tab Bar"].buttons["Sources"].tap()
srcTab.tap() app.navigationBars["Sources"].buttons["Add"].tap()
let srcAdd = app.navigationBars["Sources"].buttons["Add"]
_ = srcAdd.waitForExistence(timeout: 0.5)
srcAdd.tap()
let collectionViewsQuery = app.collectionViews let collectionViewsQuery = app.collectionViews
let appsSidestoreIoTextField = collectionViewsQuery.textFields["apps.sidestore.io"] let appsSidestoreIoTextField = collectionViewsQuery.textFields["apps.sidestore.io"]
_ = appsSidestoreIoTextField.waitForExistence(timeout: 0.5) _ = appsSidestoreIoTextField.exists || appsSidestoreIoTextField.waitForExistence(timeout: 5)
appsSidestoreIoTextField.tap() appsSidestoreIoTextField.tap()
appsSidestoreIoTextField.tap() appsSidestoreIoTextField.tap()
_ = appsSidestoreIoTextField.waitForExistence(timeout: 0.5) _ = appsSidestoreIoTextField.exists || appsSidestoreIoTextField.waitForExistence(timeout: 5)
let pasteButton = collectionViewsQuery.staticTexts["Paste"] collectionViewsQuery.staticTexts["Paste"].tap()
_ = pasteButton.waitForExistence(timeout: 0.5)
pasteButton.tap()
if app.keyboards.count > 0 { if app.keyboards.count > 0 {
appsSidestoreIoTextField.typeText("\n") // Fallback to newline so that soft kb is dismissed appsSidestoreIoTextField.typeText("\n") // Fallback to newline so that soft kb is dismissed
_ = app.exists || app.waitForExistence(timeout: 0.5)
} }
let cellsQuery = collectionViewsQuery.cells let cellsQuery = collectionViewsQuery.cells
@@ -504,26 +381,63 @@ private extension UITests {
.children(matching: .button)[source.identifier] .children(matching: .button)[source.identifier]
XCTAssert(sourceButton.exists || sourceButton.waitForExistence(timeout: 10), "Source preview for id: '\(source.alertTitle)' not found in the view") XCTAssert(sourceButton.exists || sourceButton.waitForExistence(timeout: 10), "Source preview for id: '\(source.alertTitle)' not found in the view")
_ = sourceButton.exists || sourceButton.waitForExistence(timeout: 0.5)
// let addButton = sourceButton.children(matching: .button).firstMatch // let addButton = sourceButton.children(matching: .button).firstMatch
// let addButton = sourceButton.descendants(matching: .button)["add"]
// XCTAssert(addButton.exists || addButton.waitForExistence(timeout: 0.5), " `+` button for id: '\(source.alertTitle)' not found in the preview container")
// addButton.tap()
let addButton = sourceButton.children(matching: .button)["add"] let addButton = sourceButton.children(matching: .button)["add"]
XCTAssert(addButton.waitForExistence(timeout: 1)) //TODO: fine tune down the value to make tests faster (but validate tests still works) XCTAssert(addButton.exists || addButton.waitForExistence(timeout: 0.3), " `+` button for id: '\(source.alertTitle)' not found in the preview container")
// addButton.tap() addButton.tap()
let coord = addButton.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: 0.5))
coord.tap()
if source.requiresSwipe { if source.requiresSwipe {
sourceButton.swipeUp(velocity: .slow) // Swipe up if needed. sourceButton.swipeUp(velocity: .slow) // Swipe up if needed.
_ = sourceButton.waitForExistence(timeout: 0.5)
} }
} }
} }
private func performBulkAddingRecommendedSources(for app: XCUIApplication) throws {
// Navigate to the Sources screen and open the Add Source view.
app.tabBars["Tab Bar"].buttons["Sources"].tap()
app.navigationBars["Sources"].buttons["Add"].tap()
let cellsQuery = app.collectionViews.cells
// Data model for recommended sources. NOTE: This list order is required to be the same as that of "Add Source" Screen
let recommendedSources: [(identifier: String, alertTitle: String, requiresSwipe: Bool)] = [
("SideStore Team Picks\ncommunity-apps.sidestore.io/sidecommunity.json", "SideStore Team Picks", false),
("Provenance EMU\nprovenance-emu.com/apps.json", "Provenance EMU", false),
("Countdown Respository\nneoarz.github.io/Countdown-App/Countdown.json", "Countdown Respository", false),
("OatmealDome's AltStore Source\naltstore.oatmealdome.me", "OatmealDome's AltStore Source", true),
("UTM Repository\nVirtual machines for iOS", "UTM Repository", false),
("Flyinghead\nflyinghead.github.io/flycast-builds/altstore.json", "Flyinghead", false),
// ("PojavLauncher Repository\nalt.crystall1ne.dev", "PojavLauncher Repository", false), // not a stable source, sometimes becomes unreachable, so disabled
("PokeMMO\npokemmo.eu/altstore/", "PokeMMO", true),
("Odyssey\ntheodyssey.dev/altstore/odysseysource.json", "Odyssey", false),
("Yattee\nrepos.yattee.stream/alt/apps.json", "Yattee", false),
("ThatStella7922 Source\nThe home for all apps ThatStella7922", "ThatStella7922 Source", false)
]
try performBulkAdd(app: app, sourceMappings: recommendedSources, cellsQuery: cellsQuery)
}
private func performRepeatabilityForStagingRecommendedSources(for app: XCUIApplication) throws {
// Navigate to the Sources screen and open the Add Source view.
app.tabBars["Tab Bar"].buttons["Sources"].tap()
app.navigationBars["Sources"].buttons["Add"].tap()
let cellsQuery = app.collectionViews.cells
// Data model for recommended sources. NOTE: This list order is required to be the same as that of "Add Source" Screen
let recommendedSources: [(identifier: String, alertTitle: String, requiresSwipe: Bool)] = [
("SideStore Team Picks\ncommunity-apps.sidestore.io/sidecommunity.json", "SideStore Team Picks", false),
("Provenance EMU\nprovenance-emu.com/apps.json", "Provenance EMU", false),
("Countdown Respository\nneoarz.github.io/Countdown-App/Countdown.json", "Countdown Respository", false),
("OatmealDome's AltStore Source\naltstore.oatmealdome.me", "OatmealDome's AltStore Source", false),
("UTM Repository\nVirtual machines for iOS", "UTM Repository", false),
]
let repeatCount = 3 // number of times to run the entire sequence
let timeSeed = UInt64(Date().timeIntervalSince1970) // time is unique (upto microseconds) - uncomment this to use non-deterministic seed based RNG (random number generator)
try repeatabilityTest(app: app, sourceMappings: recommendedSources, cellsQuery: cellsQuery, repeatCount: repeatCount, seed: timeSeed)
}
} }

View File

@@ -12,7 +12,7 @@ import AltStoreCore
class ImportExport { class ImportExport {
public static var documentPickerHandler: DocumentPickerHandler? private static var documentPickerHandler: DocumentPickerHandler?
public static func getPreviousBackupURL(_ backupURL: URL) -> URL { public static func getPreviousBackupURL(_ backupURL: URL) -> URL {
let backupParentDirectory = backupURL.deletingLastPathComponent() let backupParentDirectory = backupURL.deletingLastPathComponent()

View File

@@ -59,97 +59,48 @@ public class AbstractConsoleLogger<T: OutputStream>: ConsoleLogger{
originalStdout = dup(STDOUT_FILENO) originalStdout = dup(STDOUT_FILENO)
originalStderr = dup(STDERR_FILENO) originalStderr = dup(STDERR_FILENO)
let redirectedOutStream = self.outPipe?.fileHandleForWriting.fileDescriptor ?? -1
let redirectedErrStream = self.errPipe?.fileHandleForWriting.fileDescriptor ?? -1
// Redirect stdout and stderr to our pipes // Redirect stdout and stderr to our pipes
dup2(redirectedOutStream, STDOUT_FILENO) dup2(self.outPipe?.fileHandleForWriting.fileDescriptor ?? -1, STDOUT_FILENO)
dup2(redirectedErrStream, STDERR_FILENO) dup2(self.errPipe?.fileHandleForWriting.fileDescriptor ?? -1, STDERR_FILENO)
// Disable libc-level buffering
// (libc by default uses bufferring except its own console/TTYs such as for pipes)
// we do have our own buffering so we disable stdlib io level bufferring
setvbuf(stdout, nil, _IONBF, 0) // disable buffering for stdout
setvbuf(stderr, nil, _IONBF, 0) // disable buffering for stderr
// Setup readability handlers for raw data // Setup readability handlers for raw data
setupReadabilityHandler(for: outputHandle, isError: false) setupReadabilityHandler(for: outputHandle, isError: false)
setupReadabilityHandler(for: errorHandle, isError: true) setupReadabilityHandler(for: errorHandle, isError: true)
} }
let shutdownLock = NSLock()
private func setupReadabilityHandler(for handle: FileHandle?, isError: Bool) { private func setupReadabilityHandler(for handle: FileHandle?, isError: Bool) {
handle?.readabilityHandler = readHandler(isError: isError) handle?.readabilityHandler = { [weak self] handle in
let data = handle.availableData
if !data.isEmpty {
self?.writeQueue.async {
try? self?.writeData(data)
} }
private func readHandler(isError: Bool) -> (FileHandle) -> Void { // Forward to original std stream
return { [weak self] _ in if let originalFD = isError ? self?.originalStderr : self?.originalStdout {
// Lock first before touching anything data.withUnsafeBytes { (bufferPointer) -> Void in
self?.shutdownLock.lock() if let baseAddress = bufferPointer.baseAddress, bufferPointer.count > 0 {
defer { self?.shutdownLock.unlock() } write(originalFD, baseAddress, bufferPointer.count)
}
// Capture strong self *after* lock is acquired }
guard let self = self else { return }
let handle = isError ? self.errorHandle : self.outputHandle
guard let data = handle?.availableData else { return }
writeQueue.async {
try? self.writeData(data)
}
// 2. Echo to original stdout/stderr if still valid
guard let fd = isError ? self.originalStderr : self.originalStdout else {
return
}
let appName = Bundle.main.object(forInfoDictionaryKey: "CFBundleName") as? String ?? "UnknownApp"
guard fcntl(fd, F_GETFD) != -1 else {
NSLog("[%@] ConsoleLogger: Original FD (%d) is invalid, skipping echo", appName, fd)
return
}
data.withUnsafeBytes { rawBufferPointer in
guard let base = rawBufferPointer.baseAddress else { return }
var remaining = data.count
var offset = 0
let maxChunkSize = 16 * 1024 // 16 KB chunks
// write in chunks, else will throw 'Result too large'
while remaining > 0 {
let chunkSize = min(maxChunkSize, remaining)
let written = write(fd, base.advanced(by: offset), chunkSize)
if written < 0 {
NSLog("[%@] ConsoleLogger: Failed to re-echo to FD %d: %s", appName, fd, strerror(errno))
break
}
remaining -= written
offset += written
} }
} }
} }
} }
func writeData(_ data: Data) throws { func writeData(_ data: Data) throws {
throw AbstractClassError.abstractMethodInvoked throw AbstractClassError.abstractMethodInvoked
} }
func stopCapturing() { func stopCapturing() {
shutdownLock.lock()
defer { shutdownLock.unlock() }
ostream.close() ostream.close()
// Restore original stdout and stderr // Restore original stdout and stderr
if let stdout = originalStdout, stdout != STDOUT_FILENO { if let stdout = originalStdout {
dup2(stdout, STDOUT_FILENO) dup2(stdout, STDOUT_FILENO)
close(stdout) close(stdout)
} }
if let stderr = originalStderr, stderr != STDERR_FILENO { if let stderr = originalStderr {
dup2(stderr, STDERR_FILENO) dup2(stderr, STDERR_FILENO)
close(stderr) close(stderr)
} }

View File

@@ -1,67 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "2610"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "CA60C44C93D7A30E3695DD59"
BuildableName = "libem_proxy_static.a"
BlueprintName = "em_proxy-staticlib"
ReferencedContainer = "container:em_proxy.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "CA60C44C93D7A30E3695DD59"
BuildableName = "libem_proxy_static.a"
BlueprintName = "em_proxy-staticlib"
ReferencedContainer = "container:em_proxy.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@@ -1,67 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "2610"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "CA609C732349A560B9642892"
BuildableName = "libminimuxer_static.a"
BlueprintName = "minimuxer-staticlib"
ReferencedContainer = "container:minimuxer.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "CA609C732349A560B9642892"
BuildableName = "libminimuxer_static.a"
BlueprintName = "minimuxer-staticlib"
ReferencedContainer = "container:minimuxer.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@@ -8,22 +8,6 @@
"identifier": "com.sidestoreapps.community", "identifier": "com.sidestoreapps.community",
"sourceURL": "https://community-apps.sidestore.io/sidecommunity.json" "sourceURL": "https://community-apps.sidestore.io/sidecommunity.json"
}, },
{
"identifier": "com.stik.stikdebug",
"sourceURL": "https://stikdebug.xyz/index.json"
},
{
"identifier": "com.livecontainer.source",
"sourceURL": "https://raw.githubusercontent.com/LiveContainer/LiveContainer/refs/heads/main/apps.json"
},
{
"identifier": "com.aoshuang.manicemu",
"sourceURL": "https://apps.manicemu.site/altstore"
},
{
"identifier": "com.stossy11.MeloNX",
"sourceURL": "https://git.ryujinx.app/melonx/emu/-/raw/XC-ios-ht/source.json"
},
{ {
"identifier": "org.provenance-emu.provenance", "identifier": "org.provenance-emu.provenance",
"sourceURL": "https://provenance-emu.com/apps.json" "sourceURL": "https://provenance-emu.com/apps.json"
@@ -41,7 +25,11 @@
"sourceURL": "https://alt.getutm.app" "sourceURL": "https://alt.getutm.app"
}, },
{ {
"identifier": "dev.crystall1ne.alt", "identifier": "com.flyinghead.source",
"sourceURL": "https://flyinghead.github.io/flycast-builds/altstore.json"
},
{
"identifier": "dev.crystall1ne.repos.PojavLauncher",
"sourceURL": "https://alt.crystall1ne.dev" "sourceURL": "https://alt.crystall1ne.dev"
}, },
{ {
@@ -73,22 +61,6 @@
"identifier": "com.sidestoreapps.community", "identifier": "com.sidestoreapps.community",
"sourceURL": "https://community-apps.sidestore.io/sidecommunity.json" "sourceURL": "https://community-apps.sidestore.io/sidecommunity.json"
}, },
{
"identifier": "com.stik.stikdebug",
"sourceURL": "https://stikdebug.xyz/index.json"
},
{
"identifier": "com.livecontainer.source",
"sourceURL": "https://raw.githubusercontent.com/LiveContainer/LiveContainer/refs/heads/main/apps.json"
},
{
"identifier": "com.aoshuang.manicemu",
"sourceURL": "https://apps.manicemu.site/altstore"
},
{
"identifier": "com.stossy11.MeloNX",
"sourceURL": "https://git.ryujinx.app/melonx/emu/-/raw/XC-ios-ht/source.json"
},
{ {
"identifier": "org.provenance-emu.provenance", "identifier": "org.provenance-emu.provenance",
"sourceURL": "https://provenance-emu.com/apps.json" "sourceURL": "https://provenance-emu.com/apps.json"
@@ -106,7 +78,11 @@
"sourceURL": "https://alt.getutm.app" "sourceURL": "https://alt.getutm.app"
}, },
{ {
"identifier": "dev.crystall1ne.alt", "identifier": "com.flyinghead.source",
"sourceURL": "https://flyinghead.github.io/flycast-builds/altstore.json"
},
{
"identifier": "dev.crystall1ne.repos.PojavLauncher",
"sourceURL": "https://alt.crystall1ne.dev" "sourceURL": "https://alt.crystall1ne.dev"
}, },
{ {

View File

@@ -1,6 +1,3 @@
#include "../Build.xcconfig" #include "../Build.xcconfig"
PRODUCT_BUNDLE_IDENTIFIER[config=Debug] = $(ORG_IDENTIFIER).SideStore.AltBackup. //$(DEVELOPMENT_TEAM) PRODUCT_BUNDLE_IDENTIFIER = $(PRODUCT_BUNDLE_IDENTIFIER).AltBackup
//PRODUCT_BUNDLE_IDENTIFIER[config=Release] = $(ORG_IDENTIFIER).SideStore.AltBackup
//PRODUCT_BUNDLE_IDENTIFIER[config=Debug] = $(ORG_IDENTIFIER).SideStore.AltBackup
PRODUCT_BUNDLE_IDENTIFIER[config=Release] = $(ORG_IDENTIFIER).SideStore.AltBackup

View File

@@ -2,4 +2,5 @@
// Since AltStoreCore is unsigned or the team is not configured, we re-define the bundle ID here to not have extra '.' // Since AltStoreCore is unsigned or the team is not configured, we re-define the bundle ID here to not have extra '.'
// This bundle ID doesn't need to change since altStoreCore framework lives inside SideStore main app's address space and won't have conflicts with other instances // This bundle ID doesn't need to change since altStoreCore framework lives inside SideStore main app's address space and won't have conflicts with other instances
PRODUCT_BUNDLE_IDENTIFIER = $(ORG_IDENTIFIER).SideStore.AltStoreCore BUNDLE_ID = $(ORG_PREFIX).SideStore
PRODUCT_BUNDLE_IDENTIFIER = $(BUNDLE_ID).AltStoreCore

View File

@@ -1,4 +1,3 @@
#include "../Build.xcconfig" #include "../Build.xcconfig"
PRODUCT_BUNDLE_IDENTIFIER[config=Debug] = $(ORG_IDENTIFIER).SideStore.$(DEVELOPMENT_TEAM).AltWidget PRODUCT_BUNDLE_IDENTIFIER = $(PRODUCT_BUNDLE_IDENTIFIER).AltWidget
PRODUCT_BUNDLE_IDENTIFIER[config=Release] = $(ORG_IDENTIFIER).SideStore.AltWidget