2017-02-02 21:04:31 +08:00
|
|
|
//
|
|
|
|
|
// LabelTableViewCell.swift
|
|
|
|
|
// pass
|
|
|
|
|
//
|
|
|
|
|
// Created by Mingshen Sun on 2/2/2017.
|
|
|
|
|
// Copyright © 2017 Bob Sun. All rights reserved.
|
|
|
|
|
//
|
|
|
|
|
|
2017-06-13 11:42:49 +08:00
|
|
|
import passKit
|
2020-06-28 21:25:40 +02:00
|
|
|
import SVProgressHUD
|
|
|
|
|
import UIKit
|
2017-02-02 21:04:31 +08:00
|
|
|
|
2017-02-05 13:56:37 +08:00
|
|
|
struct LabelTableViewCellData {
|
|
|
|
|
var title: String
|
|
|
|
|
var content: String
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-02 21:04:31 +08:00
|
|
|
class LabelTableViewCell: UITableViewCell {
|
2020-06-28 21:25:40 +02:00
|
|
|
@IBOutlet var contentLabel: UILabel!
|
|
|
|
|
@IBOutlet var titleLabel: UILabel!
|
2018-12-09 16:59:07 -08:00
|
|
|
|
2017-04-05 00:17:39 +08:00
|
|
|
private enum CellType {
|
|
|
|
|
case password, URL, HOTP, other
|
|
|
|
|
}
|
2017-02-05 13:56:37 +08:00
|
|
|
|
2017-04-05 00:17:39 +08:00
|
|
|
private var type = CellType.other
|
|
|
|
|
private var isReveal = false
|
2018-12-09 16:59:07 -08:00
|
|
|
|
2020-06-28 21:25:40 +02:00
|
|
|
weak var delegatePasswordTableView: PasswordDetailTableViewController?
|
2018-12-09 16:59:07 -08:00
|
|
|
|
2017-04-05 00:17:39 +08:00
|
|
|
private var passwordDisplayButton: UIButton?
|
|
|
|
|
private var buttons: UIView?
|
2018-12-09 16:59:07 -08:00
|
|
|
|
2017-02-05 13:56:37 +08:00
|
|
|
var cellData: LabelTableViewCellData? {
|
|
|
|
|
didSet {
|
2017-04-05 00:17:39 +08:00
|
|
|
guard let title = cellData?.title, let content = cellData?.content else {
|
|
|
|
|
type = .other
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
titleLabel.text = title
|
2018-04-04 12:54:35 +08:00
|
|
|
if title.caseInsensitiveCompare("password") == .orderedSame {
|
2017-04-05 00:17:39 +08:00
|
|
|
type = .password
|
2017-03-07 00:52:22 +08:00
|
|
|
if isReveal {
|
2017-04-05 00:17:39 +08:00
|
|
|
contentLabel.attributedText = Utils.attributedPassword(plainPassword: content)
|
2017-03-07 00:52:22 +08:00
|
|
|
} else {
|
2017-04-05 00:17:39 +08:00
|
|
|
if content == "" {
|
|
|
|
|
contentLabel.text = ""
|
|
|
|
|
} else {
|
|
|
|
|
contentLabel.text = Globals.passwordDots
|
|
|
|
|
}
|
2017-03-07 00:52:22 +08:00
|
|
|
}
|
2017-10-07 23:05:26 -07:00
|
|
|
contentLabel.font = Globals.passwordFont
|
2019-01-14 20:57:45 +01:00
|
|
|
} else if title.caseInsensitiveCompare("HmacBased".localize()) == .orderedSame {
|
2017-04-05 00:17:39 +08:00
|
|
|
type = .HOTP
|
2017-03-07 00:52:22 +08:00
|
|
|
if isReveal {
|
2017-04-05 00:17:39 +08:00
|
|
|
contentLabel.text = content
|
2017-03-07 00:52:22 +08:00
|
|
|
} else {
|
2017-04-05 00:17:39 +08:00
|
|
|
contentLabel.text = Globals.oneTimePasswordDots
|
2017-03-07 00:52:22 +08:00
|
|
|
}
|
2017-10-07 23:05:26 -07:00
|
|
|
contentLabel.font = Globals.passwordFont
|
2018-12-07 21:50:28 +01:00
|
|
|
} else if title.lowercased().contains("url") {
|
2017-04-05 00:17:39 +08:00
|
|
|
type = .URL
|
|
|
|
|
contentLabel.text = content
|
2017-05-08 20:57:39 +08:00
|
|
|
contentLabel.font = UIFont.systemFont(ofSize: contentLabel.font.pointSize)
|
2018-04-04 12:54:35 +08:00
|
|
|
} else {
|
|
|
|
|
// default
|
2017-04-05 00:17:39 +08:00
|
|
|
type = .other
|
|
|
|
|
contentLabel.text = content
|
2017-05-08 20:57:39 +08:00
|
|
|
contentLabel.font = UIFont.systemFont(ofSize: contentLabel.font.pointSize)
|
2017-02-06 11:55:27 +08:00
|
|
|
}
|
2017-03-31 03:08:20 +08:00
|
|
|
updateButtons()
|
2017-02-05 13:56:37 +08:00
|
|
|
}
|
|
|
|
|
}
|
2018-12-09 16:59:07 -08:00
|
|
|
|
2017-02-05 00:35:23 +08:00
|
|
|
override var canBecomeFirstResponder: Bool {
|
2020-06-28 21:25:40 +02:00
|
|
|
true
|
2017-02-05 00:35:23 +08:00
|
|
|
}
|
|
|
|
|
|
2020-06-28 21:25:40 +02:00
|
|
|
override func canPerformAction(_ action: Selector, withSender _: Any?) -> Bool {
|
2017-04-05 00:17:39 +08:00
|
|
|
switch type {
|
|
|
|
|
case .password:
|
2017-02-06 11:55:27 +08:00
|
|
|
if isReveal {
|
2017-04-05 00:17:39 +08:00
|
|
|
return action == #selector(copy(_:)) || action == #selector(concealPassword(_:))
|
2017-02-06 11:55:27 +08:00
|
|
|
} else {
|
2017-04-05 00:17:39 +08:00
|
|
|
return action == #selector(copy(_:)) || action == #selector(revealPassword(_:))
|
2017-02-06 11:55:27 +08:00
|
|
|
}
|
2017-04-05 00:17:39 +08:00
|
|
|
case .URL:
|
|
|
|
|
return action == #selector(copy(_:)) || action == #selector(openLink(_:))
|
|
|
|
|
case .HOTP:
|
2017-03-07 00:52:22 +08:00
|
|
|
if isReveal {
|
2017-04-05 00:17:39 +08:00
|
|
|
return action == #selector(copy(_:)) || action == #selector(concealPassword(_:)) || action == #selector(getNextHOTP(_:))
|
2017-03-07 00:52:22 +08:00
|
|
|
} else {
|
2017-04-05 00:17:39 +08:00
|
|
|
return action == #selector(copy(_:)) || action == #selector(revealPassword(_:)) || action == #selector(getNextHOTP(_:))
|
2017-03-07 00:52:22 +08:00
|
|
|
}
|
2017-04-05 00:17:39 +08:00
|
|
|
default:
|
|
|
|
|
return action == #selector(copy(_:))
|
2017-03-07 00:52:22 +08:00
|
|
|
}
|
2017-02-05 00:35:23 +08:00
|
|
|
}
|
2017-04-05 00:17:39 +08:00
|
|
|
|
2020-06-28 21:25:40 +02:00
|
|
|
override func copy(_: Any?) {
|
2017-07-27 23:56:24 +08:00
|
|
|
SecurePasteboard.shared.copy(textToCopy: cellData?.content)
|
2017-02-05 00:35:23 +08:00
|
|
|
}
|
2018-12-09 16:59:07 -08:00
|
|
|
|
2020-06-28 21:25:40 +02:00
|
|
|
@objc
|
|
|
|
|
func revealPassword(_: Any?) {
|
2017-04-05 00:17:39 +08:00
|
|
|
let plainPassword = cellData?.content ?? ""
|
|
|
|
|
if type == .password {
|
|
|
|
|
contentLabel.attributedText = Utils.attributedPassword(plainPassword: plainPassword)
|
2017-02-24 00:24:39 +08:00
|
|
|
} else {
|
2017-04-05 00:17:39 +08:00
|
|
|
contentLabel.text = plainPassword
|
2017-02-24 00:24:39 +08:00
|
|
|
}
|
2017-02-06 11:55:27 +08:00
|
|
|
isReveal = true
|
2017-03-31 03:08:20 +08:00
|
|
|
passwordDisplayButton?.setImage(#imageLiteral(resourceName: "Invisible"), for: .normal)
|
2017-02-06 11:55:27 +08:00
|
|
|
}
|
2018-12-09 16:59:07 -08:00
|
|
|
|
2020-06-28 21:25:40 +02:00
|
|
|
@objc
|
|
|
|
|
func concealPassword(_: Any?) {
|
2017-04-05 00:17:39 +08:00
|
|
|
if type == .password {
|
|
|
|
|
if cellData?.content.isEmpty == false {
|
|
|
|
|
contentLabel.text = Globals.passwordDots
|
2019-10-01 22:36:22 +02:00
|
|
|
contentLabel.textColor = Colors.label
|
2017-04-05 00:17:39 +08:00
|
|
|
} else {
|
|
|
|
|
contentLabel.text = ""
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
contentLabel.text = Globals.oneTimePasswordDots
|
|
|
|
|
}
|
2017-02-06 11:55:27 +08:00
|
|
|
isReveal = false
|
2017-03-31 03:08:20 +08:00
|
|
|
passwordDisplayButton?.setImage(#imageLiteral(resourceName: "Visible"), for: .normal)
|
|
|
|
|
}
|
2018-12-09 16:59:07 -08:00
|
|
|
|
2020-06-28 21:25:40 +02:00
|
|
|
@objc
|
|
|
|
|
func reversePasswordDisplay(_ sender: Any?) {
|
2017-03-31 03:08:20 +08:00
|
|
|
if isReveal {
|
|
|
|
|
// conceal
|
|
|
|
|
concealPassword(sender)
|
|
|
|
|
} else {
|
|
|
|
|
// reveal
|
|
|
|
|
revealPassword(sender)
|
|
|
|
|
}
|
2017-02-06 11:55:27 +08:00
|
|
|
}
|
2017-03-31 03:08:20 +08:00
|
|
|
|
2020-06-28 21:25:40 +02:00
|
|
|
@objc
|
|
|
|
|
func openLink(_: Any?) {
|
2017-03-22 01:39:26 +08:00
|
|
|
// if isURLCell, passwordTableView should not be nil
|
2018-12-07 21:55:30 +01:00
|
|
|
delegatePasswordTableView!.openLink(to: cellData?.content)
|
2017-03-07 00:52:22 +08:00
|
|
|
}
|
2018-12-09 16:59:07 -08:00
|
|
|
|
2020-06-28 21:25:40 +02:00
|
|
|
@objc
|
|
|
|
|
func getNextHOTP(_: Any?) {
|
2017-03-22 01:39:26 +08:00
|
|
|
// if isHOTPCell, passwordTableView should not be nil
|
|
|
|
|
delegatePasswordTableView!.getNextHOTP()
|
2017-02-08 17:55:18 +08:00
|
|
|
}
|
2018-12-09 16:59:07 -08:00
|
|
|
|
2017-04-05 00:17:39 +08:00
|
|
|
private func updateButtons() {
|
2017-03-31 22:15:30 +08:00
|
|
|
// total width and height of a button
|
2020-06-28 21:25:40 +02:00
|
|
|
let height = min(bounds.height, 36.0)
|
2017-03-31 22:15:30 +08:00
|
|
|
let width = max(height * 0.8, Globals.tableCellButtonSize)
|
2018-12-09 16:59:07 -08:00
|
|
|
|
2017-03-31 22:15:30 +08:00
|
|
|
// margins (between button boundary and icon)
|
|
|
|
|
let marginY = max((height - Globals.tableCellButtonSize) / 2, 0.0)
|
|
|
|
|
let marginX = max((width - Globals.tableCellButtonSize) / 2, 0.0)
|
2018-12-09 16:59:07 -08:00
|
|
|
|
2017-04-05 00:17:39 +08:00
|
|
|
switch type {
|
|
|
|
|
case .password:
|
|
|
|
|
if let content = cellData?.content, content != "" {
|
|
|
|
|
// password button
|
|
|
|
|
passwordDisplayButton = UIButton(type: .system)
|
|
|
|
|
passwordDisplayButton!.frame = CGRect(x: 0, y: 0, width: width, height: height)
|
|
|
|
|
passwordDisplayButton!.setImage(#imageLiteral(resourceName: "Visible"), for: .normal)
|
|
|
|
|
passwordDisplayButton!.imageView?.contentMode = .scaleAspectFit
|
2020-06-28 21:25:40 +02:00
|
|
|
passwordDisplayButton!.contentEdgeInsets = UIEdgeInsets(top: marginY, left: marginX, bottom: marginY, right: marginX)
|
2019-05-01 17:49:27 +02:00
|
|
|
passwordDisplayButton!.addTarget(self, action: #selector(reversePasswordDisplay), for: UIControl.Event.touchUpInside)
|
2017-04-05 00:17:39 +08:00
|
|
|
buttons = passwordDisplayButton
|
|
|
|
|
}
|
|
|
|
|
case .HOTP:
|
2017-03-31 03:08:20 +08:00
|
|
|
// hotp button
|
|
|
|
|
let nextButton = UIButton(type: .system)
|
2017-03-31 22:15:30 +08:00
|
|
|
nextButton.frame = CGRect(x: 0, y: 0, width: width, height: height)
|
2017-03-31 03:08:20 +08:00
|
|
|
nextButton.setImage(#imageLiteral(resourceName: "Refresh"), for: .normal)
|
|
|
|
|
nextButton.imageView?.contentMode = .scaleAspectFit
|
2020-06-28 21:25:40 +02:00
|
|
|
nextButton.contentEdgeInsets = UIEdgeInsets(top: marginY, left: marginX, bottom: marginY, right: marginX)
|
2019-05-01 17:49:27 +02:00
|
|
|
nextButton.addTarget(self, action: #selector(getNextHOTP), for: UIControl.Event.touchUpInside)
|
2018-12-09 16:59:07 -08:00
|
|
|
|
2017-03-31 03:08:20 +08:00
|
|
|
// password button
|
|
|
|
|
passwordDisplayButton = UIButton(type: .system)
|
2017-03-31 22:15:30 +08:00
|
|
|
passwordDisplayButton!.frame = CGRect(x: width, y: 0, width: width, height: height)
|
|
|
|
|
|
2017-03-31 03:08:20 +08:00
|
|
|
passwordDisplayButton!.setImage(#imageLiteral(resourceName: "Visible"), for: .normal)
|
|
|
|
|
passwordDisplayButton!.imageView?.contentMode = .scaleAspectFit
|
2020-06-28 21:25:40 +02:00
|
|
|
passwordDisplayButton!.contentEdgeInsets = UIEdgeInsets(top: marginY, left: marginX, bottom: marginY, right: marginX)
|
2019-05-01 17:49:27 +02:00
|
|
|
passwordDisplayButton!.addTarget(self, action: #selector(reversePasswordDisplay), for: UIControl.Event.touchUpInside)
|
2018-12-09 16:59:07 -08:00
|
|
|
|
2017-03-31 03:08:20 +08:00
|
|
|
buttons = UIView()
|
2017-03-31 22:15:30 +08:00
|
|
|
buttons!.frame = CGRect(x: 0, y: 0, width: width * 2, height: height)
|
2017-03-31 03:08:20 +08:00
|
|
|
buttons!.addSubview(nextButton)
|
|
|
|
|
buttons!.addSubview(passwordDisplayButton!)
|
2017-04-05 00:17:39 +08:00
|
|
|
default:
|
|
|
|
|
passwordDisplayButton = nil
|
|
|
|
|
buttons = nil
|
2017-03-31 03:08:20 +08:00
|
|
|
}
|
2020-06-28 21:25:40 +02:00
|
|
|
accessoryView = buttons
|
2017-03-31 03:08:20 +08:00
|
|
|
}
|
2017-02-02 21:04:31 +08:00
|
|
|
}
|