Add crash report helper
This commit is contained in:
parent
393a134648
commit
6adcad63b3
|
@ -185,6 +185,7 @@
|
|||
D6969E9E240C81B9002843CE /* NSTextAttachment+Emoji.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6969E9D240C81B9002843CE /* NSTextAttachment+Emoji.swift */; };
|
||||
D6969EA0240C8384002843CE /* EmojiLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6969E9F240C8384002843CE /* EmojiLabel.swift */; };
|
||||
D6969EA4240DD28D002843CE /* UnknownNotificationTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = D6969EA2240DD28D002843CE /* UnknownNotificationTableViewCell.xib */; };
|
||||
D69CCBBF249E6EFD000AF167 /* CrashReporter in Frameworks */ = {isa = PBXBuildFile; productRef = D69CCBBE249E6EFD000AF167 /* CrashReporter */; };
|
||||
D6A3BC7723218E1300FD64D5 /* TimelineSegment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A3BC7323218C6E00FD64D5 /* TimelineSegment.swift */; };
|
||||
D6A3BC7923218E9200FD64D5 /* NotificationGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A3BC7823218E9200FD64D5 /* NotificationGroup.swift */; };
|
||||
D6A3BC7C232195C600FD64D5 /* ActionNotificationGroupTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A3BC7A232195C600FD64D5 /* ActionNotificationGroupTableViewCell.swift */; };
|
||||
|
@ -248,6 +249,8 @@
|
|||
D6EBF01523C55C0900AE061B /* UIApplication+Scenes.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6EBF01423C55C0900AE061B /* UIApplication+Scenes.swift */; };
|
||||
D6EBF01723C55E0D00AE061B /* UISceneSession+MastodonController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6EBF01623C55E0D00AE061B /* UISceneSession+MastodonController.swift */; };
|
||||
D6F1F84D2193B56E00F5FE67 /* Cache.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6F1F84C2193B56E00F5FE67 /* Cache.swift */; };
|
||||
D6F2E965249E8BFD005846BB /* CrashReporterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6F2E963249E8BFD005846BB /* CrashReporterViewController.swift */; };
|
||||
D6F2E966249E8BFD005846BB /* CrashReporterViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = D6F2E964249E8BFD005846BB /* CrashReporterViewController.xib */; };
|
||||
D6F953EC212519E700CF0F2B /* TimelineTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6F953EB212519E700CF0F2B /* TimelineTableViewController.swift */; };
|
||||
D6F953F021251A2900CF0F2B /* MastodonController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6F953EF21251A2900CF0F2B /* MastodonController.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
@ -554,6 +557,8 @@
|
|||
D6EBF01423C55C0900AE061B /* UIApplication+Scenes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIApplication+Scenes.swift"; sourceTree = "<group>"; };
|
||||
D6EBF01623C55E0D00AE061B /* UISceneSession+MastodonController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UISceneSession+MastodonController.swift"; sourceTree = "<group>"; };
|
||||
D6F1F84C2193B56E00F5FE67 /* Cache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Cache.swift; sourceTree = "<group>"; };
|
||||
D6F2E963249E8BFD005846BB /* CrashReporterViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrashReporterViewController.swift; sourceTree = "<group>"; };
|
||||
D6F2E964249E8BFD005846BB /* CrashReporterViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = CrashReporterViewController.xib; sourceTree = "<group>"; };
|
||||
D6F953EB212519E700CF0F2B /* TimelineTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineTableViewController.swift; sourceTree = "<group>"; };
|
||||
D6F953EF21251A2900CF0F2B /* MastodonController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonController.swift; sourceTree = "<group>"; };
|
||||
D6F98BD523AE951F008A4DAC /* Swifter.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Swifter.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
|
@ -582,6 +587,7 @@
|
|||
D61099C02144B0CC00432DC2 /* Pachyderm.framework in Frameworks */,
|
||||
D6B0539F23BD2BA300A066FA /* SheetController in Frameworks */,
|
||||
D65A37F321472F300087646E /* SwiftSoup.framework in Frameworks */,
|
||||
D69CCBBF249E6EFD000AF167 /* CrashReporter in Frameworks */,
|
||||
D6BC874521961F73006163F1 /* Gifu.framework in Frameworks */,
|
||||
0461A3902163CBAE00C0A807 /* Cache.framework in Frameworks */,
|
||||
);
|
||||
|
@ -851,6 +857,7 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
D6C693FA2162FE5D007D6A6D /* Utilities */,
|
||||
D6F2E960249E772F005846BB /* Crash Reporter */,
|
||||
D641C782213DD7F0004B4513 /* Main */,
|
||||
D641C783213DD7FE004B4513 /* Onboarding */,
|
||||
D641C781213DD7DD004B4513 /* Timeline */,
|
||||
|
@ -1333,6 +1340,15 @@
|
|||
path = Caching;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D6F2E960249E772F005846BB /* Crash Reporter */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D6F2E963249E8BFD005846BB /* CrashReporterViewController.swift */,
|
||||
D6F2E964249E8BFD005846BB /* CrashReporterViewController.xib */,
|
||||
);
|
||||
path = "Crash Reporter";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D6F953F121251A2F00CF0F2B /* Controllers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -1410,6 +1426,7 @@
|
|||
name = Tusker;
|
||||
packageProductDependencies = (
|
||||
D6B0539E23BD2BA300A066FA /* SheetController */,
|
||||
D69CCBBE249E6EFD000AF167 /* CrashReporter */,
|
||||
);
|
||||
productName = Tusker;
|
||||
productReference = D6D4DDCC212518A000E1C4BB /* Tusker.app */;
|
||||
|
@ -1505,6 +1522,7 @@
|
|||
mainGroup = D6D4DDC3212518A000E1C4BB;
|
||||
packageReferences = (
|
||||
D6B0539D23BD2BA300A066FA /* XCRemoteSwiftPackageReference "SheetController" */,
|
||||
D69CCBBD249E6EFD000AF167 /* XCRemoteSwiftPackageReference "plcrashreporter" */,
|
||||
);
|
||||
productRefGroup = D6D4DDCD212518A000E1C4BB /* Products */;
|
||||
projectDirPath = "";
|
||||
|
@ -1563,6 +1581,7 @@
|
|||
D63F9C66241C4CC3004C03CF /* AddAttachmentTableViewCell.xib in Resources */,
|
||||
D667E5E12134937B0057A976 /* TimelineStatusTableViewCell.xib in Resources */,
|
||||
D6A5FAF1217B7E05003DB2D9 /* ComposeViewController.xib in Resources */,
|
||||
D6F2E966249E8BFD005846BB /* CrashReporterViewController.xib in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -1705,6 +1724,7 @@
|
|||
D6BC9DD7232D7811002CA326 /* TimelinesPageViewController.swift in Sources */,
|
||||
D60E2F2E244248BF005F8713 /* MastodonCachePersistentStore.swift in Sources */,
|
||||
D620483623D38075008A63EF /* ContentTextView.swift in Sources */,
|
||||
D6F2E965249E8BFD005846BB /* CrashReporterViewController.swift in Sources */,
|
||||
D6A3BC802321B7E600FD64D5 /* FollowNotificationGroupTableViewCell.swift in Sources */,
|
||||
D627944D23A9A03D00D38C68 /* ListTimelineViewController.swift in Sources */,
|
||||
D6945C3823AC739F005C403C /* InstanceTimelineViewController.swift in Sources */,
|
||||
|
@ -2298,6 +2318,14 @@
|
|||
/* End XCConfigurationList section */
|
||||
|
||||
/* Begin XCRemoteSwiftPackageReference section */
|
||||
D69CCBBD249E6EFD000AF167 /* XCRemoteSwiftPackageReference "plcrashreporter" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/microsoft/plcrashreporter";
|
||||
requirement = {
|
||||
kind = upToNextMinorVersion;
|
||||
minimumVersion = 1.7.0;
|
||||
};
|
||||
};
|
||||
D6B0539D23BD2BA300A066FA /* XCRemoteSwiftPackageReference "SheetController" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://git.shadowfacts.net/shadowfacts/SheetController.git";
|
||||
|
@ -2309,6 +2337,11 @@
|
|||
/* End XCRemoteSwiftPackageReference section */
|
||||
|
||||
/* Begin XCSwiftPackageProductDependency section */
|
||||
D69CCBBE249E6EFD000AF167 /* CrashReporter */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = D69CCBBD249E6EFD000AF167 /* XCRemoteSwiftPackageReference "plcrashreporter" */;
|
||||
productName = CrashReporter;
|
||||
};
|
||||
D6B0539E23BD2BA300A066FA /* SheetController */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = D6B0539D23BD2BA300A066FA /* XCRemoteSwiftPackageReference "SheetController" */;
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
"object": {
|
||||
"pins": [
|
||||
{
|
||||
"package": "SheetController",
|
||||
"repositoryURL": "https://git.shadowfacts.net/shadowfacts/SheetController.git",
|
||||
"package": "PLCrashReporter",
|
||||
"repositoryURL": "https://github.com/microsoft/plcrashreporter",
|
||||
"state": {
|
||||
"branch": "master",
|
||||
"revision": "6926446c4e15eb7f4513c4c00df9279553b330be",
|
||||
"version": null
|
||||
"branch": null,
|
||||
"revision": "4637a7854de2cc5c354d46fb931d74bdbc2c043e",
|
||||
"version": "1.7.0"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
|
@ -7,13 +7,35 @@
|
|||
//
|
||||
|
||||
import UIKit
|
||||
import CrashReporter
|
||||
import MessageUI
|
||||
|
||||
@UIApplicationMain
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
static private(set) var crashReporter: PLCrashReporter!
|
||||
static var pendingCrashReport: PLCrashReport?
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||
#if !DEBUG
|
||||
setupCrashReporter()
|
||||
#endif
|
||||
AppShortcutItem.createItems(for: application)
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
private func setupCrashReporter() {
|
||||
let config = PLCrashReporterConfig(signalHandlerType: .BSD, symbolicationStrategy: .all)
|
||||
AppDelegate.crashReporter = PLCrashReporter(configuration: config)
|
||||
|
||||
if AppDelegate.crashReporter.hasPendingCrashReport() {
|
||||
let data = try! AppDelegate.crashReporter.loadPendingCrashReportDataAndReturnError()
|
||||
AppDelegate.crashReporter.purgePendingCrashReport()
|
||||
let report = try! PLCrashReport(data: data)
|
||||
|
||||
AppDelegate.pendingCrashReport = report
|
||||
}
|
||||
|
||||
AppDelegate.crashReporter.enable()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
|
||||
import UIKit
|
||||
import Pachyderm
|
||||
import CrashReporter
|
||||
import MessageUI
|
||||
|
||||
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
||||
|
||||
|
@ -21,17 +23,13 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
|||
|
||||
window = UIWindow(windowScene: windowScene)
|
||||
|
||||
if LocalData.shared.onboardingComplete {
|
||||
if session.mastodonController == nil {
|
||||
let account = LocalData.shared.getMostRecentAccount()!
|
||||
session.mastodonController = MastodonController.getForAccount(account)
|
||||
}
|
||||
|
||||
showAppUI()
|
||||
if let report = AppDelegate.pendingCrashReport {
|
||||
AppDelegate.pendingCrashReport = nil
|
||||
handlePendingCrashReport(report, session: session)
|
||||
} else {
|
||||
showOnboardingUI()
|
||||
showAppOrOnboardingUI(session: session)
|
||||
}
|
||||
|
||||
|
||||
window!.makeKeyAndVisible()
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(themePrefChanged), name: .themePreferenceChanged, object: nil)
|
||||
|
@ -113,6 +111,32 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
|||
try! scene.session.mastodonController?.persistentContainer.viewContext.save()
|
||||
}
|
||||
|
||||
private func handlePendingCrashReport(_ report: PLCrashReport, session: UISceneSession) {
|
||||
#if !DEBUG
|
||||
guard MFMailComposeViewController.canSendMail() else {
|
||||
print("Cannot send email")
|
||||
showAppOrOnboardingUI(session: session)
|
||||
return
|
||||
}
|
||||
|
||||
window!.rootViewController = CrashReporterViewController.create(report: report)
|
||||
#endif
|
||||
}
|
||||
|
||||
func showAppOrOnboardingUI(session: UISceneSession? = nil) {
|
||||
let session = session ?? window!.windowScene!.session
|
||||
if LocalData.shared.onboardingComplete {
|
||||
if session.mastodonController == nil {
|
||||
let account = LocalData.shared.getMostRecentAccount()!
|
||||
session.mastodonController = MastodonController.getForAccount(account)
|
||||
}
|
||||
|
||||
showAppUI()
|
||||
} else {
|
||||
showOnboardingUI()
|
||||
}
|
||||
}
|
||||
|
||||
func activateAccount(_ account: LocalData.UserAccountInfo) {
|
||||
LocalData.shared.setMostRecentAccount(account)
|
||||
window!.windowScene!.session.mastodonController = MastodonController.getForAccount(account)
|
||||
|
@ -154,3 +178,11 @@ extension SceneDelegate: OnboardingViewControllerDelegate {
|
|||
activateAccount(account)
|
||||
}
|
||||
}
|
||||
|
||||
extension SceneDelegate: MFMailComposeViewControllerDelegate {
|
||||
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
|
||||
controller.dismiss(animated: true) {
|
||||
self.showAppOrOnboardingUI()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
//
|
||||
// CrashReporterViewController.swift
|
||||
// Tusker
|
||||
//
|
||||
// Created by Shadowfacts on 6/20/20.
|
||||
// Copyright © 2020 Shadowfacts. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import CrashReporter
|
||||
import MessageUI
|
||||
|
||||
class CrashReporterViewController: UIViewController {
|
||||
|
||||
private let report: PLCrashReport
|
||||
private var reportText: String!
|
||||
|
||||
private var reportFilename: String {
|
||||
let timestamp = ISO8601DateFormatter().string(from: report.systemInfo.timestamp)
|
||||
return "Tusker-crash-\(timestamp).crash"
|
||||
}
|
||||
|
||||
@IBOutlet weak var crashReportTextView: UITextView!
|
||||
@IBOutlet weak var sendReportButton: UIButton!
|
||||
|
||||
static func create(report: PLCrashReport) -> UINavigationController {
|
||||
let nav = UINavigationController(rootViewController: CrashReporterViewController(report: report))
|
||||
nav.navigationBar.prefersLargeTitles = true
|
||||
return nav
|
||||
}
|
||||
|
||||
private init(report: PLCrashReport){
|
||||
self.report = report
|
||||
|
||||
super.init(nibName: "CrashReporterViewController", bundle: .main)
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
navigationItem.title = NSLocalizedString("Crash Detected", comment: "crash reporter title")
|
||||
navigationItem.largeTitleDisplayMode = .always
|
||||
|
||||
crashReportTextView.font = .monospacedSystemFont(ofSize: 14, weight: .regular)
|
||||
|
||||
reportText = PLCrashReportTextFormatter.stringValue(for: report, with: PLCrashReportTextFormatiOS)!
|
||||
let info = "Tusker has detected that it crashed the last time it was running. You can email the report to the developer or skip sending and continue to the app. You may review the report below before sending.\n\nIf you choose to send the report, please include any additional details about what you were doing prior to the crash that may be pertinent.\n\n"
|
||||
let attributed = NSMutableAttributedString()
|
||||
attributed.append(NSAttributedString(string: info, attributes: [
|
||||
NSAttributedString.Key.font: UIFont.systemFont(ofSize: 17),
|
||||
NSAttributedString.Key.foregroundColor: UIColor.label
|
||||
]))
|
||||
attributed.append(NSAttributedString(string: reportText, attributes: [
|
||||
NSAttributedString.Key.font: UIFont.monospacedSystemFont(ofSize: 14, weight: .regular),
|
||||
NSAttributedString.Key.foregroundColor: UIColor.label
|
||||
]))
|
||||
crashReportTextView.attributedText = attributed
|
||||
|
||||
sendReportButton.layer.cornerRadius = 12.5
|
||||
sendReportButton.layer.masksToBounds = true
|
||||
|
||||
sendReportButton.addGestureRecognizer(UILongPressGestureRecognizer(target: self, action: #selector(sendReportButtonLongPressed)))
|
||||
}
|
||||
|
||||
private func updateSendReportButtonColor(lightened: Bool, animate: Bool) {
|
||||
let color: UIColor
|
||||
if lightened {
|
||||
var hue: CGFloat = 0, saturation: CGFloat = 0, brightness: CGFloat = 0, alpha: CGFloat = 0
|
||||
UIColor.systemBlue.getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: &alpha)
|
||||
color = UIColor(hue: hue, saturation: 0.85 * saturation, brightness: brightness, alpha: alpha)
|
||||
} else {
|
||||
color = .systemBlue
|
||||
}
|
||||
if animate {
|
||||
UIView.animate(withDuration: 0.25) {
|
||||
self.sendReportButton.backgroundColor = color
|
||||
}
|
||||
} else {
|
||||
sendReportButton.backgroundColor = color
|
||||
}
|
||||
}
|
||||
|
||||
@IBAction func sendReportTouchDown(_ sender: Any) {
|
||||
updateSendReportButtonColor(lightened: true, animate: false)
|
||||
}
|
||||
|
||||
@IBAction func sendReportButtonTouchDragExit(_ sender: Any) {
|
||||
updateSendReportButtonColor(lightened: false, animate: true)
|
||||
}
|
||||
|
||||
@IBAction func sendReportButtonTouchDragEnter(_ sender: Any) {
|
||||
updateSendReportButtonColor(lightened: true, animate: true)
|
||||
}
|
||||
|
||||
@IBAction func sendReportTouchUpInside(_ sender: Any) {
|
||||
updateSendReportButtonColor(lightened: false, animate: true)
|
||||
|
||||
let composeVC = MFMailComposeViewController()
|
||||
composeVC.mailComposeDelegate = self
|
||||
composeVC.setToRecipients(["me@shadowfacts.net"])
|
||||
composeVC.setSubject("Tusker Crash Report")
|
||||
|
||||
let data = reportText.data(using: .utf8)!
|
||||
composeVC.addAttachmentData(data, mimeType: "text/plain", fileName: reportFilename)
|
||||
|
||||
self.present(composeVC, animated: true)
|
||||
}
|
||||
|
||||
@objc func sendReportButtonLongPressed() {
|
||||
let dir = FileManager.default.temporaryDirectory
|
||||
let url = dir.appendingPathComponent(reportFilename)
|
||||
try! reportText.data(using: .utf8)!.write(to: url)
|
||||
let activityController = UIActivityViewController(activityItems: [url], applicationActivities: nil)
|
||||
present(activityController, animated: true)
|
||||
}
|
||||
|
||||
@IBAction func cancelPressed(_ sender: Any) {
|
||||
(view.window!.windowScene!.delegate as! SceneDelegate).showAppOrOnboardingUI()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension CrashReporterViewController: MFMailComposeViewControllerDelegate {
|
||||
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
|
||||
controller.dismiss(animated: true) {
|
||||
(self.view.window!.windowScene!.delegate as! SceneDelegate).showAppOrOnboardingUI()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="16097" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="CrashReporterViewController" customModule="Tusker" customModuleProvider="target">
|
||||
<connections>
|
||||
<outlet property="crashReportTextView" destination="hxN-7J-Usc" id="TGd-yq-Ds5"/>
|
||||
<outlet property="sendReportButton" destination="Ofm-5l-nAp" id="6xM-hz-uvw"/>
|
||||
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
|
||||
</connections>
|
||||
</placeholder>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="center" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="a8U-KI-8PM">
|
||||
<rect key="frame" x="0.0" y="44" width="414" height="818"/>
|
||||
<subviews>
|
||||
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" verticalHuggingPriority="249" translatesAutoresizingMaskIntoConstraints="NO" id="uQy-Yw-Dba">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="722"/>
|
||||
<subviews>
|
||||
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" verticalHuggingPriority="249" scrollEnabled="NO" editable="NO" textAlignment="natural" translatesAutoresizingMaskIntoConstraints="NO" id="hxN-7J-Usc">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="166.5"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
||||
<string key="text">Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda.</string>
|
||||
<color key="textColor" systemColor="labelColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
|
||||
</textView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="LRh-7Z-mV1" firstAttribute="trailing" secondItem="hxN-7J-Usc" secondAttribute="trailing" id="1GJ-Nk-pIj"/>
|
||||
<constraint firstItem="hxN-7J-Usc" firstAttribute="leading" secondItem="LRh-7Z-mV1" secondAttribute="leading" id="dtj-bw-No1"/>
|
||||
<constraint firstItem="hxN-7J-Usc" firstAttribute="top" secondItem="LRh-7Z-mV1" secondAttribute="top" id="nvk-aw-YqH"/>
|
||||
<constraint firstItem="LRh-7Z-mV1" firstAttribute="bottom" secondItem="hxN-7J-Usc" secondAttribute="bottom" id="xAU-OS-1Zy"/>
|
||||
</constraints>
|
||||
<viewLayoutGuide key="contentLayoutGuide" id="LRh-7Z-mV1"/>
|
||||
<viewLayoutGuide key="frameLayoutGuide" id="Rgd-t7-8QN"/>
|
||||
</scrollView>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Ofm-5l-nAp">
|
||||
<rect key="frame" x="52" y="730" width="310.5" height="50"/>
|
||||
<color key="backgroundColor" systemColor="systemBlueColor" red="0.0" green="0.47843137250000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="50" id="jHf-W0-qQn"/>
|
||||
</constraints>
|
||||
<state key="normal" title="Send Crash Report">
|
||||
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="sendReportButtonTouchDragEnter:" destination="-1" eventType="touchDragEnter" id="jSF-RZ-NsG"/>
|
||||
<action selector="sendReportButtonTouchDragExit:" destination="-1" eventType="touchDragExit" id="CrB-QL-bN1"/>
|
||||
<action selector="sendReportTouchDown:" destination="-1" eventType="touchDown" id="P5K-4n-tO1"/>
|
||||
<action selector="sendReportTouchUpInside:" destination="-1" eventType="touchUpInside" id="ggd-fm-Orq"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="JiJ-Ng-jOz">
|
||||
<rect key="frame" x="169" y="788" width="76" height="30"/>
|
||||
<state key="normal" title="Don't Send"/>
|
||||
<connections>
|
||||
<action selector="cancelPressed:" destination="-1" eventType="touchUpInside" id="o4R-0Q-STS"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
</stackView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
||||
<constraints>
|
||||
<constraint firstItem="uQy-Yw-Dba" firstAttribute="width" secondItem="i5M-Pr-FkT" secondAttribute="width" id="AX2-9e-cO0"/>
|
||||
<constraint firstItem="fnl-2z-Ty3" firstAttribute="bottom" secondItem="a8U-KI-8PM" secondAttribute="bottom" id="Ec3-Px-dSW"/>
|
||||
<constraint firstItem="hxN-7J-Usc" firstAttribute="width" secondItem="i5M-Pr-FkT" secondAttribute="width" id="Evf-Yz-Iui"/>
|
||||
<constraint firstItem="a8U-KI-8PM" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" id="NDN-Jl-viT"/>
|
||||
<constraint firstItem="a8U-KI-8PM" firstAttribute="top" secondItem="fnl-2z-Ty3" secondAttribute="top" id="O8Y-sl-55I"/>
|
||||
<constraint firstItem="a8U-KI-8PM" firstAttribute="trailing" secondItem="fnl-2z-Ty3" secondAttribute="trailing" id="f59-qB-5T7"/>
|
||||
<constraint firstItem="Ofm-5l-nAp" firstAttribute="width" secondItem="i5M-Pr-FkT" secondAttribute="width" multiplier="0.75" id="ueo-xb-Tfm"/>
|
||||
</constraints>
|
||||
<viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
|
||||
<point key="canvasLocation" x="133" y="154"/>
|
||||
</view>
|
||||
</objects>
|
||||
</document>
|
Loading…
Reference in New Issue