mirror of
https://github.com/twofas/2fas-ios.git
synced 2024-11-26 04:09:58 +01:00
TF-1145 Opt-out for crashlytics
This commit is contained in:
parent
8c33dc66e8
commit
856704ece3
@ -27,10 +27,10 @@ final class FCM: NSObject, MessagingDelegate, FCMHandlerProtocol {
|
||||
|
||||
var FCMTokenObtained: FCMTokenObtainedCompletion?
|
||||
|
||||
func initialize() {
|
||||
func initialize(enableCrashlytics: Bool) {
|
||||
FirebaseApp.configure()
|
||||
#if !DEBUG
|
||||
Crashlytics.crashlytics().setCrashlyticsCollectionEnabled(true)
|
||||
Crashlytics.crashlytics().setCrashlyticsCollectionEnabled(enableCrashlytics)
|
||||
#endif
|
||||
Messaging.messaging().delegate = self
|
||||
|
||||
|
@ -24,5 +24,5 @@ public protocol FCMHandlerProtocol: AnyObject {
|
||||
|
||||
var FCMTokenObtained: FCMTokenObtainedCompletion? { get set }
|
||||
|
||||
func initialize()
|
||||
func initialize(enableCrashlytics: Bool)
|
||||
}
|
||||
|
@ -483,7 +483,8 @@ extension InteractorFactory {
|
||||
|
||||
func aboutModuleInteractor() -> AboutModuleInteracting {
|
||||
AboutModuleInteractor(
|
||||
appInfoInteractor: appInfoInteractor()
|
||||
appInfoInteractor: appInfoInteractor(),
|
||||
registerDeviceInteractor: registerDeviceInteractor()
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -36,9 +36,11 @@ enum UpdateDeviceError: Error {
|
||||
|
||||
protocol RegisterDeviceInteracting: AnyObject {
|
||||
var isDeviceRegistered: Bool { get }
|
||||
var isCrashlyticsDisabled: Bool { get }
|
||||
func initialize()
|
||||
func registerDevice(completion: @escaping (Result<Void, RegisterDeviceError>) -> Void)
|
||||
func updateDevice(completion: @escaping (Result<Void, UpdateDeviceError>) -> Void)
|
||||
func setCrashlyticsDisabled(_ disabled: Bool)
|
||||
}
|
||||
|
||||
final class RegisterDeviceInteractor {
|
||||
@ -59,9 +61,13 @@ extension RegisterDeviceInteractor: RegisterDeviceInteracting {
|
||||
mainRepository.isDeviceIDSet
|
||||
}
|
||||
|
||||
var isCrashlyticsDisabled: Bool {
|
||||
mainRepository.isCrashlyticsDisabled
|
||||
}
|
||||
|
||||
func initialize() {
|
||||
Log("RegisterDeviceInteractor - Initializing", module: .interactor)
|
||||
channelState.initialize()
|
||||
channelState.initialize(enableCrashlytics: !mainRepository.isCrashlyticsDisabled)
|
||||
}
|
||||
|
||||
func registerDevice(completion: @escaping (Result<Void, RegisterDeviceError>) -> Void) {
|
||||
@ -124,6 +130,10 @@ extension RegisterDeviceInteractor: RegisterDeviceInteracting {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func setCrashlyticsDisabled(_ disabled: Bool) {
|
||||
mainRepository.setCrashlyticsDisabled(disabled)
|
||||
}
|
||||
}
|
||||
private extension RegisterDeviceInteractor {
|
||||
func gcmTokenObtained(_ token: String) {
|
||||
|
@ -82,6 +82,8 @@ protocol MainRepository: AnyObject {
|
||||
var currentAppVersion: String { get }
|
||||
func setIntroductionAsShown()
|
||||
func introductionWasShown() -> Bool
|
||||
func setCrashlyticsDisabled(_ disabled: Bool)
|
||||
var isCrashlyticsDisabled: Bool { get }
|
||||
|
||||
// MARK: - Services
|
||||
var hasServices: Bool { get }
|
||||
|
@ -31,4 +31,12 @@ extension MainRepositoryImpl {
|
||||
func introductionWasShown() -> Bool {
|
||||
userDefaultsRepository.introductionWasShown()
|
||||
}
|
||||
|
||||
func setCrashlyticsDisabled(_ disabled: Bool) {
|
||||
userDefaultsRepository.setCrashlyticsDisabled(disabled)
|
||||
}
|
||||
|
||||
var isCrashlyticsDisabled: Bool {
|
||||
userDefaultsRepository.isCrashlyticsDisabled
|
||||
}
|
||||
}
|
||||
|
@ -72,4 +72,7 @@ protocol UserDefaultsRepository: AnyObject {
|
||||
func introductionWasShown() -> Bool
|
||||
|
||||
func clearAll()
|
||||
|
||||
var isCrashlyticsDisabled: Bool { get }
|
||||
func setCrashlyticsDisabled(_ disabled: Bool)
|
||||
}
|
||||
|
@ -44,6 +44,7 @@ final class UserDefaultsRepositoryImpl: UserDefaultsRepository {
|
||||
case isSectionZeroCollapsed = "com.2fas.SectionZeroCollapsedState"
|
||||
case viewPath = "ViewPathController.ViewStatePath"
|
||||
case introductionWasShown = "IntroductionWasShown"
|
||||
case crashlyticsDisabled
|
||||
}
|
||||
private let userDefaults = UserDefaults()
|
||||
private let sharedDefaults = UserDefaults(suiteName: Config.suiteName)!
|
||||
@ -241,6 +242,17 @@ final class UserDefaultsRepositoryImpl: UserDefaultsRepository {
|
||||
return (viewPath: node.path, savedAt: node.savedAt)
|
||||
}
|
||||
|
||||
// MARK: - Crashlytics
|
||||
|
||||
var isCrashlyticsDisabled: Bool {
|
||||
userDefaults.bool(forKey: Keys.crashlyticsDisabled.rawValue)
|
||||
}
|
||||
|
||||
func setCrashlyticsDisabled(_ disabled: Bool) {
|
||||
userDefaults.set(disabled, forKey: Keys.crashlyticsDisabled.rawValue)
|
||||
userDefaults.synchronize()
|
||||
}
|
||||
|
||||
// MARK: - Clear all
|
||||
|
||||
func clearAll() {
|
||||
|
@ -21,13 +21,17 @@ import Foundation
|
||||
|
||||
protocol AboutModuleInteracting: AnyObject {
|
||||
var currentAppVersion: String { get }
|
||||
var isCrashlyticsDisabled: Bool { get }
|
||||
func setCrashlyticsDisabled(_ disabled: Bool)
|
||||
}
|
||||
|
||||
final class AboutModuleInteractor {
|
||||
private let appInfoInteractor: AppInfoInteracting
|
||||
private let registerDeviceInteractor: RegisterDeviceInteracting
|
||||
|
||||
init(appInfoInteractor: AppInfoInteracting) {
|
||||
init(appInfoInteractor: AppInfoInteracting, registerDeviceInteractor: RegisterDeviceInteracting) {
|
||||
self.appInfoInteractor = appInfoInteractor
|
||||
self.registerDeviceInteractor = registerDeviceInteractor
|
||||
}
|
||||
}
|
||||
|
||||
@ -35,4 +39,12 @@ extension AboutModuleInteractor: AboutModuleInteracting {
|
||||
var currentAppVersion: String {
|
||||
appInfoInteractor.currentAppVersion
|
||||
}
|
||||
|
||||
var isCrashlyticsDisabled: Bool {
|
||||
registerDeviceInteractor.isCrashlyticsDisabled
|
||||
}
|
||||
|
||||
func setCrashlyticsDisabled(_ disabled: Bool) {
|
||||
registerDeviceInteractor.setCrashlyticsDisabled(disabled)
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,13 @@ import UIKit
|
||||
struct AboutSection: TableViewSection {
|
||||
let title: String
|
||||
var cells: [AboutCell]
|
||||
let footer: String?
|
||||
|
||||
init(title: String, cells: [AboutCell], footer: String? = nil) {
|
||||
self.title = title
|
||||
self.cells = cells
|
||||
self.footer = footer
|
||||
}
|
||||
}
|
||||
|
||||
struct AboutCell: Hashable {
|
||||
@ -29,6 +36,7 @@ struct AboutCell: Hashable {
|
||||
case external
|
||||
case share
|
||||
case noAccessory
|
||||
case toggle(isOn: Bool)
|
||||
}
|
||||
enum Action: Hashable {
|
||||
case writeReview
|
||||
@ -41,7 +49,7 @@ struct AboutCell: Hashable {
|
||||
|
||||
let title: String
|
||||
let accessory: AccessoryKind
|
||||
let action: Action
|
||||
let action: Action?
|
||||
}
|
||||
|
||||
extension AboutCell.AccessoryKind {
|
||||
@ -53,7 +61,7 @@ extension AboutCell.AccessoryKind {
|
||||
case .external: return Asset.externalLinkIcon.image
|
||||
.withRenderingMode(.alwaysTemplate)
|
||||
.withTintColor(Theme.Colors.Icon.theme)
|
||||
case .noAccessory: return nil
|
||||
case .noAccessory, .toggle: return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,16 @@ extension AboutPresenter {
|
||||
]),
|
||||
.init(title: T.Settings.support, cells: [
|
||||
.init(title: T.Settings.sendLogs, accessory: .noAccessory, action: .sendLogs)
|
||||
])
|
||||
]),
|
||||
.init(title: "Crash info", cells: [
|
||||
.init(
|
||||
title: "Opt-out of crash info",
|
||||
accessory: .toggle(isOn: interactor.isCrashlyticsDisabled),
|
||||
action: nil
|
||||
)
|
||||
],
|
||||
footer: "Changes will be applied in next app session"
|
||||
)
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ final class AboutPresenter {
|
||||
weak var view: AboutViewControlling?
|
||||
|
||||
private let flowController: AboutFlowControlling
|
||||
private let interactor: AboutModuleInteracting
|
||||
let interactor: AboutModuleInteracting
|
||||
|
||||
init(flowController: AboutFlowControlling, interactor: AboutModuleInteracting) {
|
||||
self.flowController = flowController
|
||||
@ -43,12 +43,14 @@ extension AboutPresenter {
|
||||
func handleSelection(at indexPath: IndexPath) {
|
||||
let menu = buildMenu()
|
||||
guard let section = menu[safe: indexPath.section],
|
||||
let cell = section.cells[safe: indexPath.row] else {
|
||||
let cell = section.cells[safe: indexPath.row],
|
||||
let action = cell.action
|
||||
else {
|
||||
reload()
|
||||
return
|
||||
}
|
||||
|
||||
switch cell.action {
|
||||
switch action {
|
||||
case .tos:
|
||||
flowController.toTOS()
|
||||
case .privacyPolicy:
|
||||
@ -63,6 +65,12 @@ extension AboutPresenter {
|
||||
flowController.toAcknowledgements()
|
||||
}
|
||||
}
|
||||
|
||||
func handleToogle() {
|
||||
let value = interactor.isCrashlyticsDisabled
|
||||
interactor.setCrashlyticsDisabled(!value)
|
||||
reload()
|
||||
}
|
||||
}
|
||||
|
||||
private extension AboutPresenter {
|
||||
|
@ -28,9 +28,9 @@ final class AboutViewController: UIViewController {
|
||||
|
||||
private let tableView = SettingsMenuTableView()
|
||||
private let footer = AboutFooter()
|
||||
|
||||
|
||||
private var tableViewAdapter: TableViewAdapter<AboutSection, AboutCell>!
|
||||
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
@ -43,6 +43,9 @@ final class AboutViewController: UIViewController {
|
||||
tableViewAdapter.titleForHeader = { [weak self] _, sectionOffset, snapshot in
|
||||
self?.titleForHeader(offset: sectionOffset, snapshot: snapshot)
|
||||
}
|
||||
tableViewAdapter.titleForFooter = { [weak self] _, sectionOffset, snapshot in
|
||||
self?.titleForFooter(offset: sectionOffset, snapshot: snapshot)
|
||||
}
|
||||
tableViewAdapter.delegatee.didSelectItem = { [weak self] tableView, indexPath, data in
|
||||
self?.didSelect(tableView: tableView, indexPath: indexPath, data: data)
|
||||
}
|
||||
@ -52,7 +55,7 @@ final class AboutViewController: UIViewController {
|
||||
setupTableViewLayout()
|
||||
|
||||
title = T.Settings.about
|
||||
|
||||
|
||||
hidesBottomBarWhenPushed = false
|
||||
navigationItem.backButtonDisplayMode = .minimal
|
||||
|
||||
@ -91,10 +94,18 @@ extension AboutViewController {
|
||||
) as? SettingsMenuTableViewCell else { return nil }
|
||||
|
||||
let accessory: SettingsMenuTableViewCell.AccessoryType = {
|
||||
guard let image = data.accessory.icon else { return .none }
|
||||
let imageView = UIImageView(image: image)
|
||||
imageView.tintColor = Theme.Colors.Icon.theme
|
||||
return .customView(customView: imageView)
|
||||
if let image = data.accessory.icon {
|
||||
let imageView = UIImageView(image: image)
|
||||
imageView.tintColor = Theme.Colors.Icon.theme
|
||||
return .customView(customView: imageView)
|
||||
}
|
||||
if case AboutCell.AccessoryKind.toggle(let isOn) = data.accessory {
|
||||
return .toggle(isEnabled: isOn) { [weak self] _, _ in
|
||||
self?.presenter.handleToogle()
|
||||
}
|
||||
}
|
||||
|
||||
return .none
|
||||
}()
|
||||
|
||||
let decorateText: SettingsMenuTableViewCell.TextDecoration = {
|
||||
@ -103,6 +114,11 @@ extension AboutViewController {
|
||||
}
|
||||
return .none
|
||||
}()
|
||||
if data.action == nil {
|
||||
cell.selectionStyle = .none
|
||||
} else {
|
||||
cell.selectionStyle = .default
|
||||
}
|
||||
cell.update(icon: nil, title: data.title, kind: accessory, decorateText: decorateText)
|
||||
return cell
|
||||
}
|
||||
@ -112,6 +128,14 @@ extension AboutViewController {
|
||||
return section.title
|
||||
}
|
||||
|
||||
func titleForFooter(
|
||||
offset: Int,
|
||||
snapshot: TableViewDataSnapshot<AboutSection, AboutCell>
|
||||
) -> String? {
|
||||
let section = snapshot.section(at: offset)
|
||||
return section.footer
|
||||
}
|
||||
|
||||
func didSelect(tableView: UITableView, indexPath: IndexPath, data: AboutCell) {
|
||||
tableView.deselectRow(at: indexPath, animated: true)
|
||||
presenter.handleSelection(at: indexPath)
|
||||
|
Loading…
Reference in New Issue
Block a user