Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Proxy-Screen #2388

Merged
merged 27 commits into from
Nov 13, 2024
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
31f455a
Add cell for proxy-settings to Advanced Settings (#2382)
zeitschlag Nov 4, 2024
a4946b4
Get proxies from core (hopefully, #2382)
zeitschlag Nov 5, 2024
7459f02
[WIP] Sketch ProxySettings-screen (#2382)
zeitschlag Nov 5, 2024
dc03551
Add cells to toggle/add proxies (#2382)
zeitschlag Nov 5, 2024
71ca66a
Properly separate newline-separated strings into a list (#2382)
zeitschlag Nov 6, 2024
bc2b3aa
Add and select proxies (#2382)
zeitschlag Nov 6, 2024
c1e56bd
Delete proxies (#2382)
zeitschlag Nov 6, 2024
a0ad969
Properly delete proxies (#2382)
zeitschlag Nov 7, 2024
786a29f
Use a tableviewcontroller, disable toggle (if needed), show alert whe…
zeitschlag Nov 7, 2024
ea9e083
Add an alert to prevent accidental proxy-deletion (#2382)
zeitschlag Nov 7, 2024
23df034
Try to fix build (#2382)
zeitschlag Nov 7, 2024
ebe04fa
Show host and protocol instead of entire proxy-URL (#2382)
zeitschlag Nov 7, 2024
91a7667
Add title to proxy-section (#2382)
zeitschlag Nov 8, 2024
5c35138
Show an error-alert in case of an invalid proxy (#2382)
zeitschlag Nov 8, 2024
acdd843
Really enable/disable proxies when tapping the cell (#2382)
zeitschlag Nov 8, 2024
f6e9629
Incorporate Feedback from PR (#2382)
zeitschlag Nov 8, 2024
864d1c7
Add different labels for different texts (#2382)
zeitschlag Nov 12, 2024
5e4df2f
Show connectivity-state (#2382)
zeitschlag Nov 12, 2024
53d4932
No alert when selecting a proxy (#2382)
zeitschlag Nov 13, 2024
4e7e800
Select proxy after adding it (#2382)
zeitschlag Nov 13, 2024
3ee31f6
Restart IO after adding a proxy (#2382)
zeitschlag Nov 13, 2024
a611de2
Update deltachat-ios/Controller/Settings/Proxy/ProxySettingsViewContr…
zeitschlag Nov 13, 2024
7727384
Update deltachat-ios/Controller/Settings/Proxy/ProxyTableViewCell.swift
zeitschlag Nov 13, 2024
913b108
Update deltachat-ios/Controller/Settings/Proxy/ProxyTableViewCell.swift
zeitschlag Nov 13, 2024
f7e520c
Update deltachat-ios/Controller/Settings/Proxy/ProxySettingsViewContr…
zeitschlag Nov 13, 2024
69ac63b
Update deltachat-ios/Controller/Settings/Proxy/ProxySettingsViewContr…
zeitschlag Nov 13, 2024
b588f39
show icon+text on swipe
r10s Nov 13, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions deltachat-ios.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,8 @@
D8C19DD02C1C9FFE00B32F6D /* ContactCardPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8C19DCF2C1C95A900B32F6D /* ContactCardPreview.swift */; };
D8CDEFE02C087CDA00146773 /* ContactCardCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8CDEFDF2C087CDA00146773 /* ContactCardCell.swift */; };
D8CDEFE22C087D1000146773 /* ContactCardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8CDEFE12C087D1000146773 /* ContactCardView.swift */; };
D8CF2DDC2CDD110F001C2352 /* ProxySettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8CF2DD92CDD110F001C2352 /* ProxySettingsViewController.swift */; };
D8CF2DDD2CDD110F001C2352 /* ProxyTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8CF2DDA2CDD110F001C2352 /* ProxyTableViewCell.swift */; };
D8FB03FD2B4EF20700A355F8 /* ReactionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8FB03FC2B4EF20700A355F8 /* ReactionsView.swift */; };
D8FB04002B4F0CF100A355F8 /* EmojiView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8FB03FF2B4F0CF000A355F8 /* EmojiView.swift */; };
/* End PBXBuildFile section */
Expand Down Expand Up @@ -609,6 +611,8 @@
D8C19DCF2C1C95A900B32F6D /* ContactCardPreview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactCardPreview.swift; sourceTree = "<group>"; };
D8CDEFDF2C087CDA00146773 /* ContactCardCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactCardCell.swift; sourceTree = "<group>"; };
D8CDEFE12C087D1000146773 /* ContactCardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactCardView.swift; sourceTree = "<group>"; };
D8CF2DD92CDD110F001C2352 /* ProxySettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProxySettingsViewController.swift; sourceTree = "<group>"; };
D8CF2DDA2CDD110F001C2352 /* ProxyTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProxyTableViewCell.swift; sourceTree = "<group>"; };
D8FB03FC2B4EF20700A355F8 /* ReactionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactionsView.swift; sourceTree = "<group>"; };
D8FB03FF2B4F0CF000A355F8 /* EmojiView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiView.swift; sourceTree = "<group>"; };
DFBB6227B203C9B6FB5F4321 /* Pods-DcShare.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DcShare.debug.xcconfig"; path = "Target Support Files/Pods-DcShare/Pods-DcShare.debug.xcconfig"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1097,6 +1101,7 @@
B28D25882913CE8600B9067F /* Settings */ = {
isa = PBXGroup;
children = (
D8CF2DDB2CDD110F001C2352 /* Proxy */,
78E45E3921D3CFBC00D4B15E /* SettingsViewController.swift */,
B2D4B63A29C38D1900B47DA8 /* ChatsAndMediaViewController.swift */,
B2172F3B29C125F2002C289E /* AdvancedViewController.swift */,
Expand Down Expand Up @@ -1165,6 +1170,15 @@
path = "Send Contact";
sourceTree = "<group>";
};
D8CF2DDB2CDD110F001C2352 /* Proxy */ = {
isa = PBXGroup;
children = (
D8CF2DD92CDD110F001C2352 /* ProxySettingsViewController.swift */,
D8CF2DDA2CDD110F001C2352 /* ProxyTableViewCell.swift */,
);
path = Proxy;
sourceTree = "<group>";
};
D8FB03FE2B4F0CE500A355F8 /* Reactions */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -1705,6 +1719,8 @@
AED423D3249F578B00B6B2BB /* AddGroupMembersViewController.swift in Sources */,
3011E8052787365D00214221 /* KeychainManager.swift in Sources */,
AE851AC5227C755A00ED86F0 /* Protocols.swift in Sources */,
D8CF2DDC2CDD110F001C2352 /* ProxySettingsViewController.swift in Sources */,
D8CF2DDD2CDD110F001C2352 /* ProxyTableViewCell.swift in Sources */,
AE728F15229D5C390047565B /* PhotoPickerAlertAction.swift in Sources */,
AECEF03E244F2D55006C90DA /* QrPageController.swift in Sources */,
AEACE2E31FB32B5C00DCDD78 /* Constants.swift in Sources */,
Expand Down
23 changes: 20 additions & 3 deletions deltachat-ios/Controller/Settings/AdvancedViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ internal final class AdvancedViewController: UITableViewController {
case videoChat
case viewLog
case accountSettings
case proxySettings
}

private var dcContext: DcContext
Expand Down Expand Up @@ -75,6 +76,14 @@ internal final class AdvancedViewController: UITableViewController {
return cell
}()

private lazy var proxySettingsCell: UITableViewCell = {
let cell = UITableViewCell(style: .default, reuseIdentifier: nil)
cell.textLabel?.text = String.localized("proxy_settings")
cell.accessoryType = .disclosureIndicator
cell.tag = CellTags.proxySettings.rawValue
return cell
}()

lazy var sentboxWatchCell: SwitchCell = {
return SwitchCell(
textLabel: String.localized("pref_watch_sent_folder"),
Expand Down Expand Up @@ -242,7 +251,7 @@ internal final class AdvancedViewController: UITableViewController {
let serverSection = SectionConfigs(
headerTitle: String.localized("pref_server"),
footerTitle: nil,
cells: [accountSettingsCell])
cells: [accountSettingsCell, proxySettingsCell])
return [viewLogSection, experimentalSection, encryptionSection, serverSection]
} else {
let appAccessSection = SectionConfigs(
Expand All @@ -256,7 +265,7 @@ internal final class AdvancedViewController: UITableViewController {
let serverSection = SectionConfigs(
headerTitle: String.localized("pref_server"),
footerTitle: String.localized("pref_only_fetch_mvbox_explain"),
cells: [accountSettingsCell, sentboxWatchCell, sendCopyToSelfCell, mvboxMoveCell, onlyFetchMvboxCell])
cells: [accountSettingsCell, sentboxWatchCell, sendCopyToSelfCell, mvboxMoveCell, onlyFetchMvboxCell, proxySettingsCell])
return [viewLogSection, experimentalSection, appAccessSection, encryptionSection, serverSection]
}
}()
Expand Down Expand Up @@ -320,7 +329,10 @@ internal final class AdvancedViewController: UITableViewController {
Utils.authenticateDeviceOwner(reason: String.localized("pref_password_and_account_settings")) { [weak self] in
self?.showAccountSettingsController()
}

case .proxySettings:
Utils.authenticateDeviceOwner(reason: String.localized("proxy_settings")) { [weak self] in
self?.showProxySettings()
}
zeitschlag marked this conversation as resolved.
Show resolved Hide resolved
case .defaultTagValue: break
}
}
Expand Down Expand Up @@ -385,6 +397,11 @@ internal final class AdvancedViewController: UITableViewController {
navigationController?.pushViewController(controller, animated: true)
}

private func showProxySettings() {
let proxySettingsController = ProxySettingsViewController(dcContext: dcContext, dcAccounts: dcAccounts)
navigationController?.pushViewController(proxySettingsController, animated: true)
}

private func showManageKeysDialog() {
let alert = UIAlertController(title: String.localized("pref_manage_keys"), message: nil, preferredStyle: .safeActionSheet)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,275 @@
import UIKit
import DcCore

enum ProxySettingsSection: Int {
case enableProxies = 0
case proxies
case add

var title: String? {
switch self {
case .enableProxies:
return nil
case .proxies:
return String.localized("proxy_list_header")
case .add:
return nil
}
}
}

class ProxySettingsViewController: UITableViewController {

let dcContext: DcContext
let dcAccounts: DcAccounts

var proxies: [String]
var selectedProxy: String?

let addProxyCell: ActionCell
let toggleProxyCell: SwitchCell

var addProxyAlert: UIAlertController?

init(dcContext: DcContext, dcAccounts: DcAccounts) {

self.dcContext = dcContext
self.dcAccounts = dcAccounts
self.proxies = dcContext.getProxies()
self.selectedProxy = proxies.first

addProxyCell = ActionCell()
addProxyCell.actionTitle = String.localized("proxy_add")
toggleProxyCell = SwitchCell(textLabel: String.localized("proxy_use_proxy"), on: dcContext.isProxyEnabled)

super.init(style: .grouped)

tableView.register(SwitchCell.self, forCellReuseIdentifier: SwitchCell.reuseIdentifier)
tableView.register(ActionCell.self, forCellReuseIdentifier: ActionCell.reuseIdentifier)
tableView.register(ProxyTableViewCell.self, forCellReuseIdentifier: ProxyTableViewCell.reuseIdentifier)

toggleProxyCell.uiSwitch.isEnabled = (proxies.isEmpty == false)
toggleProxyCell.action = { [weak self] cell in
guard let self, self.proxies.isEmpty == false else { return }

dcContext.isProxyEnabled = cell.uiSwitch.isOn
}

title = String.localized("proxy_settings")
}

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

private func selectProxy(at indexPath: IndexPath) {
let selectedProxyURL = proxies[indexPath.row]
let host = dcContext.checkQR(qrCode: selectedProxyURL).text1 ?? ""

let selectAlert = UIAlertController(
title: String.localized("proxy_use_proxy"),
message: String.localized(stringID: "proxy_use_proxy_confirm", parameter: host),
preferredStyle: .alert
)

let cancelAction = UIAlertAction(title: String.localized("cancel"), style: .cancel)
let selectAction = UIAlertAction(title: String.localized("proxy_use_proxy"), style: .default) { [weak self] _ in

guard let self else { return }
if self.dcContext.setConfigFromQR(qrCode: selectedProxyURL) {
self.selectedProxy = selectedProxyURL
self.tableView.reloadData()
self.dcAccounts.restartIO()
}
}
selectAlert.addAction(cancelAction)
selectAlert.addAction(selectAction)

present(selectAlert, animated: true)
}

private func addProxy() {
let alertController = UIAlertController(
title: String.localized("proxy_add"),
message: String.localized("proxy_add_explain"),
preferredStyle: .alert
)

let addProxyAction = UIAlertAction(title: String.localized("proxy_use_proxy"), style: .default) { [weak self] _ in
guard let self,
let proxyUrlTextfield = self.addProxyAlert?.textFields?.first,
let proxyURL = proxyUrlTextfield.text else { return }

let parsedProxy = self.dcContext.checkQR(qrCode: proxyURL)
if parsedProxy.state == DC_QR_PROXY, self.dcContext.setConfigFromQR(qrCode: proxyURL) {
self.proxies.insert(proxyURL, at: self.proxies.startIndex)
self.dcContext.setProxies(proxyURLs: self.proxies)

DispatchQueue.main.async {
self.toggleProxyCell.uiSwitch.isEnabled = (self.proxies.isEmpty == false)
self.tableView.reloadData()
}
} else {
let errorAlert = UIAlertController(title: String.localized("error"), message: String.localized("proxy_invalid"), preferredStyle: .alert)

let okAction = UIAlertAction(title: String.localized("ok"), style: .default)
errorAlert.addAction(okAction)

self.present(errorAlert, animated: true)
}
}

let cancelAction = UIAlertAction(title: String.localized("cancel"), style: .cancel)
alertController.addAction(addProxyAction)
alertController.addAction(cancelAction)
alertController.addTextField { textfield in
textfield.placeholder = String.localized("proxy_add_url_hint")
}

present(alertController, animated: true)
self.addProxyAlert = alertController
}

private func deleteProxy(at indexPath: IndexPath) {
let proxyToRemove = proxies[indexPath.row]
let host = dcContext.checkQR(qrCode: proxyToRemove).text1 ?? ""

let deleteAlert = UIAlertController(title: String.localized("proxy_delete"), message: String.localized(stringID: "proxy_delete_explain", parameter: host), preferredStyle: .alert)
zeitschlag marked this conversation as resolved.
Show resolved Hide resolved

let cancelAction = UIAlertAction(title: String.localized("cancel"), style: .cancel)
let deleteAction = UIAlertAction(title: String.localized("proxy_delete"), style: .destructive) { [weak self] _ in
guard let self else { return }

if let selectedProxy = self.selectedProxy, proxyToRemove == selectedProxy {
self.dcContext.isProxyEnabled = false
}

self.proxies.remove(at: indexPath.row)
self.dcContext.setProxies(proxyURLs: proxies)
DispatchQueue.main.async {
self.toggleProxyCell.uiSwitch.isEnabled = (self.proxies.isEmpty == false)
self.tableView.reloadData()
}
}

deleteAlert.addAction(cancelAction)
deleteAlert.addAction(deleteAction)
present(deleteAlert, animated: true)
}
}

// MARK: - UITableViewDataSource

extension ProxySettingsViewController {
override func numberOfSections(in tableView: UITableView) -> Int {
if proxies.isEmpty {
return 2
} else {
return 3
}
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if proxies.isEmpty {
if section == ProxySettingsSection.enableProxies.rawValue {
return 1
} else /* if section == ProxySettingsSection.add.rawValue */ {
return 1
}
} else {
if section == ProxySettingsSection.enableProxies.rawValue {
return 1
} else if section == ProxySettingsSection.proxies.rawValue {
return proxies.count
} else /*if section == ProxySettingsSection.add.rawValue*/ {
return 1
}
}
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

if proxies.isEmpty {
if indexPath.section == ProxySettingsSection.enableProxies.rawValue {
toggleProxyCell.uiSwitch.isOn = dcContext.isProxyEnabled
return toggleProxyCell
} else /* if indexPath.section == ProxySettingsSection.add.rawValue */ {
return addProxyCell
}
} else {
if indexPath.section == ProxySettingsSection.enableProxies.rawValue {
toggleProxyCell.uiSwitch.isOn = dcContext.isProxyEnabled
return toggleProxyCell
} else if indexPath.section == ProxySettingsSection.proxies.rawValue {
guard let cell = tableView.dequeueReusableCell(withIdentifier: ProxyTableViewCell.reuseIdentifier, for: indexPath) as? ProxyTableViewCell else { fatalError() }

let proxyUrl = proxies[indexPath.row]
cell.configure(with: proxyUrl, dcContext: dcContext)

if let selectedProxy, selectedProxy == proxyUrl {
cell.accessoryType = .checkmark
} else {
cell.accessoryType = .none
}

return cell
} else /*if indexPath.section == ProxySettingsSection.add.rawValue*/ {
return addProxyCell
}
}
}

override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
guard proxies.isEmpty == false else { return nil }


if section == ProxySettingsSection.proxies.rawValue {
return ProxySettingsSection.proxies.title
} else {
return nil
}

}
}

// MARK: - UITableViewDelegate

extension ProxySettingsViewController {
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if proxies.isEmpty {
if indexPath.section == ProxySettingsSection.enableProxies.rawValue {
// do nothing as there are no proxies that could be used
} else /* if indexPath.section == ProxySettingsSection.add.rawValue */ {
addProxy()
}
} else {
if indexPath.section == ProxySettingsSection.enableProxies.rawValue {
toggleProxyCell.uiSwitch.isOn.toggle()
} else if indexPath.section == ProxySettingsSection.proxies.rawValue {
selectProxy(at: indexPath)
} else /*if indexPath.section == ProxySettingsSection.add.rawValue*/ {
addProxy()
}
}

tableView.deselectRow(at: indexPath, animated: true)
}

override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
guard
proxies.isEmpty == false,
indexPath.section == ProxySettingsSection.proxies.rawValue
else { return nil }

let deleteAction = UIContextualAction(style: .destructive, title: String.localized("proxy_delete")) { [weak self] _, _, completion in
zeitschlag marked this conversation as resolved.
Show resolved Hide resolved
DispatchQueue.main.async {
self?.deleteProxy(at: indexPath)
completion(true)
}
}
deleteAction.backgroundColor = .red
zeitschlag marked this conversation as resolved.
Show resolved Hide resolved

let configuration = UISwipeActionsConfiguration(actions: [deleteAction])
configuration.performsFirstActionWithFullSwipe = true

return configuration
}
}
Loading
Loading