2019-06-06 14:46:23 -07:00
//
2019-09-05 11:59:10 -07:00
// S e t t i n g s V i e w C o n t r o l l e r . s w i f t
2019-06-06 14:46:23 -07:00
// A l t S t o r e
//
2019-09-05 11:59:10 -07:00
// C r e a t e d b y R i l e y T e s t u t o n 8 / 3 1 / 1 9 .
2019-06-06 14:46:23 -07:00
// C o p y r i g h t © 2 0 1 9 R i l e y T e s t u t . A l l r i g h t s r e s e r v e d .
//
import UIKit
2019-09-07 15:34:07 -07:00
import SafariServices
2019-09-12 13:23:21 -07:00
import MessageUI
2020-09-08 16:44:36 -07:00
import Intents
import IntentsUI
2019-06-06 14:46:23 -07:00
2020-09-03 16:39:08 -07:00
import AltStoreCore
2019-09-05 11:59:10 -07:00
extension SettingsViewController
{
fileprivate enum Section : Int , CaseIterable
{
case signIn
case account
case patreon
2020-09-08 16:44:36 -07:00
case appRefresh
2019-09-07 15:34:07 -07:00
case instructions
case credits
2019-09-05 11:59:10 -07:00
case debug
}
2019-09-07 15:34:07 -07:00
2020-09-08 16:44:36 -07:00
fileprivate enum AppRefreshRow : Int , CaseIterable
{
case backgroundRefresh
2023-11-28 00:44:47 +09:00
case noIdleTimeout
2020-09-08 16:44:36 -07:00
@ available ( iOS 14 , * )
case addToSiri
static var allCases : [ AppRefreshRow ] {
2023-11-28 00:44:47 +09:00
guard #available ( iOS 14 , * ) else { return [ . backgroundRefresh , . noIdleTimeout ] }
return [ . backgroundRefresh , . noIdleTimeout , . addToSiri ]
2020-09-08 16:44:36 -07:00
}
}
2019-09-07 15:34:07 -07:00
fileprivate enum CreditsRow : Int , CaseIterable
{
case developer
2022-04-13 20:06:57 -07:00
case operations
2019-09-07 15:34:07 -07:00
case designer
case softwareLicenses
}
2019-09-12 13:23:21 -07:00
fileprivate enum DebugRow : Int , CaseIterable
{
case sendFeedback
case refreshAttempts
2022-09-09 17:44:15 -05:00
case errorLog
2024-06-17 09:43:25 +10:00
case refreshSideJITServer
2023-11-25 15:11:22 +09:00
case clearCache
2023-01-09 15:15:31 +08:00
case resetPairingFile
2023-05-18 01:30:18 -07:00
case resetAdiPb
2023-01-01 12:20:08 -05:00
case advancedSettings
2023-08-30 07:24:27 +00:00
2019-09-12 13:23:21 -07:00
}
2019-09-05 11:59:10 -07:00
}
2019-06-06 14:46:23 -07:00
2023-01-04 09:52:12 -05:00
final class SettingsViewController : UITableViewController
2019-06-06 14:46:23 -07:00
{
2019-09-05 11:59:10 -07:00
private var activeTeam : Team ?
2019-06-06 14:46:23 -07:00
2019-09-05 11:59:10 -07:00
private var prototypeHeaderFooterView : SettingsHeaderFooterView !
2019-06-06 14:46:23 -07:00
2019-09-19 22:20:10 -07:00
private var debugGestureCounter = 0
private weak var debugGestureTimer : Timer ?
2019-09-05 11:59:10 -07:00
@IBOutlet private var accountNameLabel : UILabel !
@IBOutlet private var accountEmailLabel : UILabel !
@IBOutlet private var accountTypeLabel : UILabel !
2019-06-06 14:46:23 -07:00
2019-09-05 11:59:10 -07:00
@IBOutlet private var backgroundRefreshSwitch : UISwitch !
2023-11-28 00:44:47 +09:00
@IBOutlet private var noIdleTimeoutSwitch : UISwitch !
2019-06-06 14:46:23 -07:00
2024-06-17 09:43:25 +10:00
@IBOutlet private var refreshSideJITServer : UILabel !
2020-01-13 13:32:55 -08:00
@IBOutlet private var versionLabel : UILabel !
2019-10-24 13:04:30 -07:00
override var preferredStatusBarStyle : UIStatusBarStyle {
return . lightContent
}
2019-09-19 14:43:26 -07:00
required init ? ( coder aDecoder : NSCoder )
{
super . init ( coder : aDecoder )
NotificationCenter . default . addObserver ( self , selector : #selector ( SettingsViewController . openPatreonSettings ( _ : ) ) , name : AppDelegate . openPatreonSettingsDeepLinkNotification , object : nil )
}
2019-06-06 14:46:23 -07:00
override func viewDidLoad ( )
{
super . viewDidLoad ( )
2019-09-05 11:59:10 -07:00
let nib = UINib ( nibName : " SettingsHeaderFooterView " , bundle : nil )
self . prototypeHeaderFooterView = nib . instantiate ( withOwner : nil , options : nil ) [ 0 ] as ? SettingsHeaderFooterView
self . tableView . register ( nib , forHeaderFooterViewReuseIdentifier : " HeaderFooterView " )
2019-06-06 14:46:23 -07:00
2019-09-19 22:20:10 -07:00
let debugModeGestureRecognizer = UISwipeGestureRecognizer ( target : self , action : #selector ( SettingsViewController . handleDebugModeGesture ( _ : ) ) )
debugModeGestureRecognizer . delegate = self
debugModeGestureRecognizer . direction = . up
debugModeGestureRecognizer . numberOfTouchesRequired = 3
self . tableView . addGestureRecognizer ( debugModeGestureRecognizer )
2024-04-23 03:20:40 -04:00
print ( Bundle . main . infoDictionary )
var versionString : String = " "
2020-01-13 13:32:55 -08:00
if let version = Bundle . main . object ( forInfoDictionaryKey : " CFBundleShortVersionString " ) as ? String
{
2024-04-23 03:20:40 -04:00
versionString += " SideStore \( version ) "
if let xcode = Bundle . main . object ( forInfoDictionaryKey : " DTXcode " ) as ? String {
print ( xcode )
versionString += " - Xcode \( xcode ) - "
if let build = Bundle . main . object ( forInfoDictionaryKey : " DTXcodeBuild " ) as ? String {
print ( build )
versionString += " \( build ) "
}
}
if let pairing = Bundle . main . object ( forInfoDictionaryKey : " ALTPairingFile " ) as ? String {
let pair_test = pairing = = " <insert pairing file here> "
if ! pair_test {
versionString += " - \( ! pair_test ) "
}
}
2020-01-13 13:32:55 -08:00
}
else
{
2024-04-23 03:20:40 -04:00
versionString += " SideStore \t "
2020-01-13 13:32:55 -08:00
}
2024-04-23 03:20:40 -04:00
self . versionLabel . text = NSLocalizedString ( versionString , comment : " SideStore Version " )
self . tableView . contentInset . bottom = 40
2020-01-24 11:34:26 -08:00
2019-06-06 14:46:23 -07:00
self . update ( )
2021-10-06 12:16:47 -07:00
if #available ( iOS 15 , * ) , let appearance = self . tabBarController ? . tabBar . standardAppearance
{
2021-10-11 13:49:11 -07:00
appearance . stackedLayoutAppearance . normal . badgeBackgroundColor = . altPrimary
2021-10-06 12:16:47 -07:00
self . navigationController ? . tabBarItem . scrollEdgeAppearance = appearance
}
2019-06-06 14:46:23 -07:00
}
2019-09-07 15:34:07 -07:00
override func viewWillAppear ( _ animated : Bool )
{
super . viewWillAppear ( animated )
self . update ( )
}
2019-06-06 14:46:23 -07:00
}
2019-07-31 11:46:26 -07:00
private extension SettingsViewController
2019-06-06 14:46:23 -07:00
{
func update ( )
{
if let team = DatabaseManager . shared . activeTeam ( )
{
2019-09-05 11:59:10 -07:00
self . accountNameLabel . text = team . name
2019-06-06 14:46:23 -07:00
self . accountEmailLabel . text = team . account . appleID
2019-09-05 11:59:10 -07:00
self . accountTypeLabel . text = team . type . localizedDescription
2019-06-06 14:46:23 -07:00
2019-09-05 11:59:10 -07:00
self . activeTeam = team
2019-06-06 14:46:23 -07:00
}
else
{
2019-09-05 11:59:10 -07:00
self . activeTeam = nil
2019-06-06 14:46:23 -07:00
}
2019-09-05 11:59:10 -07:00
self . backgroundRefreshSwitch . isOn = UserDefaults . standard . isBackgroundRefreshEnabled
2023-11-28 12:00:20 +09:00
self . noIdleTimeoutSwitch . isOn = UserDefaults . standard . isIdleTimeoutDisableEnabled
2019-09-05 11:59:10 -07:00
2019-06-06 14:46:23 -07:00
if self . isViewLoaded
{
self . tableView . reloadData ( )
}
}
2019-09-05 11:59:10 -07:00
func prepare ( _ settingsHeaderFooterView : SettingsHeaderFooterView , for section : Section , isHeader : Bool )
{
settingsHeaderFooterView . primaryLabel . isHidden = ! isHeader
settingsHeaderFooterView . secondaryLabel . isHidden = isHeader
settingsHeaderFooterView . button . isHidden = true
settingsHeaderFooterView . layoutMargins . bottom = isHeader ? 0 : 8
switch section
{
case . signIn :
if isHeader
{
settingsHeaderFooterView . primaryLabel . text = NSLocalizedString ( " ACCOUNT " , comment : " " )
}
else
{
2022-09-14 04:45:33 -07:00
settingsHeaderFooterView . secondaryLabel . text = NSLocalizedString ( " Sign in with your Apple ID to download apps from SideStore. " , comment : " " )
2019-09-05 11:59:10 -07:00
}
case . patreon :
2019-09-25 12:43:32 -07:00
if isHeader
{
2023-06-13 23:14:01 -07:00
settingsHeaderFooterView . primaryLabel . text = NSLocalizedString ( " SUPPORT US " , comment : " " )
2019-09-25 12:43:32 -07:00
}
2022-09-14 04:27:26 -07:00
else
{
2023-06-13 23:14:01 -07:00
settingsHeaderFooterView . secondaryLabel . text = NSLocalizedString ( " Support the SideStore Team by following our socials or becoming a patron! " , comment : " " )
2022-09-14 04:27:26 -07:00
}
2022-09-14 04:45:33 -07:00
2019-09-05 11:59:10 -07:00
case . account :
settingsHeaderFooterView . primaryLabel . text = NSLocalizedString ( " ACCOUNT " , comment : " " )
settingsHeaderFooterView . button . setTitle ( NSLocalizedString ( " SIGN OUT " , comment : " " ) , for : . normal )
settingsHeaderFooterView . button . addTarget ( self , action : #selector ( SettingsViewController . signOut ( _ : ) ) , for : . primaryActionTriggered )
settingsHeaderFooterView . button . isHidden = false
2020-09-08 16:44:36 -07:00
case . appRefresh :
if isHeader
{
settingsHeaderFooterView . primaryLabel . text = NSLocalizedString ( " REFRESHING APPS " , comment : " " )
}
else
{
2023-11-27 23:18:36 -08:00
settingsHeaderFooterView . secondaryLabel . text = NSLocalizedString ( " Enable Background Refresh to automatically refresh apps in the background when connected to Wi-Fi. \n \n Disable the Idle Timeout toggle to allow SideStore to not let your device go to sleep during a refresh or install of any apps. " , comment : " " )
2020-09-08 16:44:36 -07:00
}
2019-09-05 11:59:10 -07:00
2019-09-07 15:34:07 -07:00
case . instructions :
break
case . credits :
settingsHeaderFooterView . primaryLabel . text = NSLocalizedString ( " CREDITS " , comment : " " )
2019-09-05 11:59:10 -07:00
case . debug :
settingsHeaderFooterView . primaryLabel . text = NSLocalizedString ( " DEBUG " , comment : " " )
}
}
func preferredHeight ( for settingsHeaderFooterView : SettingsHeaderFooterView , in section : Section , isHeader : Bool ) -> CGFloat
{
let widthConstraint = settingsHeaderFooterView . contentView . widthAnchor . constraint ( equalToConstant : tableView . bounds . width )
NSLayoutConstraint . activate ( [ widthConstraint ] )
defer { NSLayoutConstraint . deactivate ( [ widthConstraint ] ) }
self . prepare ( settingsHeaderFooterView , for : section , isHeader : isHeader )
let size = settingsHeaderFooterView . contentView . systemLayoutSizeFitting ( UIView . layoutFittingCompressedSize )
return size . height
}
2019-06-06 14:46:23 -07:00
}
2019-07-31 11:46:26 -07:00
private extension SettingsViewController
2019-06-06 14:46:23 -07:00
{
2019-09-05 11:59:10 -07:00
func signIn ( )
2019-06-06 14:46:23 -07:00
{
AppManager . shared . authenticate ( presentingViewController : self ) { ( result ) in
DispatchQueue . main . async {
2019-11-18 14:49:17 -08:00
switch result
{
case . failure ( OperationError . cancelled ) :
// I g n o r e
break
case . failure ( let error ) :
2020-03-30 14:07:18 -07:00
let toastView = ToastView ( error : error )
toastView . show ( in : self )
2019-11-18 14:49:17 -08:00
case . success : break
}
2019-06-06 14:46:23 -07:00
self . update ( )
}
}
}
2019-09-05 11:59:10 -07:00
@objc func signOut ( _ sender : UIBarButtonItem )
2019-06-06 14:46:23 -07:00
{
func signOut ( )
{
DatabaseManager . shared . signOut { ( error ) in
DispatchQueue . main . async {
if let error = error
{
2020-03-30 14:07:18 -07:00
let toastView = ToastView ( error : error )
toastView . show ( in : self )
2019-06-06 14:46:23 -07:00
}
self . update ( )
}
}
}
let alertController = UIAlertController ( title : NSLocalizedString ( " Are you sure you want to sign out? " , comment : " " ) , message : NSLocalizedString ( " You will no longer be able to install or refresh apps once you sign out. " , comment : " " ) , preferredStyle : . actionSheet )
alertController . addAction ( UIAlertAction ( title : NSLocalizedString ( " Sign Out " , comment : " " ) , style : . destructive ) { _ in signOut ( ) } )
alertController . addAction ( . cancel )
2023-01-09 15:15:31 +08:00
// F i x c r a s h o n i P a d
alertController . popoverPresentationController ? . barButtonItem = sender
2019-06-06 14:46:23 -07:00
self . present ( alertController , animated : true , completion : nil )
}
2019-09-05 11:59:10 -07:00
@IBAction func toggleIsBackgroundRefreshEnabled ( _ sender : UISwitch )
{
UserDefaults . standard . isBackgroundRefreshEnabled = sender . isOn
}
2019-09-19 22:20:10 -07:00
2023-11-28 00:44:47 +09:00
@IBAction func toggleNoIdleTimeoutEnabled ( _ sender : UISwitch )
{
UserDefaults . standard . isIdleTimeoutDisableEnabled = sender . isOn
}
2020-09-08 16:44:36 -07:00
@ available ( iOS 14 , * )
@IBAction func addRefreshAppsShortcut ( )
{
guard let shortcut = INShortcut ( intent : INInteraction . refreshAllApps ( ) . intent ) else { return }
let viewController = INUIAddVoiceShortcutViewController ( shortcut : shortcut )
viewController . delegate = self
viewController . modalPresentationStyle = . formSheet
self . present ( viewController , animated : true , completion : nil )
}
2023-02-07 16:11:39 -06:00
func clearCache ( )
{
2023-08-30 05:12:02 +00:00
let alertController = UIAlertController ( title : NSLocalizedString ( " Are you sure you want to clear SideStore's cache? " , comment : " " ) ,
2023-02-07 16:11:39 -06:00
message : NSLocalizedString ( " This will remove all temporary files as well as backups for uninstalled apps. " , comment : " " ) ,
preferredStyle : . actionSheet )
alertController . addAction ( UIAlertAction ( title : UIAlertAction . cancel . title , style : UIAlertAction . cancel . style ) { [ weak self ] _ in
self ? . tableView . indexPathForSelectedRow . map { self ? . tableView . deselectRow ( at : $0 , animated : true ) }
} )
alertController . addAction ( UIAlertAction ( title : NSLocalizedString ( " Clear Cache " , comment : " " ) , style : . destructive ) { [ weak self ] _ in
AppManager . shared . clearAppCache { result in
DispatchQueue . main . async {
self ? . tableView . indexPathForSelectedRow . map { self ? . tableView . deselectRow ( at : $0 , animated : true ) }
switch result
{
case . success : break
case . failure ( let error ) :
let alertController = UIAlertController ( title : NSLocalizedString ( " Unable to Clear Cache " , comment : " " ) , message : error . localizedDescription , preferredStyle : . alert )
alertController . addAction ( . ok )
self ? . present ( alertController , animated : true )
}
}
}
} )
2023-11-26 13:50:45 +09:00
if let popoverController = alertController . popoverPresentationController {
popoverController . sourceView = self . view
popoverController . sourceRect = CGRect ( x : self . view . bounds . midX , y : self . view . bounds . midY , width : 0 , height : 0 )
}
2023-02-07 16:11:39 -06:00
self . present ( alertController , animated : true )
}
2019-09-19 22:20:10 -07:00
@IBAction func handleDebugModeGesture ( _ gestureRecognizer : UISwipeGestureRecognizer )
{
self . debugGestureCounter += 1
self . debugGestureTimer ? . invalidate ( )
if self . debugGestureCounter >= 3
{
self . debugGestureCounter = 0
UserDefaults . standard . isDebugModeEnabled . toggle ( )
self . tableView . reloadData ( )
}
else
{
self . debugGestureTimer = Timer . scheduledTimer ( withTimeInterval : 0.4 , repeats : false ) { [ weak self ] ( timer ) in
self ? . debugGestureCounter = 0
}
}
}
2019-09-21 13:57:18 -07:00
func openTwitter ( username : String )
{
let twitterAppURL = URL ( string : " twitter://user?screen_name= " + username ) !
UIApplication . shared . open ( twitterAppURL , options : [ : ] ) { ( success ) in
if success
{
if let selectedIndexPath = self . tableView . indexPathForSelectedRow
{
self . tableView . deselectRow ( at : selectedIndexPath , animated : true )
}
}
else
{
let safariURL = URL ( string : " https://twitter.com/ " + username ) !
let safariViewController = SFSafariViewController ( url : safariURL )
safariViewController . preferredControlTintColor = . altPrimary
self . present ( safariViewController , animated : true , completion : nil )
}
}
}
2019-06-06 14:46:23 -07:00
}
2019-09-19 14:43:26 -07:00
private extension SettingsViewController
{
@objc func openPatreonSettings ( _ notification : Notification )
{
guard self . presentedViewController = = nil else { return }
UIView . performWithoutAnimation {
self . navigationController ? . popViewController ( animated : false )
self . performSegue ( withIdentifier : " showPatreon " , sender : nil )
}
}
}
2019-07-31 11:46:26 -07:00
extension SettingsViewController
2019-06-06 14:46:23 -07:00
{
2019-09-19 22:20:10 -07:00
override func numberOfSections ( in tableView : UITableView ) -> Int
{
var numberOfSections = super . numberOfSections ( in : tableView )
if ! UserDefaults . standard . isDebugModeEnabled
{
numberOfSections -= 1
}
return numberOfSections
}
2019-09-05 11:59:10 -07:00
override func tableView ( _ tableView : UITableView , numberOfRowsInSection section : Int ) -> Int
2019-06-06 14:46:23 -07:00
{
2019-09-05 11:59:10 -07:00
let section = Section . allCases [ section ]
switch section
{
case . signIn : return ( self . activeTeam = = nil ) ? 1 : 0
case . account : return ( self . activeTeam = = nil ) ? 0 : 3
2020-09-08 16:44:36 -07:00
case . appRefresh : return AppRefreshRow . allCases . count
2019-09-05 11:59:10 -07:00
default : return super . tableView ( tableView , numberOfRowsInSection : section . rawValue )
}
}
2020-09-08 17:11:22 -07:00
override func tableView ( _ tableView : UITableView , cellForRowAt indexPath : IndexPath ) -> UITableViewCell
{
let cell = super . tableView ( tableView , cellForRowAt : indexPath )
2023-11-28 00:44:47 +09:00
// i f # a v a i l a b l e ( i O S 1 4 , * ) { }
// e l s e i f l e t c e l l = c e l l a s ? I n s e t G r o u p T a b l e V i e w C e l l ,
// i n d e x P a t h . s e c t i o n = = S e c t i o n . a p p R e f r e s h . r a w V a l u e ,
// i n d e x P a t h . r o w = = A p p R e f r e s h R o w . b a c k g r o u n d R e f r e s h . r a w V a l u e
// {
// / / O n l y o n e r o w i s v i s i b l e p r e - i O S 1 4 .
// c e l l . s t y l e = . s i n g l e
// }
if AppRefreshRow . AllCases ( ) . count = = 1
2020-09-08 17:11:22 -07:00
{
2023-11-28 00:44:47 +09:00
if let cell = cell as ? InsetGroupTableViewCell ,
indexPath . section = = Section . appRefresh . rawValue ,
indexPath . row = = AppRefreshRow . backgroundRefresh . rawValue
{
cell . style = . single
}
2020-09-08 17:11:22 -07:00
}
2023-11-28 00:44:47 +09:00
2020-09-08 17:11:22 -07:00
return cell
}
2019-09-05 11:59:10 -07:00
override func tableView ( _ tableView : UITableView , viewForHeaderInSection section : Int ) -> UIView ?
{
let section = Section . allCases [ section ]
switch section
{
case . signIn where self . activeTeam != nil : return nil
case . account where self . activeTeam = = nil : return nil
2020-10-07 11:32:47 -07:00
case . signIn , . account , . patreon , . appRefresh , . credits , . debug :
2019-09-05 11:59:10 -07:00
let headerView = tableView . dequeueReusableHeaderFooterView ( withIdentifier : " HeaderFooterView " ) as ! SettingsHeaderFooterView
self . prepare ( headerView , for : section , isHeader : true )
return headerView
2020-09-08 16:44:36 -07:00
case . instructions : return nil
2019-09-05 11:59:10 -07:00
}
}
override func tableView ( _ tableView : UITableView , viewForFooterInSection section : Int ) -> UIView ?
{
let section = Section . allCases [ section ]
switch section
{
case . signIn where self . activeTeam != nil : return nil
2020-10-07 11:32:47 -07:00
case . signIn , . patreon , . appRefresh :
2019-09-05 11:59:10 -07:00
let footerView = tableView . dequeueReusableHeaderFooterView ( withIdentifier : " HeaderFooterView " ) as ! SettingsHeaderFooterView
self . prepare ( footerView , for : section , isHeader : false )
return footerView
2019-09-07 15:34:07 -07:00
case . account , . credits , . debug , . instructions : return nil
2019-09-05 11:59:10 -07:00
}
2019-06-06 14:46:23 -07:00
}
2019-09-05 11:59:10 -07:00
override func tableView ( _ tableView : UITableView , heightForHeaderInSection section : Int ) -> CGFloat
{
let section = Section . allCases [ section ]
switch section
{
case . signIn where self . activeTeam != nil : return 1.0
case . account where self . activeTeam = = nil : return 1.0
2020-10-07 11:32:47 -07:00
case . signIn , . account , . patreon , . appRefresh , . credits , . debug :
2019-09-05 11:59:10 -07:00
let height = self . preferredHeight ( for : self . prototypeHeaderFooterView , in : section , isHeader : true )
return height
2020-09-08 16:44:36 -07:00
case . instructions : return 0.0
2019-09-05 11:59:10 -07:00
}
}
override func tableView ( _ tableView : UITableView , heightForFooterInSection section : Int ) -> CGFloat
{
let section = Section . allCases [ section ]
switch section
{
case . signIn where self . activeTeam != nil : return 1.0
2020-10-07 11:32:47 -07:00
case . account where self . activeTeam = = nil : return 1.0
case . signIn , . patreon , . appRefresh :
2019-09-05 11:59:10 -07:00
let height = self . preferredHeight ( for : self . prototypeHeaderFooterView , in : section , isHeader : false )
return height
2019-09-07 15:34:07 -07:00
case . account , . credits , . debug , . instructions : return 0.0
2019-09-05 11:59:10 -07:00
}
}
}
2019-06-06 14:46:23 -07:00
2019-09-05 11:59:10 -07:00
extension SettingsViewController
{
override func tableView ( _ tableView : UITableView , didSelectRowAt indexPath : IndexPath )
{
let section = Section . allCases [ indexPath . section ]
switch section
{
case . signIn : self . signIn ( )
2019-09-07 15:34:07 -07:00
case . instructions : break
2020-09-08 16:44:36 -07:00
case . appRefresh :
let row = AppRefreshRow . allCases [ indexPath . row ]
switch row
{
case . backgroundRefresh : break
2023-11-28 00:44:47 +09:00
case . noIdleTimeout : break
2020-09-08 16:44:36 -07:00
case . addToSiri :
guard #available ( iOS 14 , * ) else { return }
self . addRefreshAppsShortcut ( )
}
2023-02-07 16:11:39 -06:00
2019-09-07 15:34:07 -07:00
case . credits :
let row = CreditsRow . allCases [ indexPath . row ]
switch row
{
2022-11-05 23:50:07 -07:00
case . developer : self . openTwitter ( username : " sidestore_io " )
case . operations : self . openTwitter ( username : " sidestore_io " )
2022-12-11 12:03:45 -05:00
case . designer : self . openTwitter ( username : " lit_ritt " )
2019-09-21 13:57:18 -07:00
case . softwareLicenses : break
2019-09-07 15:34:07 -07:00
}
2019-09-12 13:23:21 -07:00
case . debug :
let row = DebugRow . allCases [ indexPath . row ]
switch row
{
case . sendFeedback :
if MFMailComposeViewController . canSendMail ( )
{
let mailViewController = MFMailComposeViewController ( )
mailViewController . mailComposeDelegate = self
2022-11-05 23:50:07 -07:00
mailViewController . setToRecipients ( [ " support@sidestore.io " ] )
2019-09-12 13:23:21 -07:00
if let version = Bundle . main . object ( forInfoDictionaryKey : " CFBundleShortVersionString " ) as ? String
{
2022-11-05 23:50:07 -07:00
mailViewController . setSubject ( " SideStore Beta \( version ) Feedback " )
2019-09-12 13:23:21 -07:00
}
else
{
2022-11-05 23:50:07 -07:00
mailViewController . setSubject ( " SideStore Beta Feedback " )
2019-09-12 13:23:21 -07:00
}
self . present ( mailViewController , animated : true , completion : nil )
}
else
{
let toastView = ToastView ( text : NSLocalizedString ( " Cannot Send Mail " , comment : " " ) , detailText : nil )
2020-03-30 14:07:18 -07:00
toastView . show ( in : self )
2019-09-12 13:23:21 -07:00
}
2023-08-30 07:09:52 +00:00
2024-06-17 09:43:25 +10:00
case . refreshSideJITServer :
if #available ( iOS 17 , * ) {
let alertController = UIAlertController (
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 )
alertController . addAction ( UIAlertAction ( title : NSLocalizedString ( " Refresh " , comment : " " ) , style : . destructive ) { _ in
if UserDefaults . standard . sidejitenable {
var SJSURL = " "
if ( UserDefaults . standard . textInputSideJITServerurl ? ? " " ) . isEmpty {
SJSURL = " http://sidejitserver._http._tcp.local:8080 "
} else {
SJSURL = UserDefaults . standard . textInputSideJITServerurl ? ? " "
} // r e p l a c e w i t h y o u r U R L
let url = URL ( string : SJSURL + " /re/ " ) !
let task = URLSession . shared . dataTask ( with : url ) { ( data , response , error ) in
if let error = error {
print ( " Error: \( error ) " )
} else {
// D o n o t h i n g w i t h d a t a o r r e s p o n s e
}
}
task . resume ( )
}
} )
alertController . addAction ( . cancel )
// F i x c r a s h o n i P a d
alertController . popoverPresentationController ? . sourceView = self . tableView
alertController . popoverPresentationController ? . sourceRect = self . tableView . rectForRow ( at : indexPath )
self . present ( alertController , animated : true )
self . tableView . deselectRow ( at : indexPath , animated : true )
} else {
let alertController = UIAlertController (
title : NSLocalizedString ( " You are not on iOS 17+ This will not work " , comment : " " ) ,
message : NSLocalizedString ( " This is meant for 'SideJITServer' and it only works on iOS 17+ " , comment : " " ) ,
preferredStyle : UIAlertController . Style . actionSheet )
2023-08-30 04:47:36 +00:00
2024-06-17 09:43:25 +10:00
alertController . addAction ( UIAlertAction ( title : NSLocalizedString ( " OK " , comment : " " ) , style : . destructive ) { _ in
print ( " Not on iOS 17 " )
} )
alertController . addAction ( . cancel )
// F i x c r a s h o n i P a d
alertController . popoverPresentationController ? . sourceView = self . tableView
alertController . popoverPresentationController ? . sourceRect = self . tableView . rectForRow ( at : indexPath )
self . present ( alertController , animated : true )
self . tableView . deselectRow ( at : indexPath , animated : true )
}
case . clearCache : self . clearCache ( )
2023-01-09 15:15:31 +08:00
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 : " " ) ,
message : NSLocalizedString ( " You can reset the pairing file when you cannot sideload apps or enable JIT. You need to restart SideStore. " , comment : " " ) ,
preferredStyle : UIAlertController . Style . actionSheet )
alertController . addAction ( UIAlertAction ( title : NSLocalizedString ( " Delete and Reset " , comment : " " ) , style : . destructive ) { _ in
if fm . fileExists ( atPath : documentsPath . path ) , let contents = try ? String ( contentsOf : documentsPath ) , ! contents . isEmpty {
2024-02-23 19:46:31 -05:00
UserDefaults . standard . isPairingReset = true
2023-01-09 15:15:31 +08:00
try ? fm . removeItem ( atPath : documentsPath . path )
NSLog ( " Pairing File Reseted " )
}
self . tableView . deselectRow ( at : indexPath , animated : true )
2024-02-23 19:46:31 -05:00
let dialogMessage = UIAlertController ( title : NSLocalizedString ( " Pairing File Reset " , comment : " " ) , message : NSLocalizedString ( " Please restart SideStore " , comment : " " ) , preferredStyle : . alert )
2023-01-09 15:15:31 +08:00
self . present ( dialogMessage , animated : true , completion : nil )
} )
alertController . addAction ( . cancel )
// F i x c r a s h o n i P a d
alertController . popoverPresentationController ? . sourceView = self . tableView
alertController . popoverPresentationController ? . sourceRect = self . tableView . rectForRow ( at : indexPath )
self . present ( alertController , animated : true )
self . tableView . deselectRow ( at : indexPath , animated : true )
2023-05-18 01:30:18 -07:00
case . resetAdiPb :
let alertController = UIAlertController (
title : NSLocalizedString ( " Are you sure you want to reset the adi.pb file? " , comment : " " ) ,
message : NSLocalizedString ( " The adi.pb file is used to generate anisette data, which is required to log into an Apple ID. If you are having issues with account related things, you can try this. However, you will be required to do 2FA again. This will do nothing if you are using an older anisette server. " , comment : " " ) ,
preferredStyle : UIAlertController . Style . actionSheet )
alertController . addAction ( UIAlertAction ( title : NSLocalizedString ( " Reset adi.pb " , comment : " " ) , style : . destructive ) { _ in
if Keychain . shared . adiPb != nil {
Keychain . shared . adiPb = nil
print ( " Cleared adi.pb from keychain " )
}
self . tableView . deselectRow ( at : indexPath , animated : true )
} )
alertController . addAction ( . cancel )
// F i x c r a s h o n i P a d
alertController . popoverPresentationController ? . sourceView = self . tableView
alertController . popoverPresentationController ? . sourceRect = self . tableView . rectForRow ( at : indexPath )
self . present ( alertController , animated : true )
self . tableView . deselectRow ( at : indexPath , animated : true )
2023-01-01 12:20:08 -05:00
case . advancedSettings :
// C r e a t e t h e U R L t h a t d e e p l i n k s t o y o u r a p p ' s c u s t o m s e t t i n g s .
if let url = URL ( string : UIApplication . openSettingsURLString ) {
// A s k t h e s y s t e m t o o p e n t h a t U R L .
UIApplication . shared . open ( url )
} else {
ELOG ( " UIApplication.openSettingsURLString invalid " )
}
2022-09-09 17:44:15 -05:00
case . refreshAttempts , . errorLog : break
2023-08-30 07:24:27 +00:00
2019-09-12 13:23:21 -07:00
}
2019-09-05 11:59:10 -07:00
default : break
}
}
}
2019-09-12 13:23:21 -07:00
extension SettingsViewController : MFMailComposeViewControllerDelegate
{
func mailComposeController ( _ controller : MFMailComposeViewController , didFinishWith result : MFMailComposeResult , error : Error ? )
{
if let error = error
{
2020-03-30 14:07:18 -07:00
let toastView = ToastView ( error : error )
toastView . show ( in : self )
2019-09-12 13:23:21 -07:00
}
controller . dismiss ( animated : true , completion : nil )
}
}
2019-09-19 22:20:10 -07:00
extension SettingsViewController : UIGestureRecognizerDelegate
{
func gestureRecognizer ( _ gestureRecognizer : UIGestureRecognizer , shouldRecognizeSimultaneouslyWith otherGestureRecognizer : UIGestureRecognizer ) -> Bool
{
return true
}
}
2020-09-08 16:44:36 -07:00
extension SettingsViewController : INUIAddVoiceShortcutViewControllerDelegate
{
func addVoiceShortcutViewController ( _ controller : INUIAddVoiceShortcutViewController , didFinishWith voiceShortcut : INVoiceShortcut ? , error : Error ? )
{
if let indexPath = self . tableView . indexPathForSelectedRow
{
self . tableView . deselectRow ( at : indexPath , animated : true )
}
controller . dismiss ( animated : true , completion : nil )
guard let error = error else { return }
let toastView = ToastView ( error : error )
toastView . show ( in : self )
}
func addVoiceShortcutViewControllerDidCancel ( _ controller : INUIAddVoiceShortcutViewController )
{
if let indexPath = self . tableView . indexPathForSelectedRow
{
self . tableView . deselectRow ( at : indexPath , animated : true )
}
controller . dismiss ( animated : true , completion : nil )
}
}