mirror of
https://github.com/SideStore/SideStore.git
synced 2026-05-11 20:05:40 +02:00
Compare commits
15 Commits
d0324a2021
...
nightly
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a0d3c5ed4a | ||
|
|
0d8a2df802 | ||
|
|
9223da751d | ||
|
|
e744ed8b67 | ||
|
|
20714673b2 | ||
|
|
7f2be4cd58 | ||
|
|
f055f33bec | ||
|
|
4deda9229c | ||
|
|
c1bcadbad5 | ||
|
|
f8e199b3d4 | ||
|
|
5efed9df08 | ||
|
|
ae380e48dd | ||
|
|
db5fb89d7c | ||
|
|
2b71c36ace | ||
|
|
4aca1dfa43 |
20
.github/workflows/alpha.yml
vendored
20
.github/workflows/alpha.yml
vendored
@@ -20,7 +20,7 @@ jobs:
|
||||
UPSTREAM_CHANNEL: "nightly"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
fetch-depth: 0
|
||||
@@ -54,13 +54,13 @@ jobs:
|
||||
echo "MARKETING_VERSION=$NORMALIZED_VERSION" | tee -a $GITHUB_ENV
|
||||
|
||||
- name: Setup Xcode
|
||||
uses: maxim-lobanov/setup-xcode@v1.6.0
|
||||
uses: maxim-lobanov/setup-xcode@v1.7.0
|
||||
with:
|
||||
xcode-version: "26.2"
|
||||
|
||||
- name: Restore Cache (exact)
|
||||
id: xcode-cache-exact
|
||||
uses: actions/cache/restore@v3
|
||||
uses: actions/cache/restore@v5
|
||||
with:
|
||||
path: |
|
||||
~/Library/Developer/Xcode/DerivedData
|
||||
@@ -70,7 +70,7 @@ jobs:
|
||||
- name: Restore Cache (last)
|
||||
if: steps.xcode-cache-exact.outputs.cache-hit != 'true'
|
||||
id: xcode-cache-fallback
|
||||
uses: actions/cache/restore@v3
|
||||
uses: actions/cache/restore@v5
|
||||
with:
|
||||
path: |
|
||||
~/Library/Developer/Xcode/DerivedData
|
||||
@@ -119,7 +119,7 @@ jobs:
|
||||
|
||||
- name: Save Cache
|
||||
if: ${{ steps.xcode-cache-fallback.outputs.cache-hit != 'true' }}
|
||||
uses: actions/cache/save@v3
|
||||
uses: actions/cache/save@v5
|
||||
with:
|
||||
path: |
|
||||
~/Library/Developer/Xcode/DerivedData
|
||||
@@ -141,12 +141,12 @@ jobs:
|
||||
# --------------------------------------------------
|
||||
# artifacts
|
||||
# --------------------------------------------------
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: build-logs-${{ env.MARKETING_VERSION }}.zip
|
||||
path: build-logs.zip
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v7
|
||||
if: >
|
||||
vars.ENABLE_TESTS == '1' &&
|
||||
vars.ENABLE_TESTS_BUILD == '1'
|
||||
@@ -154,7 +154,7 @@ jobs:
|
||||
name: tests-build-logs-${{ env.SHORT_COMMIT }}.zip
|
||||
path: tests-build-logs.zip
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v7
|
||||
if: >
|
||||
vars.ENABLE_TESTS == '1' &&
|
||||
vars.ENABLE_TESTS_RUN == '1'
|
||||
@@ -166,12 +166,12 @@ jobs:
|
||||
with:
|
||||
name: SideStore-${{ env.MARKETING_VERSION }}.ipa
|
||||
path: SideStore.ipa
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: SideStore-${{ env.MARKETING_VERSION }}-dSYMs.zip
|
||||
path: SideStore.dSYMs.zip
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v7
|
||||
if: env.DEPLOY_KEY != ''
|
||||
with:
|
||||
repository: "SideStore/apps-v2.json"
|
||||
|
||||
2
.github/workflows/attach_build_products.yml
vendored
2
.github/workflows/attach_build_products.yml
vendored
@@ -24,7 +24,7 @@ jobs:
|
||||
if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/github-script@v6
|
||||
- uses: actions/github-script@v9
|
||||
with:
|
||||
# This snippet is public-domain, taken from
|
||||
# https://github.com/oprypin/nightly.link/blob/master/.github/workflows/pr-comment.yml
|
||||
|
||||
22
.github/workflows/nightly.yml
vendored
22
.github/workflows/nightly.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
||||
UPSTREAM_CHANNEL: ""
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
fetch-depth: 0
|
||||
@@ -78,14 +78,14 @@ jobs:
|
||||
|
||||
- name: Setup Xcode
|
||||
if: steps.build_gate.outputs.should_skip != 'true'
|
||||
uses: maxim-lobanov/setup-xcode@v1.6.0
|
||||
uses: maxim-lobanov/setup-xcode@v1.7.0
|
||||
with:
|
||||
xcode-version: "26.4"
|
||||
|
||||
- name: Restore Cache (exact)
|
||||
if: steps.build_gate.outputs.should_skip != 'true'
|
||||
id: xcode-cache-exact
|
||||
uses: actions/cache/restore@v3
|
||||
uses: actions/cache/restore@v5
|
||||
with:
|
||||
path: |
|
||||
~/Library/Developer/Xcode/DerivedData
|
||||
@@ -97,7 +97,7 @@ jobs:
|
||||
steps.build_gate.outputs.should_skip != 'true' &&
|
||||
steps.xcode-cache-exact.outputs.cache-hit != 'true'
|
||||
id: xcode-cache-fallback
|
||||
uses: actions/cache/restore@v3
|
||||
uses: actions/cache/restore@v5
|
||||
with:
|
||||
path: |
|
||||
~/Library/Developer/Xcode/DerivedData
|
||||
@@ -151,7 +151,7 @@ jobs:
|
||||
if: >
|
||||
steps.build_gate.outputs.should_skip != 'true' &&
|
||||
steps.xcode-cache-fallback.outputs.cache-hit != 'true'
|
||||
uses: actions/cache/save@v3
|
||||
uses: actions/cache/save@v5
|
||||
with:
|
||||
path: |
|
||||
~/Library/Developer/Xcode/DerivedData
|
||||
@@ -174,13 +174,13 @@ jobs:
|
||||
# --------------------------------------------------
|
||||
# artifacts
|
||||
# --------------------------------------------------
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v7
|
||||
if: steps.build_gate.outputs.should_skip != 'true'
|
||||
with:
|
||||
name: build-logs-${{ env.MARKETING_VERSION }}.zip
|
||||
path: build-logs.zip
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v7
|
||||
if: >
|
||||
steps.build_gate.outputs.should_skip != 'true' &&
|
||||
vars.ENABLE_TESTS == '1' &&
|
||||
@@ -189,7 +189,7 @@ jobs:
|
||||
name: tests-build-logs-${{ env.SHORT_COMMIT }}.zip
|
||||
path: tests-build-logs.zip
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v7
|
||||
if: >
|
||||
steps.build_gate.outputs.should_skip != 'true' &&
|
||||
vars.ENABLE_TESTS == '1' &&
|
||||
@@ -198,18 +198,18 @@ jobs:
|
||||
name: tests-run-logs-${{ env.SHORT_COMMIT }}.zip
|
||||
path: tests-run-logs.zip
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v7
|
||||
if: steps.build_gate.outputs.should_skip != 'true'
|
||||
with:
|
||||
name: SideStore-${{ env.MARKETING_VERSION }}.ipa
|
||||
path: SideStore.ipa
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v7
|
||||
if: steps.build_gate.outputs.should_skip != 'true'
|
||||
with:
|
||||
name: SideStore-${{ env.MARKETING_VERSION }}-dSYMs.zip
|
||||
path: SideStore.dSYMs.zip
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
if: steps.build_gate.outputs.should_skip != 'true' && env.DEPLOY_KEY != ''
|
||||
with:
|
||||
repository: "SideStore/apps-v2.json"
|
||||
|
||||
16
.github/workflows/pr.yml
vendored
16
.github/workflows/pr.yml
vendored
@@ -16,7 +16,7 @@ jobs:
|
||||
runs-on: macos-26
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
fetch-depth: 1 # shallow clone just for PR
|
||||
@@ -33,13 +33,13 @@ jobs:
|
||||
echo "MARKETING_VERSION=$NORMALIZED_VERSION" | tee -a $GITHUB_ENV
|
||||
|
||||
- name: Setup Xcode
|
||||
uses: maxim-lobanov/setup-xcode@v1.6.0
|
||||
uses: maxim-lobanov/setup-xcode@v1.7.0
|
||||
with:
|
||||
xcode-version: "26.2"
|
||||
|
||||
- name: Restore Cache (exact)
|
||||
id: xcode-cache-exact
|
||||
uses: actions/cache/restore@v3
|
||||
uses: actions/cache/restore@v5
|
||||
with:
|
||||
path: |
|
||||
~/Library/Developer/Xcode/DerivedData
|
||||
@@ -49,7 +49,7 @@ jobs:
|
||||
- name: Restore Cache (last)
|
||||
if: steps.xcode-cache-exact.outputs.cache-hit != 'true'
|
||||
id: xcode-cache-fallback
|
||||
uses: actions/cache/restore@v3
|
||||
uses: actions/cache/restore@v5
|
||||
with:
|
||||
path: |
|
||||
~/Library/Developer/Xcode/DerivedData
|
||||
@@ -67,24 +67,24 @@ jobs:
|
||||
|
||||
- name: Save Cache
|
||||
if: ${{ steps.xcode-cache-fallback.outputs.cache-hit != 'true' }}
|
||||
uses: actions/cache/save@v3
|
||||
uses: actions/cache/save@v5
|
||||
with:
|
||||
path: |
|
||||
~/Library/Developer/Xcode/DerivedData
|
||||
~/Library/Caches/org.swift.swiftpm
|
||||
key: xcode-build-cache-${{ github.ref_name }}-${{ github.sha }}
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: build-logs-${{ env.MARKETING_VERSION }}.zip
|
||||
path: build-logs.zip
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: SideStore-${{ env.MARKETING_VERSION }}.ipa
|
||||
path: SideStore-${{ env.MARKETING_VERSION }}.ipa
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: SideStore-${{ env.MARKETING_VERSION }}-dSYMs.zip
|
||||
path: SideStore.dSYMs.zip
|
||||
|
||||
18
.github/workflows/stable.yml
vendored
18
.github/workflows/stable.yml
vendored
@@ -21,7 +21,7 @@ jobs:
|
||||
UPSTREAM_CHANNEL: ""
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
fetch-depth: 0
|
||||
@@ -50,13 +50,13 @@ jobs:
|
||||
echo "SHORT_COMMIT=$SHORT_COMMIT" | tee -a $GITHUB_ENV
|
||||
|
||||
- name: Setup Xcode
|
||||
uses: maxim-lobanov/setup-xcode@v1.6.0
|
||||
uses: maxim-lobanov/setup-xcode@v1.7.0
|
||||
with:
|
||||
xcode-version: "26.0"
|
||||
xcode-version: "26.4"
|
||||
|
||||
- name: Restore Cache (exact)
|
||||
id: xcode-cache-exact
|
||||
uses: actions/cache/restore@v3
|
||||
uses: actions/cache/restore@v5
|
||||
with:
|
||||
path: |
|
||||
~/Library/Developer/Xcode/DerivedData
|
||||
@@ -66,7 +66,7 @@ jobs:
|
||||
- name: Restore Cache (last)
|
||||
if: steps.xcode-cache-exact.outputs.cache-hit != 'true'
|
||||
id: xcode-cache-fallback
|
||||
uses: actions/cache/restore@v3
|
||||
uses: actions/cache/restore@v5
|
||||
with:
|
||||
path: |
|
||||
~/Library/Developer/Xcode/DerivedData
|
||||
@@ -84,24 +84,24 @@ jobs:
|
||||
|
||||
- name: Save Cache
|
||||
if: ${{ steps.xcode-cache-fallback.outputs.cache-hit != 'true' }}
|
||||
uses: actions/cache/save@v3
|
||||
uses: actions/cache/save@v5
|
||||
with:
|
||||
path: |
|
||||
~/Library/Developer/Xcode/DerivedData
|
||||
~/Library/Caches/org.swift.swiftpm
|
||||
key: xcode-build-cache-stable-${{ github.sha }}
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: build-logs-${{ env.MARKETING_VERSION }}.zip
|
||||
path: build-logs.zip
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: SideStore-${{ env.MARKETING_VERSION }}.ipa
|
||||
path: SideStore.ipa
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: SideStore-${{ env.MARKETING_VERSION }}-dSYMs.zip
|
||||
path: SideStore.dSYMs.zip
|
||||
|
||||
@@ -640,6 +640,13 @@
|
||||
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
|
||||
|
||||
/* Begin PBXFileSystemSynchronizedGroupBuildPhaseMembershipExceptionSet section */
|
||||
174F75012F8B4F4900A53376 /* PBXFileSystemSynchronizedGroupBuildPhaseMembershipExceptionSet */ = {
|
||||
isa = PBXFileSystemSynchronizedGroupBuildPhaseMembershipExceptionSet;
|
||||
buildPhase = BFD247682284B9A500981D42 /* Resources */;
|
||||
membershipExceptions = (
|
||||
Intents/ViewApp.intentdefinition,
|
||||
);
|
||||
};
|
||||
A8EEC8CC2F4B146B00F2436D /* PBXFileSystemSynchronizedGroupBuildPhaseMembershipExceptionSet */ = {
|
||||
isa = PBXFileSystemSynchronizedGroupBuildPhaseMembershipExceptionSet;
|
||||
buildPhase = BFD247682284B9A500981D42 /* Resources */;
|
||||
@@ -651,7 +658,7 @@
|
||||
|
||||
/* Begin PBXFileSystemSynchronizedRootGroup section */
|
||||
A8BD20242F543FAD0045335F /* apps-v2.json */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = "apps-v2.json"; sourceTree = "<group>"; };
|
||||
A8EEC0502F4AF7FB00F2436D /* AltStoreCore */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (A8EEC0BF2F4AF7FB00F2436D /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = AltStoreCore; sourceTree = "<group>"; };
|
||||
A8EEC0502F4AF7FB00F2436D /* AltStoreCore */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (174F75012F8B4F4900A53376 /* PBXFileSystemSynchronizedGroupBuildPhaseMembershipExceptionSet */, A8EEC0BF2F4AF7FB00F2436D /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = AltStoreCore; sourceTree = "<group>"; };
|
||||
A8EEC3482F4B0D8600F2436D /* Shared */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (A8EEC36A2F4B0D8700F2436D /* PBXFileSystemSynchronizedBuildFileExceptionSet */, A8EEC36C2F4B0D8700F2436D /* PBXFileSystemSynchronizedBuildFileExceptionSet */, A8EEC36B2F4B0D8700F2436D /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = Shared; sourceTree = "<group>"; };
|
||||
A8EEC3B92F4B0EFC00F2436D /* AltWidget */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (A8EEC3CA2F4B0EFC00F2436D /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = AltWidget; sourceTree = "<group>"; };
|
||||
A8EEC3D92F4B0FC800F2436D /* AltBackup */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (A8EEC3E22F4B0FC800F2436D /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = AltBackup; sourceTree = "<group>"; };
|
||||
@@ -2420,8 +2427,8 @@
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/SideStore/AltSign";
|
||||
requirement = {
|
||||
kind = upToNextMajorVersion;
|
||||
minimumVersion = 0.1.0;
|
||||
branch = master;
|
||||
kind = branch;
|
||||
};
|
||||
};
|
||||
A82067C22D03E0DE00645C0D /* XCRemoteSwiftPackageReference "SemanticVersion" */ = {
|
||||
|
||||
16
AltStore.xcworkspace/contents.xcworkspacedata
generated
16
AltStore.xcworkspace/contents.xcworkspacedata
generated
@@ -1,16 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "group:AltStore.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:Dependencies/AltSign">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:Dependencies/minimuxer">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:Dependencies/Roxas/Roxas.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -203,10 +203,14 @@ class HeaderContentViewController<Header: UIView, Content: ScrollableContentView
|
||||
self.navigationBarButton = PillButton(type: .system)
|
||||
self.navigationBarButton.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 9000), for: .horizontal) // Prioritize over title length.
|
||||
|
||||
// Embed navigationBarButton in container view with Auto Layout to ensure it can automatically update its size.
|
||||
let buttonContainerView = UIView()
|
||||
buttonContainerView.addSubview(self.navigationBarButton, pinningEdgesWith: .zero)
|
||||
self.navigationItem.rightBarButtonItem = UIBarButtonItem(customView: buttonContainerView)
|
||||
if #available(iOS 26.0, *) {
|
||||
self.navigationItem.rightBarButtonItem = UIBarButtonItem(customView: self.navigationBarButton)
|
||||
} else {
|
||||
// Embed navigationBarButton in container view with Auto Layout to ensure it can automatically update its size.
|
||||
let buttonContainerView = UIView()
|
||||
buttonContainerView.addSubview(self.navigationBarButton, pinningEdgesWith: .zero)
|
||||
self.navigationItem.rightBarButtonItem = UIBarButtonItem(customView: buttonContainerView)
|
||||
}
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
self.navigationBarIconView.widthAnchor.constraint(equalToConstant: 35),
|
||||
|
||||
@@ -242,6 +242,7 @@
|
||||
<key>public.filename-extension</key>
|
||||
<array>
|
||||
<string>mobiledevicepairing</string>
|
||||
<string>mobiledevicepair</string>
|
||||
</array>
|
||||
</dict>
|
||||
</dict>
|
||||
|
||||
@@ -98,7 +98,7 @@ final class TunnelConfig: ObservableObject {
|
||||
static let shared = TunnelConfig()
|
||||
|
||||
private static let defaultOverrideIP: String = {
|
||||
if #available(iOS 26.4, *) { return "192.168.1.50" }
|
||||
// if #available(iOS 26.4, *) { return "192.168.1.50" }
|
||||
return "10.7.0.1"
|
||||
}()
|
||||
|
||||
|
||||
@@ -85,12 +85,12 @@ extension ProcessInfo {
|
||||
}
|
||||
|
||||
public 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 }
|
||||
// only true if we are 18.7.2<=26 || >=26.0.2
|
||||
if (OperatingSystemVersion(majorVersion: 18, minorVersion: 7, patchVersion: 2) <= operatingSystemVersion && operatingSystemVersion.majorVersion == 18) || operatingSystemVersion >= OperatingSystemVersion(majorVersion: 26, minorVersion: 0, patchVersion: 2) { true }
|
||||
// we are 26.0<26.0.2
|
||||
else if operatingSystemVersion < OperatingSystemVersion(majorVersion: 26, minorVersion: 0, patchVersion: 2) { false }
|
||||
// we are <18.7.2
|
||||
else if operatingSystemVersion < OperatingSystemVersion(majorVersion: 18, minorVersion: 7, patchVersion: 2) { false }
|
||||
else { true }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import WidgetKit
|
||||
|
||||
extension View
|
||||
{
|
||||
@@ -78,4 +79,59 @@ extension View
|
||||
}
|
||||
}
|
||||
|
||||
/// Opts this view into the widget accent group on iOS 16+, which lets the
|
||||
/// system tint it with the user's chosen colour in tinted (accented) mode.
|
||||
/// No-op on older OS versions where the API does not exist.
|
||||
@ViewBuilder
|
||||
func widgetAccentableIfAvailable() -> some View
|
||||
{
|
||||
if #available(iOSApplicationExtension 16, *)
|
||||
{
|
||||
self.widgetAccentable()
|
||||
}
|
||||
else
|
||||
{
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Applies `luminanceToAlpha()` only when the widget is rendering in
|
||||
/// accented (tinted) mode on iOS 16+. This converts the view's pixel
|
||||
/// brightness into opacity so the system can overlay the user's chosen
|
||||
/// tint colour correctly — without it, images appear as white rectangles
|
||||
/// in tinted mode. No-op in fullColor/dark/light mode and on older OS.
|
||||
@ViewBuilder
|
||||
func luminanceToAlphaInAccentedMode() -> some View
|
||||
{
|
||||
if #available(iOSApplicationExtension 16, *)
|
||||
{
|
||||
LuminanceToAlphaWrapper(content: self)
|
||||
}
|
||||
else
|
||||
{
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// Helper view that reads widgetRenderingMode (iOS 16+) and conditionally
|
||||
/// applies luminanceToAlpha(). Kept separate so the environment read is
|
||||
/// cleanly scoped behind the @available gate.
|
||||
@available(iOSApplicationExtension 16, *)
|
||||
private struct LuminanceToAlphaWrapper<Content: View>: View
|
||||
{
|
||||
let content: Content
|
||||
@Environment(\.widgetRenderingMode) private var renderingMode
|
||||
|
||||
var body: some View {
|
||||
if renderingMode == .accented
|
||||
{
|
||||
content.luminanceToAlpha()
|
||||
}
|
||||
else
|
||||
{
|
||||
content
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
73
AltWidget/Intents/ViewAppIntent.swift
Normal file
73
AltWidget/Intents/ViewAppIntent.swift
Normal file
@@ -0,0 +1,73 @@
|
||||
//
|
||||
// ViewAppIntent.swift
|
||||
// AltWidgetExtension
|
||||
//
|
||||
// Replaces the legacy SiriKit ViewAppIntent (ViewApp.intentdefinition) with a
|
||||
// modern AppIntents-based intent. Required because IntentConfiguration does not
|
||||
// support containerBackground on iOS 17+, causing the blank-widget bug.
|
||||
//
|
||||
|
||||
import AppIntents
|
||||
import WidgetKit
|
||||
import AltStoreCore
|
||||
|
||||
// Represents one installed app in the picker list.
|
||||
@available(iOSApplicationExtension 17, *)
|
||||
struct InstalledAppEntity: AppEntity
|
||||
{
|
||||
// Disambiguates from the AppEntity name used in AppIntents framework.
|
||||
static var typeDisplayRepresentation: TypeDisplayRepresentation = "Installed App"
|
||||
static var defaultQuery = InstalledAppQuery()
|
||||
|
||||
var id: String // bundle identifier
|
||||
var name: String
|
||||
|
||||
var displayRepresentation: DisplayRepresentation {
|
||||
DisplayRepresentation(title: "\(name)")
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOSApplicationExtension 17, *)
|
||||
struct InstalledAppQuery: EntityQuery
|
||||
{
|
||||
func entities(for identifiers: [String]) async throws -> [InstalledAppEntity]
|
||||
{
|
||||
try await DatabaseManager.shared.start()
|
||||
let context = DatabaseManager.shared.persistentContainer.newBackgroundContext()
|
||||
return try await context.performAsync {
|
||||
let fetchRequest = InstalledApp.fetchRequest()
|
||||
fetchRequest.predicate = NSPredicate(
|
||||
format: "%K IN %@",
|
||||
#keyPath(InstalledApp.bundleIdentifier),
|
||||
identifiers
|
||||
)
|
||||
fetchRequest.returnsObjectsAsFaults = false
|
||||
let apps = try context.fetch(fetchRequest)
|
||||
return apps.map { InstalledAppEntity(id: $0.bundleIdentifier, name: $0.name) }
|
||||
}
|
||||
}
|
||||
|
||||
func suggestedEntities() async throws -> [InstalledAppEntity]
|
||||
{
|
||||
try await DatabaseManager.shared.start()
|
||||
let context = DatabaseManager.shared.persistentContainer.newBackgroundContext()
|
||||
return try await context.performAsync {
|
||||
InstalledApp.all(in: context)
|
||||
.map { InstalledAppEntity(id: $0.bundleIdentifier, name: $0.name) }
|
||||
.sorted { $0.name < $1.name }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOSApplicationExtension 17, *)
|
||||
struct SelectAppIntent: WidgetConfigurationIntent
|
||||
{
|
||||
static var title: LocalizedStringResource = "Select App"
|
||||
static var description = IntentDescription("Choose which app to display.")
|
||||
|
||||
@Parameter(title: "App")
|
||||
var app: InstalledAppEntity?
|
||||
|
||||
// WidgetConfigurationIntent requires perform() — no-op for configuration intents.
|
||||
func perform() async throws -> some IntentResult { .result() }
|
||||
}
|
||||
@@ -221,3 +221,33 @@ class AppsTimelineProvider: AppsTimelineProviderBase<Intent>, IntentTimelineProv
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Modern AppIntents-based provider for AppDetailWidget on iOS 17+.
|
||||
// Replaces AppsTimelineProvider (IntentTimelineProvider) which uses the legacy
|
||||
// SiriKit Intents framework that breaks containerBackground on iOS 17+.
|
||||
@available(iOSApplicationExtension 17, *)
|
||||
class SelectAppTimelineProvider: AppsTimelineProviderBase<SelectAppIntent>, AppIntentTimelineProvider
|
||||
{
|
||||
typealias Intent = SelectAppIntent
|
||||
|
||||
func snapshot(for intent: SelectAppIntent, in context: Context) async -> AppsEntry<SelectAppIntent>
|
||||
{
|
||||
let bundleID = await resolvedBundleID(for: intent)
|
||||
return await self.snapshot(for: [bundleID], in: intent)
|
||||
}
|
||||
|
||||
func timeline(for intent: SelectAppIntent, in context: Context) async -> Timeline<AppsEntry<SelectAppIntent>>
|
||||
{
|
||||
let bundleID = await resolvedBundleID(for: intent)
|
||||
return await self.timeline(for: [bundleID], in: intent)
|
||||
}
|
||||
|
||||
// If the user hasn't picked an app yet, fall back to the first active app
|
||||
// rather than a hardcoded bundle ID that may not exist in the database.
|
||||
private func resolvedBundleID(for intent: SelectAppIntent) async -> String
|
||||
{
|
||||
if let id = intent.app?.id { return id }
|
||||
let activeIDs = await self.fetchActiveAppBundleIDs()
|
||||
return activeIDs.first ?? StoreApp.altstoreAppID
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,6 +74,9 @@ private struct ActiveAppsWidgetView: View
|
||||
|
||||
@Environment(\.colorScheme)
|
||||
private var colorScheme
|
||||
|
||||
@Environment(\.widgetRenderingMode)
|
||||
private var renderingMode
|
||||
|
||||
var body: some View {
|
||||
Group {
|
||||
@@ -92,6 +95,12 @@ private struct ActiveAppsWidgetView: View
|
||||
{
|
||||
LinearGradient(colors: [.altGradientDark, .altGradientExtraDark], startPoint: .top, endPoint: .bottom)
|
||||
}
|
||||
else if renderingMode == .accented
|
||||
{
|
||||
// Plain dark background in tinted mode so the system's
|
||||
// accent colour composites cleanly over it.
|
||||
Color.black
|
||||
}
|
||||
else
|
||||
{
|
||||
LinearGradient(colors: [.altGradientLight, .altGradientDark], startPoint: .top, endPoint: .bottom)
|
||||
@@ -128,11 +137,16 @@ private struct ActiveAppsWidgetView: View
|
||||
let daysRemaining = app.expirationDate.numberOfCalendarDays(since: entry.date)
|
||||
|
||||
HStack(spacing: 10) {
|
||||
// In tinted (accented) mode, luminanceToAlpha() converts the icon's
|
||||
// brightness into opacity so the system can tint it with the user's
|
||||
// chosen accent colour. widgetAccentable() opts the view into that
|
||||
// accent group. In fullColor mode both are no-ops (via the helpers).
|
||||
Image(uiImage: resizedIcon)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.cornerRadius(cornerRadius)
|
||||
|
||||
.luminanceToAlphaInAccentedMode()
|
||||
.mask(RoundedRectangle(cornerRadius: cornerRadius, style: .continuous))
|
||||
.widgetAccentableIfAvailable()
|
||||
|
||||
VStack(alignment: .leading, spacing: 1) {
|
||||
Text(app.name)
|
||||
@@ -151,6 +165,7 @@ private struct ActiveAppsWidgetView: View
|
||||
.font(.system(size: 13, weight: .semibold, design: .rounded))
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
.widgetAccentableIfAvailable()
|
||||
|
||||
Spacer()
|
||||
|
||||
@@ -167,6 +182,7 @@ private struct ActiveAppsWidgetView: View
|
||||
.activatesRefreshAllAppsIntent()
|
||||
// this modifier invalidates the view (disables user interaction and shows a blinking effect)
|
||||
.invalidatableContent()
|
||||
.widgetAccentableIfAvailable()
|
||||
|
||||
}
|
||||
.frame(height: rowHeight)
|
||||
|
||||
@@ -15,36 +15,52 @@ struct AppDetailWidget: Widget
|
||||
private let kind: String = "AppDetail"
|
||||
|
||||
public var body: some WidgetConfiguration {
|
||||
let configuration = IntentConfiguration(kind: kind,
|
||||
intent: ViewAppIntent.self,
|
||||
provider: AppsTimelineProvider()) { (entry) in
|
||||
AppDetailWidgetView(entry: entry)
|
||||
}
|
||||
.supportedFamilies([.systemSmall])
|
||||
.configurationDisplayName("App Status")
|
||||
.description("View remaining days until your sideloaded apps expire. Tap the countdown timer to refresh them in the background.")
|
||||
|
||||
if #available(iOS 17, *)
|
||||
// On iOS 16+ use AppIntentConfiguration — it correctly supports
|
||||
// containerBackground and contentMarginsDisabled(), unlike the legacy
|
||||
// IntentConfiguration which breaks on iOS 17+ with the
|
||||
// "Please adopt containerBackground" error.
|
||||
if #available(iOSApplicationExtension 17, *)
|
||||
{
|
||||
return configuration
|
||||
.contentMarginsDisabled()
|
||||
return AppIntentConfiguration(
|
||||
kind: kind,
|
||||
intent: SelectAppIntent.self,
|
||||
provider: SelectAppTimelineProvider()
|
||||
) { entry in
|
||||
AppDetailWidgetView(apps: entry.apps, date: entry.date, isPlaceholder: entry.isPlaceholder)
|
||||
}
|
||||
.supportedFamilies([.systemSmall])
|
||||
.configurationDisplayName("App Status")
|
||||
.description("View remaining days until your sideloaded apps expire. Tap the countdown timer to refresh them in the background.")
|
||||
.contentMarginsDisabled()
|
||||
}
|
||||
else
|
||||
{
|
||||
return configuration
|
||||
// Legacy path for iOS 15.
|
||||
return IntentConfiguration(
|
||||
kind: kind,
|
||||
intent: ViewAppIntent.self,
|
||||
provider: AppsTimelineProvider()
|
||||
) { entry in
|
||||
AppDetailWidgetView(apps: entry.apps, date: entry.date, isPlaceholder: entry.isPlaceholder)
|
||||
}
|
||||
.supportedFamilies([.systemSmall])
|
||||
.configurationDisplayName("App Status")
|
||||
.description("View remaining days until your sideloaded apps expire. Tap the countdown timer to refresh them in the background.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private struct AppDetailWidgetView: View
|
||||
{
|
||||
var entry: AppsEntry<Intent>
|
||||
let apps: [AppSnapshot]
|
||||
let date: Date
|
||||
let isPlaceholder: Bool
|
||||
|
||||
var body: some View {
|
||||
Group {
|
||||
if let app = self.entry.apps.first
|
||||
if let app = apps.first
|
||||
{
|
||||
let daysRemaining = app.expirationDate.numberOfCalendarDays(since: self.entry.date)
|
||||
let daysRemaining = app.expirationDate.numberOfCalendarDays(since: date)
|
||||
|
||||
GeometryReader { (geometry) in
|
||||
Group {
|
||||
@@ -52,11 +68,7 @@ private struct AppDetailWidgetView: View
|
||||
VStack(alignment: .leading, spacing: 5) {
|
||||
let imageHeight = geometry.size.height * 0.4
|
||||
|
||||
Image(uiImage: app.icon ?? UIImage())
|
||||
.resizable()
|
||||
.aspectRatio(CGSize(width: 1, height: 1), contentMode: .fit)
|
||||
.frame(height: imageHeight)
|
||||
.mask(RoundedRectangle(cornerRadius: imageHeight / 5.0, style: .continuous))
|
||||
AppIconView(icon: app.icon, imageHeight: imageHeight)
|
||||
|
||||
Text(app.name.uppercased())
|
||||
.font(.system(size: 12, weight: .semibold, design: .rounded))
|
||||
@@ -65,6 +77,7 @@ private struct AppDetailWidgetView: View
|
||||
.minimumScaleFactor(0.5)
|
||||
}
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.widgetAccentableIfAvailable()
|
||||
|
||||
Spacer(minLength: 0)
|
||||
|
||||
@@ -97,7 +110,7 @@ private struct AppDetailWidgetView: View
|
||||
{
|
||||
Countdown(startDate: app.refreshedDate,
|
||||
endDate: app.expirationDate,
|
||||
currentDate: self.entry.date)
|
||||
currentDate: date)
|
||||
.font(.system(size: 20, weight: .semibold, design: .rounded))
|
||||
.foregroundColor(Color.white)
|
||||
.opacity(0.8)
|
||||
@@ -108,6 +121,7 @@ private struct AppDetailWidgetView: View
|
||||
}
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.activatesRefreshAllAppsIntent()
|
||||
.widgetAccentableIfAvailable()
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
@@ -118,7 +132,7 @@ private struct AppDetailWidgetView: View
|
||||
VStack {
|
||||
// Put conditional inside VStack, or else an empty view will be returned
|
||||
// if isPlaceholder == false, which messes up layout.
|
||||
if !entry.isPlaceholder
|
||||
if !isPlaceholder
|
||||
{
|
||||
Text("App Not Found")
|
||||
.font(.system(.body, design: .rounded))
|
||||
@@ -131,15 +145,12 @@ private struct AppDetailWidgetView: View
|
||||
}
|
||||
.widgetBackground(
|
||||
backgroundView(
|
||||
icon: entry.apps.first?.icon,
|
||||
tintColor: entry.apps.first?.tintColor
|
||||
icon: apps.first?.icon,
|
||||
tintColor: apps.first?.tintColor
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private extension AppDetailWidgetView
|
||||
{
|
||||
func backgroundView(icon: UIImage? = nil, tintColor: UIColor? = nil) -> some View
|
||||
{
|
||||
let icon = icon ?? UIImage(named: "SideStore")!
|
||||
@@ -173,12 +184,6 @@ private extension AppDetailWidgetView
|
||||
.saturation(saturation)
|
||||
.blur(radius: blurRadius, opaque: true)
|
||||
.scaleEffect(geometry.size.width / imageHeight, anchor: .center)
|
||||
// .onAppear {
|
||||
// print("Geometry size: \(geometry.size)")
|
||||
// print("Image height: \(imageHeight), Geometry width: \(geometry.size.width)")
|
||||
// print("Icon size: \(icon.size)")
|
||||
// }
|
||||
|
||||
|
||||
Color(tintColor)
|
||||
.opacity(tintOpacity)
|
||||
@@ -193,6 +198,26 @@ private extension AppDetailWidgetView
|
||||
}
|
||||
}
|
||||
|
||||
// In tinted/clear mode: luminanceToAlpha converts pixel brightness → opacity so
|
||||
// the system can overlay the accent colour. Must come BEFORE the mask so the
|
||||
// squircle corners are clipped after conversion (reverse order = corner bleed).
|
||||
// widgetAccentable() opts the result into the accent group.
|
||||
private struct AppIconView: View
|
||||
{
|
||||
let icon: UIImage?
|
||||
let imageHeight: CGFloat
|
||||
|
||||
var body: some View {
|
||||
Image(uiImage: icon ?? UIImage())
|
||||
.resizable()
|
||||
.aspectRatio(CGSize(width: 1, height: 1), contentMode: .fit)
|
||||
.frame(height: imageHeight)
|
||||
.luminanceToAlphaInAccentedMode()
|
||||
.mask(RoundedRectangle(cornerRadius: imageHeight / 5.0, style: .continuous))
|
||||
.widgetAccentableIfAvailable()
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 17, *)
|
||||
#Preview(as: .systemSmall) {
|
||||
AppDetailWidget()
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// Configuration settings file format documentation can be found at:
|
||||
// https://help.apple.com/xcode/#/dev745c5c974
|
||||
|
||||
MARKETING_VERSION = 0.6.3
|
||||
CURRENT_PROJECT_VERSION = 0603
|
||||
MARKETING_VERSION = 0.6.4
|
||||
CURRENT_PROJECT_VERSION = 0604
|
||||
|
||||
// Vars to be overwritten by `CodeSigning.xcconfig` if exists
|
||||
DEVELOPMENT_TEAM = S32Z3HMYVQ
|
||||
|
||||
4
Makefile
4
Makefile
@@ -169,7 +169,7 @@ MARKETING_VERSION ?=
|
||||
BUNDLE_ID_SUFFIX ?=
|
||||
# Common build settings for xcodebuild
|
||||
COMMON_BUILD_SETTINGS = \
|
||||
-workspace AltStore.xcworkspace \
|
||||
-project AltStore.xcodeproj \
|
||||
-scheme SideStore \
|
||||
-sdk iphoneos \
|
||||
-configuration $(BUILD_CONFIG) \
|
||||
@@ -247,7 +247,7 @@ sim-boot-check:
|
||||
|
||||
clean-build:
|
||||
@echo "Cleaning build artifacts..."
|
||||
@xcodebuild clean -workspace AltStore.xcworkspace -scheme SideStore
|
||||
@xcodebuild clean -project AltStore.xcodeproj -scheme SideStore
|
||||
|
||||
fakesign-apps:
|
||||
rm -rf SideStore.xcarchive/Products/Applications/SideStore.app/Frameworks/AltStoreCore.framework/Frameworks/
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
},
|
||||
{
|
||||
"identifier": "com.livecontainer.source",
|
||||
"sourceURL": "https://raw.githubusercontent.com/LiveContainer/LiveContainer/refs/heads/main/apps.json"
|
||||
"sourceURL": "https://github.com/LiveContainer/LiveContainer/releases/download/1.0/apps.json"
|
||||
},
|
||||
{
|
||||
"identifier": "com.aoshuang.manicemu",
|
||||
@@ -95,7 +95,7 @@
|
||||
},
|
||||
{
|
||||
"identifier": "com.livecontainer.source",
|
||||
"sourceURL": "https://raw.githubusercontent.com/LiveContainer/LiveContainer/refs/heads/main/apps.json"
|
||||
"sourceURL": "https://github.com/LiveContainer/LiveContainer/releases/download/1.0/apps.json"
|
||||
},
|
||||
{
|
||||
"identifier": "com.aoshuang.manicemu",
|
||||
|
||||
Reference in New Issue
Block a user