Contribute recording

This commit is contained in:
relikd
2020-08-28 18:36:52 +02:00
parent 52fa2e460e
commit 42aa7cf926
18 changed files with 229 additions and 12 deletions

Binary file not shown.

View File

@@ -0,0 +1,26 @@
{
"images" : [
{
"filename" : "img.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "img@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "img@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"template-rendering-intent" : "template"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 247 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 423 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 572 B

View File

@@ -0,0 +1,26 @@
{
"images" : [
{
"filename" : "img.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "img@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "img@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"template-rendering-intent" : "template"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 400 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 530 B

View File

@@ -0,0 +1,63 @@
import UIKit
struct NotificationBanner {
enum Style {
case fail, ok
}
let view: UIView
init(_ msg: String, style: Style) {
let bg, fg: UIColor
let imgName: String
switch style {
case .fail:
bg = .systemRed
fg = UIColor.black.withAlphaComponent(0.80)
imgName = "circle-x"
case .ok:
bg = .systemGreen
fg = UIColor.black.withAlphaComponent(0.65)
imgName = "circle-check"
}
view = UIView()
view.backgroundColor = bg
let lbl = QuickUI.label(msg, style: .callout)
lbl.textColor = fg
lbl.numberOfLines = 0
lbl.font = lbl.font.bold()
let img = QuickUI.image(UIImage(named: imgName))
img.tintColor = fg
view.addSubview(lbl)
view.addSubview(img)
img.anchor([.leading, .centerY], to: view.layoutMarginsGuide)
lbl.anchor([.top, .bottom, .trailing], to: view.layoutMarginsGuide)
img.widthAnchor =&= 25
img.heightAnchor =&= 25
lbl.leadingAnchor =&= img.trailingAnchor + 8
img.bottomAnchor =<= view.bottomAnchor - 8
lbl.bottomAnchor =<= view.bottomAnchor - 8
}
/// Animate header banner from the top of the view. Show for `delay` seconds and then hide again.
/// - Parameter onClose: Run after the close animation finishes.
func present(in vc: UIViewController, hideAfter delay: TimeInterval = 3, onClose: (() -> Void)? = nil) {
vc.view.addSubview(view)
view.anchor([.leading, .trailing], to: vc.view!)
vc.view.layoutIfNeeded() // sets the height
let h = view.frame.height
let constraint = view.topAnchor =&= vc.view.topAnchor - h
vc.view.layoutIfNeeded() // hide view
UIView.animate(withDuration: 0.3, animations: {
constraint.constant = 0
vc.view.layoutIfNeeded() // animate view
UIView.animate(withDuration: 0.3, delay: delay, options: .curveLinear, animations: {
constraint.constant = -h
vc.view.layoutIfNeeded() // hide again
}, completion: { _ in
self.view.removeFromSuperview()
onClose?()
})
})
}
}

View File

@@ -33,7 +33,9 @@ extension FilterOptions {
}
extension Recording {
var fallbackTitle: String { get { "Unnamed Recording #\(id)" } }
var fallbackTitle: String { get {
isLongTerm ? "Background Recording" : "Unnamed Recording #\(id)"
} }
var duration: Timestamp? { get { stop == nil ? nil : stop! - start } }
var isLongTerm: Bool { (duration ?? 0) > Timestamp.hours(1) }
}

View File

@@ -39,9 +39,13 @@ func AskAlert(title: String?, text: String?, buttonText: String = "Continue", bu
/// Show alert hinting the user to go to system settings and re-enable notifications.
func NotificationsDisabledAlert(presentIn viewController: UIViewController) {
Alert(title: "Notifications Disabled",
text: "Go to System Settings > Notifications > AppCheck to re-enable notifications."
).presentIn(viewController)
AskAlert(title: "Notifications Disabled",
text: "Go to System Settings > Notifications > AppCheck to re-enable notifications.",
buttonText: "Open settings") { _ in
if let url = URL(string: UIApplication.openSettingsURLString) {
UIApplication.shared.openURL(url)
}
}.presentIn(viewController)
}
// MARK: Alert with multiple options

View File

@@ -260,7 +260,7 @@
</barButtonItem>
<barButtonItem key="rightBarButtonItem" title="Send" style="done" id="PWY-06-ykI">
<connections>
<action selector="shareRecording" destination="P0a-ZP-uEV" id="lSZ-8V-ANw"/>
<action selector="shareRecording:" destination="P0a-ZP-uEV" id="vCR-9d-91D"/>
</connections>
</barButtonItem>
</navigationItem>
@@ -274,6 +274,9 @@
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
</textView>
<activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" translatesAutoresizingMaskIntoConstraints="NO" id="eWC-xB-CJe">
<rect key="frame" x="292" y="12" width="20" height="20"/>
</activityIndicatorView>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<constraints>
@@ -283,11 +286,14 @@
<constraint firstItem="dN0-a9-t4G" firstAttribute="leading" secondItem="lie-9P-DtH" secondAttribute="leading" id="BWF-aS-ah3"/>
<constraint firstItem="lie-9P-DtH" firstAttribute="trailing" secondItem="fFm-v5-DGy" secondAttribute="trailing" id="GRg-BF-rYE"/>
<constraint firstItem="lie-9P-DtH" firstAttribute="bottom" secondItem="fFm-v5-DGy" secondAttribute="bottom" id="IE3-o5-suZ"/>
<constraint firstItem="eWC-xB-CJe" firstAttribute="trailing" secondItem="dN0-a9-t4G" secondAttribute="trailingMargin" id="NgN-7W-Ecm"/>
<constraint firstItem="lie-9P-DtH" firstAttribute="trailing" secondItem="dN0-a9-t4G" secondAttribute="trailing" id="UuJ-xj-xBK"/>
<constraint firstItem="eWC-xB-CJe" firstAttribute="centerY" secondItem="dN0-a9-t4G" secondAttribute="centerY" id="jvl-OA-Vdr"/>
</constraints>
<viewLayoutGuide key="safeArea" id="lie-9P-DtH"/>
</view>
<connections>
<outlet property="sendActivity" destination="eWC-xB-CJe" id="rx3-Jz-ppT"/>
<outlet property="text" destination="fFm-v5-DGy" id="fwm-RE-gHu"/>
</connections>
</viewController>

View File

@@ -106,7 +106,7 @@ class TVCAppSearch: UITableViewController, UISearchBarDelegate {
let alert = AskAlert(title: "App Name",
text: "Be as descriptive as possible. Preferably use app bundle id if available. Alternatively use app name or a link to a public repository.",
buttonText: "Set") {
self.delegate?.appSearch(didSelect: "un.known", appName: $0.textFields?.first?.text, developer: nil)
self.delegate?.appSearch(didSelect: "_manually", appName: $0.textFields?.first?.text, developer: nil)
self.closeThis()
}
alert.addTextField { $0.placeholder = "com.apple.notes" }

View File

@@ -21,7 +21,7 @@ class VCEditRecording: UIViewController, UITextFieldDelegate, UITextViewDelegate
if record.isLongTerm {
appId = nil
appIcon.image = nil
appTitle.text = "Background Recording"
appTitle.text = record.fallbackTitle
appDeveloper.text = nil
chooseAppTap.isEnabled = false
} else {
@@ -158,7 +158,7 @@ class VCEditRecording: UIViewController, UITextFieldDelegate, UITextViewDelegate
private func validateSaveButton() {
let changed = (appId != record.appId
|| (appTitle.text != record.title && appTitle.text != "Tap here to choose app")
|| (appTitle.text != record.title && appTitle.text != "Tap here to choose app" && appTitle.text != record.fallbackTitle)
|| appDeveloper.text != record.subtitle
|| inputNotes.text != record.notes ?? "")
buttonSave.isEnabled = changed || deleteOnCancel // always allow save for new recordings

View File

@@ -6,6 +6,7 @@ class VCShareRecording : UIViewController {
private var jsonData: Data?
@IBOutlet private var text : UITextView!
@IBOutlet private var sendActivity : UIActivityIndicatorView!
override func viewDidLoad() {
super.viewDidLoad()
@@ -59,8 +60,68 @@ class VCShareRecording : UIViewController {
dismiss(animated: true)
}
@IBAction private func shareRecording() {
print("\(String(data: jsonData!, encoding: .utf8)!)")
Alert(title: "Not implemented yet", text: nil).presentIn(self)
@IBAction private func shareRecording(_ sender: UIBarButtonItem) {
sender.isEnabled = false
sendActivity.startAnimating()
let url = URL(string: "http://127.0.0.1/api/v1/contribute/")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = jsonData
URLSession.shared.dataTask(with: request) { data, response, error in
DispatchQueue.main.async { [weak self] in
sender.isEnabled = true
self?.sendActivity.stopAnimating()
guard error == nil, let data = data,
let response = response as? HTTPURLResponse else {
self?.banner(.fail, "\(error?.localizedDescription ?? "Unkown error occurred")")
return
}
let json = (try? JSONSerialization.jsonObject(with: data, options: [])) as? [String: Any]
let status = json?["status"] as? String
let v = json?["v"] as? Int ?? 0
guard v > 0, (200 ... 299) ~= response.statusCode else {
QLog.Warning("Couldn't contribute: \(status ?? "unkown reason")")
self?.banner(.fail, "Server couldn't parse request.\nTry again later.")
return
}
var autoHide = true
if v == 1, let urlStr = json?["url"] as? String {
let nextUpdateIn = json?["when"] as? Int
self?.showOpenResultsAlert(urlStr, when: nextUpdateIn)
autoHide = false
}
self?.banner(.ok, "Thank you for your contribution.",
autoHide ? { [weak self] in self?.closeView() } : nil)
}
}.resume()
}
private func banner(_ style: NotificationBanner.Style, _ msg: String, _ closure: (() -> Void)? = nil) {
NotificationBanner(msg, style: style).present(in: self, onClose: closure)
}
private func showOpenResultsAlert(_ urlStr: String, when: Int?) {
var msg = "Your contribution is being processed and will be available "
if let when = when {
if when < 61 {
msg += "in approx. \(when) sec. "
} else {
let fmt = TimeFormat.from(Timestamp(when))
msg += "in \(fmt) min. "
}
} else {
msg += "shortly. "
}
msg += "Open results webpage now?"
let alert = Alert(title: "Thank you", text: msg, buttonText: "Not now")
alert.addAction(UIAlertAction(title: "Show results", style: .default) { _ in
if let url = URL(string: urlStr) {
UIApplication.shared.openURL(url)
}
})
alert.presentIn(self)
}
}