Compare commits

..

33 Commits

Author SHA1 Message Date
ny
0b0c87d564 If it's gonna be that way... 2024-08-05 21:31:54 -04:00
ny
4a00955461 Add availability check to fix CI build(?) 2024-08-05 21:25:00 -04:00
ny
86f804391a Fix build issues given by develop 2024-08-05 21:15:42 -04:00
June Park
be75d8b4d9 Update AuthenticationOperation.swift
Signed-off-by: June Park <rjp2030@outlook.com>
2024-08-05 20:50:38 -04:00
ny
864e03cd4a Remove Settings bundle, add SwiftUI view instead
Fix refresh all shortcut intent
2024-08-05 20:50:36 -04:00
nythepegasus
be5e84537a Removes unnecessary StoreApp convenience properties as well as fix other issues 2024-08-05 20:49:34 -04:00
nythepegasus
1ae8d336be Removes unnecessary StoreApp convenience properties 2024-08-05 20:49:34 -04:00
nythepegasus
989b8e0010 Improves error message when file does not exist at AppVersion.downloadURL 2024-08-05 20:49:34 -04:00
nythepegasus
983355d356 Verifies min/max OS version before downloading app + asks user to download older app version if necessary 2024-08-05 20:49:34 -04:00
nythepegasus
a6ff416067 Conforms AppVersion to AppProtocol 2024-08-05 20:49:34 -04:00
nythepegasus
bbf712a822 Supports optional @Managed properties 2024-08-05 20:49:34 -04:00
nythepegasus
dd0436511a Supports non-NSManagedObjects for @Managed properties
This allows us to use @Managed with properties that may or may not be NSManagedObjects at runtime (e.g. protocols). If they are, Managed will keep strong reference to context like before.
2024-08-05 20:49:34 -04:00
nythepegasus
4667841c8d Parses AppVersion.minOSVersion/maxOSVersion from source JSON 2024-08-05 20:49:34 -04:00
nythepegasus
d2f0409452 Conforms OperatingSystemVersion to Comparable 2024-08-05 20:49:34 -04:00
Riley Testut
d718d2155f Replaces StoreApp.latestVersion with latestSupportedVersion + latestAvailableVersion
We now store the latest supported version as a relationship on StoreApp, rather than the latest available version. This allows us to reference the latest supported version in predicates and sort descriptors.

However, we kept the underlying Core Data property name the same to avoid extra migration.
2024-08-05 20:49:34 -04:00
nythepegasus
d0b424f408 Skips logging cancelled errors 2024-08-05 20:49:34 -04:00
nythepegasus
3e6ca7c673 Limits quitting other AltStore/SideStore processes to database migrations 2024-08-05 20:49:33 -04:00
nythepegasus
31a3323ef2 Fixes logging non-AltServerErrors as AltServerError.underlyingError 2024-08-05 20:49:33 -04:00
nythepegasus
7edb5716b7 Fix typo 2024-08-05 20:49:33 -04:00
nythepegasus
78bf461c5b Fix wrong color in AuthenticationViewController 2024-08-05 20:49:33 -04:00
nythepegasus
8cfe8a1ac0 Fix Error Log not showing UIAlertController on iOS <=13 2024-08-05 20:49:33 -04:00
nythepegasus
9b7c0387cf Fix Error Log showing UIAlertController on iOS 14+ 2024-08-05 20:49:33 -04:00
nythepegasus
1a36726361 Fixes incorrect Search FAQ URL 2024-08-05 20:49:33 -04:00
nythepegasus
e2a5e263f4 Fixes Error Log context menu appearing while scrolling 2024-08-05 20:49:33 -04:00
nythepegasus
16d13c430c Fixes Error Log context menu covering cell content 2024-08-05 20:49:33 -04:00
nythepegasus
b024e67fee Opens Error Log when tapping ToastView 2024-08-05 20:49:33 -04:00
nythepegasus
4365ba0f1a [skip ci] Update the no wifi message to include VPN 2024-08-05 20:49:31 -04:00
nythepegasus
36ceec3ae7 Fix minimuxer status checking 2024-08-05 20:48:16 -04:00
nythepegasus
99652aae65 Include "Enable JIT" errors in Error Log 2024-08-05 20:47:02 -04:00
nythepegasus
6c8a400aec Fix format strings I broke 2024-08-05 20:47:00 -04:00
nythepegasus
c24de874e6 Finish Riley's monster commit
3b38d725d7
May the Gods have mercy on my soul.
2024-08-05 20:46:08 -04:00
nythepegasus
775167415a Adds ResultOperation.localizedFailure 2024-08-05 20:32:13 -04:00
nythepegasus
459e378522 Change error from Swift.Error to NSError 2024-08-05 20:32:13 -04:00
53 changed files with 436 additions and 1352 deletions

View File

@@ -7,7 +7,6 @@ body:
- type: markdown
attributes:
value: |
## Please note that the issue tracker is not for support
Thanks for taking the time to fill out this bug report! Before you continue filling out the report, please **[search in GitHub Issues](https://github.com/SideStore/SideStore/issues?q=is%3Aissue+is%3Aopen) for the bug you are experiencing** in case it has already been reported.
**Please use [Discord](https://discord.gg/sidestore-949183273383395328) or [GitHub Discussions](https://github.com/SideStore/SideStore/discussions) for support.**

View File

@@ -10,3 +10,6 @@
<!-- Example: -->
- [x] Finish UI changes
- [ ] Test
<!-- If your PR doesn't close an issue, you can remove the next line. -->
Closes #1234

View File

@@ -20,58 +20,3 @@ jobs:
format: name
addTo: pull
# addTo: pullandissues
nightly-link-comment:
if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success'
runs-on: ubuntu-latest
steps:
- uses: actions/github-script@v6
with:
# This snippet is public-domain, taken from
# https://github.com/oprypin/nightly.link/blob/master/.github/workflows/pr-comment.yml
script: |
async function upsertComment(owner, repo, issue_number, purpose, body) {
const {data: comments} = await github.rest.issues.listComments(
{owner, repo, issue_number});
const marker = `<!-- bot: ${purpose} -->`;
body = marker + "\n" + body;
const existing = comments.filter((c) => c.body.includes(marker));
if (existing.length > 0) {
const last = existing[existing.length - 1];
core.info(`Updating comment ${last.id}`);
await github.rest.issues.updateComment({
owner, repo,
body,
comment_id: last.id,
});
} else {
core.info(`Creating a comment in issue / PR #${issue_number}`);
await github.rest.issues.createComment({issue_number, body, owner, repo});
}
}
const {owner, repo} = context.repo;
const run_id = ${{github.event.workflow_run.id}};
const pull_requests = ${{ toJSON(github.event.workflow_run.pull_requests) }};
if (!pull_requests.length) {
return core.error("This workflow doesn't match any pull requests!");
}
const artifacts = await github.paginate(
github.rest.actions.listWorkflowRunArtifacts, {owner, repo, run_id});
if (!artifacts.length) {
return core.error(`No artifacts found`);
}
let body = `Download the artifacts for this pull request (nightly.link):\n`;
for (const art of artifacts) {
body += `\n* [${art.name}.zip](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
}
core.info("Review thread message body:", body);
for (const pr of pull_requests) {
await upsertComment(owner, repo, pr.number,
"nightly-link", body);
}

View File

@@ -11,13 +11,13 @@ jobs:
fail-fast: false
matrix:
include:
- os: 'macos-14'
version: '15.4'
- os: 'macos-12'
version: '14.2'
runs-on: ${{ matrix.os }}
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v2
with:
submodules: recursive
@@ -35,17 +35,10 @@ jobs:
run: echo "${{ steps.version.outputs.version }}"
- name: Setup Xcode
uses: maxim-lobanov/setup-xcode@v1
uses: maxim-lobanov/setup-xcode@v1.4.1
with:
xcode-version: ${{ matrix.version }}
- name: Cache Build
uses: irgaly/xcode-cache@v1
with:
key: xcode-cache-deriveddata-${{ github.sha }}
restore-keys: xcode-cache-deriveddata
- name: Build SideStore
run: make build | xcpretty && exit ${PIPESTATUS[0]}
@@ -91,13 +84,13 @@ jobs:
run: mv SideStore.ipa SideStore-${{ steps.version.outputs.version }}.ipa
- name: Upload SideStore.ipa Artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3.1.0
with:
name: SideStore-${{ steps.version.outputs.version }}.ipa
path: SideStore-${{ steps.version.outputs.version }}.ipa
- name: Upload *.dSYM Artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3.1.0
with:
name: SideStore-${{ steps.version.outputs.version }}-dSYM
path: ./*.dSYM/

View File

@@ -14,13 +14,13 @@ jobs:
fail-fast: false
matrix:
include:
- os: 'macos-14'
version: '15.4'
- os: 'macos-12'
version: '14.2'
runs-on: ${{ matrix.os }}
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v2
with:
submodules: recursive
@@ -28,7 +28,7 @@ jobs:
run: brew install ldid
- name: Cache .nightly-build-num
uses: actions/cache@v4
uses: actions/cache@v3
with:
path: .nightly-build-num
key: nightly-build-num
@@ -44,16 +44,10 @@ jobs:
run: echo "${{ steps.version.outputs.version }}"
- name: Setup Xcode
uses: maxim-lobanov/setup-xcode@v1.6.0
uses: maxim-lobanov/setup-xcode@v1.4.1
with:
xcode-version: ${{ matrix.version }}
- name: Cache Build
uses: irgaly/xcode-cache@v1
with:
key: xcode-cache-deriveddata-${{ github.sha }}
restore-keys: xcode-cache-deriveddata-
- name: Build SideStore
run: make build | xcpretty && exit ${PIPESTATUS[0]}
@@ -97,13 +91,16 @@ jobs:
run: mv SideStore.ipa SideStore-${{ steps.version.outputs.version }}.ipa
- name: Upload SideStore.ipa Artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3.1.0
with:
name: SideStore-${{ steps.version.outputs.version }}.ipa
path: SideStore-${{ steps.version.outputs.version }}.ipa
- name: Upload *.dSYM Artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3.1.0
with:
name: SideStore-${{ steps.version.outputs.version }}-dSYM
path: ./*.dSYM/
- name: Reset cache for apps.sidestore.io/nightly
run: sleep 10 && curl https://apps.sidestore.io/reset-cache/nightly/${{ secrets.SIDESOURCE_KEY }}

View File

@@ -9,13 +9,13 @@ jobs:
fail-fast: false
matrix:
include:
- os: 'macos-14'
version: '15.4'
- os: 'macos-12'
version: '14.2'
runs-on: ${{ matrix.os }}
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v2
with:
submodules: recursive
@@ -35,16 +35,10 @@ jobs:
run: echo "${{ steps.version.outputs.version }}"
- name: Setup Xcode
uses: maxim-lobanov/setup-xcode@v1.6.0
uses: maxim-lobanov/setup-xcode@v1.4.1
with:
xcode-version: ${{ matrix.version }}
- name: Cache Build
uses: irgaly/xcode-cache@v1
with:
key: xcode-cache-deriveddata-${{ github.sha }}
restore-keys: xcode-cache-deriveddata-
- name: Build SideStore
run: make build | xcpretty && exit ${PIPESTATUS[0]}
@@ -58,13 +52,13 @@ jobs:
run: mv SideStore.ipa SideStore-${{ steps.version.outputs.version }}.ipa
- name: Upload SideStore.ipa Artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3.1.0
with:
name: SideStore-${{ steps.version.outputs.version }}.ipa
path: SideStore-${{ steps.version.outputs.version }}.ipa
- name: Upload *.dSYM Artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3.1.0
with:
name: SideStore-${{ steps.version.outputs.version }}-dSYM
path: ./*.dSYM/

View File

@@ -11,13 +11,13 @@ jobs:
fail-fast: false
matrix:
include:
- os: 'macos-14'
version: '15.4'
- os: 'macos-12'
version: '14.2'
runs-on: ${{ matrix.os }}
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v2
with:
submodules: recursive
@@ -35,16 +35,10 @@ jobs:
run: echo "${{ steps.version.outputs.version }}"
- name: Setup Xcode
uses: maxim-lobanov/setup-xcode@v1.6.0
uses: maxim-lobanov/setup-xcode@v1.4.1
with:
xcode-version: ${{ matrix.version }}
- name: Cache Build
uses: irgaly/xcode-cache@v1
with:
key: xcode-cache-deriveddata-${{ github.sha }}
restore-keys: xcode-cache-deriveddata-
- name: Build SideStore
run: make build | xcpretty && exit ${PIPESTATUS[0]}
@@ -87,13 +81,13 @@ jobs:
run: mv SideStore.ipa SideStore-${{ steps.version.outputs.version }}.ipa
- name: Upload SideStore.ipa Artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3.1.0
with:
name: SideStore-${{ steps.version.outputs.version }}.ipa
path: SideStore-${{ steps.version.outputs.version }}.ipa
- name: Upload *.dSYM Artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3.1.0
with:
name: SideStore-${{ steps.version.outputs.version }}-dSYM
path: ./*.dSYM/

1
.gitignore vendored
View File

@@ -19,6 +19,7 @@ archive.xcarchive
*.perspectivev3
!default.perspectivev3
xcuserdata
## Other
*.xccheckout
*.moved-aside

View File

@@ -1,48 +0,0 @@
//
// ErrorDetailsViewController.swift
// AltServer
//
// Created by Riley Testut on 10/4/22.
// Copyright © 2022 Riley Testut. All rights reserved.
//
import AppKit
class ErrorDetailsViewController: NSViewController
{
var error: NSError? {
didSet {
self.update()
}
}
@IBOutlet private var errorCodeLabel: NSTextField!
@IBOutlet private var detailedDescriptionLabel: NSTextField!
override func viewDidLoad()
{
super.viewDidLoad()
self.detailedDescriptionLabel.preferredMaxLayoutWidth = 800
}
}
private extension ErrorDetailsViewController
{
func update()
{
if !self.isViewLoaded
{
self.loadView()
}
guard let error = self.error else { return }
self.errorCodeLabel.stringValue = error.localizedErrorCode
let font = self.detailedDescriptionLabel.font ?? NSFont.systemFont(ofSize: 12)
let detailedDescription = error.formattedDetailedDescription(with: font)
self.detailedDescriptionLabel.attributedStringValue = detailedDescription
}
}

View File

@@ -10,7 +10,6 @@
03F06CD52942C27E001C4D68 /* Bundle+AltStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF1E314122A05D4C00370A3C /* Bundle+AltStore.swift */; };
0E05025A2BEC83C500879B5C /* OperatingSystemVersion+Comparable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0502592BEC83C500879B5C /* OperatingSystemVersion+Comparable.swift */; };
0E05025C2BEC947000879B5C /* String+SideStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E05025B2BEC947000879B5C /* String+SideStore.swift */; };
0E13E5862CC8F55900E9C0DF /* ProcessInfo+SideStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E13E5852CC8F55900E9C0DF /* ProcessInfo+SideStore.swift */; };
0E1A1F912AE36A9700364CAD /* bytearray.c in Sources */ = {isa = PBXBuildFile; fileRef = 0E1A1F902AE36A9600364CAD /* bytearray.c */; };
0E764E172ADFF5740043DD4E /* AltBackup.ipa in Resources */ = {isa = PBXBuildFile; fileRef = 0E764E162ADFF5740043DD4E /* AltBackup.ipa */; };
0EA1665B2ADFE0D2003015C1 /* out-limd.c in Sources */ = {isa = PBXBuildFile; fileRef = 0EA166472ADFE0D1003015C1 /* out-limd.c */; };
@@ -60,7 +59,6 @@
99F87D0529D8B4E200B40039 /* minimuxer-helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9961EC2D29BE9F2E00AF2C6F /* minimuxer-helpers.swift */; };
99F87D1829D8E4C900B40039 /* SwiftBridgeCore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99F87D1629D8E4C900B40039 /* SwiftBridgeCore.swift */; };
99F87D1929D8E4C900B40039 /* minimuxer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99F87D1729D8E4C900B40039 /* minimuxer.swift */; };
A800F7042CE28E3800208744 /* View+AltWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = A800F7032CE28E2F00208744 /* View+AltWidget.swift */; };
B3146ED2284F581E00BBC3FD /* Roxas.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B3146ECD284F580500BBC3FD /* Roxas.framework */; };
B33FFBA8295F8E98002259E6 /* libfragmentzip.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B343F894295F7F9B002B1159 /* libfragmentzip.a */; };
B33FFBAA295F8F78002259E6 /* preboard.c in Sources */ = {isa = PBXBuildFile; fileRef = B33FFBA9295F8F78002259E6 /* preboard.c */; };
@@ -86,7 +84,6 @@
B3C395F7284F362400DA9E2F /* AppCenterAnalytics in Frameworks */ = {isa = PBXBuildFile; productRef = B3C395F6284F362400DA9E2F /* AppCenterAnalytics */; };
B3C395F9284F362400DA9E2F /* AppCenterCrashes in Frameworks */ = {isa = PBXBuildFile; productRef = B3C395F8284F362400DA9E2F /* AppCenterCrashes */; };
B3EE16B62925E27D00B3B1F5 /* AnisetteManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3EE16B52925E27D00B3B1F5 /* AnisetteManager.swift */; };
BD4513AB2C6FA98C0052BCC0 /* AppExtensionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD4513AA2C6FA98C0052BCC0 /* AppExtensionView.swift */; };
BF02419622F2199300129732 /* RefreshAttemptsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF02419522F2199300129732 /* RefreshAttemptsViewController.swift */; };
BF08858322DE795100DE9F1E /* MyAppsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF08858222DE795100DE9F1E /* MyAppsViewController.swift */; };
BF08858522DE7EC800DE9F1E /* UpdateCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF08858422DE7EC800DE9F1E /* UpdateCollectionViewCell.swift */; };
@@ -511,7 +508,6 @@
/* Begin PBXFileReference section */
0E0502592BEC83C500879B5C /* OperatingSystemVersion+Comparable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OperatingSystemVersion+Comparable.swift"; sourceTree = "<group>"; };
0E05025B2BEC947000879B5C /* String+SideStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+SideStore.swift"; sourceTree = "<group>"; };
0E13E5852CC8F55900E9C0DF /* ProcessInfo+SideStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ProcessInfo+SideStore.swift"; sourceTree = "<group>"; };
0E1A1F902AE36A9600364CAD /* bytearray.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = bytearray.c; path = src/bytearray.c; sourceTree = "<group>"; };
0E764E162ADFF5740043DD4E /* AltBackup.ipa */ = {isa = PBXFileReference; lastKnownFileType = file; name = AltBackup.ipa; path = AltStore/Resources/AltBackup.ipa; sourceTree = SOURCE_ROOT; };
0EA166412ADFE0D1003015C1 /* jplist.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jplist.c; path = Dependencies/libplist/src/jplist.c; sourceTree = SOURCE_ROOT; };
@@ -560,7 +556,6 @@
9961EC2D29BE9F2E00AF2C6F /* minimuxer-helpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "minimuxer-helpers.swift"; path = "Dependencies/minimuxer/minimuxer-helpers.swift"; sourceTree = SOURCE_ROOT; };
99F87D1629D8E4C900B40039 /* SwiftBridgeCore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SwiftBridgeCore.swift; path = Dependencies/minimuxer/SwiftBridgeCore.swift; sourceTree = SOURCE_ROOT; };
99F87D1729D8E4C900B40039 /* minimuxer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = minimuxer.swift; path = Dependencies/minimuxer/minimuxer.swift; sourceTree = SOURCE_ROOT; };
A800F7032CE28E2F00208744 /* View+AltWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+AltWidget.swift"; sourceTree = "<group>"; };
B3146EC6284F580500BBC3FD /* Roxas.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Roxas.xcodeproj; path = Dependencies/Roxas/Roxas.xcodeproj; sourceTree = "<group>"; };
B33FFBA9295F8F78002259E6 /* preboard.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = preboard.c; path = src/preboard.c; sourceTree = "<group>"; };
B33FFBAB295F8F98002259E6 /* companion_proxy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = companion_proxy.c; path = src/companion_proxy.c; sourceTree = "<group>"; };
@@ -589,7 +584,6 @@
B3C3960E284F4F9100DA9E2F /* AltStoreCore.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AltStoreCore.xcconfig; sourceTree = "<group>"; };
B3C3960F284F53E900DA9E2F /* AltBackup.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AltBackup.xcconfig; sourceTree = "<group>"; };
B3EE16B52925E27D00B3B1F5 /* AnisetteManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnisetteManager.swift; sourceTree = "<group>"; };
BD4513AA2C6FA98C0052BCC0 /* AppExtensionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppExtensionView.swift; sourceTree = "<group>"; };
BF02419522F2199300129732 /* RefreshAttemptsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RefreshAttemptsViewController.swift; sourceTree = "<group>"; };
BF08858222DE795100DE9F1E /* MyAppsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyAppsViewController.swift; sourceTree = "<group>"; };
BF08858422DE7EC800DE9F1E /* UpdateCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateCollectionViewCell.swift; sourceTree = "<group>"; };
@@ -1010,14 +1004,6 @@
name = Generated;
sourceTree = "<group>";
};
A800F6FE2CE28DE300208744 /* Extensions */ = {
isa = PBXGroup;
children = (
A800F7032CE28E2F00208744 /* View+AltWidget.swift */,
);
path = Extensions;
sourceTree = "<group>";
};
B3146EC7284F580500BBC3FD /* Products */ = {
isa = PBXGroup;
children = (
@@ -1475,7 +1461,6 @@
BF98916C250AABF3002ACF50 /* AltWidget */ = {
isa = PBXGroup;
children = (
A800F6FE2CE28DE300208744 /* Extensions */,
BF8B17F0250AC62400F8157F /* AltWidgetExtension.entitlements */,
BF98917D250AAC4F002ACF50 /* AltWidget.swift */,
BF42345825101C1D006D1EB2 /* WidgetView.swift */,
@@ -1638,7 +1623,6 @@
children = (
BF0C4EBC22A1BD8B009A2DD7 /* AppManager.swift */,
BF88F97124F8727D00BB75DF /* AppManagerErrors.swift */,
BD4513AA2C6FA98C0052BCC0 /* AppExtensionView.swift */,
);
path = "Managing Apps";
sourceTree = "<group>";
@@ -1691,7 +1675,6 @@
BFE00A1F2503097F00EB4D0C /* INInteraction+AltStore.swift */,
D57F2C9326E01BC700B9FA39 /* UIDevice+Vibration.swift */,
B376FE3D29258C8900E18883 /* OSLog+SideStore.swift */,
0E13E5852CC8F55900E9C0DF /* ProcessInfo+SideStore.swift */,
);
path = Extensions;
sourceTree = "<group>";
@@ -2500,7 +2483,6 @@
BF42345A25101C35006D1EB2 /* WidgetView.swift in Sources */,
D55E163728776CB700A627A1 /* ComplicationView.swift in Sources */,
BF98917F250AAC4F002ACF50 /* AltWidget.swift in Sources */,
A800F7042CE28E3800208744 /* View+AltWidget.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -2550,7 +2532,6 @@
BF6C8FAE2429597900125131 /* BannerCollectionViewCell.swift in Sources */,
BF6F439223644C6E00A0B879 /* RefreshAltStoreViewController.swift in Sources */,
BFE60742231B07E6002B0E8E /* SettingsHeaderFooterView.swift in Sources */,
BD4513AB2C6FA98C0052BCC0 /* AppExtensionView.swift in Sources */,
BFE338E822F10E56002E24B9 /* LaunchViewController.swift in Sources */,
BFA8172B23C5633D001B5953 /* FetchAnisetteDataOperation.swift in Sources */,
BF9ABA4722DD0638008935CF /* BrowseCollectionViewCell.swift in Sources */,
@@ -2567,7 +2548,6 @@
BF770E5822BC3D0F002A40FE /* RefreshGroup.swift in Sources */,
19B9B7452845E6DF0076EF69 /* SelectTeamViewController.swift in Sources */,
99F87D0529D8B4E200B40039 /* minimuxer-helpers.swift in Sources */,
0E13E5862CC8F55900E9C0DF /* ProcessInfo+SideStore.swift in Sources */,
BF18B0F122E25DF9005C4CF5 /* ToastView.swift in Sources */,
BF3D649F22E7B24C00E9056B /* CollapsingTextView.swift in Sources */,
BF02419622F2199300129732 /* RefreshAttemptsViewController.swift in Sources */,
@@ -3013,13 +2993,12 @@
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = AltStoreCore/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 18.0;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
LLVM_LTO = YES_THIN;
PRODUCT_BUNDLE_IDENTIFIER = "$(PRODUCT_BUNDLE_IDENTIFIER)";
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -3048,16 +3027,14 @@
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
GCC_OPTIMIZATION_LEVEL = fast;
INFOPLIST_FILE = AltStoreCore/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 18.0;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
LLVM_LTO = YES_THIN;
PRODUCT_BUNDLE_IDENTIFIER = "$(PRODUCT_BUNDLE_IDENTIFIER)";
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -3085,10 +3062,9 @@
CODE_SIGN_STYLE = Automatic;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)";
ENABLE_DEBUG_DYLIB = YES;
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
INFOPLIST_FILE = AltWidget/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 18.0;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@@ -3116,10 +3092,9 @@
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)";
ENABLE_DEBUG_DYLIB = YES;
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
INFOPLIST_FILE = AltWidget/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 18.0;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@@ -3169,7 +3144,6 @@
CODE_SIGN_IDENTITY = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
EAGER_LINKING = YES;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
@@ -3186,8 +3160,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 18.0;
LLVM_LTO = YES_THIN;
IPHONEOS_DEPLOYMENT_TARGET = 12.2;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
@@ -3198,7 +3171,6 @@
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos macosx";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG BETA";
SWIFT_ENFORCE_EXCLUSIVE_ACCESS = "debug-only";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SYSTEM_HEADER_SEARCH_PATHS = "\"$(SRCROOT)/Dependencies/AltSign/Dependencies\"";
};
@@ -3240,20 +3212,17 @@
CODE_SIGN_IDENTITY = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
EAGER_LINKING = YES;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = fast;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 18.0;
LLVM_LTO = YES_THIN;
IPHONEOS_DEPLOYMENT_TARGET = 12.2;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
OTHER_CPLUSPLUSFLAGS = (
@@ -3263,9 +3232,8 @@
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos macosx";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG BETA";
SWIFT_COMPILATION_MODE = singlefile;
SWIFT_ENFORCE_EXCLUSIVE_ACCESS = "debug-only";
SWIFT_OPTIMIZATION_LEVEL = "-Osize";
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
SYSTEM_HEADER_SEARCH_PATHS = "\"$(SRCROOT)/Dependencies/AltSign/Dependencies\"";
VALIDATE_PRODUCT = YES;
};
@@ -3275,7 +3243,7 @@
isa = XCBuildConfiguration;
baseConfigurationReference = B3C3960B284F4C9800DA9E2F /* AltStore.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = AltStore/AltStore.entitlements;
@@ -3283,11 +3251,8 @@
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)";
ENABLE_BITCODE = NO;
ENABLE_DEBUG_DYLIB = NO;
GCC_UNROLL_LOOPS = YES;
INFOPLIST_FILE = AltStore/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 18.0;
LD_EXPORT_SYMBOLS = NO;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@@ -3297,13 +3262,11 @@
"$(PROJECT_DIR)/Dependencies/libfragmentzip",
"$(PROJECT_DIR)/Dependencies/libcurl",
);
LLVM_LTO = YES_THIN;
OTHER_LDFLAGS = "";
PRODUCT_BUNDLE_IDENTIFIER = "$(PRODUCT_BUNDLE_IDENTIFIER)";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
SWIFT_ENFORCE_EXCLUSIVE_ACCESS = "debug-only";
SWIFT_OBJC_BRIDGING_HEADER = "AltStore/AltStore-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
@@ -3315,7 +3278,7 @@
isa = XCBuildConfiguration;
baseConfigurationReference = B3C3960B284F4C9800DA9E2F /* AltStore.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = AltStore/AltStore.entitlements;
@@ -3323,12 +3286,8 @@
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)";
ENABLE_BITCODE = NO;
ENABLE_DEBUG_DYLIB = NO;
GCC_OPTIMIZATION_LEVEL = fast;
GCC_UNROLL_LOOPS = YES;
INFOPLIST_FILE = AltStore/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 18.0;
LD_EXPORT_SYMBOLS = NO;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@@ -3338,16 +3297,12 @@
"$(PROJECT_DIR)/Dependencies/libfragmentzip",
"$(PROJECT_DIR)/Dependencies/libcurl",
);
LLVM_LTO = YES_THIN;
OTHER_LDFLAGS = "";
PRODUCT_BUNDLE_IDENTIFIER = "$(PRODUCT_BUNDLE_IDENTIFIER)";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
SWIFT_COMPILATION_MODE = singlefile;
SWIFT_ENFORCE_EXCLUSIVE_ACCESS = "debug-only";
SWIFT_OBJC_BRIDGING_HEADER = "AltStore/AltStore-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Osize";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};

View File

@@ -2,12 +2,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.developer.kernel.extended-virtual-addressing</key>
<true/>
<key>com.apple.developer.kernel.increased-debugging-memory-limit</key>
<true/>
<key>com.apple.developer.kernel.increased-memory-limit</key>
<true/>
<key>aps-environment</key>
<string>development</string>
<key>com.apple.developer.siri</key>
<true/>
<key>com.apple.security.application-groups</key>

View File

@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<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">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22684"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
<capability name="Named colors" minToolsVersion="9.0"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
@@ -13,8 +13,8 @@
<scene sceneID="lNR-II-WoW">
<objects>
<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">
<rect key="frame" x="0.0" y="20" width="375" height="96"/>
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" barStyle="black" largeTitles="YES" id="Aej-RF-PfV" customClass="NavigationBar" customModule="AltStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="375" height="96"/>
<autoresizingMask key="autoresizingMask"/>
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="barTintColor" name="SettingsBackground"/>
@@ -36,19 +36,19 @@
<!--Authentication View Controller-->
<scene sceneID="OCd-xc-Ms7">
<objects>
<viewController storyboardIdentifier="authenticationViewController" id="yO1-iT-7NP" customClass="AuthenticationViewController" customModule="SideStore" customModuleProvider="target" sceneMemberID="viewController">
<viewController storyboardIdentifier="authenticationViewController" id="yO1-iT-7NP" customClass="AuthenticationViewController" customModule="AltStore" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="mjy-4S-hyH">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<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>
<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"/>
<subviews>
<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>
<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"/>
@@ -57,7 +57,7 @@
<rect key="frame" x="0.0" y="0.0" width="343" height="67.5"/>
<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">
<rect key="frame" x="0.0" y="0.0" width="343" height="41"/>
<rect key="frame" x="0.0" y="0.0" width="332" height="41"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="34"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
@@ -179,7 +179,7 @@
</subviews>
</stackView>
<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>
<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"/>
@@ -198,10 +198,6 @@
</stackView>
</subviews>
<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"/>
</constraints>
</view>
@@ -219,15 +215,19 @@
<constraints>
<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 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="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="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 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="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="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"/>
</constraints>
</view>
@@ -258,13 +258,13 @@
<!--How it works-->
<scene sceneID="dMt-EA-SGy">
<objects>
<viewController storyboardIdentifier="instructionsViewController" hidesBottomBarWhenPushed="YES" id="aFi-fb-W0B" customClass="InstructionsViewController" customModule="SideStore" customModuleProvider="target" sceneMemberID="viewController">
<viewController storyboardIdentifier="instructionsViewController" hidesBottomBarWhenPushed="YES" id="aFi-fb-W0B" customClass="InstructionsViewController" customModule="AltStore" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" id="Otz-hn-WGS">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<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>
<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"/>
@@ -298,7 +298,7 @@
</subviews>
</stackView>
<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>
<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"/>
@@ -310,7 +310,7 @@
<nil key="highlightedColor"/>
</label>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="5" translatesAutoresizingMaskIntoConstraints="NO" id="dMu-eg-gIO">
<rect key="frame" x="79" y="17.5" width="264" height="60.5"/>
<rect key="frame" x="79" y="17" width="264" height="61.5"/>
<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">
<rect key="frame" x="0.0" y="0.0" width="264" height="20.5"/>
@@ -319,7 +319,7 @@
<nil key="highlightedColor"/>
</label>
<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="35"/>
<rect key="frame" x="0.0" y="25.5" width="264" height="36"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" white="1" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
@@ -329,7 +329,7 @@
</subviews>
</stackView>
<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>
<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"/>
@@ -341,7 +341,7 @@
<nil key="highlightedColor"/>
</label>
<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>
<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"/>
@@ -360,7 +360,7 @@
</subviews>
</stackView>
<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>
<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"/>
@@ -434,7 +434,7 @@
<!--Refresh AltStore-->
<scene sceneID="9Vh-dM-OqX">
<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="AltStore" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" id="R83-kV-365">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
@@ -445,7 +445,7 @@
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="tDQ-ao-1Jg">
<rect key="frame" x="16" y="570" width="343" height="89"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="xcg-hT-tDe" customClass="PillButton" customModule="SideStore" customModuleProvider="target">
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="xcg-hT-tDe" customClass="PillButton" customModule="AltStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="343" height="51"/>
<color key="backgroundColor" name="SettingsHighlighted"/>
<constraints>
@@ -493,12 +493,12 @@
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="Chr-7g-qEw" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="3025" y="734"/>
<point key="canvasLocation" x="2967" y="736"/>
</scene>
<!--Select a Team-->
<scene sceneID="ioQ-WB-CLJ">
<objects>
<viewController storyboardIdentifier="selectTeamViewController" hidesBottomBarWhenPushed="YES" id="kOD-4P-a6L" customClass="SelectTeamViewController" customModule="SideStore" customModuleProvider="target" sceneMemberID="viewController">
<viewController storyboardIdentifier="selectTeamViewController" hidesBottomBarWhenPushed="YES" id="kOD-4P-a6L" customClass="SelectTeamViewController" customModule="AltStore" customModuleProvider="target" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" indicatorStyle="white" dataMode="prototypes" style="grouped" separatorStyle="none" rowHeight="60" estimatedRowHeight="-1" sectionHeaderHeight="18" sectionFooterHeight="18" id="fWW-kX-ifH">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
@@ -506,11 +506,11 @@
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="separatorColor" white="1" alpha="0.25" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="TeamCell" textLabel="6ip-34-gmM" detailTextLabel="knk-Wf-PKf" style="IBUITableViewCellStyleSubtitle" id="qeQ-eb-2SC" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="TeamCell" textLabel="6ip-34-gmM" detailTextLabel="knk-Wf-PKf" style="IBUITableViewCellStyleSubtitle" id="qeQ-eb-2SC" customClass="InsetGroupTableViewCell" customModule="AltStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="55.5" width="375" height="60"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="qeQ-eb-2SC" id="bT4-Fc-u6I">
<rect key="frame" x="0.0" y="0.0" width="334.5" height="60"/>
<rect key="frame" x="0.0" y="0.0" width="334" height="60"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Team 1" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="6ip-34-gmM">
@@ -550,19 +550,20 @@
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="yH5-jU-aez" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="2114" y="734"/>
<point key="canvasLocation" x="1401" y="734"/>
</scene>
</scenes>
<color key="tintColor" name="Primary"/>
<resources>
<namedColor name="Primary">
<color red="0.64313725490196083" green="0.019607843137254902" blue="0.98039215686274506" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</namedColor>
</scenes>
<color key="tintColor" name="Primary"/>
<resources>
<namedColor name="Primary">
<color red="0.0040000001899898052" green="0.50199997425079346" blue="0.51800000667572021" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</namedColor>
<namedColor name="SettingsBackground">
<color red="0.45098039215686275" green="0.015686274509803921" blue="0.68627450980392157" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color red="0.0039215686274509803" green="0.50196078431372548" blue="0.51764705882352946" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</namedColor>
<namedColor name="SettingsHighlighted">
<color red="0.38823529411764707" green="0.011764705882352941" blue="0.58823529411764708" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color red="0.0080000003799796104" green="0.32199999690055847" blue="0.40400001406669617" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</namedColor>
</resources>
</document>

View File

@@ -1,96 +0,0 @@
//
// ProcessInfo+SideStore.swift
// SideStore
//
// Created by ny on 10/23/24.
// Copyright © 2024 SideStore. All rights reserved.
//
import Foundation
fileprivate struct BuildVersion: Comparable {
let prefix: String
let numericPart: Int
let suffix: Character?
init?(_ buildString: String) {
// Initialize indices
var index = buildString.startIndex
// Extract prefix (letters before the numeric part)
while index < buildString.endIndex, !buildString[index].isNumber {
index = buildString.index(after: index)
}
guard index > buildString.startIndex else { return nil }
self.prefix = String(buildString[buildString.startIndex..<index])
// Extract numeric part
let startOfNumeric = index
while index < buildString.endIndex, buildString[index].isNumber {
index = buildString.index(after: index)
}
guard let numericValue = Int(buildString[startOfNumeric..<index]) else { return nil }
self.numericPart = numericValue
// Extract suffix (if any)
if index < buildString.endIndex {
self.suffix = buildString[index]
} else {
self.suffix = nil
}
}
// Implement Comparable protocol
static func < (lhs: BuildVersion, rhs: BuildVersion) -> Bool {
// Compare prefixes
if lhs.prefix != rhs.prefix {
return lhs.prefix < rhs.prefix
}
// Compare numeric parts
if lhs.numericPart != rhs.numericPart {
return lhs.numericPart < rhs.numericPart
}
// Compare suffixes
switch (lhs.suffix, rhs.suffix) {
case let (l?, r?):
return l < r
case (nil, _?):
return true // nil is considered less than any character
case (_?, nil):
return false
default:
return false // Both are nil and equal
}
}
static func == (lhs: BuildVersion, rhs: BuildVersion) -> Bool {
return lhs.prefix == rhs.prefix &&
lhs.numericPart == rhs.numericPart &&
lhs.suffix == rhs.suffix
}
}
extension ProcessInfo {
var shortVersion: String {
operatingSystemVersionString
.replacingOccurrences(of: "Version ", with: "")
.replacingOccurrences(of: "Build ", with: "")
}
var operatingSystemBuild: String {
if let start = shortVersion.range(of: "(")?.upperBound,
let end = shortVersion.range(of: ")")?.lowerBound {
shortVersion[start..<end].replacingOccurrences(of: "Build ", with: "")
} else { "???" }
}
var sparseRestorePatched: Bool {
if operatingSystemVersion < OperatingSystemVersion(majorVersion: 18, minorVersion: 1, patchVersion: 0) { false }
else if operatingSystemVersion > OperatingSystemVersion(majorVersion: 18, minorVersion: 1, patchVersion: 1) { true }
else if operatingSystemVersion >= OperatingSystemVersion(majorVersion: 18, minorVersion: 1, patchVersion: 0),
let currentBuild = BuildVersion(operatingSystemBuild),
let targetBuild = BuildVersion("22B5054e") {
currentBuild >= targetBuild
} else { false }
}
}

View File

@@ -92,7 +92,7 @@
<key>LSRequiresIPhoneOS</key>
<true/>
<key>LSSupportsOpeningDocumentsInPlace</key>
<false/>
<true/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>

View File

@@ -118,9 +118,8 @@ private extension IntentHandler
{
// Queue response in case refreshing finishes after confirm() but before handle().
self.queuedResponses[intent] = response
DispatchQueue.main.async {
UIApplication.shared.perform(#selector(NSXPCConnection.suspend))
}
UIApplication.shared.perform(#selector(NSXPCConnection.suspend))
}
}
}

View File

@@ -159,7 +159,7 @@ final class LaunchViewController: RSTLaunchViewController, UIDocumentPickerDeleg
} 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)
let dialogMessage = UIAlertController(title: "Pairing File", message: "Select the pairing file for your device. For more information, go to https://wiki.sidestore.io/guides/getting-started/#pairing-file", preferredStyle: .alert)
// Create OK button with action handler
let ok = UIAlertAction(title: "OK", style: .default, handler: { (action) -> Void in
@@ -174,18 +174,7 @@ final class LaunchViewController: RSTLaunchViewController, UIDocumentPickerDeleg
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)
//Add OK button to a dialog message
dialogMessage.addAction(ok)
// Present Alert to

View File

@@ -1,81 +0,0 @@
//
// AppExtensionView.swift
// SideStore
//
// Created by June P on 8/17/24.
// Copyright © 2024 SideStore. All rights reserved.
//
import SwiftUI
import CAltSign
extension ALTApplication: Identifiable {}
struct AppExtensionView: View {
var extensions: Set<ALTApplication>
@State var selection: [ALTApplication] = []
var completion: (_ selection: [ALTApplication]) -> Any?
var body: some View {
NavigationView {
List {
ForEach(self.extensions.sorted {
$0.bundleIdentifier < $1.bundleIdentifier
}, id: \.self) { item in
MultipleSelectionRow(title: item.bundleIdentifier, isSelected: !selection.contains(item)) {
if self.selection.contains(item) {
self.selection.removeAll(where: { $0 == item })
}
else {
self.selection.append(item)
}
}
}
}
.navigationTitle("App Extensions")
.onDisappear {
_ = completion(selection)
}
}
}
}
struct MultipleSelectionRow: View {
var title: String
var isSelected: Bool
var action: () -> Void
var body: some View {
SwiftUI.Button(action: self.action) {
HStack {
Text(self.title)
if self.isSelected {
Spacer()
Image(systemName: "checkmark")
}
}
}
}
}
class AppExtensionViewHostingController: UIHostingController<AppExtensionView> {
var completion: Optional<(_ selection: [ALTApplication]) -> Any?> = nil
required init(extensions: Set<ALTApplication>, completion: @escaping (_ selection: [ALTApplication]) -> Any?) {
self.completion = completion
super.init(rootView: AppExtensionView(extensions: extensions, completion: completion))
}
@MainActor required dynamic init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
extension AppExtensionViewHostingController: UIPopoverPresentationControllerDelegate {
func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
return .none
}
}

View File

@@ -8,7 +8,6 @@
import Foundation
import UIKit
import SwiftUI
import UserNotifications
import MobileCoreServices
import Intents
@@ -44,7 +43,7 @@ final class AppManager
static let shared = AppManager()
private(set) var updatePatronsResult: Result<Void, Error>?
private let operationQueue = OperationQueue()
private let serialOperationQueue = OperationQueue()
@@ -240,7 +239,7 @@ extension AppManager
func deactivateApps(for app: ALTApplication, presentingViewController: UIViewController, completion: @escaping (Result<Void, Error>) -> Void)
{
guard !UserDefaults.standard.isAppLimitDisabled, let activeAppsLimit = UserDefaults.standard.activeAppsLimit else { return completion(.success(())) }
guard let activeAppsLimit = UserDefaults.standard.activeAppsLimit else { return completion(.success(())) }
DispatchQueue.main.async {
let activeApps = InstalledApp.fetchActiveApps(in: DatabaseManager.shared.viewContext)
@@ -1015,123 +1014,6 @@ private extension AppManager
return group
}
func removeAppExtensions(from application: ALTApplication, existingApp: InstalledApp?, extensions: Set<ALTApplication>, _ presentingViewController: UIViewController?, completion: @escaping (Result<Void, Error>) -> Void)
{
//App-Extensions: Ensure existing app's extensions and currently installing app's extensions must match
let existingAppEx: Set<InstalledExtension> = existingApp?.appExtensions ?? Set()
let currentAppEx: Set<ALTApplication> = application.appExtensions
let currentAppExNames = currentAppEx.map{ appEx in appEx.bundleIdentifier}
let existingAppExNames = existingAppEx.map{ appEx in appEx.bundleIdentifier}
let excessExtensions = currentAppEx.filter{
!(existingAppExNames.contains($0.bundleIdentifier))
}
let isMatching = (currentAppEx.count == existingAppEx.count) && excessExtensions.isEmpty
let diagnosticsMsg = "AppManager.removeAppExtensions: App Extensions in existingApp and currentApp are matching: \(isMatching)\n"
+ "AppManager.removeAppExtensions: existingAppEx: \(existingAppExNames); currentAppEx: \(String(describing: currentAppExNames))\n"
print(diagnosticsMsg)
// if background mode, then remove only the excess extensions
guard let presentingViewController: UIViewController = presentingViewController else {
// perform silent extensions cleanup for those that aren't already present in existing app
print("\n Performing background mode Extensions removal \n")
print("AppManager.removeAppExtensions: Excess Extensions: \(excessExtensions)")
do {
for appExtension in excessExtensions {
print("Deleting extension \(appExtension.bundleIdentifier)")
try FileManager.default.removeItem(at: appExtension.fileURL)
}
return completion(.success(()))
} catch {
return completion(.failure(error))
}
}
guard !application.appExtensions.isEmpty else { return completion(.success(())) }
let firstSentence: String
if UserDefaults.standard.activeAppLimitIncludesExtensions
{
firstSentence = NSLocalizedString("Non-developer Apple IDs are limited to 3 active apps and app extensions.", comment: "")
}
else
{
firstSentence = NSLocalizedString("Non-developer Apple IDs are limited to creating 10 App IDs per week.", comment: "")
}
let message = firstSentence + " " + NSLocalizedString("Would you like to remove this app's extensions so they don't count towards your limit? There are \(extensions.count) Extensions", comment: "")
let alertController = UIAlertController(title: NSLocalizedString("App Contains Extensions", comment: ""), message: message, preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: UIAlertAction.cancel.title, style: UIAlertAction.cancel.style, handler: { (action) in
completion(.failure(OperationError.cancelled))
}))
alertController.addAction(UIAlertAction(title: NSLocalizedString("Keep App Extensions", comment: ""), style: .default) { (action) in
completion(.success(()))
})
alertController.addAction(UIAlertAction(title: NSLocalizedString("Remove App Extensions", comment: ""), style: .destructive) { (action) in
do
{
for appExtension in application.appExtensions
{
print("Deleting extension \(appExtension.bundleIdentifier)")
try FileManager.default.removeItem(at: appExtension.fileURL)
}
completion(.success(()))
}
catch
{
completion(.failure(error))
}
})
alertController.addAction(UIAlertAction(title: NSLocalizedString("Choose App Extensions", comment: ""), style: .default) { (action) in
let popoverContentController = AppExtensionViewHostingController(extensions: extensions) { (selection) in
do
{
for appExtension in selection
{
print("Deleting extension \(appExtension.bundleIdentifier)")
try FileManager.default.removeItem(at: appExtension.fileURL)
}
completion(.success(()))
}
catch
{
completion(.failure(error))
}
return nil
}
let suiview = popoverContentController.view!
suiview.translatesAutoresizingMaskIntoConstraints = false
popoverContentController.modalPresentationStyle = .popover
if let popoverPresentationController = popoverContentController.popoverPresentationController {
popoverPresentationController.sourceView = presentingViewController.view
popoverPresentationController.sourceRect = CGRect(x: 50, y: 50, width: 4, height: 4)
popoverPresentationController.delegate = popoverContentController
DispatchQueue.main.async {
presentingViewController.present(popoverContentController, animated: true)
}
}
})
DispatchQueue.main.async {
presentingViewController.present(alertController, animated: true)
}
}
private func _install(_ app: AppProtocol, operation appOperation: AppOperation, group: RefreshGroup, context: InstallAppOperationContext? = nil, additionalEntitlements: [ALTEntitlement: Any]? = nil, cacheApp: Bool = true, completionHandler: @escaping (Result<InstalledApp, Error>) -> Void) -> Progress
{
let progress = Progress.discreteProgress(totalUnitCount: 100)
@@ -1204,52 +1086,6 @@ private extension AppManager
}
verifyOperation.addDependency(downloadOperation)
/* Remove App Extensions */
let removeAppExtensionsOperation = RSTAsyncBlockOperation { [weak self] (operation) in
do
{
if let error = context.error
{
throw error
}
/*
guard case .install = appOperation else {
operation.finish()
return
}
*/
guard let extensions = context.app?.appExtensions else {
throw OperationError.invalidParameters("AppManager._install.removeAppExtensionsOperation: context.app?.appExtensions is nil")
}
guard let currentApp = context.app else {
throw OperationError.invalidParameters("AppManager._install.removeAppExtensionsOperation: context.app is nil")
}
self?.removeAppExtensions(from: currentApp,
existingApp: app as? InstalledApp,
extensions: extensions,
context.authenticatedContext.presentingViewController
) { result in
switch result {
case .success(): break
case .failure(let error): context.error = error
}
operation.finish()
}
}
catch
{
context.error = error
operation.finish()
}
}
removeAppExtensionsOperation.addDependency(verifyOperation)
/* Refresh Anisette Data */
let refreshAnisetteDataOperation = FetchAnisetteDataOperation(context: group.context)
@@ -1260,7 +1096,7 @@ private extension AppManager
case .success(let anisetteData): group.context.session?.anisetteData = anisetteData
}
}
refreshAnisetteDataOperation.addDependency(removeAppExtensionsOperation)
refreshAnisetteDataOperation.addDependency(verifyOperation)
/* Fetch Provisioning Profiles */
@@ -1295,20 +1131,13 @@ private extension AppManager
throw error
}
guard let profiles = context.provisioningProfiles else {
throw OperationError.invalidParameters("AppManager._install.deactivateAppsOperation: context.provisioningProfiles is nil")
}
guard let profiles = context.provisioningProfiles else { throw OperationError.invalidParameters }
if !profiles.contains(where: { $1.isFreeProvisioningProfile == true }) {
operation.finish()
return
}
guard
let app = context.app,
let presentingViewController = context.authenticatedContext.presentingViewController
else {
throw OperationError.invalidParameters("AppManager._install.deactivateAppsOperation: self.context.app or context.authenticatedContext.presentingViewController is nil")
}
guard let app = context.app, let presentingViewController = context.authenticatedContext.presentingViewController else { throw OperationError.invalidParameters }
self?.deactivateApps(for: app, presentingViewController: presentingViewController) { result in
switch result
@@ -1328,6 +1157,7 @@ private extension AppManager
}
deactivateAppsOperation.addDependency(fetchProvisioningProfilesOperation)
/* Patch App */
let patchAppOperation = RSTAsyncBlockOperation { operation in
do
@@ -1347,9 +1177,7 @@ private extension AppManager
throw error
}
guard let app = context.app else {
throw OperationError.invalidParameters("AppManager._install.patchAppOperation: context.app is nil")
}
guard let app = context.app else { throw OperationError.invalidParameters }
guard let isUntetherRequired = app.bundle.infoDictionary?[Bundle.Info.untetherRequired] as? Bool,
let minimumiOSVersionString = app.bundle.infoDictionary?[Bundle.Info.untetherMinimumiOSVersion] as? String,
@@ -1454,7 +1282,7 @@ private extension AppManager
progress.addChild(installOperation.progress, withPendingUnitCount: 30)
installOperation.addDependency(sendAppOperation)
let operations = [downloadOperation, verifyOperation, removeAppExtensionsOperation, refreshAnisetteDataOperation, fetchProvisioningProfilesOperation, deactivateAppsOperation, patchAppOperation, resignAppOperation, sendAppOperation, installOperation]
let operations = [downloadOperation, verifyOperation, refreshAnisetteDataOperation, fetchProvisioningProfilesOperation, deactivateAppsOperation, patchAppOperation, resignAppOperation, sendAppOperation, installOperation]
group.add(operations)
self.run(operations, context: group.context)
@@ -1468,25 +1296,6 @@ private extension AppManager
let context = AppOperationContext(bundleIdentifier: app.bundleIdentifier, authenticatedContext: group.context)
context.app = ALTApplication(fileURL: app.fileURL)
let validateAppExtensionsOperation = RSTAsyncBlockOperation {(op) in
//App-Extensions: Ensure DB data and disk state must match
let dbAppEx: Set<InstalledExtension> = app.appExtensions
let diskAppEx: Set<ALTApplication> = context.app!.appExtensions
let diskAppExNames = diskAppEx.map { $0.bundleIdentifier }
let dbAppExNames = dbAppEx.map{ $0.bundleIdentifier }
let isMatching = Set(dbAppExNames) == Set(diskAppExNames)
let errMessage = "AppManager.refresh: App Extensions in DB and Disk are matching: \(isMatching)\n"
+ "AppManager.refresh: dbAppEx: \(dbAppExNames); diskAppEx: \(String(describing: diskAppExNames))\n"
print(errMessage)
if(!isMatching){
completionHandler(.failure(OperationError.refreshAppFailed(message: errMessage)))
}
op.finish()
}
/* Fetch Provisioning Profiles */
let fetchProvisioningProfilesOperation = FetchProvisioningProfilesOperation(context: context)
fetchProvisioningProfilesOperation.resultHandler = { (result) in
@@ -1497,8 +1306,6 @@ private extension AppManager
}
}
progress.addChild(fetchProvisioningProfilesOperation.progress, withPendingUnitCount: 60)
fetchProvisioningProfilesOperation.addDependency(validateAppExtensionsOperation)
/* Refresh */
let refreshAppOperation = RefreshAppOperation(context: context)
@@ -1532,7 +1339,7 @@ private extension AppManager
progress.addChild(refreshAppOperation.progress, withPendingUnitCount: 40)
refreshAppOperation.addDependency(fetchProvisioningProfilesOperation)
let operations = [validateAppExtensionsOperation, fetchProvisioningProfilesOperation, refreshAppOperation]
let operations = [fetchProvisioningProfilesOperation, refreshAppOperation]
group.add(operations)
self.run(operations, context: group.context)
@@ -1993,43 +1800,7 @@ private extension AppManager
UNUserNotificationCenter.current().add(request)
}
func log(_ error: Error, for operation: AppOperation)
{
// Sanitize NSError on same thread before performing background task.
let sanitizedError = (error as NSError).sanitizedForSerialization()
let loggedErrorOperation: LoggedError.Operation = {
switch operation
{
case .install: return .install
case .update: return .update
case .refresh: return .refresh
case .activate: return .activate
case .deactivate: return .deactivate
case .backup: return .backup
case .restore: return .restore
}
}()
DatabaseManager.shared.persistentContainer.performBackgroundTask { context in
var app = operation.app
if let managedApp = app as? NSManagedObject, let tempApp = context.object(with: managedApp.objectID) as? AppProtocol
{
app = tempApp
}
do
{
_ = LoggedError(error: sanitizedError, app: app, operation: loggedErrorOperation, context: context)
try context.save()
}
catch let saveError
{
print("[ALTLog] Failed to log error \(sanitizedError.domain) code \(sanitizedError.code) for \(app.bundleIdentifier):", saveError)
}
}
}
func run(_ operations: [Foundation.Operation], context: OperationContext?, requiresSerialQueue: Bool = false)
{
// Find "Install AltStore" operation if it already exists in `context`

View File

@@ -783,7 +783,7 @@ private extension MyAppsViewController
}
let unzipProgress = Progress.discreteProgress(totalUnitCount: 1)
let unzipAppOperation = BlockOperation {
let unzipAppOperation = BlockOperation {
do
{
if let error = context.error
@@ -791,9 +791,7 @@ private extension MyAppsViewController
throw error
}
guard let fileURL = context.fileURL else {
throw OperationError.invalidParameters("MyAppsViewController.sideloadApp.unzipAppOperation: context.fileURL is nil")
}
guard let fileURL = context.fileURL else { throw OperationError.invalidParameters }
defer {
try? FileManager.default.removeItem(at: fileURL)
}
@@ -817,7 +815,38 @@ private extension MyAppsViewController
{
unzipAppOperation.addDependency(downloadOperation)
}
let removeAppExtensionsProgress = Progress.discreteProgress(totalUnitCount: 1)
let removeAppExtensionsOperation = RSTAsyncBlockOperation { [weak self] (operation) in
do
{
if let error = context.error
{
throw error
}
guard let application = context.application else { throw OperationError.invalidParameters }
DispatchQueue.main.async {
self?.removeAppExtensions(from: application) { (result) in
switch result
{
case .success: removeAppExtensionsProgress.completedUnitCount = 1
case .failure(let error): context.error = error
}
operation.finish()
}
}
}
catch
{
context.error = error
operation.finish()
}
}
removeAppExtensionsOperation.addDependency(unzipAppOperation)
progress.addChild(removeAppExtensionsProgress, withPendingUnitCount: 5)
let installProgress = Progress.discreteProgress(totalUnitCount: 100)
let installAppOperation = RSTAsyncBlockOperation { (operation) in
do
@@ -827,9 +856,7 @@ private extension MyAppsViewController
throw error
}
guard let application = context.application else {
throw OperationError.invalidParameters("MyAppsViewController.sideloadApp.installAppOperation: context.application is nil")
}
guard let application = context.application else { throw OperationError.invalidParameters }
let group = AppManager.shared.install(application, presentingViewController: self) { (result) in
switch result
@@ -874,17 +901,15 @@ private extension MyAppsViewController
}
}
}
installAppOperation.addDependency(unzipAppOperation)
progress.addChild(installProgress, withPendingUnitCount: 65)
installAppOperation.addDependency(removeAppExtensionsOperation)
self.sideloadingProgress = progress
self.sideloadingProgressView.progress = 0
self.sideloadingProgressView.isHidden = false
self.sideloadingProgressView.observedProgress = self.sideloadingProgress
let operations = [downloadOperation, unzipAppOperation, installAppOperation].compactMap { $0 }
let operations = [downloadOperation, unzipAppOperation, removeAppExtensionsOperation, installAppOperation].compactMap { $0 }
self.operationQueue.addOperations(operations, waitUntilFinished: false)
}
@@ -933,6 +958,49 @@ private extension MyAppsViewController
cell.bannerView.iconImageView.isIndicatingActivity = false
}
func removeAppExtensions(from application: ALTApplication, completion: @escaping (Result<Void, Error>) -> Void)
{
guard !application.appExtensions.isEmpty else { return completion(.success(())) }
let firstSentence: String
if UserDefaults.standard.activeAppLimitIncludesExtensions
{
firstSentence = NSLocalizedString("Non-developer Apple IDs are limited to 3 active apps and app extensions.", comment: "")
}
else
{
firstSentence = NSLocalizedString("Non-developer Apple IDs are limited to creating 10 App IDs per week.", comment: "")
}
let message = firstSentence + " " + NSLocalizedString("Would you like to remove this app's extensions so they don't count towards your limit?", comment: "")
let alertController = UIAlertController(title: NSLocalizedString("App Contains Extensions", comment: ""), message: message, preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: UIAlertAction.cancel.title, style: UIAlertAction.cancel.style, handler: { (action) in
completion(.failure(OperationError.cancelled))
}))
alertController.addAction(UIAlertAction(title: NSLocalizedString("Keep App Extensions", comment: ""), style: .default) { (action) in
completion(.success(()))
})
alertController.addAction(UIAlertAction(title: NSLocalizedString("Remove App Extensions", comment: ""), style: .destructive) { (action) in
do
{
for appExtension in application.appExtensions
{
try FileManager.default.removeItem(at: appExtension.fileURL)
}
completion(.success(()))
}
catch
{
completion(.failure(error))
}
})
self.present(alertController, animated: true, completion: nil)
}
}
private extension MyAppsViewController
@@ -998,7 +1066,7 @@ private extension MyAppsViewController
}
}
if !UserDefaults.standard.isAppLimitDisabled && UserDefaults.standard.activeAppsLimit != nil, #available(iOS 13, *)
if UserDefaults.standard.activeAppsLimit != nil, #available(iOS 13, *)
{
// UserDefaults.standard.activeAppsLimit is only non-nil on iOS 13.3.1 or later, so the #available check is just so we can use Combine.
@@ -1088,7 +1156,7 @@ private extension MyAppsViewController
message = NSLocalizedString("This will also erase all backup data for this app.", comment: "")
}
let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
let alertController = UIAlertController(title: title, message: message, preferredStyle: .actionSheet)
alertController.addAction(.cancel)
alertController.addAction(UIAlertAction(title: NSLocalizedString("Remove", comment: ""), style: .destructive, handler: { (action) in
AppManager.shared.remove(installedApp) { (result) in
@@ -1251,15 +1319,9 @@ private extension MyAppsViewController
@available(iOS 14, *)
func enableJIT(for installedApp: InstalledApp)
{
let sidejitenabled = UserDefaults.standard.sidejitenable
if #unavailable(iOS 17) {
guard minimuxerStatus else { return }
}
guard minimuxerStatus else { return }
if #available(iOS 17, *), !sidejitenabled {
if #available(iOS 17, *) {
ToastView(error: (OperationError.tooNewError as NSError).withLocalizedTitle("No iOS 17 On Device JIT!"), opensLog: true).show(in: self)
AppManager.shared.log(OperationError.tooNewError, operation: .enableJIT, app: installedApp)
return
@@ -1358,7 +1420,7 @@ extension MyAppsViewController
headerView.layoutMargins.left = self.view.layoutMargins.left
headerView.layoutMargins.right = self.view.layoutMargins.right
if UserDefaults.standard.activeAppsLimit == nil || UserDefaults.standard.isAppLimitDisabled
if UserDefaults.standard.activeAppsLimit == nil
{
headerView.textLabel.text = NSLocalizedString("Installed", comment: "")
}
@@ -1757,7 +1819,7 @@ extension MyAppsViewController: UICollectionViewDragDelegate
return []
case .activeApps, .inactiveApps:
guard UserDefaults.standard.activeAppsLimit != nil && !UserDefaults.standard.isAppLimitDisabled else { return [] }
guard UserDefaults.standard.activeAppsLimit != nil else { return [] }
guard let cell = collectionView.cellForItem(at: indexPath as IndexPath) as? InstalledAppCollectionViewCell else { return [] }
let item = self.dataSource.item(at: indexPath)
@@ -1812,7 +1874,6 @@ extension MyAppsViewController: UICollectionViewDropDelegate
func collectionView(_ collectionView: UICollectionView, dropSessionDidUpdate session: UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?) -> UICollectionViewDropProposal
{
guard
!UserDefaults.standard.isAppLimitDisabled,
let activeAppsLimit = UserDefaults.standard.activeAppsLimit,
let installedApp = session.items.first?.localObject as? InstalledApp
else { return UICollectionViewDropProposal(operation: .cancel) }

View File

@@ -241,11 +241,12 @@ final class AuthenticationOperation: ResultOperation<(ALTTeam, ALTCertificate, A
}
let activeAppsMinimumVersion = OperatingSystemVersion(majorVersion: 13, minorVersion: 3, patchVersion: 1)
if team.type == .free, !UserDefaults.standard.isAppLimitDisabled, ProcessInfo().sparseRestorePatched {
if team.type == .free, ProcessInfo.processInfo.isOperatingSystemAtLeast(activeAppsMinimumVersion)
{
UserDefaults.standard.activeAppsLimit = ALTActiveAppsLimit
} else if UserDefaults.standard.isAppLimitDisabled, !ProcessInfo().sparseRestorePatched {
UserDefaults.standard.activeAppsLimit = 10
} else {
}
else
{
UserDefaults.standard.activeAppsLimit = nil
}
@@ -489,7 +490,7 @@ private extension AuthenticationOperation
{
func requestCertificate()
{
let machineName: String = "SideStore - \(team.account.firstName)'s \(UIDevice.current.name)"
let machineName = "SideStore - " + UIDevice.current.name
ALTAppleAPI.shared.addCertificate(machineName: machineName, to: team, session: session) { (certificate, error) in
do
{
@@ -523,50 +524,16 @@ private extension AuthenticationOperation
func replaceCertificate(from certificates: [ALTCertificate])
{
let ourCertificates = certificates.filter { a in
a.machineName?.starts(with: "SideStore") == true || a.machineName?.starts(with: "AltStore") == true
}
guard let certificate = certificates.first(where: { $0.machineName?.starts(with: "SideStore") == true }) ?? certificates.first else { return completionHandler(.failure(OperationError.notAuthenticated)) }
if ourCertificates.isEmpty {
return requestCertificate()
}
// We don't have private keys for any of the certificates,
// so we need to revoke one and create a new one.
var certsText = ""
for certificate in ourCertificates {
if let name = certificate.machineName {
certsText.append("\(name)\n")
}
}
let alertController = UIAlertController(title: NSLocalizedString("Would you like to revoke your previous certificates?\n\(certsText)", comment: ""), message: nil, preferredStyle: .alert)
let noAction = UIAlertAction(title: NSLocalizedString("No", comment: ""), style: .default) { (action) in
requestCertificate()
}
let yesAction = UIAlertAction(title: NSLocalizedString("Yes", comment: ""), style: .default) { (action) in
for certificate in ourCertificates {
ALTAppleAPI.shared.revoke(certificate, for: team, session: session) { (success, error) in
if let error = error, !success
{
completionHandler(.failure(error))
}
}
}
requestCertificate()
}
alertController.addAction(noAction)
alertController.addAction(yesAction)
DispatchQueue.main.async {
if self.navigationController.presentingViewController != nil
ALTAppleAPI.shared.revoke(certificate, for: team, session: session) { (success, error) in
if let error = error, !success
{
self.navigationController.present(alertController, animated: true, completion: nil)
completionHandler(.failure(error))
}
else
{
self.presentingViewController?.present(alertController, animated: true, completion: nil)
requestCertificate()
}
}
}
@@ -614,6 +581,8 @@ private extension AuthenticationOperation
}
else
{
// We don't have private keys for any of the certificates,
// so we need to revoke one and create a new one.
replaceCertificate(from: certificates)
}
}

View File

@@ -48,9 +48,7 @@ class BackupAppOperation: ResultOperation<Void>
{
if let error = self.context.error { throw error }
guard let installedApp = self.context.installedApp, let context = installedApp.managedObjectContext else {
throw OperationError.invalidParameters("BackupAppOperation.main: self.context.installedApp or installedApp.managedObjectContext is nil")
}
guard let installedApp = self.context.installedApp, let context = installedApp.managedObjectContext else { throw OperationError.invalidParameters }
context.perform {
do
{

View File

@@ -20,7 +20,6 @@ final class DownloadAppOperation: ResultOperation<ALTApplication>
private let appName: String
private let bundleIdentifier: String
private var sourceURL: URL?
private let destinationURL: URL
private let session = URLSession(configuration: .default)
@@ -33,7 +32,6 @@ final class DownloadAppOperation: ResultOperation<ALTApplication>
self.appName = app.name
self.bundleIdentifier = app.bundleIdentifier
self.sourceURL = app.url
self.destinationURL = destinationURL
super.init()
@@ -113,7 +111,7 @@ private extension DownloadAppOperation {
}
func download(@Managed _ app: AppProtocol) {
guard let sourceURL = self.sourceURL else { return self.finish(.failure(OperationError.appNotFound(name: self.appName))) }
guard let sourceURL = $app.url else { return self.finish(.failure(OperationError.appNotFound(name: self.appName))) }
self.downloadIPA(from: sourceURL) { result in
do

View File

@@ -50,9 +50,7 @@ final class EnableJITOperation<Context: EnableJITContext>: ResultOperation<Void>
return
}
guard let installedApp = self.context.installedApp else {
return self.finish(.failure(OperationError.invalidParameters("EnableJITOperation.main: self.context.installedApp is nil")))
}
guard let installedApp = self.context.installedApp else { return self.finish(.failure(OperationError.invalidParameters)) }
if #available(iOS 17, *) {
let sideJITenabled = UserDefaults.standard.sidejitenable
let SideJITIP = UserDefaults.standard.textInputSideJITServerurl ?? ""

View File

@@ -39,9 +39,7 @@ final class FetchAppIDsOperation: ResultOperation<([AppID], NSManagedObjectConte
guard
let team = self.context.team,
let session = self.context.session
else {
return self.finish(.failure(OperationError.invalidParameters("FetchAppIDsOperation.main: self.context.team or self.context.session is nil")))
}
else { return self.finish(.failure(OperationError.invalidParameters)) }
ALTAppleAPI.shared.fetchAppIDs(for: team, session: session) { (appIDs, error) in
self.managedObjectContext.perform {

View File

@@ -43,8 +43,7 @@ final class FetchProvisioningProfilesOperation: ResultOperation<[String: ALTProv
guard
let team = self.context.team,
let session = self.context.session
else {
return self.finish(.failure(OperationError.invalidParameters("FetchProvisioningProfilesOperation.main: self.context.team or self.context.session is nil"))) }
else { return self.finish(.failure(OperationError.invalidParameters)) }
guard let app = self.context.app else { return self.finish(.failure(OperationError.appNotFound(name: nil))) }
@@ -263,10 +262,6 @@ extension FetchProvisioningProfilesOperation
{
throw OperationError.maximumAppIDLimitReached(appName: application.name, requiredAppIDs: requiredAppIDs, availableAppIDs: availableAppIDs, expirationDate: expirationDate)
}
else
{
throw ALTAppleAPIError(.maximumAppIDLimitReached)
}
}
}
//App ID name must be ascii. If the name is not ascii, using bundleID instead

View File

@@ -43,9 +43,7 @@ final class InstallAppOperation: ResultOperation<InstalledApp>
let certificate = self.context.certificate,
let resignedApp = self.context.resignedApp,
let provisioningProfiles = self.context.provisioningProfiles
else {
return self.finish(.failure(OperationError.invalidParameters("InstallAppOperation.main: self.context.certificate or self.context.resignedApp or self.context.provisioningProfiles is nil")))
}
else { return self.finish(.failure(OperationError.invalidParameters)) }
let backgroundContext = DatabaseManager.shared.persistentContainer.newBackgroundContext()
backgroundContext.perform {
@@ -114,22 +112,6 @@ final class InstallAppOperation: ResultOperation<InstalledApp>
}
installedApp.appExtensions = installedExtensions
// Remove stale "PlugIns" (Extensions) from currently installed App
if let installedAppExns = ALTApplication(fileURL: installedApp.fileURL)?.appExtensions {
let currentAppExns = Set(installedApp.appExtensions).map{ $0.bundleIdentifier }
let staleAppExns = installedAppExns.filter{ !currentAppExns.contains($0.bundleIdentifier) }
for staleAppExn in staleAppExns {
do {
try FileManager.default.removeItem(at: staleAppExn.fileURL)
print("InstallAppOperation.appExtensions: removed stale app-extension: \(staleAppExn.fileURL)")
} catch {
print("InstallAppOperation.appExtensions processing error Error: \(error)")
}
}
}
self.context.beginInstallationHandler?(installedApp)
@@ -240,10 +222,8 @@ final class InstallAppOperation: ResultOperation<InstalledApp>
do
{
if(FileManager.default.fileExists(atPath: fileURL.path)){
try FileManager.default.removeItem(at: fileURL)
print("Removed refreshed IPA")
}
try FileManager.default.removeItem(at: fileURL)
print("Removed refreshed IPA")
}
catch
{

View File

@@ -35,7 +35,6 @@ extension OperationError
case noSources
case openAppFailed//(name: String)
case missingAppGroup
case refreshAppFailed
// Connection
case noWiFi = 1200
@@ -56,6 +55,7 @@ extension OperationError
static let notAuthenticated: OperationError = .init(code: .notAuthenticated)
static let unknownUDID: OperationError = .init(code: .unknownUDID)
static let invalidApp: OperationError = .init(code: .invalidApp)
static let invalidParameters: OperationError = .init(code: .invalidParameters)
static let noSources: OperationError = .init(code: .noSources)
static let missingAppGroup: OperationError = .init(code: .missingAppGroup)
@@ -78,7 +78,6 @@ extension OperationError
static func openAppFailed(name: String?) -> OperationError {
OperationError(code: .openAppFailed, appName: name)
}
static let domain = OperationError(code: .unknown)._domain
static func SideJITIssue(error: String?) -> OperationError {
var o = OperationError(code: .SideJITIssue)
@@ -108,13 +107,6 @@ extension OperationError
OperationError(code: .anisetteV3Error, failureReason: message)
}
static func refreshAppFailed(message: String) -> OperationError {
OperationError(code: .refreshAppFailed, failureReason: message)
}
static func invalidParameters(_ message: String? = nil) -> OperationError {
OperationError(code: .invalidParameters, failureReason: message)
}
}
@@ -163,6 +155,7 @@ struct OperationError: ALTLocalizedError {
case .notAuthenticated: return NSLocalizedString("You are not signed in.", 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 .invalidParameters: return NSLocalizedString("Invalid parameters.", 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 .missingAppGroup: return NSLocalizedString("SideStore's shared app group could not be accessed.", comment: "")
@@ -173,7 +166,7 @@ struct OperationError: ALTLocalizedError {
let appName = self.appName ?? NSLocalizedString("The app", comment: "")
return String(format: NSLocalizedString("SideStore was denied permission to launch %@.", comment: ""), appName)
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 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 .tooNewError: return NSLocalizedString("iOS 17 has changed how JIT is enabled therefore SideStore cannot enable it 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 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 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 Samw Wifi as SideJITServer", comment: "")
@@ -183,16 +176,7 @@ struct OperationError: ALTLocalizedError {
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 cache: %@", comment: "")
case .SideJITIssue: return NSLocalizedString("An error occurred while using SideJIT: %@", comment: "")
case .refreshAppFailed:
let message = self._failureReason ?? ""
return String(format: NSLocalizedString("Unable to refresh App\n%@", comment: ""), message)
case .invalidParameters:
let message = self._failureReason.map { ": \n\($0)" } ?? "."
return String(format: NSLocalizedString("Invalid parameters%@", comment: ""), message)
}
}
var recoverySuggestion: String? {
@@ -245,7 +229,7 @@ extension MinimuxerError: LocalizedError {
case .NoDevice:
return NSLocalizedString("Cannot fetch the device from the muxer", comment: "")
case .NoConnection:
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: "")
return NSLocalizedString("Unable to connect to the device, make sure Wireguard is enabled and you're connected to WiFi", comment: "")
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 jitterbugpair to generate it", comment: "")
@@ -275,7 +259,7 @@ extension MinimuxerError: LocalizedError {
case .CreateAfc:
return self.createService(name: "AFC")
case .RwAfc:
return NSLocalizedString("AFC was unable to manage files on the device. This usually means an invalid pairing.", comment: "")
return NSLocalizedString("AFC was unable to manage files on the device", comment: "")
case .InstallApp(let message):
return NSLocalizedString("Unable to install the app: \(message.toString())", comment: "")
case .UninstallApp:

View File

@@ -98,9 +98,7 @@ final class PatchAppOperation: ResultOperation<Void>
return
}
guard let resignedApp = self.context.resignedApp else {
return self.finish(.failure(OperationError.invalidParameters("PatchAppOperation.main: self.context.resignedApp is nil")))
}
guard let resignedApp = self.context.resignedApp else { return self.finish(.failure(OperationError.invalidParameters)) }
self.progressHandler?(self.progress, NSLocalizedString("Downloading iOS firmware...", comment: ""))

View File

@@ -35,15 +35,9 @@ final class RefreshAppOperation: ResultOperation<InstalledApp>
do
{
if let error = self.context.error {
print("RefreshAppOperation.main: ERROR: self.context.app = \(self.context.app!); self.context.error is \(error)")
return self.finish(.failure(error))
}
guard let profiles = self.context.provisioningProfiles else {
return self.finish(.failure(OperationError.invalidParameters("RefreshAppOperation.main: self.context.provisioningProfiles is nil")))
}
if let error = self.context.error { return self.finish(.failure(error)) }
guard let profiles = self.context.provisioningProfiles else { return self.finish(.failure(OperationError.invalidParameters)) }
guard let app = self.context.app else { return self.finish(.failure(OperationError(.appNotFound(name: nil)))) }
for p in profiles {

View File

@@ -35,9 +35,7 @@ final class RemoveAppBackupOperation: ResultOperation<Void>
return
}
guard let installedApp = self.context.installedApp else {
return self.finish(.failure(OperationError.invalidParameters("RemoveAppBackupOperation.main: self.context.installedApp is nil")))
}
guard let installedApp = self.context.installedApp else { return self.finish(.failure(OperationError.invalidParameters)) }
installedApp.managedObjectContext?.perform {
guard let backupDirectoryURL = FileManager.default.backupDirectoryURL(for: installedApp) else { return self.finish(.failure(OperationError.missingAppGroup)) }

View File

@@ -33,9 +33,7 @@ final class RemoveAppOperation: ResultOperation<InstalledApp>
return
}
guard let installedApp = self.context.installedApp else {
return self.finish(.failure(OperationError.invalidParameters("RemoveAppOperation.main: self.context.installedApp is nil")))
}
guard let installedApp = self.context.installedApp else { return self.finish(.failure(OperationError.invalidParameters)) }
installedApp.managedObjectContext?.perform {
let resignedBundleIdentifier = installedApp.resignedBundleIdentifier

View File

@@ -42,12 +42,7 @@ final class ResignAppOperation: ResultOperation<ALTApplication>
let profiles = self.context.provisioningProfiles,
let team = self.context.team,
let certificate = self.context.certificate
else {
return self.finish(.failure(OperationError.invalidParameters("ResignAppOperation.main: " +
"self.context.team or " +
"self.context.provisioningProfiles or" +
"self.context.certificate is nil")))
}
else { return self.finish(.failure(OperationError.invalidParameters)) }
// Prepare app bundle
let prepareAppProgress = Progress.discreteProgress(totalUnitCount: 2)

View File

@@ -36,9 +36,7 @@ final class SendAppOperation: ResultOperation<()>
return self.finish(.failure(error))
}
guard let resignedApp = self.context.resignedApp else {
return self.finish(.failure(OperationError.invalidParameters("SendAppOperation.main: self.resignedApp is nil")))
}
guard let resignedApp = self.context.resignedApp else { return self.finish(.failure(OperationError.invalidParameters)) }
// self.context.resignedApp.fileURL points to the app bundle, but we want the .ipa.
let app = AnyApp(name: resignedApp.name, bundleIdentifier: self.context.bundleIdentifier, url: resignedApp.fileURL)

View File

@@ -116,12 +116,8 @@ final class VerifyAppOperation: ResultOperation<Void>
{
throw error
}
let appName = self.context.app?.name ?? NSLocalizedString("The app", comment: "")
self.localizedFailure = String(format: NSLocalizedString("%@ could not be installed.", comment: ""), appName)
guard let app = self.context.app else {
throw OperationError.invalidParameters("VerifyAppOperation.main: self.context.app is nil")
}
guard let app = self.context.app else { throw OperationError.invalidParameters }
if !["ny.litritt.ignited", "com.litritt.ignited"].contains(where: { $0 == app.bundleIdentifier }) {
guard app.bundleIdentifier == self.context.bundleIdentifier else {

View File

@@ -23,198 +23,157 @@ struct Server: Codable {
var address: String
}
struct AniServer: Codable {
var name: String
var url: URL
}
class AnisetteViewModel: ObservableObject {
@Published var selected: String = ""
@Published var source: String = "https://servers.sidestore.io/servers.json"
@Published var servers: [Server] = []
init() {
// using the custom Anisette list
if !UserDefaults.standard.menuAnisetteList.isEmpty {
self.source = UserDefaults.standard.menuAnisetteList
}
}
func getListOfServers() {
guard let url = URL(string: source) else { return }
URLSession.shared.dataTask(with: url) { data, response, error in
URLSession.shared.dataTask(with: URL(string: source)!) { data, response, error in
if let error = error {
return
}
if let data = data {
do {
let decoder = Foundation.JSONDecoder()
let servers = try decoder.decode(AnisetteServerData.self, from: data)
let servers = try Foundation.JSONDecoder().decode(AnisetteServerData.self, from: data)
DispatchQueue.main.async {
self.servers = servers.servers
self.servers = servers.servers.map { Server(name: $0.name, address: $0.address) }
}
} catch {
// Handle decoding error
print("Failed to decode JSON: \(error)")
}
}
}.resume()
}
.resume()
for server in servers {
print(server)
print(server.name.count)
print(server.name)
}
}
}
struct AnisetteServers: View {
@Environment(\.presentationMode) var presentationMode
@StateObject var viewModel: AnisetteViewModel = AnisetteViewModel()
@State var selected: String? = nil
@State private var showingConfirmation = false
var errorCallback: () -> ()
var body: some View {
ZStack {
Color(UIColor.systemBackground)
.ignoresSafeArea()
.onAppear {
viewModel.getListOfServers()
}
VStack {
if #available(iOS 16.0, *) {
SwiftUI.List($viewModel.servers, id: \.address, selection: $selected) { server in
HStack {
VStack(alignment: .leading) {
Text("\(server.name.wrappedValue)")
.font(.headline)
.foregroundColor(.primary)
Text("\(server.address.wrappedValue)")
.font(.subheadline)
.foregroundColor(.secondary)
}
Spacer()
if selected != nil {
if server.address.wrappedValue == selected {
Spacer()
Image(systemName: "checkmark.circle.fill")
.foregroundColor(.accentColor)
.onAppear {
UserDefaults.standard.menuAnisetteURL = server.address.wrappedValue
print(UserDefaults.synchronize(.standard)())
print(UserDefaults.standard.menuAnisetteURL)
print(server.address.wrappedValue)
}
}
}
}
.padding()
.background(RoundedRectangle(cornerRadius: 10).fill(Color(UIColor.secondarySystemBackground)))
.shadow(color: Color.black.opacity(0.2), radius: 5, x: 0, y: 5)
NavigationView {
ZStack {
Color(UIColor(named: "SettingsBackground")!).ignoresSafeArea(.all)
.onAppear {
viewModel.getListOfServers()
}
.listStyle(.plain)
.scrollContentBackground(.hidden)
.listRowBackground(Color(UIColor.systemBackground))
} else {
List(selection: $selected) {
ForEach($viewModel.servers, id: \.name) { server in
VStack {
VStack {
if #available(iOS 16.0, *) {
SwiftUI.List($viewModel.servers, id: \.address, selection: $selected) { server in
HStack {
Text("\(server.name.wrappedValue)")
.foregroundColor(.primary)
.frame(alignment: .center)
Text("\(server.address.wrappedValue)")
.foregroundColor(.secondary)
.frame(alignment: .center)
VStack(alignment: .leading) {
Text("\(server.name.wrappedValue)")
.font(.headline)
.underline(true, color: .white)
Text("\(server.address.wrappedValue)")
.fontWeight(.thin)
}
if selected != nil {
if server.address.wrappedValue == selected {
Spacer()
Image(systemName: "checkmark")
.onAppear {
UserDefaults.standard.menuAnisetteURL = server.address.wrappedValue
print(UserDefaults.synchronize(.standard)())
print(UserDefaults.standard.menuAnisetteURL)
print(server.address.wrappedValue)
}
}
}
}
}
Spacer()
.backgroundStyle((selected == nil) ? Color(UIColor(named: "SettingsHighlighted")!) : Color(UIColor(named: "SettingsBackground")!))
.listRowSeparatorTint(.white)
.listRowBackground((selected == nil) ? Color(UIColor(named: "SettingsHighlighted")!).ignoresSafeArea(.all) : Color(UIColor(named: "SettingsBackground")!).ignoresSafeArea(.all))
}
.padding()
.background(RoundedRectangle(cornerRadius: 10).fill(Color(UIColor.secondarySystemBackground)))
.shadow(color: Color.black.opacity(0.2), radius: 5, x: 0, y: 5)
}
.listStyle(.plain)
}
VStack(spacing: 16) {
TextField("Anisette Server List", text: $viewModel.source)
.padding()
.background(RoundedRectangle(cornerRadius: 10).fill(Color(UIColor.secondarySystemFill)))
.foregroundColor(.primary)
.frame(height: 60)
.shadow(color: Color.black.opacity(0.2), radius: 5, x: 0, y: 5)
.onChange(of: viewModel.source) { newValue in
UserDefaults.standard.menuAnisetteList = newValue
viewModel.getListOfServers()
}
HStack(spacing: 16) {
SUIButton(action: {
presentationMode.wrappedValue.dismiss()
}) {
HStack{
Spacer()
Text("Back")
.fontWeight(.semibold)
Spacer()
}
.contentShape(Rectangle())
}
.buttonStyle(PlainButtonStyle())
.padding()
.background(RoundedRectangle(cornerRadius: 10).fill(Color.accentColor))
.foregroundColor(.white)
.shadow(color: Color.accentColor.opacity(0.4), radius: 10, x: 0, y: 5)
SUIButton(action: {
viewModel.getListOfServers()
}) {
HStack{
Spacer()
Text("Refresh Servers")
.fontWeight(.semibold)
.frame(maxWidth: .infinity)
Spacer()
}
.contentShape(Rectangle())
}
.buttonStyle(PlainButtonStyle())
.padding()
.background(RoundedRectangle(cornerRadius: 10).fill(Color.accentColor))
.foregroundColor(.white)
.shadow(color: Color.accentColor.opacity(0.4), radius: 10, x: 0, y: 5)
.listStyle(.plain)
.scrollContentBackground(.hidden)
.listRowBackground(Color(UIColor(named: "SettingsBackground")!).ignoresSafeArea(.all))
}
SUIButton(action: {
showingConfirmation = true
}) {
Text("Reset adi.pb")
.fontWeight(.semibold)
.frame(maxWidth: .infinity)
}
.buttonStyle(PlainButtonStyle())
.padding()
.background(RoundedRectangle(cornerRadius: 10).fill(Color.red))
.foregroundColor(.white)
.shadow(color: Color.red.opacity(0.4), radius: 10, x: 0, y: 5)
.alert(isPresented: $showingConfirmation) {
Alert(
title: Text("Reset adi.pb"),
message: Text("are you sure to clear the adi.pb from keychain"),
primaryButton: .default(Text("do it")) {
#if !DEBUG
if Keychain.shared.adiPb != nil {
Keychain.shared.adiPb = nil
} else {
List(selection: $selected) {
ForEach($viewModel.servers, id: \.name) { server in
VStack {
HStack {
Text("\(server.name.wrappedValue)")
.foregroundColor(.white)
.frame(alignment: .center)
Text("\(server.address.wrappedValue)")
.foregroundColor(.white)
.frame(alignment: .center)
}
}
#endif
print("Cleared adi.pb from keychain")
errorCallback()
presentationMode.wrappedValue.dismiss()
},
secondaryButton: .cancel(Text("cancel")) {
print("canceled")
Spacer()
}
)
}
.listStyle(.plain)
// Fallback on earlier versions
}
if #available(iOS 15.0, *) {
TextField("Anisette Server List", text: $viewModel.source)
.padding(.leading, 5)
.padding(.vertical, 10)
.frame(alignment: .center)
.textFieldStyle(.plain)
.border(.white, width: 1)
.onSubmit {
UserDefaults.standard.menuAnisetteList = viewModel.source
viewModel.getListOfServers()
}
SUIButton(action: {
viewModel.getListOfServers()
}, label: {
Text("Refresh Servers")
})
.padding(.bottom, 20)
SUIButton(role: .destructive, action: {
#if !DEBUG
if Keychain.shared.adiPb != nil {
Keychain.shared.adiPb = nil
}
#endif
print("Cleared adi.pb from keychain")
errorCallback()
self.presentationMode.wrappedValue.dismiss()
}, label: {
Text("Reset adi.pb")
// if (selected != nil) {
// Text("\(selected!.uuidString)")
// }
})
.padding(.bottom, 20)
} else {
// Fallback on earlier versions
}
}
.padding(.horizontal)
.padding(.bottom)
}
}
.navigationBarHidden(true)
.navigationTitle("")
.frame(maxWidth: .infinity, maxHeight: .infinity)
.navigationTitle("Anisette Servers")
.onAppear {
if UserDefaults.standard.menuAnisetteList != "" {
viewModel.source = UserDefaults.standard.menuAnisetteList
} else {
viewModel.source = "https://servers.sidestore.io/servers.json"
}
print(UserDefaults.standard.menuAnisetteURL)
print(UserDefaults.standard.menuAnisetteList)
}
}
}

View File

@@ -105,8 +105,8 @@ private extension ErrorLogViewController
self?.searchFAQ(for: loggedError)
},
UIAction(title: NSLocalizedString("View More Details", comment: ""), image: UIImage(systemName: "ellipsis.circle")) { [weak self] _ in
self?.viewMoreDetails(for: loggedError)
},
}
])
cell.menuButton.menu = menu

View File

@@ -128,7 +128,7 @@ private extension PatreonViewController
let isPatronText = NSLocalizedString("""
Hey ,
Youre the best. Your account was linked successfully, so you now have access to any beta versions of our apps. You can find them all in the Browse tab.
Youre the best. Your account was linked successfully, so you now have access to the beta versions of all of our apps. You can find them all in the Browse tab.
Thanks for all of your support. Enjoy!
- SideTeam
@@ -175,7 +175,7 @@ private extension PatreonViewController
@objc func openPatreonURL(_ sender: UIButton)
{
let patreonURL = URL(string: "https://www.patreon.com/SideStoreIO")!
let patreonURL = URL(string: "https://www.patreon.com/SideStore")!
let safariViewController = SFSafariViewController(url: patreonURL)
safariViewController.preferredControlTintColor = self.view.tintColor
@@ -348,7 +348,7 @@ extension PatreonViewController: UICollectionViewDelegateFlowLayout
switch section
{
case .about: return .zero
case .patrons: return CGSize(width: 320, height: 44)
case .patrons: return CGSize(width: 0, height: 0)
}
}
}

View File

@@ -21,7 +21,7 @@
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="separatorColor" white="1" alpha="0.25" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<label key="tableFooterView" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="SideStore 1.0" textAlignment="center" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" id="bUR-rp-Nw2">
<rect key="frame" x="0.0" y="1347" width="375" height="25"/>
<rect key="frame" x="0.0" y="1245" width="375" height="25"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" white="1" alpha="0.69999999999999996" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
@@ -272,44 +272,8 @@
<userDefinedRuntimeAttribute type="boolean" keyPath="isSelectable" value="YES"/>
</userDefinedRuntimeAttributes>
</tableViewCell>
<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="495" width="375" height="51"/>
<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">
<rect key="frame" x="0.0" y="0.0" width="375" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Disable App Limit" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="W95-fD-NAd" userLabel="Disable App Limit">
<rect key="frame" x="30" y="15.5" width="142.5" height="20.5"/>
<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="1aa-og-ZXD">
<rect key="frame" x="296" y="10" width="51" height="31"/>
<connections>
<action selector="toggleDisableAppLimit:" destination="aMk-Xp-UL8" eventType="valueChanged" id="zYc-B2-JPg"/>
</connections>
</switch>
</subviews>
<constraints>
<constraint firstAttribute="trailingMargin" secondItem="1aa-og-ZXD" secondAttribute="trailing" id="1Xa-t6-jAC"/>
<constraint firstItem="W95-fD-NAd" firstAttribute="leading" secondItem="wQ8-9w-iiw" secondAttribute="leadingMargin" id="J49-tg-KMa"/>
<constraint firstItem="1aa-og-ZXD" firstAttribute="centerY" secondItem="wQ8-9w-iiw" secondAttribute="centerY" id="UMz-ax-ln4"/>
<constraint firstItem="W95-fD-NAd" firstAttribute="centerY" secondItem="wQ8-9w-iiw" secondAttribute="centerY" id="bFd-lr-0xw"/>
</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="amC-sE-8O0" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="546" width="375" height="51"/>
<rect key="frame" x="0.0" y="495" width="375" height="51"/>
<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">
<rect key="frame" x="0.0" y="0.0" width="375" height="51"/>
@@ -341,19 +305,19 @@
<tableViewSection headerTitle="" id="eHy-qI-w5w">
<cells>
<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="637" width="375" height="51"/>
<rect key="frame" x="0.0" y="586" width="375" height="51"/>
<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">
<rect key="frame" x="0.0" y="0.0" width="375" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="How it works" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="2CC-iw-3bd">
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="How it works" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="2CC-iw-3bd">
<rect key="frame" x="30" y="15.5" width="105" height="20.5"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" image="Next" translatesAutoresizingMaskIntoConstraints="NO" id="WtV-Dt-sDn">
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="Next" translatesAutoresizingMaskIntoConstraints="NO" id="WtV-Dt-sDn">
<rect key="frame" x="327" y="16.5" width="18" height="18"/>
</imageView>
</subviews>
@@ -381,7 +345,7 @@
<tableViewSection headerTitle="" id="J90-vn-u2O">
<cells>
<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="728" width="375" height="51"/>
<rect key="frame" x="0.0" y="677" width="375" height="51"/>
<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">
<rect key="frame" x="0.0" y="0.0" width="375" height="51"/>
@@ -425,7 +389,7 @@
</userDefinedRuntimeAttributes>
</tableViewCell>
<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="774.5" width="375" height="51"/>
<rect key="frame" x="0.0" y="721" width="375" height="51"/>
<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">
<rect key="frame" x="0.0" y="0.0" width="375" height="51"/>
@@ -469,28 +433,28 @@
</userDefinedRuntimeAttributes>
</tableViewCell>
<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="830" width="375" height="51"/>
<rect key="frame" x="0.0" y="772" width="375" height="51"/>
<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">
<rect key="frame" x="0.0" y="0.0" width="375" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Asset Designer" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="fGU-Fp-XgM">
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Asset Designer" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="fGU-Fp-XgM">
<rect key="frame" x="30" y="15.5" width="115.5" height="20.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" white="1" alpha="0.80000000000000004" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<stackView opaque="NO" contentMode="scaleToFill" ambiguous="YES" spacing="14" translatesAutoresizingMaskIntoConstraints="NO" id="R8B-DW-7mY">
<stackView opaque="NO" contentMode="scaleToFill" spacing="14" translatesAutoresizingMaskIntoConstraints="NO" id="R8B-DW-7mY">
<rect key="frame" x="206" y="15.5" width="139" height="20.5"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Chris (LitRitt)" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="hId-3P-41T">
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Chris (LitRitt)" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="hId-3P-41T">
<rect key="frame" x="0.0" y="0.0" width="107" height="20.5"/>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" image="Next" translatesAutoresizingMaskIntoConstraints="NO" id="baq-cE-fMY">
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="Next" translatesAutoresizingMaskIntoConstraints="NO" id="baq-cE-fMY">
<rect key="frame" x="121" y="0.0" width="18" height="20.5"/>
</imageView>
</subviews>
@@ -513,19 +477,19 @@
</userDefinedRuntimeAttributes>
</tableViewCell>
<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="881" width="375" height="51"/>
<rect key="frame" x="0.0" y="823" width="375" height="51"/>
<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">
<rect key="frame" x="0.0" y="0.0" width="375" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Licenses" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="D6b-cd-pVK">
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Licenses" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="D6b-cd-pVK">
<rect key="frame" x="30" y="15.5" width="67.5" height="20.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" white="1" alpha="0.80000000000000004" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" image="Next" translatesAutoresizingMaskIntoConstraints="NO" id="s79-GQ-khr">
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="Next" translatesAutoresizingMaskIntoConstraints="NO" id="s79-GQ-khr">
<rect key="frame" x="327" y="16.5" width="18" height="18"/>
</imageView>
</subviews>
@@ -553,19 +517,19 @@
<tableViewSection headerTitle="" id="OMa-EK-hRI">
<cells>
<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="972" width="375" height="51"/>
<rect key="frame" x="0.0" y="914" width="375" height="51"/>
<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">
<rect key="frame" x="0.0" y="0.0" width="375" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<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="30" y="15.5" width="125.5" height="20.5"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" image="Next" translatesAutoresizingMaskIntoConstraints="NO" id="Jyy-x0-Owj">
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="Next" translatesAutoresizingMaskIntoConstraints="NO" id="Jyy-x0-Owj">
<rect key="frame" x="327" y="16.5" width="18" height="18"/>
</imageView>
</subviews>
@@ -586,19 +550,19 @@
</userDefinedRuntimeAttributes>
</tableViewCell>
<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="1023" width="375" height="51"/>
<rect key="frame" x="0.0" y="965" width="375" height="51"/>
<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">
<rect key="frame" x="0.0" y="0.0" width="375" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<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.5" width="187.5" height="20.5"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" image="Next" translatesAutoresizingMaskIntoConstraints="NO" id="4d3-me-Hqc">
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="Next" translatesAutoresizingMaskIntoConstraints="NO" id="4d3-me-Hqc">
<rect key="frame" x="327" y="16.5" width="18" height="18"/>
</imageView>
</subviews>
@@ -622,19 +586,19 @@
</connections>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="rE2-P4-OaE" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="1074" width="375" height="51"/>
<rect key="frame" x="0.0" y="1016" width="375" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="rE2-P4-OaE" id="qIT-rz-ZUb">
<rect key="frame" x="0.0" y="0.0" width="375" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<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="PWC-OG-5jx">
<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="PWC-OG-5jx">
<rect key="frame" x="30" y="15.5" width="119" height="20.5"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" image="Next" translatesAutoresizingMaskIntoConstraints="NO" id="VfB-c5-5wG">
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="Next" translatesAutoresizingMaskIntoConstraints="NO" id="VfB-c5-5wG">
<rect key="frame" x="327" y="16.5" width="18" height="18"/>
</imageView>
</subviews>
@@ -658,19 +622,19 @@
</connections>
</tableViewCell>
<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="1125" width="375" height="51"/>
<rect key="frame" x="0.0" y="1067" width="375" height="51"/>
<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">
<rect key="frame" x="0.0" y="0.0" width="375" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<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">
<rect key="frame" x="30" y="15.5" width="183" height="21"/>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Refresh SideJITServer" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="46q-DB-5nc">
<rect key="frame" x="30" y="15.5" width="183" height="20.5"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" image="Next" translatesAutoresizingMaskIntoConstraints="NO" id="wvD-eZ-nQI">
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="Next" translatesAutoresizingMaskIntoConstraints="NO" id="wvD-eZ-nQI">
<rect key="frame" x="327" y="16.5" width="18" height="18"/>
</imageView>
</subviews>
@@ -691,19 +655,19 @@
</userDefinedRuntimeAttributes>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="eZ3-BT-q4D" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="1176" width="375" height="51"/>
<rect key="frame" x="0.0" y="1074" width="375" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="eZ3-BT-q4D" id="17m-VV-hzf">
<rect key="frame" x="0.0" y="0.0" width="375" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<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="IbH-V1-ce3">
<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="IbH-V1-ce3">
<rect key="frame" x="30" y="15.5" width="98.5" height="20.5"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" image="Next" translatesAutoresizingMaskIntoConstraints="NO" id="FZe-BJ-fOm">
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="Next" translatesAutoresizingMaskIntoConstraints="NO" id="FZe-BJ-fOm">
<rect key="frame" x="327" y="16.5" width="18" height="18"/>
</imageView>
</subviews>
@@ -724,19 +688,19 @@
</userDefinedRuntimeAttributes>
</tableViewCell>
<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="1227" width="375" height="51"/>
<rect key="frame" x="0.0" y="1125" width="375" height="51"/>
<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">
<rect key="frame" x="0.0" y="0.0" width="375" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<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.5" width="140" height="20.5"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" image="Next" translatesAutoresizingMaskIntoConstraints="NO" id="r09-mH-pOD">
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="Next" translatesAutoresizingMaskIntoConstraints="NO" id="r09-mH-pOD">
<rect key="frame" x="327" y="16.5" width="18" height="18"/>
</imageView>
</subviews>
@@ -757,7 +721,7 @@
</userDefinedRuntimeAttributes>
</tableViewCell>
<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="1278" width="375" height="51"/>
<rect key="frame" x="0.0" y="1176" width="375" height="51"/>
<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">
<rect key="frame" x="0.0" y="0.0" width="375" height="51"/>
@@ -769,7 +733,7 @@
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" image="Next" translatesAutoresizingMaskIntoConstraints="NO" id="0dh-yd-7i9">
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="Next" translatesAutoresizingMaskIntoConstraints="NO" id="0dh-yd-7i9">
<rect key="frame" x="327" y="16.5" width="18" height="18"/>
</imageView>
</subviews>
@@ -802,7 +766,6 @@
<outlet property="accountNameLabel" destination="CnN-M1-AYK" id="Ldc-Py-Bix"/>
<outlet property="accountTypeLabel" destination="434-MW-Den" id="mNB-QE-4Jg"/>
<outlet property="backgroundRefreshSwitch" destination="DPu-zD-Als" id="eiG-Hv-Vko"/>
<outlet property="disableAppLimitSwitch" destination="1aa-og-ZXD" id="oVL-Md-yZ8"/>
<outlet property="noIdleTimeoutSwitch" destination="iQA-wm-5ag" id="jHC-js-q0Y"/>
<outlet property="versionLabel" destination="bUR-rp-Nw2" id="85I-5R-hqz"/>
</connections>

View File

@@ -32,17 +32,13 @@ extension SettingsViewController
{
case backgroundRefresh
case noIdleTimeout
case disableAppLimit
@available(iOS 14, *)
case addToSiri
static var allCases: [AppRefreshRow] {
var c: [AppRefreshRow] = [.backgroundRefresh, .noIdleTimeout]
guard #available(iOS 14, *) else { return c }
if !ProcessInfo().sparseRestorePatched { c.append(.disableAppLimit) }
c.append(.addToSiri)
return c
guard #available(iOS 14, *) else { return [.backgroundRefresh, .noIdleTimeout] }
return [.backgroundRefresh, .noIdleTimeout, .addToSiri]
}
}
@@ -83,7 +79,6 @@ final class SettingsViewController: UITableViewController
@IBOutlet private var backgroundRefreshSwitch: UISwitch!
@IBOutlet private var noIdleTimeoutSwitch: UISwitch!
@IBOutlet private var disableAppLimitSwitch: UISwitch!
@IBOutlet private var refreshSideJITServer: UILabel!
@@ -195,7 +190,6 @@ private extension SettingsViewController
self.backgroundRefreshSwitch.isOn = UserDefaults.standard.isBackgroundRefreshEnabled
self.noIdleTimeoutSwitch.isOn = UserDefaults.standard.isIdleTimeoutDisableEnabled
self.disableAppLimitSwitch.isOn = UserDefaults.standard.isAppLimitDisabled
if self.isViewLoaded
{
@@ -247,7 +241,7 @@ private extension SettingsViewController
}
else
{
settingsHeaderFooterView.secondaryLabel.text = NSLocalizedString("Enable Background Refresh to automatically refresh apps in the background when connected to Wi-Fi. \n\nEnable Disable Idle Timeout to allow SideStore to keep your device awake during a refresh or install of any apps.", comment: "")
settingsHeaderFooterView.secondaryLabel.text = NSLocalizedString("Enable Background Refresh to automatically refresh apps in the background when connected to Wi-Fi. \n\nDisable the Idle Timeout toggle to allow SideStore to not let your device go to sleep during a refresh or install of any apps.", comment: "")
}
case .instructions:
@@ -323,10 +317,6 @@ private extension SettingsViewController
self.present(alertController, animated: true, completion: nil)
}
@IBAction func toggleDisableAppLimit(_ sender: UISwitch) {
UserDefaults.standard.isAppLimitDisabled = sender.isOn
}
@IBAction func toggleIsBackgroundRefreshEnabled(_ sender: UISwitch)
{
UserDefaults.standard.isBackgroundRefreshEnabled = sender.isOn
@@ -551,7 +541,7 @@ extension SettingsViewController
switch section
{
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, .appRefresh:
let height = self.preferredHeight(for: self.prototypeHeaderFooterView, in: section, isHeader: false)
return height
@@ -576,7 +566,6 @@ extension SettingsViewController
{
case .backgroundRefresh: break
case .noIdleTimeout: break
case .disableAppLimit: break
case .addToSiri:
guard #available(iOS 14, *) else { return }
self.addRefreshAppsShortcut()
@@ -598,102 +587,35 @@ extension SettingsViewController
switch row
{
case .sendFeedback:
let alertController = UIAlertController(title: "Send Feedback", message: "Choose a method to send feedback:", preferredStyle: .actionSheet)
// Option 1: GitHub
alertController.addAction(UIAlertAction(title: "GitHub", style: .default) { _ in
if let githubURL = URL(string: "https://github.com/SideStore/SideStore/issues") {
let safariViewController = SFSafariViewController(url: githubURL)
safariViewController.preferredControlTintColor = .altPrimary
self.present(safariViewController, animated: true, completion: nil)
if MFMailComposeViewController.canSendMail()
{
let mailViewController = MFMailComposeViewController()
mailViewController.mailComposeDelegate = self
mailViewController.setToRecipients(["support@sidestore.io"])
if let version = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String
{
mailViewController.setSubject("SideStore Beta \(version) Feedback")
}
})
// Option 2: Discord
alertController.addAction(UIAlertAction(title: "Discord", style: .default) { _ in
if let discordURL = URL(string: "https://discord.gg/sidestore-949183273383395328") {
let safariViewController = SFSafariViewController(url: discordURL)
safariViewController.preferredControlTintColor = .altPrimary
self.present(safariViewController, animated: true, completion: nil)
else
{
mailViewController.setSubject("SideStore Beta Feedback")
}
})
// Option 3: Mail
// alertController.addAction(UIAlertAction(title: "Send Email", style: .default) { _ in
// if MFMailComposeViewController.canSendMail() {
// let mailViewController = MFMailComposeViewController()
// mailViewController.mailComposeDelegate = self
// mailViewController.setToRecipients(["support@sidestore.io"])
//
// if let version = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String {
// mailViewController.setSubject("SideStore Beta \(version) Feedback")
// } else {
// mailViewController.setSubject("SideStore Beta Feedback")
// }
//
// self.present(mailViewController, animated: true, completion: nil)
// } else {
// let toastView = ToastView(text: NSLocalizedString("Cannot Send Mail", comment: ""), detailText: nil)
// toastView.show(in: self)
// }
// })
// Cancel action
alertController.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
// For iPad: Set the source view if presenting on iPad to avoid crashes
if let popoverController = alertController.popoverPresentationController {
popoverController.sourceView = self.view
popoverController.sourceRect = self.view.bounds
self.present(mailViewController, animated: true, completion: nil)
}
else
{
let toastView = ToastView(text: NSLocalizedString("Cannot Send Mail", comment: ""), detailText: nil)
toastView.show(in: self)
}
// Present the action sheet
self.present(alertController, animated: true, completion: nil)
case .refreshSideJITServer:
if #available(iOS 17, *) {
let alertController = UIAlertController(
title: NSLocalizedString("SideJITServer", comment: ""),
message: NSLocalizedString("Settings for SideJITServer", comment: ""),
title: NSLocalizedString("Are you sure to Refresh SideJITServer?", comment: ""),
message: NSLocalizedString("if you do not have SideJITServer setup this will do nothing", comment: ""),
preferredStyle: UIAlertController.Style.actionSheet)
if UserDefaults.standard.sidejitenable {
alertController.addAction(UIAlertAction(title: NSLocalizedString("Disable", comment: ""), style: .default){ _ in
UserDefaults.standard.sidejitenable = false
})
} else {
alertController.addAction(UIAlertAction(title: NSLocalizedString("Enable", comment: ""), style: .default){ _ in
UserDefaults.standard.sidejitenable = true
})
}
alertController.addAction(UIAlertAction(title: NSLocalizedString("Server Address", comment: ""), style: .default){ _ in
let alertController1 = UIAlertController(title: "SideJITServer Address", message: "Please Enter the SideJITServer Address Below. (this is not needed if SideJITServer has already been detected)", preferredStyle: .alert)
alertController1.addTextField { textField in
textField.placeholder = "SideJITServer Address"
}
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
alertController1.addAction(cancelAction)
let okAction = UIAlertAction(title: "OK", style: .default) { _ in
if let text = alertController1.textFields?.first?.text {
UserDefaults.standard.textInputSideJITServerurl = text
}
}
alertController1.addAction(okAction)
// Present the alert controller
self.present(alertController1, animated: true)
})
alertController.addAction(UIAlertAction(title: NSLocalizedString("Refresh", comment: ""), style: .destructive){ _ in
if UserDefaults.standard.sidejitenable {
@@ -702,7 +624,7 @@ extension SettingsViewController
SJSURL = "http://sidejitserver._http._tcp.local:8080"
} else {
SJSURL = UserDefaults.standard.textInputSideJITServerurl ?? ""
}
} // replace with your URL
let url = URL(string: SJSURL + "/re/")!
@@ -718,10 +640,8 @@ extension SettingsViewController
task.resume()
}
})
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
alertController.addAction(cancelAction)
alertController.addAction(.cancel)
//Fix crash on iPad
alertController.popoverPresentationController?.sourceView = self.tableView
alertController.popoverPresentationController?.sourceRect = self.tableView.rectForRow(at: indexPath)
@@ -733,6 +653,10 @@ extension SettingsViewController
message: NSLocalizedString("This is meant for 'SideJITServer' and it only works on iOS 17+ ", comment: ""),
preferredStyle: UIAlertController.Style.actionSheet)
alertController.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: ""), style: .destructive){ _ in
print("Not on iOS 17")
})
alertController.addAction(.cancel)
//Fix crash on iPad
alertController.popoverPresentationController?.sourceView = self.tableView
@@ -745,11 +669,8 @@ extension SettingsViewController
case .clearCache: self.clearCache()
case .resetPairingFile:
let filename = "ALTPairingFile.mobiledevicepairing"
let fm = FileManager.default
let documentsPath = fm.documentsDirectory.appendingPathComponent("/\(filename)")
let alertController = UIAlertController(
title: NSLocalizedString("Are you sure to reset the pairing file?", comment: ""),
@@ -772,7 +693,6 @@ extension SettingsViewController
alertController.popoverPresentationController?.sourceRect = self.tableView.rectForRow(at: indexPath)
self.present(alertController, animated: true)
self.tableView.deselectRow(at: indexPath, animated: true)
case .anisetteServers:
self.prepare(for: UIStoryboardSegue(identifier: "anisetteServers", source: self, destination: UIHostingController(rootView: AnisetteServers(selected: "", errorCallback: {
ToastView(text: "Reset adi.pb", detailText: "Buh").show(in: self)

View File

@@ -32,7 +32,6 @@ public extension UserDefaults
@NSManaged var isBackgroundRefreshEnabled: Bool
@NSManaged var isIdleTimeoutDisableEnabled: Bool
@NSManaged var isAppLimitDisabled: Bool
@NSManaged var isPairingReset: Bool
@NSManaged var isDebugModeEnabled: Bool
@NSManaged var presentedLaunchReminderNotification: Bool
@@ -78,7 +77,6 @@ public extension UserDefaults
let localServerSupportsRefreshing = !ProcessInfo.processInfo.isOperatingSystemAtLeast(ios14)
let defaults = [
#keyPath(UserDefaults.isAppLimitDisabled): false,
#keyPath(UserDefaults.isBackgroundRefreshEnabled): true,
#keyPath(UserDefaults.isIdleTimeoutDisableEnabled): true,
#keyPath(UserDefaults.isPairingReset): true,
@@ -86,7 +84,6 @@ public extension UserDefaults
#keyPath(UserDefaults.activeAppLimitIncludesExtensions): activeAppLimitIncludesExtensions,
#keyPath(UserDefaults.localServerSupportsRefreshing): localServerSupportsRefreshing,
#keyPath(UserDefaults.requiresAppGroupMigration): true,
#keyPath(UserDefaults.menuAnisetteList): "https://servers.sidestore.io/servers.json",
#keyPath(UserDefaults.menuAnisetteURL): "https://ani.sidestore.io"
] as [String : Any]

View File

@@ -163,9 +163,8 @@ public extension InstalledApp
class func updatesFetchRequest() -> NSFetchRequest<InstalledApp>
{
let fetchRequest = InstalledApp.fetchRequest() as NSFetchRequest<InstalledApp>
fetchRequest.predicate = NSPredicate(format: "%K == YES AND %K == YES",
#keyPath(InstalledApp.isActive), #keyPath(InstalledApp.hasUpdate))
fetchRequest.predicate = NSPredicate(format: "%K == YES AND %K != nil AND %K != %K",
#keyPath(InstalledApp.isActive), #keyPath(InstalledApp.storeApp), #keyPath(InstalledApp.version), #keyPath(InstalledApp.storeApp.latestSupportedVersion.version))
return fetchRequest
}

View File

@@ -169,31 +169,6 @@ public class StoreApp: NSManagedObject, Decodable, Fetchable
return self._versions.array as! [AppVersion]
}
@nonobjc public var size: Int64? {
guard let version = self.latestSupportedVersion else { return nil }
return version.size
}
@nonobjc public var version: String? {
guard let version = self.latestSupportedVersion else { return nil }
return version.version
}
@nonobjc public var versionDescription: String? {
guard let version = self.latestSupportedVersion else { return nil }
return version.localizedDescription
}
@nonobjc public var versionDate: Date? {
guard let version = self.latestSupportedVersion else { return nil }
return version.date
}
@nonobjc public var downloadURL: URL? {
guard let version = self.latestSupportedVersion else { return nil }
return version.downloadURL
}
private override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?)
{
super.init(entity: entity, insertInto: context)

View File

@@ -10,30 +10,29 @@ import Foundation
import AuthenticationServices
import CoreData
private let clientID = "my4hpHHG4iVRme6QALnQGlhSBQiKdB_AinrVgPpIpiC-xiHstTYiLKO5vfariFo1"
private let clientSecret = "Zow0ggt9YgwIyd4DVLoO9Z02KuuIXW44xhx4lfL27x2u-_u4FE4rYR48bEKREPS5"
private let clientID = "ZMx0EGUWe4TVWYXNZZwK_fbIK5jHFVWoUf1Qb-sqNXmT-YzAGwDPxxq7ak3_W5Q2"
private let clientSecret = "1hktsZB89QyN69cB4R0tu55R4TCPQGXxvebYUUh7Y-5TLSnRswuxs6OUjdJ74IJt"
private let campaignID = "12794837"
typealias PatreonAPIError = PatreonAPIErrorCode.Error
enum PatreonAPIErrorCode: Int, ALTErrorEnum, CaseIterable
{
case unknown
case notAuthenticated
case invalidAccessToken
var errorFailureReason: String {
switch self
{
case .unknown: return NSLocalizedString("An unknown error occurred.", comment: "")
case .notAuthenticated: return NSLocalizedString("No connected Patreon account.", comment: "")
case .invalidAccessToken: return NSLocalizedString("Invalid access token.", comment: "")
}
}
}
private let campaignID = "2863968"
extension PatreonAPI
{
enum Error: LocalizedError
{
case unknown
case notAuthenticated
case invalidAccessToken
var errorDescription: String? {
switch self
{
case .unknown: return NSLocalizedString("An unknown error occurred.", comment: "")
case .notAuthenticated: return NSLocalizedString("No connected Patreon account.", comment: "")
case .invalidAccessToken: return NSLocalizedString("Invalid access token.", comment: "")
}
}
}
enum AuthorizationType
{
case none
@@ -111,7 +110,7 @@ public extension PatreonAPI
let components = URLComponents(url: callbackURL, resolvingAgainstBaseURL: false),
let codeQueryItem = components.queryItems?.first(where: { $0.name == "code" }),
let code = codeQueryItem.value
else { throw PatreonAPIError(.unknown) }
else { throw Error.unknown }
self.fetchAccessToken(oauthCode: code) { (result) in
switch result
@@ -152,9 +151,9 @@ public extension PatreonAPI
self.send(request, authorizationType: .user) { (result: Result<AccountResponse, Swift.Error>) in
switch result
{
case .failure(~PatreonAPIErrorCode.notAuthenticated):
case .failure(Error.notAuthenticated):
self.signOut() { (result) in
completion(.failure(PatreonAPIError(.notAuthenticated)))
completion(.failure(Error.notAuthenticated))
}
case .failure(let error): completion(.failure(error))
@@ -358,11 +357,11 @@ private extension PatreonAPI
{
case .none: break
case .creator:
guard let creatorAccessToken = Keychain.shared.patreonCreatorAccessToken else { return completion(.failure(PatreonAPIError(.invalidAccessToken))) }
guard let creatorAccessToken = Keychain.shared.patreonCreatorAccessToken else { return completion(.failure(Error.invalidAccessToken)) }
request.setValue("Bearer " + creatorAccessToken, forHTTPHeaderField: "Authorization")
case .user:
guard let accessToken = Keychain.shared.patreonAccessToken else { return completion(.failure(PatreonAPIError(.notAuthenticated))) }
guard let accessToken = Keychain.shared.patreonAccessToken else { return completion(.failure(Error.notAuthenticated)) }
request.setValue("Bearer " + accessToken, forHTTPHeaderField: "Authorization")
}
@@ -375,8 +374,8 @@ private extension PatreonAPI
{
switch authorizationType
{
case .creator: completion(.failure(PatreonAPIError(.invalidAccessToken)))
case .none: completion(.failure(PatreonAPIError(.notAuthenticated)))
case .creator: completion(.failure(Error.invalidAccessToken))
case .none: completion(.failure(Error.notAuthenticated))
case .user:
self.refreshAccessToken() { (result) in
switch result

View File

@@ -82,7 +82,6 @@ struct ComplicationView: View
}
.gaugeStyle(.accessoryCircularCapacity)
.unredacted()
.widgetBackground(Color.clear)
}
}

View File

@@ -1,27 +0,0 @@
//
// View+AltWidget.swift
// AltStore
//
// Created by Riley Testut on 8/18/23.
// Copyright © 2023 Riley Testut. All rights reserved.
//
import SwiftUI
extension View
{
@ViewBuilder
func widgetBackground(_ backgroundView: some View) -> some View
{
if #available(iOSApplicationExtension 17, *)
{
containerBackground(for: .widget) {
backgroundView
}
}
else
{
background(backgroundView)
}
}
}

View File

@@ -104,8 +104,7 @@ struct WidgetView : View
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
.widgetBackground(backgroundView(icon: entry.app?.icon, tintColor: entry.app?.tintColor))
.background(backgroundView(icon: entry.app?.icon, tintColor: entry.app?.tintColor))
}
}

View File

@@ -1,8 +1,8 @@
// Configuration settings file format documentation can be found at:
// https://help.apple.com/xcode/#/dev745c5c974
MARKETING_VERSION = 0.5.9
CURRENT_PROJECT_VERSION = 5090
MARKETING_VERSION = 0.5.6
CURRENT_PROJECT_VERSION = 5060
// Vars to be overwritten by `CodeSigning.xcconfig` if exists
DEVELOPMENT_TEAM = S32Z3HMYVQ

View File

@@ -1,37 +0,0 @@
Developer Certificate of Origin
Version 1.1
Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
Everyone is permitted to copy and distribute verbatim copies of this
license document, but changing it is not allowed.
Developer's Certificate of Origin 1.1
By making a contribution to this project, I certify that:
(a) The contribution was created in whole or in part by me and I
have the right to submit it under the open source license
indicated in the file; or
(b) The contribution is based upon previous work that, to the best
of my knowledge, is covered under an appropriate open source
license and I have the right under that license to submit that
work with modifications, whether created in whole or in part
by me, under the same open source license (unless I am
permitted to submit under a different license), as indicated
in the file; or
(c) The contribution was provided directly to me by some other
person who certified (a), (b) or (c) and I have not modified
it.
(d) I understand and agree that this project and the contribution
are public and that a record of the contribution (including all
personal information I submit with it, including my sign-off) is
maintained indefinitely and may be redistributed consistent with
this project or the open source license(s) involved.

View File

@@ -2,8 +2,6 @@
Thank you for your interest in contributing to SideStore! SideStore is a community driven project, and it's made possible by people like you.
By contributing to this Project (SideStore), you agree to the Developer's Certificate of Origin found in [CERTIFICATE-OF-ORIGIN.md](CERTIFICATE-OF-ORIGIN.md). Any contributions to this project after the addition of the Developer's Certificate of Origin are subject to its policy.
There are many ways to contribute to SideStore, so if you aren't a developer, there are still many other ways you can help out:
- [Writing documentation](https://github.com/SideStore/SideStore-Docs)

View File

@@ -3,34 +3,6 @@
# Ensure we are in Dependencies directory
cd "$(dirname "$0")"
# Detect if Homebrew is in /opt/homebrew (Apple Silicon) or /usr/local (Intel)
if [[ -d "/opt/homebrew" ]]; then
export PATH="/opt/homebrew/bin:$PATH"
elif [[ -d "/usr/local" ]]; then
export PATH="/usr/local/bin:$PATH"
fi
# Check if wget and curl are installed; if not, install them via Homebrew
if ! command -v wget &> /dev/null; then
echo "wget not found, attempting to install via Homebrew..."
if command -v brew &> /dev/null; then
brew install wget
else
echo "Homebrew is not installed. Please install Homebrew and rerun the script."
exit 1
fi
fi
if ! command -v curl &> /dev/null; then
echo "curl not found, attempting to install via Homebrew..."
if command -v brew &> /dev/null; then
brew install curl
else
echo "Homebrew is not installed. Please install Homebrew and rerun the script."
exit 1
fi
fi
check_for_update() {
if [ -f ".skip-prebuilt-fetch-$1" ]; then
echo "Skipping prebuilt fetch for $1 since .skip-prebuilt-fetch-$1 exists. If you are developing $1 alongside SideStore, don't remove this file, or this script will replace your locally built binaries with the ones built by GitHub Actions."

View File

@@ -24,7 +24,7 @@
outputFiles = (
"$(OBJECT_FILE_DIR)/$(CARGO_XCODE_TARGET_ARCH)-$(EXECUTABLE_NAME)",
);
script = "# generated with cargo-xcode 1.5.0\n# modified to use prebuilt binaries\n\nset -eu;\n\nBUILT_SRC=\"./minimuxer/${LIB_FILE_NAME+libminimuxer-ios}.a\"\nln -f -- \"$BUILT_SRC\" \"$TARGET_BUILD_DIR/$EXECUTABLE_PATH\" || cp \"$BUILT_SRC\" \"$TARGET_BUILD_DIR/$EXECUTABLE_PATH\"\necho \"$BUILT_SRC -> $TARGET_BUILD_DIR/$EXECUTABLE_PATH\"\n\n# xcode generates dep file, but for its own path, so append our rename to it\n#DEP_FILE_SRC=\"minimuxer/target/${CARGO_XCODE_TARGET_TRIPLE}/release/${CARGO_XCODE_CARGO_DEP_FILE_NAME}\"\n#if [ -f \"$DEP_FILE_SRC\" ]; then\n# DEP_FILE_DST=\"${DERIVED_FILE_DIR}/${CARGO_XCODE_TARGET_ARCH}-${EXECUTABLE_NAME}.d\"\n# cp -f \"$DEP_FILE_SRC\" \"$DEP_FILE_DST\"\n# echo >> \"$DEP_FILE_DST\" \"$SCRIPT_OUTPUT_FILE_0: $BUILT_SRC\"\n#fi\n\n# lipo script needs to know all the platform-specific files that have been built\n# archs is in the file name, so that paths don't stay around after archs change\n# must match input for LipoScript\n#FILE_LIST=\"${DERIVED_FILE_DIR}/${ARCHS}-${EXECUTABLE_NAME}.xcfilelist\"\n#touch \"$FILE_LIST\"\n#if ! egrep -q \"$SCRIPT_OUTPUT_FILE_0\" \"$FILE_LIST\" ; then\n# echo >> \"$FILE_LIST\" \"$SCRIPT_OUTPUT_FILE_0\"\n#fi\n";
script = "# generated with cargo-xcode 1.5.0\n# modified to use prebuilt binaries\n\nset -eu;\n\nBUILT_SRC=\"./minimuxer/$LIB_FILE_NAME.a\"\nln -f -- \"$BUILT_SRC\" \"$TARGET_BUILD_DIR/$EXECUTABLE_PATH\" || cp \"$BUILT_SRC\" \"$TARGET_BUILD_DIR/$EXECUTABLE_PATH\"\necho \"$BUILT_SRC -> $TARGET_BUILD_DIR/$EXECUTABLE_PATH\"\n\n# xcode generates dep file, but for its own path, so append our rename to it\n#DEP_FILE_SRC=\"minimuxer/target/${CARGO_XCODE_TARGET_TRIPLE}/release/${CARGO_XCODE_CARGO_DEP_FILE_NAME}\"\n#if [ -f \"$DEP_FILE_SRC\" ]; then\n# DEP_FILE_DST=\"${DERIVED_FILE_DIR}/${CARGO_XCODE_TARGET_ARCH}-${EXECUTABLE_NAME}.d\"\n# cp -f \"$DEP_FILE_SRC\" \"$DEP_FILE_DST\"\n# echo >> \"$DEP_FILE_DST\" \"$SCRIPT_OUTPUT_FILE_0: $BUILT_SRC\"\n#fi\n\n# lipo script needs to know all the platform-specific files that have been built\n# archs is in the file name, so that paths don't stay around after archs change\n# must match input for LipoScript\n#FILE_LIST=\"${DERIVED_FILE_DIR}/${ARCHS}-${EXECUTABLE_NAME}.xcfilelist\"\n#touch \"$FILE_LIST\"\n#if ! egrep -q \"$SCRIPT_OUTPUT_FILE_0\" \"$FILE_LIST\" ; then\n# echo >> \"$FILE_LIST\" \"$SCRIPT_OUTPUT_FILE_0\"\n#fi\n";
};
/* End PBXBuildRule section */

View File

@@ -73,7 +73,6 @@ public extension NSError
{
var userInfo = self.userInfo
userInfo[NSLocalizedDescriptionKey] = self.localizedDescription
userInfo[NSLocalizedFailureErrorKey] = self.localizedFailure
userInfo[NSLocalizedFailureReasonErrorKey] = self.localizedFailureReason
userInfo[NSLocalizedRecoverySuggestionErrorKey] = self.localizedRecoverySuggestion
userInfo[NSDebugDescriptionErrorKey] = self.localizedDebugDescription
@@ -125,7 +124,6 @@ public extension NSError
var userInfo = self.userInfo
userInfo[NSDebugDescriptionErrorKey] = self.localizedDebugDescription
userInfo[NSLocalizedDescriptionKey] = self.localizedDescription
userInfo[NSLocalizedFailureErrorKey] = self.localizedFailure
userInfo[NSLocalizedFailureReasonErrorKey] = self.localizedFailureReason
userInfo[NSLocalizedRecoverySuggestionErrorKey] = self.localizedRecoverySuggestion