diff --git a/.periphery.yml b/.periphery.yml
new file mode 100644
index 0000000000000000000000000000000000000000..a933780ac9d597adfc611306bd23a541c61a072a
--- /dev/null
+++ b/.periphery.yml
@@ -0,0 +1,7 @@
+retain_objc_accessible: true
+retain_public: true
+schemes:
+- VLC-iOS
+targets:
+- VLC-iOS
+workspace: VLC.xcworkspace
diff --git a/Sources/Helpers/KeychainCoordinator.swift b/Sources/Helpers/KeychainCoordinator.swift
index e2a7d20e2ba2a7bcfc02c2c2f0dd174cbcaae98c..2002b0093936a4558cdeb1207d4b624101052590 100644
--- a/Sources/Helpers/KeychainCoordinator.swift
+++ b/Sources/Helpers/KeychainCoordinator.swift
@@ -52,8 +52,8 @@ class KeychainCoordinator: NSObject {
 
     private lazy var passcodeLockController: PasscodeLockController = {
         let passcodeController = PasscodeLockController(action: .enter)
-        passcodeController?.delegate = self
-        return passcodeController!
+        passcodeController.delegate = self
+        return passcodeController
     }()
 
     override init() {
diff --git a/Sources/Settings/Controller/PasscodeLockController.swift b/Sources/Settings/Controller/PasscodeLockController.swift
index 96ac64b496bb0dffa25c3dd777497384c41516d1..0fe209135bf7fb84ddc62d920b97f1305ba67be7 100644
--- a/Sources/Settings/Controller/PasscodeLockController.swift
+++ b/Sources/Settings/Controller/PasscodeLockController.swift
@@ -134,7 +134,7 @@ class PasscodeLockController: UIViewController {
 
     // MARK: - Init
 
-    convenience init?(action: PasscodeAction) {
+    convenience init(action: PasscodeAction) {
         self.init()
         self.action = action
         setup()
diff --git a/Sources/Settings/Controller/SettingsController.swift b/Sources/Settings/Controller/SettingsController.swift
index 4f943378eb9a7712d13eb26ae362da93380383e5..0965fd1c57476271942a46ad193f1a66c6867846 100644
--- a/Sources/Settings/Controller/SettingsController.swift
+++ b/Sources/Settings/Controller/SettingsController.swift
@@ -20,9 +20,12 @@ import LocalAuthentication
 
 extension Notification.Name {
     static let VLCDisableGroupingDidChangeNotification = Notification.Name("disableGroupingDidChangeNotfication")
+    static let VLCDidToggleSettingNotification = Notification.Name("didToggleSettingNotification")
 }
 
 class SettingsController: UITableViewController {
+    static let toggleNotificationKey = "toggleNotificationKey"
+    static let toggleNotificationValue = "toggleNotificationValue"
 
     private let cellReuseIdentifier = "settingsCell"
     private let sectionHeaderReuseIdentifier = "sectionHeaderReuseIdentifier"
@@ -36,6 +39,13 @@ class SettingsController: UITableViewController {
     private var isBackingUp = false
     private let isLabActivated: Bool = true
 
+    /// the source of all data.
+    private var settingsSections: [SettingsSection] = [] {
+        didSet {
+            tableView.reloadData()
+        }
+    }
+
     override var preferredStatusBarStyle: UIStatusBarStyle {
         return PresentationTheme.current.colors.statusBarStyle
     }
@@ -62,6 +72,7 @@ class SettingsController: UITableViewController {
         registerTableViewClasses()
         setupBarButton()
         addObservers()
+        reloadSettingsSections()
     }
 
 // MARK: - Setup Functions
@@ -94,6 +105,10 @@ class SettingsController: UITableViewController {
                                        selector: #selector(miniPlayerIsHidden),
                                        name: NSNotification.Name(rawValue: VLCPlayerDisplayControllerHideMiniPlayer),
                                        object: nil)
+        notificationCenter.addObserver(self,
+                                       selector: #selector(didToggleSettingNotification(note:)),
+                                       name: .VLCDidToggleSettingNotification,
+                                       object: nil)
     }
 
     private func registerTableViewClasses() {
@@ -148,7 +163,7 @@ class SettingsController: UITableViewController {
         self.view.backgroundColor = PresentationTheme.current.colors.background
         setNavBarAppearance()
         self.setNeedsStatusBarAppearanceUpdate()
-        self.tableView.reloadData() // When theme changes hide the black theme section if needed
+        self.reloadSettingsSections() // When theme changes hide the black theme section if needed
     }
 
     @objc private func miniPlayerIsShown() {
@@ -165,7 +180,40 @@ class SettingsController: UITableViewController {
                                                    right: 0)
     }
 
+    @objc private func didToggleSettingNotification(note: Notification) {
+        guard let preferenceKey = note.userInfo?[Self.toggleNotificationKey] as? String else { return }
+        guard let isOn = note.userInfo?[Self.toggleNotificationValue] as? Bool else { return }
+
+        userDefaults.set(isOn, forKey: preferenceKey)
+
+        switch preferenceKey {
+        case kVLCSettingPasscodeOnKey:
+            passcodeLockSwitchOn(state: isOn)
+        case kVLCSettingHideLibraryInFilesApp:
+            medialibraryHidingLockSwitchOn(state: isOn)
+        case kVLCSettingBackupMediaLibrary:
+            mediaLibraryBackupActivateSwitchOn(state: isOn)
+        case kVLCSettingsDisableGrouping:
+            medialibraryDisableGroupingSwitchOn(state: isOn)
+        case kVLCSettingPlaybackTapSwipeEqual, kVLCSettingPlaybackForwardBackwardEqual:
+            reloadSettingsSections()
+        default:
+            break
+        }
+    }
+
 // MARK: - Helper Functions
+    private func showDonation(indexPath: IndexPath) {
+        if #available(iOS 10, *) {
+            ImpactFeedbackGenerator().selectionChanged()
+        }
+        let donationVC = VLCDonationViewController(nibName: "VLCDonationViewController", bundle: nil)
+        let donationNC = UINavigationController(rootViewController: donationVC)
+        donationNC.modalPresentationStyle = .popover
+        donationNC.modalTransitionStyle = .flipHorizontal
+        donationNC.popoverPresentationController?.sourceView = tableView.cellForRow(at: indexPath)
+        present(donationNC, animated: true, completion: nil)
+    }
 
     private func forceRescanAlert() {
         NotificationFeedbackGenerator().warning()
@@ -196,24 +244,8 @@ class SettingsController: UITableViewController {
         UIApplication.shared.open(url, options: [:], completionHandler: nil)
     }
 
-    private func showActionSheet(for sectionType: SectionType?) {
-        guard let sectionType = sectionType else { return }
-        guard !sectionType.containsSwitch else { return }
-        guard let preferenceKey = sectionType.preferenceKey else {
-            assertionFailure("SettingsController: No Preference Key Available.")
-            return
-        }
-
-        var playbackTitle: String? = nil
-        if sectionType is PlaybackControlOptions {
-            playbackTitle = sectionType.description
-        }
-        specifierManager.playbackTitle = playbackTitle
-
-        showActionSheet(preferenceKey: preferenceKey)
-    }
-
-    private func showActionSheet(preferenceKey: String?) {
+    private func showActionSheet(title: String, preferenceKey: String) {
+        specifierManager.playbackTitle = title
         specifierManager.preferenceKey = preferenceKey
         specifierManager.settingsBundle = settingsBundle
         actionSheet.delegate = specifierManager
@@ -238,9 +270,11 @@ class SettingsController: UITableViewController {
         }
     }
 
-    private func playHaptics(sectionType: SectionType?) {
-        guard let sectionType = sectionType else { return }
-        if !sectionType.containsSwitch {
+    private func playHaptics(settingsItem: SettingsItem) {
+        switch settingsItem.action {
+        case .toggle:
+            break
+        default:
             ImpactFeedbackGenerator().selectionChanged()
         }
     }
@@ -276,227 +310,69 @@ class SettingsController: UITableViewController {
 
 extension SettingsController {
 
+    func reloadSettingsSections() {
+        // , passcodeLockSwitchOn: true
+        settingsSections = SettingsSection
+            .sections(isLabActivated: isLabActivated,
+                      isBackingUp: isBackingUp,
+                      isForwardBackwardEqual: userDefaults.bool(forKey: kVLCSettingPlaybackForwardBackwardEqual),
+                      isTapSwipeEqual: userDefaults.bool(forKey: kVLCSettingPlaybackTapSwipeEqual))
+    }
+
     override func numberOfSections(in tableView: UITableView) -> Int {
-        var numberOfSections = SettingsSection.allCases.count
-        // Remove the last section if the lab is deactivated
-        if isLabActivated == false {
-            numberOfSections = numberOfSections - 1
-        }
-        return numberOfSections
+        settingsSections.count
     }
 
     override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
-        guard let settingsSection = SettingsSection(rawValue: section) else { return 0 }
-        switch settingsSection {
-        case .main:
-            return MainOptions.allCases.count
-        case .donation:
-            return DonationOptions.allCases.count
-        case .generic:
-            return GenericOptions.allCases.count
-        case .privacy:
-            return PrivacyOptions.allCases.count
-        case .gestureControl:
-            return PlaybackControlOptions.allCases.count
-        case .video:
-            return VideoOptions.allCases.count
-        case .subtitles:
-            return SubtitlesOptions.allCases.count
-        case .audio:
-            return AudioOptions.allCases.count
-        case .casting:
-            return CastingOptions.allCases.count
-        case .mediaLibrary:
-            return MediaLibraryOptions.allCases.count
-        case .network:
-            return NetworkOptions.allCases.count
-        case .lab:
-            return Lab.allCases.count
-        case .reset:
-            return Reset.allCases.count
-        }
+        settingsSections[section].items.count
     }
 
     override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
-        if indexPath == [SettingsSection.privacy.rawValue, PrivacyOptions.enableBiometrics.rawValue] && !userDefaults.bool(forKey: kVLCSettingPasscodeOnKey) {
-            //If the passcode lock is on we return a default UITableViewCell else
-            //while hiding the biometric option row using a cell height of 0
-            //constraint warnings will be printed to the console since the cell height (0)
-            //collapses on given constraints (Top, leading, trailing, Bottom of StackView to Cell)
+        guard let cell = tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier, for: indexPath) as? SettingsCell else {
             return UITableViewCell()
         }
 
-        let forwardBackwardEqual = userDefaults.bool(forKey: kVLCSettingPlaybackForwardBackwardEqual)
-        let tapSwipeEqual = userDefaults.bool(forKey: kVLCSettingPlaybackTapSwipeEqual)
+        cell.settingsBundle = settingsBundle
 
-        // Here we skip the Settings Cell's initialization in order to avoid console warnings
-        // when the cell is supposed to be hidden and therefore the cell's height is equal to 0.
-        if indexPath.row == PlaybackControlOptions.backwardSkipLength.rawValue &&
-            forwardBackwardEqual {
-            return UITableViewCell()
-        } else if indexPath.row == PlaybackControlOptions.forwardSkipLengthSwipe.rawValue &&
-                    tapSwipeEqual {
-            return UITableViewCell()
-        } else if indexPath.row == PlaybackControlOptions.backwardSkipLengthSwipe.rawValue &&
-                    (tapSwipeEqual || forwardBackwardEqual) {
-            return UITableViewCell()
-        }
+        let section = settingsSections[indexPath.section]
+        let settingsItem = section.items[indexPath.row]
+        cell.settingsItem = settingsItem
 
-        guard let cell = tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier, for: indexPath) as? SettingsCell else {
-            return UITableViewCell()
-        }
-        cell.settingsBundle = settingsBundle
-        guard let section = SettingsSection(rawValue: indexPath.section) else {
-            return UITableViewCell()
-        }
-        switch section {
-        case .main:
-            cell.sectionType = MainOptions(rawValue: indexPath.row)
-        case .generic:
-            cell.sectionType = GenericOptions(rawValue: indexPath.row)
-            if indexPath.row == GenericOptions.automaticallyPlayNextItem.rawValue {
-                cell.subtitleLabel.text = nil
-            }
-        case .donation:
-            cell.sectionType = DonationOptions(rawValue: indexPath.row)
-        case .privacy:
-            let privacy = PrivacyOptions(rawValue: indexPath.row)
-            let isPasscodeOn = userDefaults.bool(forKey: kVLCSettingPasscodeOnKey)
-            if indexPath.row == PrivacyOptions.enableBiometrics.rawValue {
-                if !isPasscodeOn || privacy?.preferenceKey == nil {
-                    //If Passcode Lock Switch is off or Biometric Row Preference Key returns nil
-                    //We hide the cell
-                    cell.isHidden = true
-                }
-            }
-            cell.sectionType = privacy
-            cell.passcodeSwitchDelegate = self
-            cell.medialibraryHidingSwitchDelegate = self
-        case .gestureControl:
-            let gestureControlOptions = PlaybackControlOptions(rawValue: indexPath.row)
-            cell.sectionType = gestureControlOptions
-            cell.skipDurationDelegate = self
-        case .video:
-            cell.sectionType = VideoOptions(rawValue: indexPath.row)
-        case .subtitles:
-            cell.sectionType = SubtitlesOptions(rawValue: indexPath.row)
-        case .audio:
-            cell.sectionType = AudioOptions(rawValue: indexPath.row)
-        case .casting:
-            cell.sectionType = CastingOptions(rawValue: indexPath.row)
-        case .mediaLibrary:
-            let mediaLibOptions = MediaLibraryOptions(rawValue: indexPath.row)
-            if indexPath.row == MediaLibraryOptions.forceVLCToRescanTheMediaLibrary.rawValue {
-                cell.mainLabel.textColor = PresentationTheme.current.colors.orangeUI
-            }
-            cell.mediaLibraryBackupSwitchDelegate = self
-            cell.medialibraryDisableGroupingSwitchDelegate = self
-            if indexPath.row == MediaLibraryOptions.includeMediaLibInDeviceBackup.rawValue {
-                if isBackingUp {
-                    cell.accessoryView = .none
-                    cell.accessoryType = .none 
-                    cell.activityIndicator.startAnimating()
-                } else {
-                    cell.activityIndicator.stopAnimating()
-                }
-                cell.showsActivityIndicator = isBackingUp
-            }
-            cell.sectionType = mediaLibOptions
-            if indexPath.row == 0 {
-                cell.accessoryView = .none
-                cell.accessoryType = .none
-            }
-        case .network:
-            cell.sectionType = NetworkOptions(rawValue: indexPath.row)
-        case .lab:
-            let lab = Lab(rawValue: indexPath.row)
-            cell.sectionType = lab
-            if indexPath.row == 1 {
-                cell.accessoryView = .none
-                cell.accessoryType = .none
-            }
-        case .reset:
-            cell.sectionType = Reset(rawValue: indexPath.row)
-            cell.accessoryView = .none
-            cell.accessoryType = .none
-        }
         return cell
     }
 
     override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
         tableView.deselectRow(at: indexPath, animated: true)
-        guard let section = SettingsSection(rawValue: indexPath.section) else { return }
-        if section == .main && indexPath.row == 0 {
+
+        let section = settingsSections[indexPath.section]
+        let settingsItem = section.items[indexPath.row]
+
+        playHaptics(settingsItem: settingsItem)
+
+        switch settingsItem.action {
+        case .isLoading:
+            break
+        case .toggle:
+            break // we get a notification from the switch and do our work there
+        case .openPrivacySettings:
             openPrivacySettings()
-            return
-        }
-        if section == .mediaLibrary && indexPath.row == 0 {
+        case .forceRescanAlert:
             forceRescanAlert()
-            return
-        }
-        if section == .lab && indexPath.row == 1 {
+        case .exportMediaLibrary:
             exportMediaLibrary()
-            return
-        }
-        switch section {
-        case .main:
-            let mainSection = MainOptions(rawValue: indexPath.row)
-            playHaptics(sectionType: mainSection)
-            showActionSheet(for: mainSection)
         case .donation:
-            ImpactFeedbackGenerator().selectionChanged()
-            let donationVC = VLCDonationViewController(nibName: "VLCDonationViewController", bundle: nil)
-            let donationNC = UINavigationController(rootViewController: donationVC)
-            donationNC.modalPresentationStyle = .popover
-            donationNC.modalTransitionStyle = .flipHorizontal
-            donationNC.popoverPresentationController?.sourceView = tableView.cellForRow(at: indexPath)
-            present(donationNC, animated: true, completion: nil)
-        case .generic:
-            let genericSection = GenericOptions(rawValue: indexPath.row)
-            playHaptics(sectionType: genericSection)
-            showActionSheet(for: genericSection)
-        case .privacy:
-            let privacySection = PrivacyOptions(rawValue: indexPath.row)
-            playHaptics(sectionType: privacySection)
-        case .gestureControl:
-            let gestureSection = PlaybackControlOptions(rawValue: indexPath.row)
-            playHaptics(sectionType: gestureSection)
-            showActionSheet(for: gestureSection)
-        case .video:
-            let videoSection = VideoOptions(rawValue: indexPath.row)
-            playHaptics(sectionType: videoSection)
-            showActionSheet(for: videoSection)
-        case .subtitles:
-            let subtitleSection = SubtitlesOptions(rawValue: indexPath.row)
-            playHaptics(sectionType: subtitleSection)
-            showActionSheet(for: subtitleSection)
-        case .audio:
-            let audioSection = AudioOptions(rawValue: indexPath.row)
-            playHaptics(sectionType: audioSection)
-            showActionSheet(for: audioSection)
-        case .casting:
-            let castingSection = CastingOptions(rawValue: indexPath.row)
-            playHaptics(sectionType: castingSection)
-            showActionSheet(for: castingSection)
-        case .mediaLibrary:
-            break
-        case .network:
-            let networkSection = NetworkOptions(rawValue: indexPath.row)
-            playHaptics(sectionType: networkSection)
-            showActionSheet(for: networkSection)
-        case .lab:
-            break
-        case .reset:
-            let resetSection = Reset(rawValue: indexPath.row)
-            playHaptics(sectionType: resetSection)
+            showDonation(indexPath: indexPath)
+        case .displayResetAlert:
             displayResetAlert()
+        case .showActionSheet(let title, let preferenceKey, _):
+            showActionSheet(title: title, preferenceKey: preferenceKey)
         }
     }
 
     override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
         guard let headerView = tableView.dequeueReusableHeaderFooterView( withIdentifier: sectionHeaderReuseIdentifier) as? SettingsHeaderView else { return nil }
-        guard let description = SettingsSection.init(rawValue: section)?.description else { return nil }
-        headerView.sectionHeaderLabel.text = settingsBundle.localizedString(forKey: description, value: description, table: "Root")
+        guard let title = settingsSections[section].title else { return nil }
+        headerView.sectionHeaderLabel.text = settingsBundle.localizedString(forKey: title, value: title, table: "Root")
         return headerView
     }
 
@@ -520,37 +396,7 @@ extension SettingsController {
     }
 
     override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
-        let automaticDimension = UITableView.automaticDimension
-
-        if indexPath == [SettingsSection.privacy.rawValue, PrivacyOptions.enableBiometrics.rawValue] {
-            let isPasscodeOn = userDefaults.bool(forKey: kVLCSettingPasscodeOnKey)
-            let privacySection = PrivacyOptions(rawValue: indexPath.row)
-            if privacySection?.preferenceKey == nil {
-                //LAContext canEvaluatePolicy supports iOS 11.0.1 and above.
-                //If canEvaluatePolicy is not supported the preference key for the biometric row is nil.
-                //Therefore we never show the biometric options row in this case
-                return 0
-            }
-            return isPasscodeOn ? automaticDimension : 0 //If Passcode Lock is turned off we hide the biometric options row
-        }
-
-        let tapSwipeEqual = userDefaults.bool(forKey: kVLCSettingPlaybackTapSwipeEqual)
-        let forwardBackwardEqual = userDefaults.bool(forKey: kVLCSettingPlaybackForwardBackwardEqual)
-        let playbackControlsSection: Int = SettingsSection.gestureControl.rawValue
-
-        // Hide the unused skip duration cells depending on the settings selected by the user
-        if indexPath == [playbackControlsSection, PlaybackControlOptions.backwardSkipLength.rawValue] &&
-            forwardBackwardEqual {
-            return 0
-        } else if indexPath == [playbackControlsSection, PlaybackControlOptions.forwardSkipLengthSwipe.rawValue] &&
-                    tapSwipeEqual {
-            return 0
-        } else if indexPath == [playbackControlsSection, PlaybackControlOptions.backwardSkipLengthSwipe.rawValue] &&
-                    (tapSwipeEqual || forwardBackwardEqual) {
-            return 0
-        }
-
-        return automaticDimension
+        UITableView.automaticDimension
     }
 }
 
@@ -559,14 +405,14 @@ extension SettingsController: MediaLibraryDeviceBackupDelegate {
     func medialibraryDidStartExclusion() {
         DispatchQueue.main.async {
             self.isBackingUp = true
-            self.tableView.reloadData()
+            self.reloadSettingsSections()
         }
     }
 
     func medialibraryDidCompleteExclusion() {
         DispatchQueue.main.async {
             self.isBackingUp = false
-            self.tableView.reloadData()
+            self.reloadSettingsSections()
         }
     }
 }
@@ -574,48 +420,48 @@ extension SettingsController: MediaLibraryDeviceBackupDelegate {
 extension SettingsController: MediaLibraryHidingDelegate {
     func medialibraryDidStartHiding() {
         DispatchQueue.main.async {
-            self.tableView.reloadData()
+            self.reloadSettingsSections()
         }
     }
 
     func medialibraryDidCompleteHiding() {
         DispatchQueue.main.async {
-            self.tableView.reloadData()
+            self.reloadSettingsSections()
         }
     }
 }
 
 // MARK: - SwitchOn Delegates
 
-extension SettingsController: PasscodeActivateDelegate {
+extension SettingsController {
 
     func passcodeLockSwitchOn(state: Bool) {
         if state {
-            guard let passcodeLockController = PasscodeLockController(action: .set) else { return }
+            let passcodeLockController = PasscodeLockController(action: .set)
             let passcodeNavigationController = UINavigationController(rootViewController: passcodeLockController)
             passcodeNavigationController.modalPresentationStyle = .fullScreen
             present(passcodeNavigationController, animated: true) {
-                self.tableView.reloadData() //To show/hide biometric row
+                self.reloadSettingsSections() //To show/hide biometric row
             }
         } else {
-            tableView.reloadData()
+            reloadSettingsSections()
         }
     }
 }
 
-extension SettingsController: MedialibraryHidingActivateDelegate {
+extension SettingsController {
     func medialibraryHidingLockSwitchOn(state: Bool) {
         mediaLibraryService.hideMediaLibrary(state)
     }
 }
 
-extension SettingsController: MediaLibraryBackupActivateDelegate {
+extension SettingsController {
     func mediaLibraryBackupActivateSwitchOn(state: Bool) {
         mediaLibraryService.excludeFromDeviceBackup(state)
     }
 }
 
-extension SettingsController: MediaLibraryDisableGroupingDelegate {
+extension SettingsController {
     func medialibraryDisableGroupingSwitchOn(state: Bool) {
         notificationCenter.post(name: .VLCDisableGroupingDidChangeNotification, object: self)
     }
diff --git a/Sources/Settings/Model/SettingsSection.swift b/Sources/Settings/Model/SettingsSection.swift
index 811216e511329a4f43e95698bf788f80337e15a5..853778c0bc82640640f8bb57a0c7428e7af05556 100644
--- a/Sources/Settings/Model/SettingsSection.swift
+++ b/Sources/Settings/Model/SettingsSection.swift
@@ -17,832 +17,779 @@
 import Foundation
 import LocalAuthentication
 
-enum SettingsSection: Int, CaseIterable, CustomStringConvertible {
-    case main
-    case donation
-    case generic
-    case privacy
-    case gestureControl
-    case video
-    case subtitles
-    case audio
-    case casting
-    case mediaLibrary
-    case network
-    case lab
-    case reset
-
-    var description: String {
-        switch self {
-        case .main:
-            return ""
-        case .donation:
-            return ""
-        case .generic:
-            return "SETTINGS_GENERIC_TITLE"
-        case .privacy:
-            return "SETTINGS_PRIVACY_TITLE"
-        case .gestureControl:
-            return "SETTINGS_GESTURES"
-        case .video:
-            return "SETTINGS_VIDEO_TITLE"
-        case .subtitles:
-            return "SETTINGS_SUBTITLES_TITLE"
-        case .audio:
-            return "SETTINGS_AUDIO_TITLE"
-        case .casting:
-            return "SETTINGS_CASTING"
-        case .mediaLibrary:
-            return "SETTINGS_MEDIA_LIBRARY"
-        case .network:
-            return "SETTINGS_NETWORK"
-        case .lab:
-            return "SETTINGS_LAB"
-        case .reset:
-            return "SETTINGS_RESET_TITLE"
-        }
-    }
-}
-
-enum MainOptions: Int, CaseIterable, SectionType {
-    case privacy
-    case appearance
-
-    var description: String {
-        switch self {
-        case .privacy:
-            return "SETTINGS_PRIVACY_TITLE"
-        case .appearance:
-            return "SETTINGS_DARKTHEME"
+// MARK: - SettingsItem
+struct SettingsItem: Equatable {
+    let title: String
+    let subtitle: String?
+    let action: Action
+    let emphasizedTitle: Bool
+
+    @available(*, deprecated, message: "access from self.action")
+    var preferenceKey: String? {
+        switch action {
+        case .toggle(let preferenceKey):
+            return preferenceKey
+        case .showActionSheet(_, let preferenceKey, _):
+            return preferenceKey
+        default:
+            return nil
         }
     }
 
-    var containsSwitch: Bool {
-        switch self {
-        case .privacy:
-            return false
-        case .appearance:
-            return false
-        }
+    init(title: String, subtitle: String?, action: Action, emphasizedTitle: Bool = false) {
+        self.title = title
+        self.subtitle = subtitle
+        self.action = action
+        self.emphasizedTitle = emphasizedTitle
     }
 
-    var containsInfobutton: Bool { return false }
-
-    var subtitle: String? {
-        switch self {
-        case .privacy:
-            return "SETTINGS_PRIVACY_SUBTITLE"
-        case .appearance:
-            return "SETTINGS_THEME_SYSTEM"
-        }
+    enum Action: Equatable {
+        case isLoading
+        case toggle(preferenceKey: String)
+        case showActionSheet(title: String, preferenceKey: String, hasInfo: Bool)
+        case donation
+        case openPrivacySettings
+        case forceRescanAlert
+        case exportMediaLibrary
+        case displayResetAlert
     }
+}
 
-    var preferenceKey: String? {
-        switch self {
-        case .privacy:
-            return kVLCSettingPasscodeOnKey
-        case .appearance:
-            return kVLCSettingAppTheme
-        }
+// MARK: - SettingsSection
+struct SettingsSection: Equatable {
+    let title: String?
+    let items: [SettingsItem]
+
+    var isEmpty: Bool {
+        items.isEmpty
+    }
+
+    static func sections(isLabActivated: Bool, isBackingUp: Bool, isForwardBackwardEqual: Bool, isTapSwipeEqual: Bool) -> [SettingsSection] {
+        [
+            MainOptions.section(),
+            DonationOptions.section(),
+            GenericOptions.section(),
+            PrivacyOptions.section(),
+            GestureControlOptions.section(isForwardBackwardEqual: isForwardBackwardEqual, isTapSwipeEqual: isTapSwipeEqual),
+            VideoOptions.section(),
+            SubtitlesOptions.section(),
+            AudioOptions.section(),
+            CastingOptions.section(),
+            MediaLibraryOptions.section(isBackingUp: isBackingUp),
+            NetworkOptions.section(),
+            Lab.section(isLabActivated: isLabActivated),
+            Reset.section()
+        ].compactMap { $0 }
     }
 }
 
-enum DonationOptions: Int, CaseIterable, SectionType {
-    case donate
-
-    var description: String {
-        return "SETTINGS_DONATE"
+// MARK: - MainOptions
+enum MainOptions {
+    static var privacy: SettingsItem {
+        .init(
+            title: "SETTINGS_PRIVACY_TITLE",
+            subtitle: "SETTINGS_PRIVACY_SUBTITLE",
+            action: .openPrivacySettings
+        )
     }
 
-    var containsSwitch: Bool { return false }
-
-    var containsInfobutton: Bool { return false }
-
-    var subtitle: String? {
-        return "SETTINGS_DONATE_LONG"
+    static var appearance: SettingsItem {
+        .init(
+            title: "SETTINGS_DARKTHEME",
+            subtitle: "SETTINGS_THEME_SYSTEM",
+            action: .showActionSheet(title: "SETTINGS_DARKTHEME", preferenceKey: kVLCSettingAppTheme, hasInfo: false)
+        )
     }
 
-    var preferenceKey: String? { return nil }
+    static func section() -> SettingsSection? {
+        .init(title: nil, items: [
+            privacy,
+            appearance
+        ])
+    }
 }
 
-enum GenericOptions: Int, CaseIterable, SectionType {
-    case defaultPlaybackSpeed
-    case continueAudioPlayback
-    case playVideoInFullScreen
-    case continueVideoPlayback
-    case automaticallyPlayNextItem
-    case enableTextScrollingInMediaList
-    case rememberPlayerState
-    case restoreLastPlayedMedia
-
-    var description: String {
-        switch self {
-        case .defaultPlaybackSpeed:
-            return "SETTINGS_PLAYBACK_SPEED_DEFAULT"
-        case .continueAudioPlayback:
-            return "SETTINGS_CONTINUE_AUDIO_PLAYBACK"
-        case .playVideoInFullScreen:
-            return "SETTINGS_VIDEO_FULLSCREEN"
-        case .continueVideoPlayback:
-            return "SETTINGS_CONTINUE_VIDEO_PLAYBACK"
-        case .automaticallyPlayNextItem:
-            return "SETTINGS_NETWORK_PLAY_ALL"
-        case .enableTextScrollingInMediaList:
-            return "SETTINGS_ENABLE_MEDIA_CELL_TEXT_SCROLLING"
-        case .rememberPlayerState:
-            return "SETTINGS_REMEMBER_PLAYER_STATE"
-        case .restoreLastPlayedMedia:
-            return "SETTINGS_RESTORE_LAST_PLAYED_MEDIA"
-        }
+// MARK: - DonationOptions
+enum DonationOptions {
+    static var donate: SettingsItem {
+        .init(
+            title: "SETTINGS_DONATE",
+            subtitle: "SETTINGS_DONATE_LONG",
+            action: .donation
+        )
     }
 
-    var containsSwitch: Bool {
-        switch self {
-        case .defaultPlaybackSpeed:
-            return false
-        case .continueAudioPlayback:
-            return false
-        case .playVideoInFullScreen:
-            return true
-        case .continueVideoPlayback:
-            return false
-        case .automaticallyPlayNextItem:
-            return false
-        case .enableTextScrollingInMediaList:
-            return true
-        case .rememberPlayerState:
-            return true
-        case .restoreLastPlayedMedia:
-            return true
-        }
+    static func section() -> SettingsSection? {
+        .init(title: "SETTINGS_DONATE_TITLE", items: [donate])
     }
+}
 
-    var containsInfobutton: Bool {
-        switch self {
-        case .continueAudioPlayback:
-            return true
-        case .continueVideoPlayback:
-            return true
-        default:
-            return false
-        }
+// MARK: - GenericOptions
+enum GenericOptions {
+    static var defaultPlaybackSpeed: SettingsItem {
+        .init(
+            title: "SETTINGS_PLAYBACK_SPEED_DEFAULT",
+            subtitle: "1.00x",
+            action: .showActionSheet(title: "SETTINGS_PLAYBACK_SPEED_DEFAULT", preferenceKey: kVLCSettingPlaybackSpeedDefaultValue, hasInfo: false)
+        )
+    }
+
+    static var continueAudioPlayback: SettingsItem {
+        .init(
+            title: "SETTINGS_CONTINUE_AUDIO_PLAYBACK",
+            subtitle: "SETTINGS_CONTINUE_PLAYBACK_ALWAYS",
+            action: .showActionSheet(title: "SETTINGS_CONTINUE_AUDIO_PLAYBACK", preferenceKey: kVLCSettingContinueAudioPlayback, hasInfo: true)
+        )
+    }
+
+    static var playVideoInFullScreen: SettingsItem {
+        .init(
+            title: "SETTINGS_VIDEO_FULLSCREEN",
+            subtitle: nil,
+            action: .toggle(preferenceKey: kVLCSettingVideoFullscreenPlayback)
+        )
+    }
+
+    static var continueVideoPlayback: SettingsItem {
+        .init(
+            title: "SETTINGS_CONTINUE_VIDEO_PLAYBACK",
+            subtitle: "SETTINGS_CONTINUE_PLAYBACK_ALWAYS",
+            action: .showActionSheet(title: "SETTINGS_CONTINUE_VIDEO_PLAYBACK", preferenceKey: kVLCSettingContinuePlayback, hasInfo: true)
+        )
+    }
+
+    static var automaticallyPlayNextItem: SettingsItem {
+        .init(
+            title: "SETTINGS_NETWORK_PLAY_ALL",
+            subtitle: nil,
+            action: .showActionSheet(title: "SETTINGS_NETWORK_PLAY_ALL", preferenceKey: kVLCAutomaticallyPlayNextItem, hasInfo: false)
+        )
+    }
+
+    static var enableTextScrollingInMediaList: SettingsItem {
+        .init(
+            title: "SETTINGS_NETWORK_PLAY_ALL",
+            subtitle: nil,
+            action: .toggle(preferenceKey: kVLCSettingEnableMediaCellTextScrolling)
+        )
+    }
+
+    static var rememberPlayerState: SettingsItem {
+        .init(
+            title: "SETTINGS_REMEMBER_PLAYER_STATE",
+            subtitle: nil,
+            action: .toggle(preferenceKey: kVLCPlayerShouldRememberState)
+        )
+    }
+
+    static var restoreLastPlayedMedia: SettingsItem {
+        .init(
+            title: "SETTINGS_RESTORE_LAST_PLAYED_MEDIA",
+            subtitle: nil,
+            action: .toggle(preferenceKey: kVLCRestoreLastPlayedMedia)
+        )
+    }
+
+    static func section() -> SettingsSection? {
+        .init(title: "SETTINGS_GENERIC_TITLE", items: [
+            defaultPlaybackSpeed,
+            continueAudioPlayback,
+            playVideoInFullScreen,
+            continueVideoPlayback,
+            automaticallyPlayNextItem,
+            enableTextScrollingInMediaList,
+            rememberPlayerState,
+            restoreLastPlayedMedia
+        ])
     }
 
-    var subtitle: String? {
-        switch self {
-        case .defaultPlaybackSpeed:
-            return "1.00x"
-        case .continueAudioPlayback:
-            return "SETTINGS_CONTINUE_PLAYBACK_ALWAYS"
-        case .playVideoInFullScreen:
-            return nil
-        case .continueVideoPlayback:
-            return "SETTINGS_CONTINUE_PLAYBACK_ALWAYS"
-        case .automaticallyPlayNextItem:
-            return nil
-        case .enableTextScrollingInMediaList:
-            return nil
-        case .rememberPlayerState:
-            return nil
-        case .restoreLastPlayedMedia:
-            return nil
-        }
-    }
+}
 
-    var preferenceKey: String? {
-        switch self {
-        case .defaultPlaybackSpeed:
-            return kVLCSettingPlaybackSpeedDefaultValue
-        case .continueAudioPlayback:
-            return kVLCSettingContinueAudioPlayback
-        case .playVideoInFullScreen:
-            return kVLCSettingVideoFullscreenPlayback
-        case .continueVideoPlayback:
-            return kVLCSettingContinuePlayback
-        case .automaticallyPlayNextItem:
-            return kVLCAutomaticallyPlayNextItem
-        case .enableTextScrollingInMediaList:
-            return kVLCSettingEnableMediaCellTextScrolling
-        case .rememberPlayerState:
-            return kVLCPlayerShouldRememberState
-        case .restoreLastPlayedMedia:
-            return kVLCRestoreLastPlayedMedia
-        }
+// MARK: - PrivacyOptions
+enum PrivacyOptions {
+    static var passcodeLock: SettingsItem {
+        .init(
+            title: "SETTINGS_PASSCODE_LOCK",
+            subtitle: "SETTINGS_PASSCODE_LOCK_SUBTITLE",
+            action: .toggle(preferenceKey: kVLCSettingPasscodeOnKey)
+        )
     }
-}
 
-enum PrivacyOptions: Int, CaseIterable, SectionType {
-    case passcodeLock
-    case enableBiometrics
-    case hideLibraryInFilesApp
-
-    var description: String {
-        switch self {
-        case .passcodeLock:
-            return "SETTINGS_PASSCODE_LOCK"
-        case .enableBiometrics:
-            let authContext = LAContext()
-            let _ = authContext.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: nil)
+    static var enableBiometrics: SettingsItem? {
+        let authContext = LAContext()
+
+        if authContext.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: nil) {
             switch authContext.biometryType {
-            case .none:
-                return ""
             case .touchID:
-                return "SETTINGS_PASSCODE_LOCK_ALLOWTOUCHID"
+                return .init(
+                    title: "SETTINGS_PASSCODE_LOCK_ALLOWTOUCHID",
+                    subtitle: nil,
+                    action: .toggle(preferenceKey: kVLCSettingPasscodeAllowTouchID)
+                )
             case .faceID:
-                return "SETTINGS_PASSCODE_LOCK_ALLOWFACEID"
+                return .init(
+                    title: "SETTINGS_PASSCODE_LOCK_ALLOWFACEID",
+                    subtitle: nil,
+                    action: .toggle(preferenceKey: kVLCSettingPasscodeAllowFaceID)
+                )
+            case .none, .opticID:
+                fallthrough
             @unknown default:
-                return ""
+                return nil
             }
-        case .hideLibraryInFilesApp:
-            return "SETTINGS_HIDE_LIBRARY_IN_FILES_APP"
         }
-    }
 
-    var containsSwitch: Bool {
-        switch self {
-        case .passcodeLock:
-            return true
-        case .enableBiometrics:
-            return true
-        case .hideLibraryInFilesApp:
-            return true
-        }
+        return nil
     }
 
-    var containsInfobutton: Bool { return false }
-
-    var subtitle: String? {
-        switch self {
-        case .passcodeLock:
-            return "SETTINGS_PASSCODE_LOCK_SUBTITLE"
-        case .enableBiometrics:
-            return nil
-        case .hideLibraryInFilesApp:
-            return "SETTINGS_HIDE_LIBRARY_IN_FILES_APP_SUBTITLE"
-        }
+    static var hideLibraryInFilesApp: SettingsItem {
+        .init(
+            title: "SETTINGS_HIDE_LIBRARY_IN_FILES_APP",
+            subtitle: "SETTINGS_HIDE_LIBRARY_IN_FILES_APP_SUBTITLE",
+            action: .toggle(preferenceKey: kVLCSettingHideLibraryInFilesApp)
+        )
     }
 
-    var preferenceKey: String? {
-        switch self {
-        case .passcodeLock:
-            return kVLCSettingPasscodeOnKey
-        case .enableBiometrics:
-            let authContext = LAContext()
-                let _ = authContext.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: nil)
-                switch authContext.biometryType {
-                case .none:
-                    return nil
-                case .touchID:
-                    return kVLCSettingPasscodeAllowTouchID
-                case .faceID:
-                    return kVLCSettingPasscodeAllowFaceID
-                @unknown default:
-                    return nil
-                }
-        case .hideLibraryInFilesApp:
-            return kVLCSettingHideLibraryInFilesApp
-        }
+    static func section() -> SettingsSection? {
+        .init(title: "SETTINGS_PRIVACY_TITLE", items: [
+            passcodeLock,
+            enableBiometrics,
+            hideLibraryInFilesApp
+        ].compactMap({$0}))
     }
 }
 
-enum PlaybackControlOptions: Int, CaseIterable, SectionType {
-    case swipeUpDownForVolume
-    case twoFingerTap
-    case swipeUpDownForBrightness
-    case swipeRightLeftToSeek
-    case pinchToClose
-    case forwardBackwardEqual
-    case tapSwipeEqual
-    case forwardSkipLength
-    case backwardSkipLength
-    case forwardSkipLengthSwipe
-    case backwardSkipLengthSwipe
-    case longTouchToSpeedUp
-
-    var containsInfobutton: Bool { return false }
-
-    var containsSwitch: Bool {
-        switch self {
-        case .swipeUpDownForVolume:
-            return true
-        case .twoFingerTap:
-            return true
-        case .swipeUpDownForBrightness:
-            return true
-        case .swipeRightLeftToSeek:
-            return true
-        case .pinchToClose:
-            return true
-        case .forwardBackwardEqual:
-            return true
-        case .tapSwipeEqual:
-            return true
-        case .forwardSkipLength:
-            return false
-        case .backwardSkipLength:
-            return false
-        case .forwardSkipLengthSwipe:
-            return false
-        case .backwardSkipLengthSwipe:
-            return false
-        case .longTouchToSpeedUp:
-            return true
-        }
-    }
-
-    var description: String {
+// MARK: - GestureControlOptions
+enum GestureControlOptions {
+    static var swipeUpDownForVolume: SettingsItem {
+        .init(
+            title: "SETTINGS_GESTURES_VOLUME",
+            subtitle: nil,
+            action: .toggle(preferenceKey: kVLCSettingVolumeGesture)
+        )
+    }
+
+    static var twoFingerTap: SettingsItem {
+        .init(
+            title: "SETTINGS_GESTURES_PLAYPAUSE",
+            subtitle: nil,
+            action: .toggle(preferenceKey: kVLCSettingPlayPauseGesture)
+        )
+    }
+
+    static var swipeUpDownForBrightness: SettingsItem {
+        .init(
+            title: "SETTINGS_GESTURES_BRIGHTNESS",
+            subtitle: nil,
+            action: .toggle(preferenceKey: kVLCSettingBrightnessGesture)
+        )
+    }
+
+    static var swipeRightLeftToSeek: SettingsItem {
+        .init(
+            title: "SETTINGS_GESTURES_SEEK",
+            subtitle: nil,
+            action: .toggle(preferenceKey: kVLCSettingSeekGesture)
+        )
+    }
+
+    static var pinchToClose: SettingsItem {
+        .init(
+            title: "SETTINGS_GESTURES_CLOSE",
+            subtitle: nil,
+            action: .toggle(preferenceKey: kVLCSettingCloseGesture)
+        )
+    }
+
+    static var forwardBackwardEqual: SettingsItem {
+        .init(
+            title: "SETTINGS_GESTURES_FORWARD_BACKWARD_EQUAL",
+            subtitle: nil,
+            action: .toggle(preferenceKey: kVLCSettingPlaybackForwardBackwardEqual)
+        )
+    }
+
+    static var tapSwipeEqual: SettingsItem {
+        .init(
+            title: "SETTINGS_GESTURES_TAP_SWIPE_EQUAL",
+            subtitle: nil,
+            action: .toggle(preferenceKey: kVLCSettingPlaybackTapSwipeEqual)
+        )
+    }
+
+    static var forwardSkipLength: SettingsItem {
+        .init(
+            title: dynamicForwardSkipDescription(),
+            subtitle: nil,
+            action: .showActionSheet(title: dynamicForwardSkipDescription(), preferenceKey: kVLCSettingPlaybackForwardSkipLength, hasInfo: false)
+        )
+    }
+
+    static var backwardSkipLength: SettingsItem {
+        .init(
+            title: dynamicBackwardSkipDescription(),
+            subtitle: nil,
+            action: .showActionSheet(title: dynamicBackwardSkipDescription(), preferenceKey: kVLCSettingPlaybackBackwardSkipLength, hasInfo: false)
+        )
+    }
+
+    static var forwardSkipLengthSwipe: SettingsItem {
+        .init(
+            title: dynamicForwardSwipeDescription(),
+            subtitle: nil,
+            action: .showActionSheet(title: dynamicForwardSwipeDescription(), preferenceKey: kVLCSettingPlaybackForwardSkipLengthSwipe, hasInfo: false)
+        )
+    }
+
+    static var backwardSkipLengthSwipe: SettingsItem {
+        .init(
+            title: "SETTINGS_PLAYBACK_SKIP_BACKWARD_SWIPE",
+            subtitle: nil,
+            action: .showActionSheet(title: "SETTINGS_PLAYBACK_SKIP_BACKWARD_SWIPE", preferenceKey: kVLCSettingPlaybackBackwardSkipLengthSwipe, hasInfo: false)
+        )
+    }
+
+    static var longTouchToSpeedUp: SettingsItem {
+        .init(
+            title: "SETINGS_LONG_TOUCH_SPEED_UP",
+            subtitle: nil,
+            action: .toggle(preferenceKey: kVLCSettingPlaybackLongTouchSpeedUp)
+        )
+    }
+
+    static func section(isForwardBackwardEqual: Bool, isTapSwipeEqual: Bool) -> SettingsSection? {
+        .init(title: "SETTINGS_GESTURES", items: [
+            swipeUpDownForVolume,
+            twoFingerTap,
+            swipeUpDownForBrightness,
+            swipeRightLeftToSeek,
+            pinchToClose,
+            forwardBackwardEqual,
+            tapSwipeEqual,
+            forwardSkipLength,
+            isForwardBackwardEqual ? nil : backwardSkipLength,
+            isTapSwipeEqual ? nil : forwardSkipLengthSwipe,
+            (isTapSwipeEqual || isForwardBackwardEqual) ? nil : backwardSkipLengthSwipe,
+            longTouchToSpeedUp
+        ].compactMap({$0}))
+    }
+
+    private static func dynamicForwardSkipDescription() -> String {
         let forwardBackwardEqual = UserDefaults.standard.bool(forKey: kVLCSettingPlaybackForwardBackwardEqual)
         let tapSwipeEqual = UserDefaults.standard.bool(forKey: kVLCSettingPlaybackTapSwipeEqual)
-        switch self {
-        case .swipeUpDownForVolume:
-            return "SETTINGS_GESTURES_VOLUME"
-        case .twoFingerTap:
-            return "SETTINGS_GESTURES_PLAYPAUSE"
-        case .swipeUpDownForBrightness:
-            return "SETTINGS_GESTURES_BRIGHTNESS"
-        case .swipeRightLeftToSeek:
-            return "SETTINGS_GESTURES_SEEK"
-        case .pinchToClose:
-            return "SETTINGS_GESTURES_CLOSE"
-        case .forwardBackwardEqual:
-            return "SETTINGS_GESTURES_FORWARD_BACKWARD_EQUAL"
-        case .tapSwipeEqual:
-            return "SETTINGS_GESTURES_TAP_SWIPE_EQUAL"
-        case .forwardSkipLength:
-            if forwardBackwardEqual && tapSwipeEqual {
-                return "SETTINGS_PLAYBACK_SKIP_GENERIC"
-            } else if forwardBackwardEqual && !tapSwipeEqual {
-                return "SETTINGS_PLAYBACK_SKIP_TAP"
-            } else if !forwardBackwardEqual && !tapSwipeEqual {
-                return "SETTINGS_PLAYBACK_SKIP_FORWARD_TAP"
-            }
-            return  "SETTINGS_PLAYBACK_SKIP_FORWARD"
-        case .backwardSkipLength:
-            if tapSwipeEqual {
-                return "SETTINGS_PLAYBACK_SKIP_BACKWARD"
-            }
-            return "SETTINGS_PLAYBACK_SKIP_BACKWARD_TAP"
-        case .forwardSkipLengthSwipe:
-            if forwardBackwardEqual {
-                return "SETTINGS_PLAYBACK_SKIP_SWIPE"
-            }
-            return "SETTINGS_PLAYBACK_SKIP_FORWARD_SWIPE"
-        case .backwardSkipLengthSwipe:
-            return "SETTINGS_PLAYBACK_SKIP_BACKWARD_SWIPE"
-        case .longTouchToSpeedUp:
-            return "SETINGS_LONG_TOUCH_SPEED_UP"
-        }
-    }
-
-    var subtitle: String? { return nil }
 
-    var preferenceKey: String? {
-        switch self {
-        case .swipeUpDownForVolume:
-            return kVLCSettingVolumeGesture
-        case .twoFingerTap:
-            return kVLCSettingPlayPauseGesture
-        case .swipeUpDownForBrightness:
-            return kVLCSettingBrightnessGesture
-        case .swipeRightLeftToSeek:
-            return kVLCSettingSeekGesture
-        case .pinchToClose:
-            return kVLCSettingCloseGesture
-        case .forwardBackwardEqual:
-            return kVLCSettingPlaybackForwardBackwardEqual
-        case .tapSwipeEqual:
-            return kVLCSettingPlaybackTapSwipeEqual
-        case .forwardSkipLength:
-            return kVLCSettingPlaybackForwardSkipLength
-        case .backwardSkipLength:
-            return kVLCSettingPlaybackBackwardSkipLength
-        case .forwardSkipLengthSwipe:
-            return kVLCSettingPlaybackForwardSkipLengthSwipe
-        case .backwardSkipLengthSwipe:
-            return kVLCSettingPlaybackBackwardSkipLengthSwipe
-        case .longTouchToSpeedUp:
-            return kVLCSettingPlaybackLongTouchSpeedUp
+        if forwardBackwardEqual && tapSwipeEqual {
+            return "SETTINGS_PLAYBACK_SKIP_GENERIC"
+        } else if forwardBackwardEqual && !tapSwipeEqual {
+            return "SETTINGS_PLAYBACK_SKIP_TAP"
+        } else if !forwardBackwardEqual && !tapSwipeEqual {
+            return "SETTINGS_PLAYBACK_SKIP_FORWARD_TAP"
+        } else {
+            return "SETTINGS_PLAYBACK_SKIP_FORWARD"
         }
     }
-}
 
-enum VideoOptions: Int, CaseIterable, SectionType {
-    case deBlockingFilter
-    case deInterlace
-    case hardwareDecoding
-    case rememberPlayerBrightness
-
-    var description: String {
-        switch self {
-        case .deBlockingFilter:
-            return "SETTINGS_SKIP_LOOP_FILTER"
-        case .deInterlace:
-            return "SETTINGS_DEINTERLACE"
-        case .hardwareDecoding:
-            return "SETTINGS_HWDECODING"
-        case .rememberPlayerBrightness:
-            return "SETTINGS_REMEMBER_PLAYER_BRIGHTNESS"
-        }
-    }
+    private static func dynamicBackwardSkipDescription() -> String {
+        let tapSwipeEqual = UserDefaults.standard.bool(forKey: kVLCSettingPlaybackTapSwipeEqual)
 
-    var containsSwitch: Bool {
-        switch self {
-        case .deBlockingFilter:
-            return false
-        case .deInterlace:
-            return false
-        case .hardwareDecoding:
-            return false
-        case .rememberPlayerBrightness:
-            return true
+        if tapSwipeEqual {
+            return "SETTINGS_PLAYBACK_SKIP_BACKWARD"
+        } else {
+            return "SETTINGS_PLAYBACK_SKIP_BACKWARD_TAP"
         }
     }
 
-    var containsInfobutton: Bool {
-        switch self {
-        case .deBlockingFilter:
-            return true
-        case .deInterlace:
-            return true
-        case .hardwareDecoding:
-            return true
-        case .rememberPlayerBrightness:
-            return false
-        }
-    }
+    private static func dynamicForwardSwipeDescription() -> String {
+        let forwardBackwardEqual = UserDefaults.standard.bool(forKey: kVLCSettingPlaybackForwardBackwardEqual)
 
-    var subtitle: String? {
-        switch self {
-        case .deBlockingFilter:
-            return "SETTINGS_SKIP_LOOP_FILTER_NONREF"
-        case .deInterlace:
-            return "SETTINGS_DEINTERLACE_OFF"
-        case .hardwareDecoding:
-            return "SETTINGS_HWDECODING_ON"
-        case .rememberPlayerBrightness:
-            return nil
+        if forwardBackwardEqual {
+            return "SETTINGS_PLAYBACK_SKIP_SWIPE"
+        } else {
+            return "SETTINGS_PLAYBACK_SKIP_FORWARD_SWIPE"
         }
     }
+}
 
-    var preferenceKey: String? {
-        switch self {
-        case .deBlockingFilter:
-            return kVLCSettingSkipLoopFilter
-        case .deInterlace:
-            return kVLCSettingDeinterlace
-        case .hardwareDecoding:
-            return kVLCSettingHardwareDecoding
-        case .rememberPlayerBrightness:
-            return kVLCPlayerShouldRememberBrightness
-        }
+// MARK: - PlaybackControlOptions
+enum PlaybackControlOptions {
+    static var swipeUpDownForVolume: SettingsItem {
+        .init(
+            title: "SETTINGS_GESTURES_VOLUME",
+            subtitle: nil,
+            action: .toggle(preferenceKey: kVLCSettingVolumeGesture)
+        )
+    }
+
+    static var twoFingerTap: SettingsItem {
+        .init(
+            title: "SETTINGS_GESTURES_PLAYPAUSE",
+            subtitle: nil,
+            action: .toggle(preferenceKey: kVLCSettingPlayPauseGesture)
+        )
+    }
+
+    static var swipeUpDownForBrightness: SettingsItem {
+        .init(
+            title: "SETTINGS_GESTURES_BRIGHTNESS",
+            subtitle: nil,
+            action: .toggle(preferenceKey: kVLCSettingBrightnessGesture)
+        )
+    }
+
+    static var swipeRightLeftToSeek: SettingsItem {
+        .init(
+            title: "SETTINGS_GESTURES_SEEK",
+            subtitle: nil,
+            action: .toggle(preferenceKey: kVLCSettingSeekGesture)
+        )
+    }
+
+    static var longTouchToSpeedUp: SettingsItem {
+        .init(
+            title: "SETINGS_LONG_TOUCH_SPEED_UP",
+            subtitle: nil,
+            action: .toggle(preferenceKey: kVLCSettingPlaybackLongTouchSpeedUp)
+        )
+    }
+
+    static func section() -> SettingsSection? {
+        .init(title: "SETTINGS_GESTURES", items: [
+            swipeUpDownForVolume,
+            twoFingerTap,
+            swipeUpDownForBrightness,
+            swipeRightLeftToSeek,
+            longTouchToSpeedUp
+        ])
     }
 }
 
-enum SubtitlesOptions: Int, CaseIterable, SectionType {
-    case disableSubtitles
-    case font
-    case relativeFontSize
-    case useBoldFont
-    case fontColor
-    case textEncoding
-
-    var description: String {
-        switch self {
-        case .disableSubtitles:
-            return "SETTINGS_SUBTITLES_DISABLE"
-        case .font:
-            return "SETTINGS_SUBTITLES_FONT"
-        case .relativeFontSize:
-            return "SETTINGS_SUBTITLES_FONTSIZE"
-        case .useBoldFont:
-            return "SETTINGS_SUBTITLES_BOLDFONT"
-        case .fontColor:
-            return "SETTINGS_SUBTITLES_FONTCOLOR"
-        case .textEncoding:
-            return "SETTINGS_SUBTITLES_TEXT_ENCODING"
-        }
+// MARK: - VideoOptions
+enum VideoOptions {
+    static var deBlockingFilter: SettingsItem {
+        .init(
+            title: "SETTINGS_SKIP_LOOP_FILTER",
+            subtitle: "SETTINGS_SKIP_LOOP_FILTER_NONREF",
+            action: .showActionSheet(title: "SETTINGS_SKIP_LOOP_FILTER", preferenceKey: kVLCSettingSkipLoopFilter, hasInfo: true)
+        )
     }
 
-    var containsSwitch: Bool {
-        switch self {
-        case .disableSubtitles:
-            return true
-        case .font:
-            return false
-        case .relativeFontSize:
-            return false
-        case .useBoldFont:
-            return true
-        case .fontColor:
-            return false
-        case .textEncoding:
-            return false
-        }
+    static var deInterlace: SettingsItem {
+        .init(
+            title: "SETTINGS_DEINTERLACE",
+            subtitle: "SETTINGS_DEINTERLACE_OFF",
+            action: .showActionSheet(title: "SETTINGS_DEINTERLACE", preferenceKey: kVLCSettingDeinterlace, hasInfo: true)
+        )
     }
 
-    var subtitle: String? {
-        switch self {
-        case .disableSubtitles:
-            return "SETTINGS_SUBTITLES_DISABLE_LONG"
-        case .font:
-            return "Arial"
-        case .relativeFontSize:
-            return "SETTINGS_SUBTITLES_FONTSIZE_NORMAL"
-        case .useBoldFont:
-            return nil
-        case .fontColor:
-            return "SETTINGS_SUBTITLES_FONTCOLOR_BLACK"
-        case .textEncoding:
-            return "Western European (Windows-1252)"
-        }
+    static var hardwareDecoding: SettingsItem {
+        .init(
+            title: "SETTINGS_HWDECODING",
+            subtitle: "SETTINGS_HWDECODING_ON",
+            action: .showActionSheet(title: "SETTINGS_HWDECODING", preferenceKey: kVLCSettingHardwareDecoding, hasInfo: true)
+        )
     }
 
-    var preferenceKey: String? {
-        switch self {
-        case .disableSubtitles:
-            return kVLCSettingDisableSubtitles
-        case .font:
-            return kVLCSettingSubtitlesFont
-        case .relativeFontSize:
-            return kVLCSettingSubtitlesFontSize
-        case .useBoldFont:
-            return kVLCSettingSubtitlesBoldFont
-        case .fontColor:
-            return kVLCSettingSubtitlesFontColor
-        case .textEncoding:
-            return kVLCSettingTextEncoding
-        }
+    static var rememberPlayerBrightness: SettingsItem {
+        .init(
+            title: "SETTINGS_REMEMBER_PLAYER_BRIGHTNESS",
+            subtitle: nil,
+            action: .toggle(preferenceKey: kVLCPlayerShouldRememberBrightness)
+        )
     }
 
-    var containsInfobutton: Bool { return true }
+    static func section() -> SettingsSection? {
+        .init(title: "SETTINGS_VIDEO_TITLE", items: [
+            deBlockingFilter,
+            deInterlace,
+            hardwareDecoding,
+            rememberPlayerBrightness
+        ])
+    }
 }
 
-enum CastingOptions: Int, CaseIterable, SectionType {
-    case audioPassThrough
-    case conversionQuality
-
-    var description: String {
-        switch self {
-        case .audioPassThrough:
-            return "SETTINGS_PTCASTING"
-        case .conversionQuality:
-            return "SETTINGS_CASTING_CONVERSION_QUALITY"
-        }
+// MARK: - SubtitlesOptions
+enum SubtitlesOptions {
+    static var disableSubtitles: SettingsItem {
+        .init(
+            title: "SETTINGS_SUBTITLES_DISABLE",
+            subtitle: "SETTINGS_SUBTITLES_DISABLE_LONG",
+            action: .toggle(preferenceKey: kVLCSettingDisableSubtitles)
+        )
+    }
+
+    static var font: SettingsItem {
+        .init(
+            title: "SETTINGS_SUBTITLES_FONT",
+            subtitle: "Arial",
+            action: .showActionSheet(title: "SETTINGS_SUBTITLES_FONT", preferenceKey: kVLCSettingSubtitlesFont, hasInfo: true)
+        )
+    }
+
+    static var relativeFontSize: SettingsItem {
+        .init(
+            title: "SETTINGS_SUBTITLES_FONTSIZE",
+            subtitle: "SETTINGS_SUBTITLES_FONTSIZE_NORMAL",
+            action: .showActionSheet(title: "SETTINGS_SUBTITLES_FONTSIZE", preferenceKey: kVLCSettingSubtitlesFontSize, hasInfo: true)
+        )
+    }
+
+    static var useBoldFont: SettingsItem {
+        .init(
+            title: "SETTINGS_SUBTITLES_BOLDFONT",
+            subtitle: nil,
+            action: .toggle(preferenceKey: kVLCSettingSubtitlesBoldFont)
+        )
+    }
+
+    static var fontColor: SettingsItem {
+        .init(
+            title: "SETTINGS_SUBTITLES_FONTCOLOR",
+            subtitle: "SETTINGS_SUBTITLES_FONTCOLOR_BLACK",
+            action: .showActionSheet(title: "SETTINGS_SUBTITLES_FONTCOLOR", preferenceKey: kVLCSettingSubtitlesFontColor, hasInfo: true)
+        )
+    }
+
+    static var textEncoding: SettingsItem {
+        .init(
+            title: "SETTINGS_SUBTITLES_TEXT_ENCODING",
+            subtitle: "Western European (Windows-1252)",
+            action: .showActionSheet(title: "SETTINGS_SUBTITLES_TEXT_ENCODING", preferenceKey: kVLCSettingTextEncoding, hasInfo: true)
+        )
+    }
+
+    static func section() -> SettingsSection? {
+        .init(title: "SETTINGS_SUBTITLES_TITLE", items: [
+            disableSubtitles,
+            font,
+            relativeFontSize,
+            useBoldFont,
+            fontColor,
+            textEncoding
+        ])
     }
+}
 
-    var containsSwitch: Bool {
-        switch self {
-        case .audioPassThrough:
-            return true
-        case .conversionQuality:
-            return false
-        }
+// MARK: - CastingOptions
+enum CastingOptions {
+    static var audioPassThrough: SettingsItem {
+        .init(
+            title: "SETTINGS_PTCASTING",
+            subtitle: "SETTINGS_PTCASTINGLONG",
+            action: .toggle(preferenceKey: kVLCSettingCastingAudioPassthrough)
+        )
     }
 
-    var preferenceKey: String? {
-        switch self {
-        case .audioPassThrough:
-            return kVLCSettingCastingAudioPassthrough
-        case .conversionQuality:
-            return kVLCSettingCastingConversionQuality
-        }
+    static var conversionQuality: SettingsItem {
+        .init(
+            title: "SETTINGS_CASTING_CONVERSION_QUALITY",
+            subtitle: "SETTINGS_MEDIUM",
+            action: .showActionSheet(title: "SETTINGS_CASTING_CONVERSION_QUALITY", preferenceKey: kVLCSettingCastingConversionQuality, hasInfo: false)
+        )
     }
 
-    var subtitle: String? {
-        switch self {
-        case .audioPassThrough:
-            return "SETTINGS_PTCASTINGLONG"
-        case .conversionQuality:
-            return "SETTINGS_MEDIUM"
-        }
+    static func section() -> SettingsSection? {
+        .init(title: "SETTINGS_CASTING", items: [
+            audioPassThrough,
+            conversionQuality
+        ])
     }
-
-    var containsInfobutton: Bool { return false }
 }
 
-enum AudioOptions: Int, CaseIterable, SectionType {
-    case preampLevel
-    case timeStretchingAudio
-    case audioPlaybackInBackground
-
-    var description: String {
-        switch self {
-        case .preampLevel:
-            return "SETTINGS_AUDIO_PREAMP_LEVEL"
-        case .timeStretchingAudio:
-            return "SETTINGS_TIME_STRETCH_AUDIO"
-        case .audioPlaybackInBackground:
-            return "SETTINGS_BACKGROUND_AUDIO"
-        }
-    }
-
-    var containsSwitch: Bool {
-        switch self {
-        case .preampLevel:
-            return false
-        default:
-            return true
-        }
-    }
-    var subtitle: String? {
-        switch self {
-        case .preampLevel:
-            return "6 dB"
-        case .timeStretchingAudio:
-            return "SETTINGS_TIME_STRETCH_AUDIO_LONG"
-        default:
-            return nil
-        }
+// MARK: - AudioOptions
+enum AudioOptions {
+    static var preampLevel: SettingsItem {
+        .init(
+            title: "SETTINGS_AUDIO_PREAMP_LEVEL",
+            subtitle: "6 dB",
+            action: .showActionSheet(title: "SETTINGS_AUDIO_PREAMP_LEVEL", preferenceKey: kVLCSettingDefaultPreampLevel, hasInfo: false)
+        )
     }
 
-    var preferenceKey: String? {
-        switch self {
-        case .preampLevel:
-            return kVLCSettingDefaultPreampLevel
-        case .timeStretchingAudio:
-            return kVLCSettingStretchAudio
-        case .audioPlaybackInBackground:
-            return kVLCSettingContinueAudioInBackgroundKey
-        }
+    static var timeStretchingAudio: SettingsItem {
+        .init(
+            title: "SETTINGS_TIME_STRETCH_AUDIO",
+            subtitle: "SETTINGS_TIME_STRETCH_AUDIO_LONG",
+            action: .toggle(preferenceKey: kVLCSettingStretchAudio)
+        )
     }
 
-    var containsInfobutton: Bool { return false }
-}
-
-enum MediaLibraryOptions: Int, CaseIterable, SectionType {
-    case forceVLCToRescanTheMediaLibrary
-    case optimiseItemNamesForDisplay
-    case disableGrouping
-    case showVideoThumbnails
-    case showAudioArtworks
-    case includeMediaLibInDeviceBackup
-
-    var description: String {
-        switch self {
-        case .forceVLCToRescanTheMediaLibrary:
-            return "SETTINGS_MEDIA_LIBRARY_RESCAN"
-        case .optimiseItemNamesForDisplay:
-            return "SETTINGS_DECRAPIFY"
-        case .disableGrouping:
-            return "SETTINGS_DISABLE_GROUPING"
-        case .showVideoThumbnails:
-            return "SETTINGS_SHOW_THUMBNAILS"
-        case .showAudioArtworks:
-            return "SETTINGS_SHOW_ARTWORKS"
-        case .includeMediaLibInDeviceBackup:
-            return "SETTINGS_BACKUP_MEDIA_LIBRARY"
-        }
+    static var audioPlaybackInBackground: SettingsItem {
+        .init(
+            title: "SETTINGS_BACKGROUND_AUDIO",
+            subtitle: nil,
+            action: .toggle(preferenceKey: kVLCSettingContinueAudioInBackgroundKey)
+        )
     }
 
-    var containsSwitch: Bool {
-        switch self {
-        case .forceVLCToRescanTheMediaLibrary:
-            return false
-        default:
-            return true
-        }
+    static func section() -> SettingsSection? {
+        .init(title: "SETTINGS_AUDIO_TITLE", items: [
+            preampLevel,
+            timeStretchingAudio,
+            audioPlaybackInBackground
+        ])
     }
+}
 
-    var subtitle: String? { return nil }
-
-    var preferenceKey: String? {
-        switch self {
-        case .forceVLCToRescanTheMediaLibrary:
-            return nil
-        case .optimiseItemNamesForDisplay:
-            return kVLCSettingsDecrapifyTitles
-        case .disableGrouping:
-            return kVLCSettingsDisableGrouping
-        case .showVideoThumbnails:
-            return kVLCSettingShowThumbnails
-        case .showAudioArtworks:
-            return kVLCSettingShowArtworks
-        case .includeMediaLibInDeviceBackup:
-            return kVLCSettingBackupMediaLibrary
-        }
+// MARK: - MediaLibraryOptions
+enum MediaLibraryOptions {
+    static var forceVLCToRescanTheMediaLibrary: SettingsItem {
+        .init(
+            title: "SETTINGS_MEDIA_LIBRARY_RESCAN",
+            subtitle: nil,
+            action: .forceRescanAlert,
+            emphasizedTitle: true
+        )
+    }
+
+    static var optimiseItemNamesForDisplay: SettingsItem {
+        .init(
+            title: "SETTINGS_DECRAPIFY",
+            subtitle: nil,
+            action: .toggle(preferenceKey: kVLCSettingsDecrapifyTitles)
+        )
+    }
+
+    static var disableGrouping: SettingsItem {
+        .init(
+            title: "SETTINGS_DISABLE_GROUPING",
+            subtitle: nil,
+            action: .toggle(preferenceKey: kVLCSettingsDisableGrouping)
+        )
+    }
+
+    static var showVideoThumbnails: SettingsItem {
+        .init(
+            title: "SETTINGS_SHOW_THUMBNAILS",
+            subtitle: nil,
+            action: .toggle(preferenceKey: kVLCSettingShowThumbnails)
+        )
+    }
+
+    static var showAudioArtworks: SettingsItem {
+        .init(
+            title: "SETTINGS_SHOW_ARTWORKS",
+            subtitle: nil,
+            action: .toggle(preferenceKey: kVLCSettingShowArtworks)
+        )
+    }
+
+    static var includeMediaLibInDeviceBackup: SettingsItem {
+        .init(
+            title: "SETTINGS_BACKUP_MEDIA_LIBRARY",
+            subtitle: nil,
+            action: .toggle(preferenceKey: kVLCSettingBackupMediaLibrary)
+        )
+    }
+
+    static var includeMediaLibInDeviceBackupWhenBackingUp: SettingsItem {
+        .init(
+            title: "SETTINGS_BACKUP_MEDIA_LIBRARY",
+            subtitle: nil,
+            action: .isLoading
+        )
+    }
+
+    static func section(isBackingUp: Bool) -> SettingsSection? {
+        .init(title: "SETTINGS_MEDIA_LIBRARY", items: [
+            forceVLCToRescanTheMediaLibrary,
+            optimiseItemNamesForDisplay,
+            disableGrouping,
+            showVideoThumbnails,
+            showAudioArtworks,
+            {
+                if isBackingUp {
+                    return includeMediaLibInDeviceBackupWhenBackingUp
+                } else {
+                    return includeMediaLibInDeviceBackup
+                }
+            }()
+        ])
     }
-
-    var containsInfobutton: Bool { return false }
 }
 
-enum NetworkOptions: Int, CaseIterable, SectionType {
-    case networkCachingLevel
-    case ipv6SupportForWiFiSharing
-    case forceSMBv1
-    case rtspctp
-
-    var description: String {
-        switch self {
-        case .networkCachingLevel:
-            return "SETTINGS_NETWORK_CACHING_TITLE"
-        case .ipv6SupportForWiFiSharing:
-            return "SETTINGS_WIFISHARING_IPv6"
-        case .forceSMBv1:
-            return "SETTINGS_FORCE_SMBV1"
-        case .rtspctp:
-            return "SETTINGS_RTSP_TCP"
-        }
+// MARK: - NetworkOptions
+enum NetworkOptions {
+    static var networkCachingLevel: SettingsItem {
+        .init(
+            title: "SETTINGS_NETWORK_CACHING_TITLE",
+            subtitle: "SETTINGS_NETWORK_CACHING_LEVEL_NORMAL",
+            action: .showActionSheet(title: "SETTINGS_NETWORK_CACHING_TITLE", preferenceKey: kVLCSettingNetworkCaching, hasInfo: true)
+        )
     }
 
-    var containsSwitch: Bool {
-        switch self {
-        case .networkCachingLevel:
-            return false
-        case .ipv6SupportForWiFiSharing:
-            return true
-        case .forceSMBv1:
-            return true
-        case .rtspctp:
-            return true
-        }
+    static var ipv6SupportForWiFiSharing: SettingsItem {
+        .init(
+            title: "SETTINGS_WIFISHARING_IPv6",
+            subtitle: nil,
+            action: .toggle(preferenceKey: kVLCSettingWiFiSharingIPv6)
+        )
     }
 
-    var subtitle: String? {
-        switch self {
-        case .networkCachingLevel:
-            return "SETTINGS_NETWORK_CACHING_LEVEL_NORMAL"
-        case .ipv6SupportForWiFiSharing:
-            return nil
-        case .forceSMBv1:
-            return "SETTINGS_FORCE_SMBV1_LONG"
-        case .rtspctp:
-            return nil
-        }
+    static var forceSMBv1: SettingsItem {
+        .init(
+            title: "SETTINGS_FORCE_SMBV1",
+            subtitle: "SETTINGS_FORCE_SMBV1_LONG",
+            action: .toggle(preferenceKey: kVLCForceSMBV1)
+        )
     }
 
-    var preferenceKey: String? {
-        switch self {
-        case .networkCachingLevel:
-            return kVLCSettingNetworkCaching
-        case .ipv6SupportForWiFiSharing:
-            return kVLCSettingWiFiSharingIPv6
-        case .forceSMBv1:
-            return kVLCForceSMBV1
-        case .rtspctp:
-            return kVLCSettingNetworkRTSPTCP
-        }
+    static var rtspctp: SettingsItem {
+        .init(
+            title: "SETTINGS_RTSP_TCP",
+            subtitle: nil,
+            action: .toggle(preferenceKey: kVLCSettingNetworkRTSPTCP)
+        )
     }
 
-    var containsInfobutton: Bool {
-        switch self {
-        case .networkCachingLevel:
-            return true
-        case .ipv6SupportForWiFiSharing:
-            return false
-        case .forceSMBv1:
-            return false
-        case .rtspctp:
-            return false
-        }
+    static func section() -> SettingsSection? {
+        .init(title: "SETTINGS_NETWORK", items: [
+            networkCachingLevel,
+            ipv6SupportForWiFiSharing,
+            forceSMBv1,
+            rtspctp
+        ])
     }
 }
 
-enum Lab: Int, CaseIterable, SectionType {
-    case debugLogging
-    case exportLibrary
-
-    var description: String {
-        switch self {
-        case .debugLogging:
-            return "SETTINGS_DEBUG_LOG"
-        case .exportLibrary:
-            return "SETTINGS_EXPORT_LIBRARY"
-        }
+// MARK: - Lab
+enum Lab {
+    static var debugLogging: SettingsItem {
+        .init(
+            title: "SETTINGS_DEBUG_LOG",
+            subtitle: nil,
+            action: .toggle(preferenceKey: kVLCSaveDebugLogs)
+        )
     }
 
-    var containsSwitch: Bool {
-        switch self {
-        case .exportLibrary:
-            return false
-        default:
-            return true
-        }
+    static var exportLibrary: SettingsItem {
+        .init(
+            title: "SETTINGS_EXPORT_LIBRARY",
+            subtitle: nil,
+            action: .exportMediaLibrary
+        )
     }
 
-    var subtitle: String? { return nil }
+    static func section(isLabActivated: Bool) -> SettingsSection? {
+        guard isLabActivated else { return nil }
 
-    var preferenceKey: String? {
-        switch self {
-        case .debugLogging:
-            return kVLCSaveDebugLogs
-        case .exportLibrary:
-            return nil
-        }
+        return .init(title: "SETTINGS_LAB", items: [
+            debugLogging,
+            exportLibrary
+        ])
     }
-
-    var containsInfobutton: Bool { return false }
 }
 
-enum Reset: Int, CaseIterable, SectionType {
-    case resetOptions
-
-    var containsSwitch: Bool { return false }
-
-    var subtitle: String? { return nil }
-
-    var preferenceKey: String? { return kVLCResetSettings }
-
-    var containsInfobutton: Bool { return false }
+// MARK: - Reset
+enum Reset {
+    static var resetOptions: SettingsItem {
+        .init(
+            title: "SETTINGS_RESET",
+            subtitle: nil,
+            action: .displayResetAlert
+        )
+    }
 
-    var description: String { return "SETTINGS_RESET" }
+    static func section() -> SettingsSection? {
+        .init(title: "SETTINGS_RESET_TITLE", items: [resetOptions])
+    }
 }
diff --git a/Sources/Settings/View/SettingsCell.swift b/Sources/Settings/View/SettingsCell.swift
index a076c54a9e6c823e936f03d76404dbc70b8cbff0..0b01c47cf5db9e65b5f30c755d29881d204da75c 100644
--- a/Sources/Settings/View/SettingsCell.swift
+++ b/Sources/Settings/View/SettingsCell.swift
@@ -11,40 +11,11 @@
 
 import UIKit
 
-protocol SectionType: CustomStringConvertible {
-    var containsSwitch: Bool { get }
-    var subtitle: String? { get }
-    var preferenceKey: String? { get }
-    var containsInfobutton: Bool { get }
-}
-
-protocol PasscodeActivateDelegate: AnyObject {
-    func passcodeLockSwitchOn(state: Bool)
-}
-
-protocol MedialibraryHidingActivateDelegate: AnyObject {
-    func medialibraryHidingLockSwitchOn(state: Bool)
-}
-
-protocol MediaLibraryBackupActivateDelegate: AnyObject {
-    func mediaLibraryBackupActivateSwitchOn(state: Bool)
-}
-
-protocol MediaLibraryDisableGroupingDelegate: AnyObject {
-    func medialibraryDisableGroupingSwitchOn(state: Bool)
-}
-
 class SettingsCell: UITableViewCell {
 
-    private let userDefaults = UserDefaults.standard
-    private let notificationCenter = NotificationCenter.default
+    private var userDefaults: UserDefaults { UserDefaults.standard }
+    private var notificationCenter: NotificationCenter { NotificationCenter.default }
     var settingsBundle = Bundle()
-    var showsActivityIndicator = false
-    weak var passcodeSwitchDelegate: PasscodeActivateDelegate?
-    weak var skipDurationDelegate: UITableViewController?
-    weak var medialibraryHidingSwitchDelegate: MedialibraryHidingActivateDelegate?
-    weak var mediaLibraryBackupSwitchDelegate: MediaLibraryBackupActivateDelegate?
-    weak var medialibraryDisableGroupingSwitchDelegate: MediaLibraryDisableGroupingDelegate?
 
     lazy var switchControl: UISwitch = {
         let switchControl = UISwitch()
@@ -98,54 +69,78 @@ class SettingsCell: UITableViewCell {
         return stackView
     }()
 
-    var sectionType: SectionType? {
+    var settingsItem: SettingsItem? {
         didSet {
-            guard let sectionType = sectionType else {
+            guard let settingsItem = settingsItem else {
                 assertionFailure("No Section Type provided")
                 return
             }
-            mainLabel.text = settingsBundle.localizedString(forKey: sectionType.description, value: sectionType.description, table: "Root")
-            if let subtitle = sectionType.subtitle {
+
+            mainLabel.text = settingsBundle.localizedString(forKey: settingsItem.title, value: settingsItem.title, table: "Root")
+
+            mainLabel.textColor = settingsItem.emphasizedTitle
+                ? PresentationTheme.current.colors.orangeUI
+                : PresentationTheme.current.colors.cellTextColor
+
+            if let subtitle = settingsItem.subtitle {
                 //Handles No Value (No user-defaults value set) case
                 subtitleLabel.text = settingsBundle.localizedString(forKey: subtitle, value: subtitle, table: "Root")
             }
             else {
-                subtitleLabel.text = sectionType.subtitle
+                subtitleLabel.text = settingsItem.subtitle
             }
-            switchControl.isHidden = !sectionType.containsSwitch
-            infoButton.isHidden = !sectionType.containsInfobutton
-            if switchControl.isHidden && infoButton.isHidden {
+
+            switch settingsItem.action {
+            case .isLoading:
+                switchControl.isHidden = true
+                infoButton.isHidden = true
+                activityIndicator.isHidden = false
+                accessoryView = .none
+                accessoryType = .none
+                selectionStyle = .none
+            case .toggle(_):
+                switchControl.isHidden = false
+                infoButton.isHidden = true
+                activityIndicator.isHidden = true
+                accessoryView = switchControl
+                accessoryType = .none
+                selectionStyle = .none
+            case .showActionSheet(_, _, let hasInfo):
+                switchControl.isHidden = true
+                infoButton.isHidden = !hasInfo
+                activityIndicator.isHidden = true
                 accessoryView = .none
                 accessoryType = .disclosureIndicator
                 selectionStyle = .default
+            case .donation:
+                switchControl.isHidden = true
+                infoButton.isHidden = true
+                activityIndicator.isHidden = true
+                accessoryView = .none
+                accessoryType = .disclosureIndicator
+                selectionStyle = .default
+            case .openPrivacySettings:
+                switchControl.isHidden = true
+                infoButton.isHidden = true
+                activityIndicator.isHidden = true
+                accessoryView = .none
+                accessoryType = .disclosureIndicator
+                selectionStyle = .default
+            case .forceRescanAlert, .exportMediaLibrary, .displayResetAlert:
+                switchControl.isHidden = true
+                infoButton.isHidden = true
+                activityIndicator.isHidden = true
+                accessoryView = .none
+                accessoryType = .none
+                selectionStyle = .default
             }
-            else {
-                //When Media Library is adding or removing files to device backup
-                //We show a Activity Indicator instead of a switch while the process
-                //is going on. On completion, we show the switch again
-                if showsActivityIndicator && sectionType.preferenceKey == kVLCSettingBackupMediaLibrary {
-                    activityIndicator.isHidden = false
-                    accessoryView = .none
-                    selectionStyle = .none
-                } else {
-                    if switchControl.isHidden == false {
-                        activityIndicator.isHidden = true
-                        accessoryView = switchControl
-                        selectionStyle = .none
-                    } else {
-                        addSubview(infoButton)
-                        infoButton.translatesAutoresizingMaskIntoConstraints = false
-                        NSLayoutConstraint.activate([
-                            infoButton.centerYAnchor.constraint(equalTo: stackView.centerYAnchor),
-                            infoButton.trailingAnchor.constraint(equalTo: safeAreaLayoutGuide.trailingAnchor, constant: -40)
-                        ])
-
-                        accessoryView = .none
-                        accessoryType = .disclosureIndicator
-                        selectionStyle = .default
-                    }
-                }
+
+            if !activityIndicator.isHidden {
+                activityIndicator.startAnimating()
+            } else {
+                activityIndicator.stopAnimating()
             }
+
             updateSwitch()
             updateSubtitle()
         }
@@ -189,6 +184,14 @@ class SettingsCell: UITableViewCell {
             activityIndicator.centerYAnchor.constraint(equalTo: stackView.centerYAnchor)
         ])
         activityIndicator.isHidden = true
+
+        addSubview(infoButton)
+        infoButton.translatesAutoresizingMaskIntoConstraints = false
+        NSLayoutConstraint.activate([
+            infoButton.centerYAnchor.constraint(equalTo: stackView.centerYAnchor),
+            infoButton.trailingAnchor.constraint(equalTo: layoutGuide.trailingAnchor, constant: -40)
+        ])
+        infoButton.isHidden = true
     }
 
     private func setupObservers() {
@@ -203,19 +206,20 @@ class SettingsCell: UITableViewCell {
     }
 
     @objc func handleSwitchAction(sender: UISwitch) {
-        guard let key = sectionType?.preferenceKey else { return }
-        userDefaults.set(sender.isOn ? true : false, forKey: key)
-
-        if sectionType?.preferenceKey == kVLCSettingPasscodeOnKey {
-            passcodeSwitchDelegate?.passcodeLockSwitchOn(state: sender.isOn)
-        } else if sectionType?.preferenceKey == kVLCSettingHideLibraryInFilesApp {
-            medialibraryHidingSwitchDelegate?.medialibraryHidingLockSwitchOn(state: sender.isOn)
-        } else if sectionType?.preferenceKey == kVLCSettingBackupMediaLibrary {
-            mediaLibraryBackupSwitchDelegate?.mediaLibraryBackupActivateSwitchOn(state: sender.isOn)
-        } else if sectionType?.preferenceKey == kVLCSettingsDisableGrouping {
-            medialibraryDisableGroupingSwitchDelegate?.medialibraryDisableGroupingSwitchOn(state: sender.isOn)
-        } else if sectionType?.preferenceKey == kVLCSettingPlaybackTapSwipeEqual || sectionType?.preferenceKey == kVLCSettingPlaybackForwardBackwardEqual {
-            skipDurationDelegate?.tableView.reloadData()
+        guard let settingsItem else { return }
+
+        switch settingsItem.action {
+        case .toggle(let preferenceKey):
+            let note = Notification(name: .VLCDidToggleSettingNotification,
+                                    object: nil,
+                                    userInfo: [
+                                        SettingsController.toggleNotificationKey: preferenceKey,
+                                        SettingsController.toggleNotificationValue: sender.isOn
+                                    ])
+            notificationCenter.post(note)
+
+        default:
+            break
         }
     }
 
@@ -237,7 +241,7 @@ class SettingsCell: UITableViewCell {
     }
 
     @objc func infoTapped(sender: UIButton) {
-        guard let settingSpecifier = getSettingsSpecifier(for: (sectionType?.preferenceKey)!) else {
+        guard let settingSpecifier = getSettingsSpecifier(for: (settingsItem?.preferenceKey)!) else {
             return
         }
 
@@ -266,14 +270,19 @@ class SettingsCell: UITableViewCell {
     }
 
     private func updateSwitch() {
-        if let key = self.sectionType?.preferenceKey {
-            let value = self.userDefaults.bool(forKey: key)
-            self.switchControl.isOn = value ? true : false
+        guard let settingsItem else { return }
+
+        switch settingsItem.action {
+        case .toggle(let preferenceKey):
+            let value = self.userDefaults.bool(forKey: preferenceKey)
+            self.switchControl.isOn = value
+        default:
+            break
         }
     }
 
     private func updateSubtitle() {
-        if let subtitle = self.getSubtitle(for: self.sectionType?.preferenceKey ?? "") {
+        if let subtitle = self.getSubtitle(for: self.settingsItem?.preferenceKey ?? "") {
             self.subtitleLabel.text = settingsBundle.localizedString(forKey: subtitle, value: subtitle, table: "Root")
         }
     }