Skip to content
Snippets Groups Projects
SettingsController.swift 11 KiB
Newer Older
Bruno Muniz's avatar
Bruno Muniz committed
import HUD
import DrawerFeature
Bruno Muniz's avatar
Bruno Muniz committed
import UIKit
import Theme
import Shared
import Combine
import DependencyInjection
import ScrollViewController

public final class SettingsController: UIViewController {
Bruno Muniz's avatar
Bruno Muniz committed
    @Dependency private var hud: HUD
Bruno Muniz's avatar
Bruno Muniz committed
    @Dependency private var coordinator: SettingsCoordinating
    @Dependency private var statusBarController: StatusBarStyleControlling

    lazy private var scrollViewController = ScrollViewController()
    lazy private var screenView = SettingsView {
        switch $0 {
        case .icognitoKeyboard:
            self.presentInfo(
                title: Localized.Settings.InfoDrawer.Icognito.title,
                subtitle: Localized.Settings.InfoDrawer.Icognito.subtitle
Bruno Muniz's avatar
Bruno Muniz committed
            )
        case .biometrics:
            self.presentInfo(
                title: Localized.Settings.InfoDrawer.Biometrics.title,
                subtitle: Localized.Settings.InfoDrawer.Biometrics.subtitle
Bruno Muniz's avatar
Bruno Muniz committed
            )
        case .notifications:
            self.presentInfo(
                title: Localized.Settings.InfoDrawer.Notifications.title,
                subtitle: Localized.Settings.InfoDrawer.Notifications.subtitle,
Bruno Muniz's avatar
Bruno Muniz committed
                urlString: "https://links.xx.network/denseids"
            )

        case .dummyTraffic:
            self.presentInfo(
                title: Localized.Settings.InfoDrawer.Traffic.title,
                subtitle: Localized.Settings.InfoDrawer.Traffic.subtitle,
Bruno Muniz's avatar
Bruno Muniz committed
                urlString: "https://links.xx.network/covertraffic"
            )
        }
    }

    private let viewModel = SettingsViewModel()
    private var cancellables = Set<AnyCancellable>()
    private var drawerCancellables = Set<AnyCancellable>()
Bruno Muniz's avatar
Bruno Muniz committed

    public override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        statusBarController.style.send(.darkContent)
        navigationController?.navigationBar
            .customize(backgroundColor: Asset.neutralWhite.color)
    }

    public override func viewDidLoad() {
        super.viewDidLoad()

        setupNavigationBar()
        setupScrollView()
        setupBindings()

        viewModel.loadCachedSettings()
    }

    private func setupNavigationBar() {
        navigationItem.backButtonTitle = ""

        let titleLabel = UILabel()
        titleLabel.text = Localized.Settings.title
        titleLabel.textColor = Asset.neutralActive.color
        titleLabel.font = Fonts.Mulish.semiBold.font(size: 18.0)
Bruno Muniz's avatar
Bruno Muniz committed

        let menuButton = UIButton()
        menuButton.tintColor = Asset.neutralDark.color
        menuButton.setImage(Asset.chatListMenu.image, for: .normal)
        menuButton.addTarget(self, action: #selector(didTapMenu), for: .touchUpInside)
        menuButton.snp.makeConstraints { $0.width.equalTo(50) }
Bruno Muniz's avatar
Bruno Muniz committed

        navigationItem.leftBarButtonItem = UIBarButtonItem(
            customView: UIStackView(arrangedSubviews: [menuButton, titleLabel])
Bruno Muniz's avatar
Bruno Muniz committed
        )
    }

    private func setupScrollView() {
        scrollViewController.view.backgroundColor = Asset.neutralWhite.color

        addChild(scrollViewController)
        view.addSubview(scrollViewController.view)

        scrollViewController.view.snp.makeConstraints { $0.edges.equalToSuperview() }
        scrollViewController.didMove(toParent: self)
        scrollViewController.contentView = screenView
    }

    private func setupBindings() {
        viewModel.hud
            .receive(on: DispatchQueue.main)
            .sink { [hud] in hud.update(with: $0) }
            .store(in: &cancellables)

        screenView.inAppNotifications.switcherView
            .publisher(for: .valueChanged)
            .sink { [weak viewModel] in viewModel?.didToggleInAppNotifications() }
            .store(in: &cancellables)

        screenView.dummyTraffic.switcherView
            .publisher(for: .valueChanged)
            .sink { [weak viewModel] in viewModel?.didToggleDummyTraffic() }
            .store(in: &cancellables)

        screenView.remoteNotifications.switcherView
            .publisher(for: .valueChanged)
            .sink { [weak viewModel] in viewModel?.didTogglePushNotifications() }
            .store(in: &cancellables)

        screenView.hideActiveApp.switcherView
            .publisher(for: .valueChanged)
            .sink { [weak viewModel] in viewModel?.didToggleHideActiveApps() }
            .store(in: &cancellables)

        screenView.icognitoKeyboard.switcherView
            .publisher(for: .valueChanged)
            .sink { [weak viewModel] in viewModel?.didToggleIcognitoKeyboard() }
            .store(in: &cancellables)

        screenView.biometrics.switcherView
            .publisher(for: .valueChanged)
            .sink { [weak viewModel] in viewModel?.didToggleBiometrics() }
            .store(in: &cancellables)

        screenView.privacyPolicyButton
Bruno Muniz's avatar
Bruno Muniz committed
            .publisher(for: .touchUpInside)
            .receive(on: DispatchQueue.main)
            .sink { [unowned self] in
                presentDrawer(
                    title: Localized.Settings.Drawer.title(Localized.Settings.privacyPolicy),
                    subtitle: Localized.Settings.Drawer.subtitle(Localized.Settings.privacyPolicy),
Bruno Muniz's avatar
Bruno Muniz committed
                    actionTitle: Localized.ChatList.Dashboard.open) {
                        guard let url = URL(string: "https://elixxir.io/privategrity-corporation-privacy-policy/") else { return }
Bruno Muniz's avatar
Bruno Muniz committed
                        UIApplication.shared.open(url, options: [:])
                    }
            }.store(in: &cancellables)

        screenView.disclosuresButton
Bruno Muniz's avatar
Bruno Muniz committed
            .publisher(for: .touchUpInside)
            .receive(on: DispatchQueue.main)
            .sink { [unowned self] in
                presentDrawer(
                    title: Localized.Settings.Drawer.title(Localized.Settings.disclosures),
                    subtitle: Localized.Settings.Drawer.subtitle(Localized.Settings.disclosures),
Bruno Muniz's avatar
Bruno Muniz committed
                    actionTitle: Localized.ChatList.Dashboard.open) {
                        guard let url = URL(string: "https://elixxir.io/privategrity-corporation-terms-of-use/") else { return }
Bruno Muniz's avatar
Bruno Muniz committed
                        UIApplication.shared.open(url, options: [:])
                    }
            }.store(in: &cancellables)

        screenView.deleteButton
Bruno Muniz's avatar
Bruno Muniz committed
            .publisher(for: .touchUpInside)
            .receive(on: DispatchQueue.main)
            .sink { [unowned self] in coordinator.toDelete(from: self) }
            .store(in: &cancellables)

        screenView.accountBackupButton
            .publisher(for: .touchUpInside)
            .receive(on: DispatchQueue.main)
            .sink { [unowned self] in coordinator.toBackup(from: self) }
            .store(in: &cancellables)
Bruno Muniz's avatar
Bruno Muniz committed

        screenView.advancedButton
Bruno Muniz's avatar
Bruno Muniz committed
            .publisher(for: .touchUpInside)
            .receive(on: DispatchQueue.main)
            .sink { [unowned self] in coordinator.toAdvanced(from: self) }
            .store(in: &cancellables)

        viewModel.state
            .map(\.isBiometricsPossible)
            .removeDuplicates()
            .receive(on: DispatchQueue.main)
            .sink { [weak screenView] in screenView?.biometrics.switcherView.isEnabled = $0 }
            .store(in: &cancellables)

        viewModel.state
            .removeDuplicates()
            .receive(on: DispatchQueue.main)
            .sink { [unowned self] state in
                screenView.biometrics.switcherView.setOn(state.isBiometricsEnabled, animated: true)
                screenView.hideActiveApp.switcherView.setOn(state.isHideActiveApps, animated: true)
                screenView.icognitoKeyboard.switcherView.setOn(state.isIcognitoKeyboard, animated: true)
                screenView.inAppNotifications.switcherView.setOn(state.isInAppNotification, animated: true)
                screenView.remoteNotifications.switcherView.setOn(state.isPushNotification, animated: true)
                screenView.dummyTraffic.switcherView.setOn(state.isDummyTrafficOn, animated: true)
            }.store(in: &cancellables)
    }

    private func presentDrawer(
Bruno Muniz's avatar
Bruno Muniz committed
        title: String,
        subtitle: String,
        actionTitle: String,
        action: @escaping () -> Void
    ) {
        let actionButton = CapsuleButton()
        actionButton.setStyle(.red)
        actionButton.setTitle(actionTitle, for: .normal)

        let cancelButton = CapsuleButton()
        cancelButton.setStyle(.seeThrough)
        cancelButton.setTitle(Localized.ChatList.Dashboard.cancel, for: .normal)

        let drawer = DrawerController(with: [
            DrawerImage(
                image: Asset.drawerNegative.image
            ),
            DrawerText(
Bruno Muniz's avatar
Bruno Muniz committed
                font: Fonts.Mulish.semiBold.font(size: 18.0),
                text: title,
                color: Asset.neutralActive.color
            ),
            DrawerText(
Bruno Muniz's avatar
Bruno Muniz committed
                font: Fonts.Mulish.semiBold.font(size: 14.0),
                text: subtitle,
                color: Asset.neutralWeak.color,
                lineHeightMultiple: 1.35,
                spacingAfter: 25
            ),
            DrawerStack(
Bruno Muniz's avatar
Bruno Muniz committed
                spacing: 20.0,
                views: [actionButton, cancelButton]
Bruno Muniz's avatar
Bruno Muniz committed
            )
        ])

        actionButton.publisher(for: .touchUpInside)
            .receive(on: DispatchQueue.main)
            .sink {
                drawer.dismiss(animated: true) { [weak self] in
Bruno Muniz's avatar
Bruno Muniz committed
                    guard let self = self else { return }
                    self.drawerCancellables.removeAll()
Bruno Muniz's avatar
Bruno Muniz committed

                    action()
                }
            }.store(in: &drawerCancellables)
Bruno Muniz's avatar
Bruno Muniz committed

        cancelButton.publisher(for: .touchUpInside)
            .receive(on: DispatchQueue.main)
            .sink {
                drawer.dismiss(animated: true) { [weak self] in
                    self?.drawerCancellables.removeAll()
Bruno Muniz's avatar
Bruno Muniz committed
                }
            }.store(in: &drawerCancellables)
Bruno Muniz's avatar
Bruno Muniz committed

        coordinator.toDrawer(drawer, from: self)
    @objc private func didTapMenu() {
        coordinator.toSideMenu(from: self)
Bruno Muniz's avatar
Bruno Muniz committed
    }
}

extension SettingsController {
    private func presentInfo(
        title: String,
        subtitle: String,
        urlString: String = ""
    ) {
        let actionButton = CapsuleButton()
        actionButton.set(
            style: .seeThrough,
            title: Localized.Settings.InfoDrawer.action
        let drawer = DrawerController(with: [
            DrawerText(
Bruno Muniz's avatar
Bruno Muniz committed
                font: Fonts.Mulish.bold.font(size: 26.0),
                text: title,
                color: Asset.neutralActive.color,
                alignment: .left,
                spacingAfter: 19
            ),
            DrawerLinkText(
Bruno Muniz's avatar
Bruno Muniz committed
                text: subtitle,
                urlString: urlString,
                spacingAfter: 37
            ),
            DrawerStack(views: [
                actionButton,
                FlexibleSpace()
            ])
Bruno Muniz's avatar
Bruno Muniz committed
        ])

        actionButton.publisher(for: .touchUpInside)
            .receive(on: DispatchQueue.main)
            .sink {
                drawer.dismiss(animated: true) { [weak self] in
Bruno Muniz's avatar
Bruno Muniz committed
                    guard let self = self else { return }
                    self.drawerCancellables.removeAll()
Bruno Muniz's avatar
Bruno Muniz committed
                }
            }.store(in: &drawerCancellables)
Bruno Muniz's avatar
Bruno Muniz committed

        coordinator.toDrawer(drawer, from: self)
Bruno Muniz's avatar
Bruno Muniz committed
    }
}