summaryrefslogtreecommitdiffhomepage
path: root/ios/MullvadVPN/View controllers/ProblemReport/ProblemReportReviewViewController.swift
blob: 52cb59c257035b9f6bc158c971318c06d20aa775 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
//
//  ProblemReportReviewViewController.swift
//  MullvadVPN
//
//  Created by pronebird on 10/02/2021.
//  Copyright © 2025 Mullvad VPN AB. All rights reserved.
//

import UIKit

class ProblemReportReviewViewController: UIViewController {
    private let spinnerView = SpinnerActivityIndicatorView(style: .large)
    private var textView = UITextView()
    private let interactor: ProblemReportInteractor
    private lazy var spinnerContainerView: UIView = {
        let view = UIView()
        view.backgroundColor = .black.withAlphaComponent(0.5)
        return view
    }()

    init(interactor: ProblemReportInteractor) {
        self.interactor = interactor
        super.init(nibName: nil, bundle: nil)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .secondaryColor
        view.setAccessibilityIdentifier(.appLogsView)

        navigationItem.title = NSLocalizedString("App logs", comment: "")

        navigationItem.rightBarButtonItem = UIBarButtonItem(
            systemItem: .done,
            primaryAction: UIAction(handler: { [weak self] _ in
                self?.dismiss(animated: true)
            })
        )
        navigationItem.rightBarButtonItem?.setAccessibilityIdentifier(.appLogsDoneButton)

        #if DEBUG
            navigationItem.leftBarButtonItem = UIBarButtonItem(
                systemItem: .action,
                primaryAction: UIAction(handler: { [weak self] _ in
                    self?.share()
                })
            )
            navigationItem.leftBarButtonItem?.setAccessibilityIdentifier(.appLogsShareButton)
        #endif

        textView.setAccessibilityIdentifier(.problemReportAppLogsTextView)
        textView.translatesAutoresizingMaskIntoConstraints = false
        textView.isEditable = false
        textView.font = .mullvadSmall
        textView.adjustsFontForContentSizeCategory = true
        textView.backgroundColor = .systemBackground
        textView.textAlignment = .left

        view.addConstrainedSubviews([textView]) {
            textView.pinEdgesToSuperview(.all().excluding(.top))
            textView.pinEdgeToSuperviewMargin(.top(0))
        }

        textView.addConstrainedSubviews([spinnerContainerView]) {
            spinnerContainerView.pinEdgesToSuperview()
            spinnerContainerView.widthAnchor.constraint(equalTo: textView.widthAnchor)
            spinnerContainerView.heightAnchor.constraint(equalTo: textView.heightAnchor)
        }

        spinnerContainerView.addConstrainedSubviews([spinnerView]) {
            spinnerView.centerXAnchor.constraint(equalTo: view.centerXAnchor)
            spinnerView.centerYAnchor.constraint(equalTo: view.centerYAnchor)
        }

        // Used to layout constraints so that navigation controller could properly adjust the text
        // view insets.
        view.layoutIfNeeded()

        loadLogs()
    }

    override func selectAll(_ sender: Any?) {
        textView.selectAll(sender)
    }

    private func loadLogs() {
        spinnerView.startAnimating()
        interactor.fetchReportString { [weak self] reportString in
            guard let self else { return }
            Task { @MainActor in
                textView.text = reportString
                spinnerView.stopAnimating()
                spinnerContainerView.isHidden = true
            }
        }
    }

    #if DEBUG
        private func share() {
            interactor.fetchReportString { [weak self] reportString in
                guard let self, !reportString.isEmpty else { return }
                Task { @MainActor in
                    let activityController = UIActivityViewController(
                        activityItems: [reportString],
                        applicationActivities: nil
                    )

                    activityController.popoverPresentationController?.barButtonItem = navigationItem.leftBarButtonItem

                    present(activityController, animated: true)
                }
            }
        }
    #endif
}