mirror of
https://github.com/SideStore/SideStore.git
synced 2026-02-22 13:13:24 +01:00
[skip ci] Merge pull request #419 from Nythepegasus/chore/up-fixes
[Chore] Pull upstream changes from AltStore
This commit is contained in:
@@ -218,7 +218,7 @@ final class AppViewController: UIViewController
|
|||||||
self._shouldResetLayout = false
|
self._shouldResetLayout = false
|
||||||
}
|
}
|
||||||
|
|
||||||
let statusBarHeight = UIApplication.shared.statusBarFrame.height
|
let statusBarHeight = self.view.window?.windowScene?.statusBarManager?.statusBarFrame.height ?? 0
|
||||||
let cornerRadius = self.contentViewControllerShadowView.layer.cornerRadius
|
let cornerRadius = self.contentViewControllerShadowView.layer.cornerRadius
|
||||||
|
|
||||||
let inset = 12 as CGFloat
|
let inset = 12 as CGFloat
|
||||||
@@ -323,7 +323,7 @@ final class AppViewController: UIViewController
|
|||||||
|
|
||||||
self.backButtonContainerView.layer.cornerRadius = self.backButtonContainerView.bounds.midY
|
self.backButtonContainerView.layer.cornerRadius = self.backButtonContainerView.bounds.midY
|
||||||
|
|
||||||
self.scrollView.scrollIndicatorInsets.top = statusBarHeight
|
self.scrollView.verticalScrollIndicatorInsets.top = statusBarHeight
|
||||||
|
|
||||||
// Adjust content offset + size.
|
// Adjust content offset + size.
|
||||||
let contentOffset = self.scrollView.contentOffset
|
let contentOffset = self.scrollView.contentOffset
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ final class CollapsingTextView: UITextView
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var lineSpacing: CGFloat = 2 {
|
var lineSpacing: Double = 2 {
|
||||||
didSet {
|
didSet {
|
||||||
self.setNeedsLayout()
|
self.setNeedsLayout()
|
||||||
}
|
}
|
||||||
@@ -34,7 +34,19 @@ final class CollapsingTextView: UITextView
|
|||||||
{
|
{
|
||||||
super.awakeFromNib()
|
super.awakeFromNib()
|
||||||
|
|
||||||
|
self.initialize()
|
||||||
|
}
|
||||||
|
|
||||||
|
private func initialize()
|
||||||
|
{
|
||||||
|
if #available(iOS 16, *)
|
||||||
|
{
|
||||||
|
self.updateText()
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
self.layoutManager.delegate = self
|
self.layoutManager.delegate = self
|
||||||
|
}
|
||||||
|
|
||||||
self.textContainerInset = .zero
|
self.textContainerInset = .zero
|
||||||
self.textContainer.lineFragmentPadding = 0
|
self.textContainer.lineFragmentPadding = 0
|
||||||
@@ -108,6 +120,25 @@ private extension CollapsingTextView
|
|||||||
{
|
{
|
||||||
self.isCollapsed.toggle()
|
self.isCollapsed.toggle()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@available(iOS 16, *)
|
||||||
|
func updateText()
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
let style = NSMutableParagraphStyle()
|
||||||
|
style.lineSpacing = self.lineSpacing
|
||||||
|
|
||||||
|
var attributedText = try AttributedString(self.attributedText, including: \.uiKit)
|
||||||
|
attributedText[AttributeScopes.UIKitAttributes.ParagraphStyleAttribute.self] = style
|
||||||
|
|
||||||
|
self.attributedText = NSAttributedString(attributedText)
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
print("[ALTLog] Failed to update CollapsingTextView line spacing:", error)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension CollapsingTextView: NSLayoutManagerDelegate
|
extension CollapsingTextView: NSLayoutManagerDelegate
|
||||||
|
|||||||
@@ -8,6 +8,12 @@
|
|||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
|
extension PillButton
|
||||||
|
{
|
||||||
|
static let minimumSize = CGSize(width: 77, height: 31)
|
||||||
|
static let contentInsets = NSDirectionalEdgeInsets(top: 7, leading: 13, bottom: 7, trailing: 13)
|
||||||
|
}
|
||||||
|
|
||||||
final class PillButton: UIButton
|
final class PillButton: UIButton
|
||||||
{
|
{
|
||||||
override var accessibilityValue: String? {
|
override var accessibilityValue: String? {
|
||||||
@@ -70,9 +76,7 @@ final class PillButton: UIButton
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
override var intrinsicContentSize: CGSize {
|
override var intrinsicContentSize: CGSize {
|
||||||
var size = super.intrinsicContentSize
|
let size = self.sizeThatFits(CGSize(width: Double.infinity, height: .infinity))
|
||||||
size.width += 26
|
|
||||||
size.height += 3
|
|
||||||
return size
|
return size
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,6 +92,8 @@ final class PillButton: UIButton
|
|||||||
self.layer.masksToBounds = true
|
self.layer.masksToBounds = true
|
||||||
self.accessibilityTraits.formUnion([.updatesFrequently, .button])
|
self.accessibilityTraits.formUnion([.updatesFrequently, .button])
|
||||||
|
|
||||||
|
self.contentEdgeInsets = UIEdgeInsets(top: Self.contentInsets.top, left: Self.contentInsets.leading, bottom: Self.contentInsets.bottom, right: Self.contentInsets.trailing)
|
||||||
|
|
||||||
self.activityIndicatorView.style = .medium
|
self.activityIndicatorView.style = .medium
|
||||||
self.activityIndicatorView.isUserInteractionEnabled = false
|
self.activityIndicatorView.isUserInteractionEnabled = false
|
||||||
|
|
||||||
@@ -119,6 +125,15 @@ final class PillButton: UIButton
|
|||||||
|
|
||||||
self.update()
|
self.update()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override func sizeThatFits(_ size: CGSize) -> CGSize
|
||||||
|
{
|
||||||
|
var size = super.sizeThatFits(size)
|
||||||
|
size.width = max(size.width, PillButton.minimumSize.width)
|
||||||
|
size.height = max(size.height, PillButton.minimumSize.height)
|
||||||
|
|
||||||
|
return size
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private extension PillButton
|
private extension PillButton
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import UIKit
|
|||||||
import MobileCoreServices
|
import MobileCoreServices
|
||||||
import Intents
|
import Intents
|
||||||
import Combine
|
import Combine
|
||||||
|
import UniformTypeIdentifiers
|
||||||
|
|
||||||
import AltStoreCore
|
import AltStoreCore
|
||||||
import AltSign
|
import AltSign
|
||||||
@@ -701,18 +702,9 @@ private extension MyAppsViewController
|
|||||||
|
|
||||||
@IBAction func sideloadApp(_ sender: UIBarButtonItem)
|
@IBAction func sideloadApp(_ sender: UIBarButtonItem)
|
||||||
{
|
{
|
||||||
let supportedTypes: [String]
|
let supportedTypes = UTType.types(tag: "ipa", tagClass: .filenameExtension, conformingTo: nil)
|
||||||
|
|
||||||
if let types = UTTypeCreateAllIdentifiersForTag(kUTTagClassFilenameExtension, "ipa" as CFString, nil)?.takeRetainedValue()
|
let documentPickerViewController = UIDocumentPickerViewController(forOpeningContentTypes: supportedTypes, asCopy: true)
|
||||||
{
|
|
||||||
supportedTypes = (types as NSArray).map { $0 as! String }
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
supportedTypes = ["com.apple.itunes.ipa"] // Declared by the system.
|
|
||||||
}
|
|
||||||
|
|
||||||
let documentPickerViewController = UIDocumentPickerViewController(documentTypes: supportedTypes, in: .import)
|
|
||||||
documentPickerViewController.delegate = self
|
documentPickerViewController.delegate = self
|
||||||
self.present(documentPickerViewController, animated: true, completion: nil)
|
self.present(documentPickerViewController, animated: true, completion: nil)
|
||||||
}
|
}
|
||||||
@@ -1246,8 +1238,11 @@ private extension MyAppsViewController
|
|||||||
{
|
{
|
||||||
guard let backupURL = FileManager.default.backupDirectoryURL(for: installedApp) else { return }
|
guard let backupURL = FileManager.default.backupDirectoryURL(for: installedApp) else { return }
|
||||||
|
|
||||||
let documentPicker = UIDocumentPickerViewController(url: backupURL, in: .exportToService)
|
let documentPicker = UIDocumentPickerViewController(forExporting: [backupURL], asCopy: true)
|
||||||
documentPicker.delegate = self
|
|
||||||
|
// Don't set delegate to avoid conflicting with import callbacks.
|
||||||
|
// documentPicker.delegate = self
|
||||||
|
|
||||||
self.present(documentPicker, animated: true, completion: nil)
|
self.present(documentPicker, animated: true, completion: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2050,16 +2045,9 @@ extension MyAppsViewController: UIDocumentPickerDelegate
|
|||||||
{
|
{
|
||||||
guard let fileURL = urls.first else { return }
|
guard let fileURL = urls.first else { return }
|
||||||
|
|
||||||
switch controller.documentPickerMode
|
|
||||||
{
|
|
||||||
case .import, .open:
|
|
||||||
self.sideloadApp(at: fileURL) { (result) in
|
self.sideloadApp(at: fileURL) { (result) in
|
||||||
print("Sideloaded app at \(fileURL) with result:", result)
|
print("Sideloaded app at \(fileURL) with result:", result)
|
||||||
}
|
}
|
||||||
|
|
||||||
case .exportToService, .moveToService: break
|
|
||||||
@unknown default: break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -426,6 +426,10 @@ extension NewsViewController: UICollectionViewDelegateFlowLayout
|
|||||||
return previousSize
|
return previousSize
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Take layout margins into account.
|
||||||
|
self.prototypeCell.layoutMargins.left = self.view.layoutMargins.left
|
||||||
|
self.prototypeCell.layoutMargins.right = self.view.layoutMargins.right
|
||||||
|
|
||||||
let widthConstraint = self.prototypeCell.contentView.widthAnchor.constraint(equalToConstant: collectionView.bounds.width)
|
let widthConstraint = self.prototypeCell.contentView.widthAnchor.constraint(equalToConstant: collectionView.bounds.width)
|
||||||
NSLayoutConstraint.activate([widthConstraint])
|
NSLayoutConstraint.activate([widthConstraint])
|
||||||
defer { NSLayoutConstraint.deactivate([widthConstraint]) }
|
defer { NSLayoutConstraint.deactivate([widthConstraint]) }
|
||||||
|
|||||||
@@ -29,6 +29,9 @@ class BackupAppOperation: ResultOperation<Void>
|
|||||||
private var appName: String?
|
private var appName: String?
|
||||||
private var timeoutTimer: Timer?
|
private var timeoutTimer: Timer?
|
||||||
|
|
||||||
|
private weak var applicationWillReturnObserver: NSObjectProtocol?
|
||||||
|
private weak var backupResponseObserver: NSObjectProtocol?
|
||||||
|
|
||||||
init(action: Action, context: InstallAppOperationContext)
|
init(action: Action, context: InstallAppOperationContext)
|
||||||
{
|
{
|
||||||
self.action = action
|
self.action = action
|
||||||
@@ -153,8 +156,11 @@ private extension BackupAppOperation
|
|||||||
{
|
{
|
||||||
func registerObservers()
|
func registerObservers()
|
||||||
{
|
{
|
||||||
var applicationWillReturnObserver: NSObjectProtocol!
|
self.applicationWillReturnObserver = NotificationCenter.default.addObserver(forName: UIApplication.willEnterForegroundNotification, object: nil, queue: .main) { [weak self] (notification) in
|
||||||
applicationWillReturnObserver = NotificationCenter.default.addObserver(forName: UIApplication.willEnterForegroundNotification, object: nil, queue: .main) { [weak self] (notification) in
|
defer {
|
||||||
|
self?.applicationWillReturnObserver.map { NotificationCenter.default.removeObserver($0) }
|
||||||
|
}
|
||||||
|
|
||||||
guard let self = self, !self.isFinished else { return }
|
guard let self = self, !self.isFinished else { return }
|
||||||
|
|
||||||
self.timeoutTimer = Timer.scheduledTimer(withTimeInterval: 5, repeats: false) { [weak self] (timer) in
|
self.timeoutTimer = Timer.scheduledTimer(withTimeInterval: 5, repeats: false) { [weak self] (timer) in
|
||||||
@@ -166,18 +172,17 @@ private extension BackupAppOperation
|
|||||||
self.finish(.failure(OperationError.timedOut))
|
self.finish(.failure(OperationError.timedOut))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NotificationCenter.default.removeObserver(applicationWillReturnObserver!)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var backupResponseObserver: NSObjectProtocol!
|
self.backupResponseObserver = NotificationCenter.default.addObserver(forName: AppDelegate.appBackupDidFinish, object: nil, queue: nil) { [weak self] (notification) in
|
||||||
backupResponseObserver = NotificationCenter.default.addObserver(forName: AppDelegate.appBackupDidFinish, object: nil, queue: nil) { [weak self] (notification) in
|
defer {
|
||||||
|
self?.backupResponseObserver.map { NotificationCenter.default.removeObserver($0) }
|
||||||
|
}
|
||||||
|
|
||||||
self?.timeoutTimer?.invalidate()
|
self?.timeoutTimer?.invalidate()
|
||||||
|
|
||||||
let result = notification.userInfo?[AppDelegate.appBackupResultKey] as? Result<Void, Error> ?? .failure(OperationError.unknownResult)
|
let result = notification.userInfo?[AppDelegate.appBackupResultKey] as? Result<Void, Error> ?? .failure(OperationError.unknownResult)
|
||||||
self?.finish(result)
|
self?.finish(result)
|
||||||
|
|
||||||
NotificationCenter.default.removeObserver(backupResponseObserver!)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user