Improve Account section for providers

This commit is contained in:
Davide De Rosa 2019-04-05 16:17:34 +02:00
parent 00a4fe9a74
commit bc457270cc
4 changed files with 166 additions and 82 deletions

View File

@ -329,6 +329,30 @@
</subviews> </subviews>
</tableViewCellContentView> </tableViewCellContentView>
</tableViewCell> </tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="SettingTableViewCell" textLabel="fgS-Wv-Ps8" detailTextLabel="5Qq-6l-gb9" style="IBUITableViewCellStyleValue1" id="WlQ-JJ-3z3" customClass="SettingTableViewCell" customModule="Passepartout" customModuleProvider="target">
<rect key="frame" x="0.0" y="99.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="WlQ-JJ-3z3" id="2P7-8h-6AC">
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="fgS-Wv-Ps8">
<rect key="frame" x="15" y="12" width="33.5" height="20.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Detail" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="5Qq-6l-gb9">
<rect key="frame" x="316" y="12" width="44" height="20.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</tableViewCellContentView>
</tableViewCell>
</prototypes> </prototypes>
<connections> <connections>
<outlet property="dataSource" destination="eIk-8Z-CLS" id="GbK-wM-Fhp"/> <outlet property="dataSource" destination="eIk-8Z-CLS" id="GbK-wM-Fhp"/>

View File

@ -56,6 +56,26 @@ class AccountViewController: UIViewController, TableModelHost {
return Credentials(username, password).trimmed() return Credentials(username, password).trimmed()
} }
private var guidanceString: String? {
guard let name = infrastructureName else {
return nil
}
let V = L10n.Account.Sections.Guidance.Footer.Infrastructure.self
switch name {
case .mullvad:
return V.mullvad(name.rawValue)
case .pia:
return V.pia(name.rawValue)
case .tunnelBear:
return V.tunnelbear(name.rawValue)
case .windscribe:
return V.windscribe(name.rawValue)
}
}
private var guidanceURL: String? { private var guidanceURL: String? {
guard let name = infrastructureName else { guard let name = infrastructureName else {
return nil return nil
@ -80,41 +100,24 @@ class AccountViewController: UIViewController, TableModelHost {
model.clear() model.clear()
model.add(.credentials) model.add(.credentials)
model.setHeader("", for: .credentials) model.setHeader(L10n.Account.Sections.Credentials.header, for: .credentials)
model.set([.username, .password], in: .credentials) model.set([.username, .password], in: .credentials)
if let name = infrastructureName { if let name = infrastructureName {
let V = L10n.Account.SuggestionFooter.self if let guidanceString = guidanceString {
var guidance: String?
switch name {
case .mullvad:
guidance = V.Infrastructure.mullvad
case .pia:
guidance = V.Infrastructure.pia
case .tunnelBear:
guidance = V.Infrastructure.tunnelbear
case .windscribe:
guidance = V.Infrastructure.windscribe
}
model.add(.noAccount)
model.set([], in: .noAccount)
if guidance != nil {
let footer: String
if let _ = guidanceURL { if let _ = guidanceURL {
footer = "\(guidance!) \(V.guidanceLink)" model.add(.guidance)
model.setFooter(guidanceString, for: .guidance)
model.set([.openGuide], in: .guidance)
} else { } else {
footer = guidance! model.setFooter(guidanceString, for: .credentials)
} }
model.setFooter(footer, for: .credentials) model.setHeader("", for: .registration)
} }
if let _ = referralURL { if let _ = referralURL {
model.setFooter(V.referral, for: .noAccount) model.add(.registration)
model.setFooter(L10n.Account.Sections.Registration.footer(name.rawValue), for: .registration)
model.set([.signUp], in: .registration)
} }
} }
} }
@ -154,6 +157,20 @@ class AccountViewController: UIViewController, TableModelHost {
delegate?.accountController(self, didEnterCredentials: newCredentials) delegate?.accountController(self, didEnterCredentials: newCredentials)
} }
private func openGuidanceURL() {
guard let urlString = guidanceURL else {
return
}
UIApplication.shared.open(URL(string: urlString)!, options: [:], completionHandler: nil)
}
private func openReferralURL() {
guard let urlString = referralURL else {
return
}
UIApplication.shared.open(URL(string: urlString)!, options: [:], completionHandler: nil)
}
@IBAction private func done() { @IBAction private func done() {
view.endEditing(true) view.endEditing(true)
delegate?.accountControllerDidComplete(self) delegate?.accountControllerDidComplete(self)
@ -166,13 +183,19 @@ extension AccountViewController: UITableViewDataSource, UITableViewDelegate, Fie
enum SectionType: Int { enum SectionType: Int {
case credentials case credentials
case noAccount case guidance
case registration
} }
enum RowType: Int { enum RowType: Int {
case username case username
case password case password
case openGuide
case signUp
} }
private static let footerButtonTag = 1000 private static let footerButtonTag = 1000
@ -181,6 +204,10 @@ extension AccountViewController: UITableViewDataSource, UITableViewDelegate, Fie
return model.count return model.count
} }
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return model.header(for: section)
}
func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? { func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? {
return model.footer(for: section) return model.footer(for: section)
} }
@ -189,26 +216,14 @@ extension AccountViewController: UITableViewDataSource, UITableViewDelegate, Fie
return model.headerHeight(for: section) return model.headerHeight(for: section)
} }
func tableView(_ tableView: UITableView, willDisplayFooterView view: UIView, forSection section: Int) {
var optButton = view.viewWithTag(AccountViewController.footerButtonTag + section) as? UIButton
if optButton == nil {
let button = UIButton()
button.frame = view.bounds
button.tag = AccountViewController.footerButtonTag + section
view.addSubview(button)
optButton = button
}
optButton?.addTarget(self, action: #selector(footerTapped(_:)), for: .touchUpInside)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return model.count(for: section) return model.count(for: section)
} }
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = Cells.field.dequeue(from: tableView, for: indexPath)
switch model.row(at: indexPath) { switch model.row(at: indexPath) {
case .username: case .username:
let cell = Cells.field.dequeue(from: tableView, for: indexPath)
cellUsername = cell cellUsername = cell
cell.caption = L10n.Account.Cells.Username.caption cell.caption = L10n.Account.Cells.Username.caption
cell.field.placeholder = usernamePlaceholder ?? L10n.Account.Cells.Username.placeholder cell.field.placeholder = usernamePlaceholder ?? L10n.Account.Cells.Username.placeholder
@ -218,8 +233,12 @@ extension AccountViewController: UITableViewDataSource, UITableViewDelegate, Fie
cell.field.keyboardType = .emailAddress cell.field.keyboardType = .emailAddress
cell.field.returnKeyType = .next cell.field.returnKeyType = .next
cell.field.textContentType = .username cell.field.textContentType = .username
cell.captionWidth = 120.0
cell.delegate = self
return cell
case .password: case .password:
let cell = Cells.field.dequeue(from: tableView, for: indexPath)
cellPassword = cell cellPassword = cell
cell.caption = L10n.Account.Cells.Password.caption cell.caption = L10n.Account.Cells.Password.caption
cell.field.placeholder = L10n.Account.Cells.Password.placeholder cell.field.placeholder = L10n.Account.Cells.Password.placeholder
@ -228,10 +247,39 @@ extension AccountViewController: UITableViewDataSource, UITableViewDelegate, Fie
cell.field.text = currentCredentials?.password cell.field.text = currentCredentials?.password
cell.field.returnKeyType = .done cell.field.returnKeyType = .done
cell.field.textContentType = .password cell.field.textContentType = .password
cell.captionWidth = 120.0
cell.delegate = self
return cell
case .openGuide:
let cell = Cells.setting.dequeue(from: tableView, for: indexPath)
cell.leftText = L10n.Account.Cells.OpenGuide.caption
cell.applyAction(Theme.current)
return cell
case .signUp:
guard let name = infrastructureName else {
fatalError("Sign-up shown when not a provider profile")
}
let cell = Cells.setting.dequeue(from: tableView, for: indexPath)
cell.leftText = L10n.Account.Cells.Signup.caption(name.rawValue)
cell.applyAction(Theme.current)
return cell
} }
cell.captionWidth = 120.0 }
cell.delegate = self
return cell func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
switch model.row(at: indexPath) {
case .openGuide:
openGuidanceURL()
case .signUp:
openReferralURL()
default:
break
}
tableView.deselectRow(at: indexPath, animated: true)
} }
func fieldCellDidEdit(_: FieldTableViewCell) { func fieldCellDidEdit(_: FieldTableViewCell) {
@ -251,22 +299,4 @@ extension AccountViewController: UITableViewDataSource, UITableViewDelegate, Fie
break break
} }
} }
@objc private func footerTapped(_ sender: Any?) {
guard let button = sender as? UIButton, let section = SectionType(rawValue: button.tag - AccountViewController.footerButtonTag) else {
return
}
var urlString: String?
switch section {
case .credentials:
urlString = guidanceURL
case .noAccount:
urlString = referralURL
}
guard let url = urlString else {
return
}
UIApplication.shared.open(URL(string: url)!, options: [:], completionHandler: nil)
}
} }

View File

@ -129,18 +129,20 @@
"service.alerts.masks_private_data.messages.must_reconnect" = "In order to safely reset the current debug log and apply the new masking preference, you must reconnect to the VPN now."; "service.alerts.masks_private_data.messages.must_reconnect" = "In order to safely reset the current debug log and apply the new masking preference, you must reconnect to the VPN now.";
"service.alerts.buttons.reconnect" = "Reconnect"; "service.alerts.buttons.reconnect" = "Reconnect";
"account.sections.credentials.header" = "Credentials";
"account.sections.guidance.footer.infrastructure.mullvad" = "Use your %@ website account number and password \"m\".";
"account.sections.guidance.footer.infrastructure.pia" = "Use your %@ website credentials. Your username is usually numeric with a \"p\" prefix.";
"account.sections.guidance.footer.infrastructure.tunnelbear" = "Use your %@ website credentials. Your username is usually your email.";
"account.sections.guidance.footer.infrastructure.windscribe" = "Find your credentials in the OpenVPN Config Generator on the %@ website.";
"account.sections.registration.footer" = "Go get an account on the %@ website.";
"account.cells.username.caption" = "Username"; "account.cells.username.caption" = "Username";
"account.cells.username.placeholder" = "username"; "account.cells.username.placeholder" = "username";
"account.cells.password.caption" = "Password"; "account.cells.password.caption" = "Password";
"account.cells.password.placeholder" = "secret"; "account.cells.password.placeholder" = "secret";
//"account.cells.password_confirm.caption" = "Confirm"; //"account.cells.password_confirm.caption" = "Confirm";
//"account.cells.password_confirm.mismatch" = "Passwords don't match!"; //"account.cells.password_confirm.mismatch" = "Passwords don't match!";
"account.suggestion_footer.infrastructure.mullvad" = "Use your website account number and password \"m\"."; "account.cells.open_guide.caption" = "See your credentials";
"account.suggestion_footer.infrastructure.pia" = "Use your website credentials. Your username is usually numeric with a \"p\" prefix."; "account.cells.signup.caption" = "Register with %@";
"account.suggestion_footer.infrastructure.tunnelbear" = "Use your website credentials. Your username is usually your email.";
"account.suggestion_footer.infrastructure.windscribe" = "Find your credentials in the OpenVPN Config Generator on the website.";
"account.suggestion_footer.guidance_link" = "Tap to open web page.";
"account.suggestion_footer.referral" = "Don't have an account? Tap here to get one.";
"endpoint.sections.location_addresses.header" = "Addresses"; "endpoint.sections.location_addresses.header" = "Addresses";
"endpoint.sections.location_protocols.header" = "Protocols"; "endpoint.sections.location_protocols.header" = "Protocols";

View File

@ -67,12 +67,22 @@ public enum L10n {
public enum Account { public enum Account {
public enum Cells { public enum Cells {
public enum OpenGuide {
/// Find your credentials
public static let caption = L10n.tr("Localizable", "account.cells.open_guide.caption")
}
public enum Password { public enum Password {
/// Password /// Password
public static let caption = L10n.tr("Localizable", "account.cells.password.caption") public static let caption = L10n.tr("Localizable", "account.cells.password.caption")
/// secret /// secret
public static let placeholder = L10n.tr("Localizable", "account.cells.password.placeholder") public static let placeholder = L10n.tr("Localizable", "account.cells.password.placeholder")
} }
public enum Signup {
/// Register with %@
public static func caption(_ p1: String) -> String {
return L10n.tr("Localizable", "account.cells.signup.caption", p1)
}
}
public enum Username { public enum Username {
/// Username /// Username
public static let caption = L10n.tr("Localizable", "account.cells.username.caption") public static let caption = L10n.tr("Localizable", "account.cells.username.caption")
@ -80,20 +90,38 @@ public enum L10n {
public static let placeholder = L10n.tr("Localizable", "account.cells.username.placeholder") public static let placeholder = L10n.tr("Localizable", "account.cells.username.placeholder")
} }
} }
public enum SuggestionFooter { public enum Sections {
/// Tap to open web page. public enum Credentials {
public static let guidanceLink = L10n.tr("Localizable", "account.suggestion_footer.guidance_link") /// Credentials
/// Don't have an account? Tap here to get one. public static let header = L10n.tr("Localizable", "account.sections.credentials.header")
public static let referral = L10n.tr("Localizable", "account.suggestion_footer.referral") }
public enum Infrastructure { public enum Guidance {
/// Use your website account number and password "m". public enum Footer {
public static let mullvad = L10n.tr("Localizable", "account.suggestion_footer.infrastructure.mullvad") public enum Infrastructure {
/// Use your website credentials. Your username is usually numeric with a "p" prefix. /// Use your %@ website account number and password "m".
public static let pia = L10n.tr("Localizable", "account.suggestion_footer.infrastructure.pia") public static func mullvad(_ p1: String) -> String {
/// Use your website credentials. Your username is usually your email. return L10n.tr("Localizable", "account.sections.guidance.footer.infrastructure.mullvad", p1)
public static let tunnelbear = L10n.tr("Localizable", "account.suggestion_footer.infrastructure.tunnelbear") }
/// Find your credentials in the OpenVPN Config Generator on the website. /// Use your %@ website credentials. Your username is usually numeric with a "p" prefix.
public static let windscribe = L10n.tr("Localizable", "account.suggestion_footer.infrastructure.windscribe") public static func pia(_ p1: String) -> String {
return L10n.tr("Localizable", "account.sections.guidance.footer.infrastructure.pia", p1)
}
/// Use your %@ website credentials. Your username is usually your email.
public static func tunnelbear(_ p1: String) -> String {
return L10n.tr("Localizable", "account.sections.guidance.footer.infrastructure.tunnelbear", p1)
}
/// Find your credentials in the OpenVPN Config Generator on the %@ website.
public static func windscribe(_ p1: String) -> String {
return L10n.tr("Localizable", "account.sections.guidance.footer.infrastructure.windscribe", p1)
}
}
}
}
public enum Registration {
/// Go get an account on the %@ website.
public static func footer(_ p1: String) -> String {
return L10n.tr("Localizable", "account.sections.registration.footer", p1)
}
} }
} }
} }