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 .
//
2020-09-08 16:44:36 -07:00
import Intents
import IntentsUI
2023-03-01 00:48:36 -05:00
import MessageUI
import SafariServices
import UIKit
2019-06-06 14:46:23 -07:00
2023-03-01 00:48:36 -05:00
import SideStoreCore
2020-09-03 16:39:08 -07:00
2023-03-01 00:48:36 -05:00
private extension SettingsViewController {
enum Section : Int , CaseIterable {
2019-09-05 11:59:10 -07:00
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
}
2023-03-01 00:48:36 -05:00
enum AppRefreshRow : Int , CaseIterable {
2020-09-08 16:44:36 -07:00
case backgroundRefresh
2023-03-01 00:48:36 -05:00
2020-09-08 16:44:36 -07:00
@ available ( iOS 14 , * )
case addToSiri
2023-03-01 00:48:36 -05:00
2020-09-08 16:44:36 -07:00
static var allCases : [ AppRefreshRow ] {
guard #available ( iOS 14 , * ) else { return [ . backgroundRefresh ] }
return [ . backgroundRefresh , . addToSiri ]
}
}
2023-03-01 00:48:36 -05:00
enum CreditsRow : Int , CaseIterable {
2019-09-07 15:34:07 -07:00
case developer
2022-04-13 20:06:57 -07:00
case operations
2019-09-07 15:34:07 -07:00
case designer
case softwareLicenses
}
2023-03-01 00:48:36 -05:00
enum DebugRow : Int , CaseIterable {
2019-09-12 13:23:21 -07:00
case sendFeedback
case refreshAttempts
2022-09-09 17:44:15 -05:00
case errorLog
2023-01-09 15:15:31 +08:00
case resetPairingFile
2023-01-01 12:20:08 -05:00
case advancedSettings
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-03-01 00:48:36 -05:00
final class SettingsViewController : UITableViewController {
2019-09-05 11:59:10 -07:00
private var activeTeam : Team ?
2023-03-01 00:48:36 -05:00
2019-09-05 11:59:10 -07:00
private var prototypeHeaderFooterView : SettingsHeaderFooterView !
2023-03-01 00:48:36 -05:00
2019-09-19 22:20:10 -07:00
private var debugGestureCounter = 0
private weak var debugGestureTimer : Timer ?
2023-03-01 00:48:36 -05:00
2019-09-05 11:59:10 -07:00
@IBOutlet private var accountNameLabel : UILabel !
@IBOutlet private var accountEmailLabel : UILabel !
@IBOutlet private var accountTypeLabel : UILabel !
2023-03-01 00:48:36 -05:00
2019-09-05 11:59:10 -07:00
@IBOutlet private var backgroundRefreshSwitch : UISwitch !
2023-03-01 00:48:36 -05:00
2020-01-13 13:32:55 -08:00
@IBOutlet private var versionLabel : UILabel !
2023-03-01 00:48:36 -05:00
2019-10-24 13:04:30 -07:00
override var preferredStatusBarStyle : UIStatusBarStyle {
2023-03-01 00:48:36 -05:00
. lightContent
2019-10-24 13:04:30 -07:00
}
2023-03-01 00:48:36 -05:00
required init ? ( coder aDecoder : NSCoder ) {
2019-09-19 14:43:26 -07:00
super . init ( coder : aDecoder )
2023-03-01 00:48:36 -05:00
2023-03-01 19:09:33 -05:00
NotificationCenter . default . addObserver ( self , selector : #selector ( SettingsViewController . openPatreonSettings ( _ : ) ) , name : SideStoreAppDelegate . openPatreonSettingsDeepLinkNotification , object : nil )
2019-09-19 14:43:26 -07:00
}
2023-03-01 00:48:36 -05:00
override func viewDidLoad ( ) {
2019-06-06 14:46:23 -07:00
super . viewDidLoad ( )
2023-03-01 00:48:36 -05:00
2023-03-02 01:09:10 -05:00
let nib = UINib ( nibName : " SettingsHeaderFooterView " , bundle : Bundle ( for : SettingsHeaderFooterView . self ) )
2023-03-01 00:48:36 -05:00
prototypeHeaderFooterView = nib . instantiate ( withOwner : nil , options : nil ) [ 0 ] as ? SettingsHeaderFooterView
tableView . register ( nib , forHeaderFooterViewReuseIdentifier : " HeaderFooterView " )
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
2023-03-01 00:48:36 -05:00
tableView . addGestureRecognizer ( debugModeGestureRecognizer )
if let version = Bundle . main . object ( forInfoDictionaryKey : " CFBundleShortVersionString " ) as ? String {
versionLabel . text = NSLocalizedString ( String ( format : " SideStore %@ " , version ) , comment : " SideStore Version " )
} else {
versionLabel . text = NSLocalizedString ( " SideStore " , comment : " " )
2020-01-13 13:32:55 -08:00
}
2023-03-01 00:48:36 -05:00
tableView . contentInset . bottom = 20
update ( )
if #available ( iOS 15 , * ) , let appearance = 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
}
2023-03-01 00:48:36 -05:00
override func viewWillAppear ( _ animated : Bool ) {
2019-09-07 15:34:07 -07:00
super . viewWillAppear ( animated )
2023-03-01 00:48:36 -05:00
update ( )
2019-09-07 15:34:07 -07:00
}
2019-06-06 14:46:23 -07:00
}
2023-03-01 00:48:36 -05:00
private extension SettingsViewController {
func update ( ) {
if let team = DatabaseManager . shared . activeTeam ( ) {
accountNameLabel . text = team . name
accountEmailLabel . text = team . account . appleID
accountTypeLabel . text = team . type . localizedDescription
activeTeam = team
} else {
activeTeam = nil
2019-06-06 14:46:23 -07:00
}
2023-03-01 00:48:36 -05:00
backgroundRefreshSwitch . isOn = UserDefaults . standard . isBackgroundRefreshEnabled
if isViewLoaded {
tableView . reloadData ( )
2019-06-06 14:46:23 -07:00
}
}
2023-03-01 00:48:36 -05:00
func prepare ( _ settingsHeaderFooterView : SettingsHeaderFooterView , for section : Section , isHeader : Bool ) {
2019-09-05 11:59:10 -07:00
settingsHeaderFooterView . primaryLabel . isHidden = ! isHeader
settingsHeaderFooterView . secondaryLabel . isHidden = isHeader
settingsHeaderFooterView . button . isHidden = true
2023-03-01 00:48:36 -05:00
2019-09-05 11:59:10 -07:00
settingsHeaderFooterView . layoutMargins . bottom = isHeader ? 0 : 8
2023-03-01 00:48:36 -05:00
switch section {
2019-09-05 11:59:10 -07:00
case . signIn :
2023-03-01 00:48:36 -05:00
if isHeader {
2019-09-05 11:59:10 -07:00
settingsHeaderFooterView . primaryLabel . text = NSLocalizedString ( " ACCOUNT " , comment : " " )
2023-03-01 00:48:36 -05:00
} 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
}
2023-03-01 00:48:36 -05:00
2019-09-05 11:59:10 -07:00
case . patreon :
2023-03-01 00:48:36 -05:00
if isHeader {
2019-09-25 12:43:32 -07:00
settingsHeaderFooterView . primaryLabel . text = NSLocalizedString ( " PATREON " , comment : " " )
2023-03-01 00:48:36 -05:00
} else {
2022-11-05 23:50:07 -07:00
settingsHeaderFooterView . secondaryLabel . text = NSLocalizedString ( " Support the SideStore Team by 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 : " " )
2023-03-01 00:48:36 -05:00
2019-09-05 11:59:10 -07:00
settingsHeaderFooterView . button . setTitle ( NSLocalizedString ( " SIGN OUT " , comment : " " ) , for : . normal )
settingsHeaderFooterView . button . addTarget ( self , action : #selector ( SettingsViewController . signOut ( _ : ) ) , for : . primaryActionTriggered )
settingsHeaderFooterView . button . isHidden = false
2023-03-01 00:48:36 -05:00
2020-09-08 16:44:36 -07:00
case . appRefresh :
2023-03-01 00:48:36 -05:00
if isHeader {
2020-09-08 16:44:36 -07:00
settingsHeaderFooterView . primaryLabel . text = NSLocalizedString ( " REFRESHING APPS " , comment : " " )
2023-03-01 00:48:36 -05:00
} else {
2022-11-05 23:50:07 -07:00
settingsHeaderFooterView . secondaryLabel . text = NSLocalizedString ( " Enable Background Refresh to automatically refresh apps in the background when connected to Wi-Fi. " , comment : " " )
2020-09-08 16:44:36 -07:00
}
2023-03-01 00:48:36 -05:00
2019-09-07 15:34:07 -07:00
case . instructions :
break
2023-03-01 00:48:36 -05:00
2019-09-07 15:34:07 -07:00
case . credits :
settingsHeaderFooterView . primaryLabel . text = NSLocalizedString ( " CREDITS " , comment : " " )
2023-03-01 00:48:36 -05:00
2019-09-05 11:59:10 -07:00
case . debug :
settingsHeaderFooterView . primaryLabel . text = NSLocalizedString ( " DEBUG " , comment : " " )
}
}
2023-03-01 00:48:36 -05:00
func preferredHeight ( for settingsHeaderFooterView : SettingsHeaderFooterView , in section : Section , isHeader : Bool ) -> CGFloat {
2019-09-05 11:59:10 -07:00
let widthConstraint = settingsHeaderFooterView . contentView . widthAnchor . constraint ( equalToConstant : tableView . bounds . width )
NSLayoutConstraint . activate ( [ widthConstraint ] )
defer { NSLayoutConstraint . deactivate ( [ widthConstraint ] ) }
2023-03-01 00:48:36 -05:00
prepare ( settingsHeaderFooterView , for : section , isHeader : isHeader )
2019-09-05 11:59:10 -07:00
let size = settingsHeaderFooterView . contentView . systemLayoutSizeFitting ( UIView . layoutFittingCompressedSize )
return size . height
}
2019-06-06 14:46:23 -07:00
}
2023-03-01 00:48:36 -05:00
private extension SettingsViewController {
func signIn ( ) {
AppManager . shared . authenticate ( presentingViewController : self ) { result in
2019-06-06 14:46:23 -07:00
DispatchQueue . main . async {
2023-03-01 00:48:36 -05:00
switch result {
2019-11-18 14:49:17 -08:00
case . failure ( OperationError . cancelled ) :
// I g n o r e
break
2023-03-01 00:48:36 -05:00
case let . failure ( error ) :
2020-03-30 14:07:18 -07:00
let toastView = ToastView ( error : error )
toastView . show ( in : self )
2023-03-01 00:48:36 -05:00
2019-11-18 14:49:17 -08:00
case . success : break
}
2023-03-01 00:48:36 -05:00
2019-06-06 14:46:23 -07:00
self . update ( )
}
}
}
2023-03-01 00:48:36 -05:00
@objc func signOut ( _ sender : UIBarButtonItem ) {
func signOut ( ) {
DatabaseManager . shared . signOut { error in
2019-06-06 14:46:23 -07:00
DispatchQueue . main . async {
2023-03-01 00:48:36 -05:00
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
}
2023-03-01 00:48:36 -05:00
2019-06-06 14:46:23 -07:00
self . update ( )
}
}
}
2023-03-01 00:48:36 -05:00
2019-06-06 14:46:23 -07:00
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-03-01 00:48:36 -05:00
// F i x c r a s h o n i P a d
2023-01-09 15:15:31 +08:00
alertController . popoverPresentationController ? . barButtonItem = sender
2023-03-01 00:48:36 -05:00
present ( alertController , animated : true , completion : nil )
2019-06-06 14:46:23 -07:00
}
2023-03-01 00:48:36 -05:00
@IBAction func toggleIsBackgroundRefreshEnabled ( _ sender : UISwitch ) {
2019-09-05 11:59:10 -07:00
UserDefaults . standard . isBackgroundRefreshEnabled = sender . isOn
}
2023-03-01 00:48:36 -05:00
2020-09-08 16:44:36 -07:00
@ available ( iOS 14 , * )
2023-03-01 00:48:36 -05:00
@IBAction func addRefreshAppsShortcut ( ) {
2020-09-08 16:44:36 -07:00
guard let shortcut = INShortcut ( intent : INInteraction . refreshAllApps ( ) . intent ) else { return }
2023-03-01 00:48:36 -05:00
2020-09-08 16:44:36 -07:00
let viewController = INUIAddVoiceShortcutViewController ( shortcut : shortcut )
viewController . delegate = self
viewController . modalPresentationStyle = . formSheet
2023-03-01 00:48:36 -05:00
present ( viewController , animated : true , completion : nil )
2020-09-08 16:44:36 -07:00
}
2023-03-01 00:48:36 -05:00
@IBAction func handleDebugModeGesture ( _ : UISwipeGestureRecognizer ) {
debugGestureCounter += 1
debugGestureTimer ? . invalidate ( )
if debugGestureCounter >= 3 {
debugGestureCounter = 0
2019-09-19 22:20:10 -07:00
UserDefaults . standard . isDebugModeEnabled . toggle ( )
2023-03-01 00:48:36 -05:00
tableView . reloadData ( )
} else {
debugGestureTimer = Timer . scheduledTimer ( withTimeInterval : 0.4 , repeats : false ) { [ weak self ] _ in
2019-09-19 22:20:10 -07:00
self ? . debugGestureCounter = 0
}
}
}
2023-03-01 00:48:36 -05:00
func openTwitter ( username : String ) {
2019-09-21 13:57:18 -07:00
let twitterAppURL = URL ( string : " twitter://user?screen_name= " + username ) !
2023-03-01 00:48:36 -05:00
UIApplication . shared . open ( twitterAppURL , options : [ : ] ) { success in
if success {
if let selectedIndexPath = self . tableView . indexPathForSelectedRow {
2019-09-21 13:57:18 -07:00
self . tableView . deselectRow ( at : selectedIndexPath , animated : true )
}
2023-03-01 00:48:36 -05:00
} else {
2019-09-21 13:57:18 -07:00
let safariURL = URL ( string : " https://twitter.com/ " + username ) !
2023-03-01 00:48:36 -05:00
2019-09-21 13:57:18 -07:00
let safariViewController = SFSafariViewController ( url : safariURL )
safariViewController . preferredControlTintColor = . altPrimary
self . present ( safariViewController , animated : true , completion : nil )
}
}
}
2019-06-06 14:46:23 -07:00
}
2023-03-01 00:48:36 -05:00
private extension SettingsViewController {
@objc func openPatreonSettings ( _ : Notification ) {
guard presentedViewController = = nil else { return }
2019-09-19 14:43:26 -07:00
UIView . performWithoutAnimation {
self . navigationController ? . popViewController ( animated : false )
self . performSegue ( withIdentifier : " showPatreon " , sender : nil )
}
}
}
2023-03-01 00:48:36 -05:00
extension SettingsViewController {
override func numberOfSections ( in tableView : UITableView ) -> Int {
2019-09-19 22:20:10 -07:00
var numberOfSections = super . numberOfSections ( in : tableView )
2023-03-01 00:48:36 -05:00
if ! UserDefaults . standard . isDebugModeEnabled {
2019-09-19 22:20:10 -07:00
numberOfSections -= 1
}
2023-03-01 00:48:36 -05:00
2019-09-19 22:20:10 -07:00
return numberOfSections
}
2023-03-01 00:48:36 -05:00
override func tableView ( _ tableView : UITableView , numberOfRowsInSection section : Int ) -> Int {
2019-09-05 11:59:10 -07:00
let section = Section . allCases [ section ]
2023-03-01 00:48:36 -05:00
switch section {
case . signIn : return ( activeTeam = = nil ) ? 1 : 0
case . account : return ( 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 )
}
}
2023-03-01 00:48:36 -05:00
override func tableView ( _ tableView : UITableView , cellForRowAt indexPath : IndexPath ) -> UITableViewCell {
2020-09-08 17:11:22 -07:00
let cell = super . tableView ( tableView , cellForRowAt : indexPath )
2023-03-01 00:48:36 -05:00
if #available ( iOS 14 , * ) { } else if let cell = cell as ? InsetGroupTableViewCell ,
indexPath . section = = Section . appRefresh . rawValue ,
indexPath . row = = AppRefreshRow . backgroundRefresh . rawValue {
2020-09-08 17:11:22 -07:00
// 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 .
cell . style = . single
}
2023-03-01 00:48:36 -05:00
2020-09-08 17:11:22 -07:00
return cell
}
2023-03-01 00:48:36 -05:00
override func tableView ( _ tableView : UITableView , viewForHeaderInSection section : Int ) -> UIView ? {
2019-09-05 11:59:10 -07:00
let section = Section . allCases [ section ]
2023-03-01 00:48:36 -05:00
switch section {
case . signIn where activeTeam != nil : return nil
case . account where 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
2023-03-01 00:48:36 -05:00
prepare ( headerView , for : section , isHeader : true )
2019-09-05 11:59:10 -07:00
return headerView
2023-03-01 00:48:36 -05:00
2020-09-08 16:44:36 -07:00
case . instructions : return nil
2019-09-05 11:59:10 -07:00
}
}
2023-03-01 00:48:36 -05:00
override func tableView ( _ tableView : UITableView , viewForFooterInSection section : Int ) -> UIView ? {
2019-09-05 11:59:10 -07:00
let section = Section . allCases [ section ]
2023-03-01 00:48:36 -05:00
switch section {
case . signIn where 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
2023-03-01 00:48:36 -05:00
prepare ( footerView , for : section , isHeader : false )
2019-09-05 11:59:10 -07:00
return footerView
2023-03-01 00:48:36 -05:00
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
}
2023-03-01 00:48:36 -05:00
override func tableView ( _ : UITableView , heightForHeaderInSection section : Int ) -> CGFloat {
2019-09-05 11:59:10 -07:00
let section = Section . allCases [ section ]
2023-03-01 00:48:36 -05:00
switch section {
case . signIn where activeTeam != nil : return 1.0
case . account where activeTeam = = nil : return 1.0
2020-10-07 11:32:47 -07:00
case . signIn , . account , . patreon , . appRefresh , . credits , . debug :
2023-03-01 00:48:36 -05:00
let height = preferredHeight ( for : prototypeHeaderFooterView , in : section , isHeader : true )
2019-09-05 11:59:10 -07:00
return height
2023-03-01 00:48:36 -05:00
2020-09-08 16:44:36 -07:00
case . instructions : return 0.0
2019-09-05 11:59:10 -07:00
}
}
2023-03-01 00:48:36 -05:00
override func tableView ( _ : UITableView , heightForFooterInSection section : Int ) -> CGFloat {
2019-09-05 11:59:10 -07:00
let section = Section . allCases [ section ]
2023-03-01 00:48:36 -05:00
switch section {
case . signIn where activeTeam != nil : return 1.0
case . account where activeTeam = = nil : return 1.0
2020-10-07 11:32:47 -07:00
case . signIn , . patreon , . appRefresh :
2023-03-01 00:48:36 -05:00
let height = preferredHeight ( for : prototypeHeaderFooterView , in : section , isHeader : false )
2019-09-05 11:59:10 -07:00
return height
2023-03-01 00:48:36 -05:00
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
2023-03-01 00:48:36 -05:00
extension SettingsViewController {
override func tableView ( _ : UITableView , didSelectRowAt indexPath : IndexPath ) {
2019-09-05 11:59:10 -07:00
let section = Section . allCases [ indexPath . section ]
2023-03-01 00:48:36 -05:00
switch section {
case . signIn : 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 ]
2023-03-01 00:48:36 -05:00
switch row {
2020-09-08 16:44:36 -07:00
case . backgroundRefresh : break
case . addToSiri :
guard #available ( iOS 14 , * ) else { return }
2023-03-01 00:48:36 -05:00
addRefreshAppsShortcut ( )
2020-09-08 16:44:36 -07:00
}
2023-03-01 00:48:36 -05:00
2019-09-07 15:34:07 -07:00
case . credits :
let row = CreditsRow . allCases [ indexPath . row ]
2023-03-01 00:48:36 -05:00
switch row {
case . developer : openTwitter ( username : " sidestore_io " )
case . operations : openTwitter ( username : " sidestore_io " )
case . designer : openTwitter ( username : " lit_ritt " )
2019-09-21 13:57:18 -07:00
case . softwareLicenses : break
2019-09-07 15:34:07 -07:00
}
2023-03-01 00:48:36 -05:00
2019-09-12 13:23:21 -07:00
case . debug :
let row = DebugRow . allCases [ indexPath . row ]
2023-03-01 00:48:36 -05:00
switch row {
2019-09-12 13:23:21 -07:00
case . sendFeedback :
2023-03-01 00:48:36 -05:00
if MFMailComposeViewController . canSendMail ( ) {
2019-09-12 13:23:21 -07:00
let mailViewController = MFMailComposeViewController ( )
mailViewController . mailComposeDelegate = self
2022-11-05 23:50:07 -07:00
mailViewController . setToRecipients ( [ " support@sidestore.io " ] )
2023-03-01 00:48:36 -05: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 " )
2023-03-01 00:48:36 -05:00
} else {
2022-11-05 23:50:07 -07:00
mailViewController . setSubject ( " SideStore Beta Feedback " )
2019-09-12 13:23:21 -07:00
}
2023-03-01 00:48:36 -05:00
present ( mailViewController , animated : true , completion : nil )
} else {
2019-09-12 13:23:21 -07:00
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-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 : " " ) ,
2023-03-01 00:48:36 -05:00
preferredStyle : UIAlertController . Style . actionSheet
)
alertController . addAction ( UIAlertAction ( title : NSLocalizedString ( " Delete and Reset " , comment : " " ) , style : . destructive ) { _ in
2023-01-09 15:15:31 +08:00
if fm . fileExists ( atPath : documentsPath . path ) , let contents = try ? String ( contentsOf : documentsPath ) , ! contents . isEmpty {
try ? fm . removeItem ( atPath : documentsPath . path )
NSLog ( " Pairing File Reseted " )
}
self . tableView . deselectRow ( at : indexPath , animated : true )
let dialogMessage = UIAlertController ( title : NSLocalizedString ( " Pairing File Reseted " , comment : " " ) , message : NSLocalizedString ( " Please restart SideStore " , comment : " " ) , preferredStyle : . alert )
self . present ( dialogMessage , animated : true , completion : nil )
} )
alertController . addAction ( . cancel )
2023-03-01 00:48:36 -05:00
// F i x c r a s h o n i P a d
alertController . popoverPresentationController ? . sourceView = tableView
alertController . popoverPresentationController ? . sourceRect = tableView . rectForRow ( at : indexPath )
present ( alertController , animated : true )
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
2019-09-12 13:23:21 -07:00
}
2023-03-01 00:48:36 -05:00
2019-09-05 11:59:10 -07:00
default : break
}
}
}
2019-09-12 13:23:21 -07:00
2023-03-01 00:48:36 -05:00
extension SettingsViewController : MFMailComposeViewControllerDelegate {
func mailComposeController ( _ controller : MFMailComposeViewController , didFinishWith _ : 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
}
2023-03-01 00:48:36 -05:00
2019-09-12 13:23:21 -07:00
controller . dismiss ( animated : true , completion : nil )
}
}
2019-09-19 22:20:10 -07:00
2023-03-01 00:48:36 -05:00
extension SettingsViewController : UIGestureRecognizerDelegate {
func gestureRecognizer ( _ : UIGestureRecognizer , shouldRecognizeSimultaneouslyWith _ : UIGestureRecognizer ) -> Bool {
true
2019-09-19 22:20:10 -07:00
}
}
2020-09-08 16:44:36 -07:00
2023-03-01 00:48:36 -05:00
extension SettingsViewController : INUIAddVoiceShortcutViewControllerDelegate {
func addVoiceShortcutViewController ( _ controller : INUIAddVoiceShortcutViewController , didFinishWith _ : INVoiceShortcut ? , error : Error ? ) {
if let indexPath = tableView . indexPathForSelectedRow {
tableView . deselectRow ( at : indexPath , animated : true )
2020-09-08 16:44:36 -07:00
}
2023-03-01 00:48:36 -05:00
2020-09-08 16:44:36 -07:00
controller . dismiss ( animated : true , completion : nil )
2023-03-01 00:48:36 -05:00
2020-09-08 16:44:36 -07:00
guard let error = error else { return }
2023-03-01 00:48:36 -05:00
2020-09-08 16:44:36 -07:00
let toastView = ToastView ( error : error )
toastView . show ( in : self )
}
2023-03-01 00:48:36 -05:00
func addVoiceShortcutViewControllerDidCancel ( _ controller : INUIAddVoiceShortcutViewController ) {
if let indexPath = tableView . indexPathForSelectedRow {
tableView . deselectRow ( at : indexPath , animated : true )
2020-09-08 16:44:36 -07:00
}
2023-03-01 00:48:36 -05:00
2020-09-08 16:44:36 -07:00
controller . dismiss ( animated : true , completion : nil )
}
}