Restore reconnect action (#232)
* Add "Reconnect" in profile view * Add "Reconnect" in profile context menu * Update CHANGELOG * Restrict "Reconnect" in context menu to iOS 16 SwiftUI does not react properly to state updates.
This commit is contained in:
parent
9962401d74
commit
c0cc10ab94
|
@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
- OpenVPN: Support for `--remote-random-hostname`. [tunnelkit#286](https://github.com/passepartoutvpn/tunnelkit/pull/286)
|
- OpenVPN: Support for `--remote-random-hostname`. [tunnelkit#286](https://github.com/passepartoutvpn/tunnelkit/pull/286)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Restore "Reconnect" action in profiles. [#232](https://github.com/passepartoutvpn/passepartout-apple/pull/232)
|
||||||
|
|
||||||
## 2.0.1 (2022-10-17)
|
## 2.0.1 (2022-10-17)
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
|
@ -245,6 +245,10 @@ extension View {
|
||||||
"ellipsis.circle"
|
"ellipsis.circle"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var themeReconnectImage: String {
|
||||||
|
"arrow.clockwise"
|
||||||
|
}
|
||||||
|
|
||||||
var themeShortcutsImage: String {
|
var themeShortcutsImage: String {
|
||||||
"mic"
|
"mic"
|
||||||
}
|
}
|
||||||
|
@ -290,10 +294,6 @@ extension View {
|
||||||
"slider.horizontal.3"
|
"slider.horizontal.3"
|
||||||
}
|
}
|
||||||
|
|
||||||
var themeProviderRefreshImage: String {
|
|
||||||
"arrow.clockwise"
|
|
||||||
}
|
|
||||||
|
|
||||||
var themeNetworkSettingsImage: String {
|
var themeNetworkSettingsImage: String {
|
||||||
// "network"
|
// "network"
|
||||||
"globe"
|
"globe"
|
||||||
|
|
|
@ -85,8 +85,7 @@ extension OrganizerView {
|
||||||
} label: {
|
} label: {
|
||||||
profileLabel(forHeader: header)
|
profileLabel(forHeader: header)
|
||||||
}.contextMenu {
|
}.contextMenu {
|
||||||
duplicateButton(forHeader: header)
|
ProfileContextMenu(header: header)
|
||||||
deleteButton(forHeader: header)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,23 +96,6 @@ extension OrganizerView {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func duplicateButton(forHeader header: Profile.Header) -> some View {
|
|
||||||
ProfileView.DuplicateButton(
|
|
||||||
header: header,
|
|
||||||
setAsCurrent: false
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func deleteButton(forHeader header: Profile.Header) -> some View {
|
|
||||||
DestructiveButton {
|
|
||||||
withAnimation {
|
|
||||||
profileManager.removeProfiles(withIds: [header.id])
|
|
||||||
}
|
|
||||||
} label: {
|
|
||||||
Label(L10n.Global.Strings.delete, systemImage: themeDeleteImage)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private var sortedHeaders: [Profile.Header] {
|
private var sortedHeaders: [Profile.Header] {
|
||||||
profileManager.headers
|
profileManager.headers
|
||||||
.sorted()
|
.sorted()
|
||||||
|
@ -146,3 +128,52 @@ extension OrganizerView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension OrganizerView {
|
||||||
|
struct ProfileContextMenu: View {
|
||||||
|
@ObservedObject private var profileManager: ProfileManager
|
||||||
|
|
||||||
|
@ObservedObject private var currentVPNState: ObservableVPNState
|
||||||
|
|
||||||
|
let header: Profile.Header
|
||||||
|
|
||||||
|
init(header: Profile.Header) {
|
||||||
|
profileManager = .shared
|
||||||
|
currentVPNState = .shared
|
||||||
|
self.header = header
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
if #available(iOS 16, *), isActiveProfileNotDisconnected {
|
||||||
|
reconnectButton
|
||||||
|
}
|
||||||
|
duplicateButton
|
||||||
|
deleteButton
|
||||||
|
}
|
||||||
|
|
||||||
|
private var isActiveProfileNotDisconnected: Bool {
|
||||||
|
profileManager.isActiveProfile(header.id) && currentVPNState.vpnStatus != .disconnected
|
||||||
|
}
|
||||||
|
|
||||||
|
private var reconnectButton: some View {
|
||||||
|
ProfileView.ReconnectButton()
|
||||||
|
}
|
||||||
|
|
||||||
|
private var duplicateButton: some View {
|
||||||
|
ProfileView.DuplicateButton(
|
||||||
|
header: header,
|
||||||
|
setAsCurrent: false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var deleteButton: some View {
|
||||||
|
DestructiveButton {
|
||||||
|
withAnimation {
|
||||||
|
profileManager.removeProfiles(withIds: [header.id])
|
||||||
|
}
|
||||||
|
} label: {
|
||||||
|
Label(L10n.Global.Strings.delete, systemImage: themeDeleteImage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -42,6 +42,8 @@ extension ProfileView {
|
||||||
|
|
||||||
@ObservedObject private var vpnManager: VPNManager
|
@ObservedObject private var vpnManager: VPNManager
|
||||||
|
|
||||||
|
@ObservedObject private var currentVPNState: ObservableVPNState
|
||||||
|
|
||||||
@ObservedObject private var currentProfile: ObservableProfile
|
@ObservedObject private var currentProfile: ObservableProfile
|
||||||
|
|
||||||
private var header: Profile.Header {
|
private var header: Profile.Header {
|
||||||
|
@ -61,6 +63,7 @@ extension ProfileView {
|
||||||
init(currentProfile: ObservableProfile, modalType: Binding<ModalType?>) {
|
init(currentProfile: ObservableProfile, modalType: Binding<ModalType?>) {
|
||||||
profileManager = .shared
|
profileManager = .shared
|
||||||
vpnManager = .shared
|
vpnManager = .shared
|
||||||
|
currentVPNState = .shared
|
||||||
self.currentProfile = currentProfile
|
self.currentProfile = currentProfile
|
||||||
_modalType = modalType
|
_modalType = modalType
|
||||||
}
|
}
|
||||||
|
@ -90,10 +93,20 @@ extension ProfileView {
|
||||||
|
|
||||||
private var mainView: some View {
|
private var mainView: some View {
|
||||||
Menu {
|
Menu {
|
||||||
shortcutsButton
|
if isActiveProfileNotDisconnected {
|
||||||
|
ReconnectButton()
|
||||||
|
}
|
||||||
|
ShortcutsButton(
|
||||||
|
modalType: $modalType
|
||||||
|
)
|
||||||
Divider()
|
Divider()
|
||||||
renameButton
|
RenameButton(
|
||||||
duplicateButton
|
modalType: $modalType
|
||||||
|
)
|
||||||
|
DuplicateButton(
|
||||||
|
header: header,
|
||||||
|
setAsCurrent: true
|
||||||
|
)
|
||||||
uninstallVPNButton
|
uninstallVPNButton
|
||||||
Divider()
|
Divider()
|
||||||
deleteProfileButton
|
deleteProfileButton
|
||||||
|
@ -102,23 +115,8 @@ extension ProfileView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var shortcutsButton: some View {
|
private var isActiveProfileNotDisconnected: Bool {
|
||||||
ShortcutsButton(
|
profileManager.isActiveProfile(header.id) && currentVPNState.vpnStatus != .disconnected
|
||||||
modalType: $modalType
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private var renameButton: some View {
|
|
||||||
RenameButton(
|
|
||||||
modalType: $modalType
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private var duplicateButton: some View {
|
|
||||||
DuplicateButton(
|
|
||||||
header: currentProfile.value.header,
|
|
||||||
setAsCurrent: true
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private var uninstallVPNButton: some View {
|
private var uninstallVPNButton: some View {
|
||||||
|
@ -149,6 +147,26 @@ extension ProfileView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension ProfileView {
|
||||||
|
struct ReconnectButton: View {
|
||||||
|
@ObservedObject private var vpnManager: VPNManager
|
||||||
|
|
||||||
|
init() {
|
||||||
|
vpnManager = .shared
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
Button {
|
||||||
|
Task { @MainActor in
|
||||||
|
await vpnManager.reconnect()
|
||||||
|
}
|
||||||
|
} label: {
|
||||||
|
Label(L10n.Global.Strings.reconnect, systemImage: themeReconnectImage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct ShortcutsButton: View {
|
struct ShortcutsButton: View {
|
||||||
@ObservedObject private var productManager: ProductManager
|
@ObservedObject private var productManager: ProductManager
|
||||||
|
|
Loading…
Reference in New Issue