mirror of
https://github.com/SideStore/SideStore.git
synced 2026-02-17 18:53:40 +01:00
Adds altstore://source?url=[link] deep link to add sources
This commit is contained in:
@@ -54,11 +54,13 @@ extension AppDelegate
|
|||||||
{
|
{
|
||||||
static let openPatreonSettingsDeepLinkNotification = Notification.Name("com.rileytestut.AltStore.OpenPatreonSettingsDeepLinkNotification")
|
static let openPatreonSettingsDeepLinkNotification = Notification.Name("com.rileytestut.AltStore.OpenPatreonSettingsDeepLinkNotification")
|
||||||
static let importAppDeepLinkNotification = Notification.Name("com.rileytestut.AltStore.ImportAppDeepLinkNotification")
|
static let importAppDeepLinkNotification = Notification.Name("com.rileytestut.AltStore.ImportAppDeepLinkNotification")
|
||||||
|
static let addSourceDeepLinkNotification = Notification.Name("com.rileytestut.AltStore.AddSourceDeepLinkNotification")
|
||||||
|
|
||||||
static let appBackupDidFinish = Notification.Name("com.rileytestut.AltStore.AppBackupDidFinish")
|
static let appBackupDidFinish = Notification.Name("com.rileytestut.AltStore.AppBackupDidFinish")
|
||||||
|
|
||||||
static let importAppDeepLinkURLKey = "fileURL"
|
static let importAppDeepLinkURLKey = "fileURL"
|
||||||
static let appBackupResultKey = "result"
|
static let appBackupResultKey = "result"
|
||||||
|
static let addSourceDeepLinkURLKey = "sourceURL"
|
||||||
}
|
}
|
||||||
|
|
||||||
@UIApplicationMain
|
@UIApplicationMain
|
||||||
@@ -183,6 +185,16 @@ private extension AppDelegate
|
|||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
|
||||||
|
case "source":
|
||||||
|
let queryItems = components.queryItems?.reduce(into: [String: String]()) { $0[$1.name.lowercased()] = $1.value } ?? [:]
|
||||||
|
guard let sourceURLString = queryItems["url"], let sourceURL = URL(string: sourceURLString) else { return false }
|
||||||
|
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
NotificationCenter.default.post(name: AppDelegate.addSourceDeepLinkNotification, object: nil, userInfo: [AppDelegate.addSourceDeepLinkURLKey: sourceURL])
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
|
||||||
default: return false
|
default: return false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,13 @@ import Roxas
|
|||||||
|
|
||||||
class SourcesViewController: UICollectionViewController
|
class SourcesViewController: UICollectionViewController
|
||||||
{
|
{
|
||||||
|
var deepLinkSourceURL: URL? {
|
||||||
|
didSet {
|
||||||
|
guard let sourceURL = self.deepLinkSourceURL else { return }
|
||||||
|
self.addSource(url: sourceURL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private lazy var dataSource = self.makeDataSource()
|
private lazy var dataSource = self.makeDataSource()
|
||||||
|
|
||||||
override func viewDidLoad()
|
override func viewDidLoad()
|
||||||
@@ -21,6 +28,27 @@ class SourcesViewController: UICollectionViewController
|
|||||||
|
|
||||||
self.collectionView.dataSource = self.dataSource
|
self.collectionView.dataSource = self.dataSource
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override func viewWillAppear(_ animated: Bool)
|
||||||
|
{
|
||||||
|
super.viewWillAppear(animated)
|
||||||
|
|
||||||
|
if self.deepLinkSourceURL != nil
|
||||||
|
{
|
||||||
|
self.navigationItem.leftBarButtonItem?.isIndicatingActivity = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func viewDidAppear(_ animated: Bool)
|
||||||
|
{
|
||||||
|
super.viewDidAppear(animated)
|
||||||
|
|
||||||
|
if let sourceURL = self.deepLinkSourceURL
|
||||||
|
{
|
||||||
|
self.addSource(url: sourceURL)
|
||||||
|
self.deepLinkSourceURL = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private extension SourcesViewController
|
private extension SourcesViewController
|
||||||
@@ -67,26 +95,6 @@ private extension SourcesViewController
|
|||||||
{
|
{
|
||||||
@IBAction func addSource()
|
@IBAction func addSource()
|
||||||
{
|
{
|
||||||
func addSource(url: URL)
|
|
||||||
{
|
|
||||||
AppManager.shared.fetchSource(sourceURL: url) { (result) in
|
|
||||||
do
|
|
||||||
{
|
|
||||||
let source = try result.get()
|
|
||||||
try source.managedObjectContext?.save()
|
|
||||||
}
|
|
||||||
catch let error as NSError
|
|
||||||
{
|
|
||||||
let error = error.withLocalizedFailure(NSLocalizedString("Could not add source.", comment: ""))
|
|
||||||
|
|
||||||
DispatchQueue.main.async {
|
|
||||||
let toastView = ToastView(error: error)
|
|
||||||
toastView.show(in: self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let alertController = UIAlertController(title: NSLocalizedString("Add Source", comment: ""), message: nil, preferredStyle: .alert)
|
let alertController = UIAlertController(title: NSLocalizedString("Add Source", comment: ""), message: nil, preferredStyle: .alert)
|
||||||
alertController.addTextField { (textField) in
|
alertController.addTextField { (textField) in
|
||||||
textField.placeholder = "https://apps.altstore.io"
|
textField.placeholder = "https://apps.altstore.io"
|
||||||
@@ -95,14 +103,77 @@ private extension SourcesViewController
|
|||||||
alertController.addAction(.cancel)
|
alertController.addAction(.cancel)
|
||||||
alertController.addAction(UIAlertAction(title: NSLocalizedString("Add", comment: ""), style: .default) { (action) in
|
alertController.addAction(UIAlertAction(title: NSLocalizedString("Add", comment: ""), style: .default) { (action) in
|
||||||
guard let text = alertController.textFields![0].text, let sourceURL = URL(string: text) else { return }
|
guard let text = alertController.textFields![0].text, let sourceURL = URL(string: text) else { return }
|
||||||
addSource(url: sourceURL)
|
self.addSource(url: sourceURL)
|
||||||
})
|
})
|
||||||
|
|
||||||
self.present(alertController, animated: true, completion: nil)
|
self.present(alertController, animated: true, completion: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func addSource(url: URL)
|
||||||
|
{
|
||||||
|
guard self.view.window != nil else { return }
|
||||||
|
|
||||||
|
self.navigationItem.leftBarButtonItem?.isIndicatingActivity = true
|
||||||
|
|
||||||
|
func finish(error: Error?)
|
||||||
|
{
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
if let error = error
|
||||||
|
{
|
||||||
|
self.present(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.navigationItem.leftBarButtonItem?.isIndicatingActivity = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AppManager.shared.fetchSource(sourceURL: url) { (result) in
|
||||||
|
do
|
||||||
|
{
|
||||||
|
let source = try result.get()
|
||||||
|
let sourceName = source.name
|
||||||
|
let managedObjectContext = source.managedObjectContext
|
||||||
|
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
let alertController = UIAlertController(title: String(format: NSLocalizedString("Would you like to add the source “%@”?", comment: ""), sourceName),
|
||||||
|
message: NSLocalizedString("Sources control what apps appear in AltStore. Make sure to only add sources that you trust.", comment: ""), preferredStyle: .alert)
|
||||||
|
alertController.addAction(UIAlertAction(title: UIAlertAction.cancel.title, style: UIAlertAction.cancel.style) { _ in
|
||||||
|
finish(error: nil)
|
||||||
|
})
|
||||||
|
alertController.addAction(UIAlertAction(title: UIAlertAction.ok.title, style: UIAlertAction.ok.style) { _ in
|
||||||
|
managedObjectContext?.perform {
|
||||||
|
do
|
||||||
|
{
|
||||||
|
try managedObjectContext?.save()
|
||||||
|
finish(error: nil)
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
finish(error: error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
self.present(alertController, animated: true, completion: nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
finish(error: error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func present(_ error: Error)
|
func present(_ error: Error)
|
||||||
{
|
{
|
||||||
|
if let transitionCoordinator = self.transitionCoordinator
|
||||||
|
{
|
||||||
|
transitionCoordinator.animate(alongsideTransition: nil) { _ in
|
||||||
|
self.present(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
let nsError = error as NSError
|
let nsError = error as NSError
|
||||||
let message = nsError.userInfo[NSDebugDescriptionErrorKey] as? String ?? nsError.localizedRecoverySuggestion
|
let message = nsError.userInfo[NSDebugDescriptionErrorKey] as? String ?? nsError.localizedRecoverySuggestion
|
||||||
|
|
||||||
|
|||||||
@@ -21,12 +21,52 @@ extension TabBarController
|
|||||||
|
|
||||||
class TabBarController: UITabBarController
|
class TabBarController: UITabBarController
|
||||||
{
|
{
|
||||||
|
private var initialSegue: (identifier: String, sender: Any?)?
|
||||||
|
|
||||||
|
private var _viewDidAppear = false
|
||||||
|
|
||||||
required init?(coder aDecoder: NSCoder)
|
required init?(coder aDecoder: NSCoder)
|
||||||
{
|
{
|
||||||
super.init(coder: aDecoder)
|
super.init(coder: aDecoder)
|
||||||
|
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(TabBarController.openPatreonSettings(_:)), name: AppDelegate.openPatreonSettingsDeepLinkNotification, object: nil)
|
NotificationCenter.default.addObserver(self, selector: #selector(TabBarController.openPatreonSettings(_:)), name: AppDelegate.openPatreonSettingsDeepLinkNotification, object: nil)
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(TabBarController.importApp(_:)), name: AppDelegate.importAppDeepLinkNotification, object: nil)
|
NotificationCenter.default.addObserver(self, selector: #selector(TabBarController.importApp(_:)), name: AppDelegate.importAppDeepLinkNotification, object: nil)
|
||||||
|
NotificationCenter.default.addObserver(self, selector: #selector(TabBarController.presentSources(_:)), name: AppDelegate.addSourceDeepLinkNotification, object: nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
override func viewDidAppear(_ animated: Bool)
|
||||||
|
{
|
||||||
|
super.viewDidAppear(animated)
|
||||||
|
|
||||||
|
_viewDidAppear = true
|
||||||
|
|
||||||
|
if let (identifier, sender) = self.initialSegue
|
||||||
|
{
|
||||||
|
self.initialSegue = nil
|
||||||
|
self.performSegue(withIdentifier: identifier, sender: sender)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
|
||||||
|
{
|
||||||
|
guard segue.identifier == "presentSources",
|
||||||
|
let notification = sender as? Notification,
|
||||||
|
let sourceURL = notification.userInfo?[AppDelegate.addSourceDeepLinkURLKey] as? URL
|
||||||
|
else { return }
|
||||||
|
|
||||||
|
let navigationController = segue.destination as! UINavigationController
|
||||||
|
let sourcesViewController = navigationController.viewControllers.first as! SourcesViewController
|
||||||
|
sourcesViewController.deepLinkSourceURL = sourceURL
|
||||||
|
}
|
||||||
|
|
||||||
|
override func performSegue(withIdentifier identifier: String, sender: Any?)
|
||||||
|
{
|
||||||
|
guard _viewDidAppear else {
|
||||||
|
self.initialSegue = (identifier, sender)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
super.performSegue(withIdentifier: identifier, sender: sender)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,6 +74,31 @@ extension TabBarController
|
|||||||
{
|
{
|
||||||
@objc func presentSources(_ sender: Any)
|
@objc func presentSources(_ sender: Any)
|
||||||
{
|
{
|
||||||
|
if let presentedViewController = self.presentedViewController
|
||||||
|
{
|
||||||
|
if let navigationController = presentedViewController as? UINavigationController,
|
||||||
|
let sourcesViewController = navigationController.viewControllers.first as? SourcesViewController
|
||||||
|
{
|
||||||
|
if let notification = (sender as? Notification),
|
||||||
|
let sourceURL = notification.userInfo?[AppDelegate.addSourceDeepLinkURLKey] as? URL
|
||||||
|
{
|
||||||
|
sourcesViewController.deepLinkSourceURL = sourceURL
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Don't dismiss SourcesViewController if it's already presented.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
presentedViewController.dismiss(animated: true) {
|
||||||
|
self.presentSources(sender)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
self.performSegue(withIdentifier: "presentSources", sender: sender)
|
self.performSegue(withIdentifier: "presentSources", sender: sender)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user