Minor UI fixes (#910)
Update library with some more meaningful names for Profile accessors. Refactor a few things about TV here and there.
This commit is contained in:
parent
366dc62231
commit
9b366dcaa0
|
@ -41,7 +41,7 @@
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "git@github.com:passepartoutvpn/passepartoutkit-source",
|
"location" : "git@github.com:passepartoutvpn/passepartoutkit-source",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "db4c0f0c01c237a7b50aa0f5c4acb33316c799f0"
|
"revision" : "0d7f912460ca5365740d7196fe5db5a38e23d3e1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -48,7 +48,7 @@ let package = Package(
|
||||||
],
|
],
|
||||||
dependencies: [
|
dependencies: [
|
||||||
// .package(url: "git@github.com:passepartoutvpn/passepartoutkit-source", from: "0.11.0"),
|
// .package(url: "git@github.com:passepartoutvpn/passepartoutkit-source", from: "0.11.0"),
|
||||||
.package(url: "git@github.com:passepartoutvpn/passepartoutkit-source", revision: "db4c0f0c01c237a7b50aa0f5c4acb33316c799f0"),
|
.package(url: "git@github.com:passepartoutvpn/passepartoutkit-source", revision: "0d7f912460ca5365740d7196fe5db5a38e23d3e1"),
|
||||||
// .package(path: "../../../passepartoutkit-source"),
|
// .package(path: "../../../passepartoutkit-source"),
|
||||||
.package(url: "git@github.com:passepartoutvpn/passepartoutkit-source-openvpn-openssl", from: "0.9.1"),
|
.package(url: "git@github.com:passepartoutvpn/passepartoutkit-source-openvpn-openssl", from: "0.9.1"),
|
||||||
// .package(url: "git@github.com:passepartoutvpn/passepartoutkit-source-openvpn-openssl", revision: "031863a1cd683962a7dfe68e20b91fa820a1ecce"),
|
// .package(url: "git@github.com:passepartoutvpn/passepartoutkit-source-openvpn-openssl", revision: "031863a1cd683962a7dfe68e20b91fa820a1ecce"),
|
||||||
|
|
|
@ -168,10 +168,10 @@ extension AppCoordinator {
|
||||||
enterDetail(of: profile)
|
enterDetail(of: profile)
|
||||||
},
|
},
|
||||||
onEditProviderEntity: {
|
onEditProviderEntity: {
|
||||||
guard let pair = $0.firstProviderModuleWithMetadata else {
|
guard let pair = $0.selectedProvider else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
present(.editProviderEntity($0, pair.0, pair.1))
|
present(.editProviderEntity($0, pair.module, pair.selection))
|
||||||
},
|
},
|
||||||
onMigrateProfiles: {
|
onMigrateProfiles: {
|
||||||
modalRoute = .migrateProfiles
|
modalRoute = .migrateProfiles
|
||||||
|
|
|
@ -134,12 +134,12 @@ private extension InstalledProfileView {
|
||||||
|
|
||||||
var providerSelectorButton: some View {
|
var providerSelectorButton: some View {
|
||||||
profile?
|
profile?
|
||||||
.firstProviderModuleWithMetadata
|
.selectedProvider
|
||||||
.map { _, provider in
|
.map { _, selection in
|
||||||
Button {
|
Button {
|
||||||
flow?.onEditProviderEntity(profile!)
|
flow?.onEditProviderEntity(profile!)
|
||||||
} label: {
|
} label: {
|
||||||
providerSelectorLabel(with: provider)
|
providerSelectorLabel(with: selection)
|
||||||
}
|
}
|
||||||
.buttonStyle(.plain)
|
.buttonStyle(.plain)
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,7 +87,7 @@ private extension ProfileContextMenu {
|
||||||
|
|
||||||
var providerConnectToButton: some View {
|
var providerConnectToButton: some View {
|
||||||
profile?
|
profile?
|
||||||
.firstProviderModuleWithMetadata
|
.selectedProvider
|
||||||
.map { _ in
|
.map { _ in
|
||||||
Button(Strings.Ui.ProfileContext.connectTo) {
|
Button(Strings.Ui.ProfileContext.connectTo) {
|
||||||
flow?.onEditProviderEntity(profile!)
|
flow?.onEditProviderEntity(profile!)
|
||||||
|
|
|
@ -58,7 +58,7 @@ struct ReportIssueButton {
|
||||||
}
|
}
|
||||||
|
|
||||||
var currentProvider: (ProviderID, Date?)? {
|
var currentProvider: (ProviderID, Date?)? {
|
||||||
guard let id = installedProfile?.firstProviderModuleWithMetadata?.1.id else {
|
guard let id = installedProfile?.selectedProvider?.selection.id else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
let lastUpdate = providerManager.lastUpdate(for: id)
|
let lastUpdate = providerManager.lastUpdate(for: id)
|
||||||
|
|
|
@ -54,27 +54,31 @@ struct ActiveProfileView: View {
|
||||||
var errorHandler: ErrorHandler
|
var errorHandler: ErrorHandler
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack {
|
VStack(spacing: .zero) {
|
||||||
|
Spacer()
|
||||||
|
|
||||||
VStack {
|
VStack {
|
||||||
currentProfileView
|
VStack {
|
||||||
statusView
|
currentProfileView
|
||||||
}
|
statusView
|
||||||
.padding(.bottom)
|
}
|
||||||
|
.padding(.bottom)
|
||||||
|
|
||||||
profile.map {
|
profile.map {
|
||||||
detailView(for: $0)
|
detailView(for: $0)
|
||||||
}
|
}
|
||||||
.padding(.bottom)
|
.padding(.bottom)
|
||||||
|
|
||||||
Group {
|
Group {
|
||||||
toggleConnectionButton
|
toggleConnectionButton
|
||||||
switchProfileButton
|
switchProfileButton
|
||||||
|
}
|
||||||
|
.clipShape(RoundedRectangle(cornerRadius: 50))
|
||||||
}
|
}
|
||||||
.clipShape(RoundedRectangle(cornerRadius: 50))
|
.padding(.horizontal, 100)
|
||||||
|
|
||||||
|
Spacer()
|
||||||
}
|
}
|
||||||
.padding([.top, .horizontal], 100)
|
|
||||||
|
|
||||||
Spacer()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,28 +100,19 @@ private extension ActiveProfileView {
|
||||||
|
|
||||||
func detailView(for profile: Profile) -> some View {
|
func detailView(for profile: Profile) -> some View {
|
||||||
VStack(spacing: 10) {
|
VStack(spacing: 10) {
|
||||||
if let connectionModule = profile.modules.first(where: { $0 is ConnectionModule }) {
|
if let connectionModule = profile.firstConnectionModule(ifActive: true) {
|
||||||
HStack {
|
DetailRowView(title: Strings.Global.protocol) {
|
||||||
Text(Strings.Global.protocol)
|
|
||||||
.fontWeight(.light)
|
|
||||||
Spacer()
|
|
||||||
Text(connectionModule.moduleHandler.id.name)
|
Text(connectionModule.moduleHandler.id.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let providerPair = profile.firstProviderModuleWithMetadata {
|
if let pair = profile.selectedProvider {
|
||||||
if let provider = providerManager.provider(withId: providerPair.1.id) {
|
if let metadata = providerManager.provider(withId: pair.selection.id) {
|
||||||
HStack {
|
DetailRowView(title: Strings.Global.provider) {
|
||||||
Text(Strings.Global.provider)
|
Text(metadata.description)
|
||||||
.fontWeight(.light)
|
|
||||||
Spacer()
|
|
||||||
Text(provider.description)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let entity = providerPair.1.entity {
|
if let entity = pair.selection.entity {
|
||||||
HStack {
|
DetailRowView(title: Strings.Global.country) {
|
||||||
Text(Strings.Global.country)
|
|
||||||
.fontWeight(.light)
|
|
||||||
Spacer()
|
|
||||||
ThemeCountryText(entity.header.countryCode)
|
ThemeCountryText(entity.header.countryCode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,12 +128,8 @@ private extension ActiveProfileView {
|
||||||
nextProfileId: .constant(nil),
|
nextProfileId: .constant(nil),
|
||||||
interactiveManager: interactiveManager,
|
interactiveManager: interactiveManager,
|
||||||
errorHandler: errorHandler,
|
errorHandler: errorHandler,
|
||||||
onProviderEntityRequired: { _ in
|
onProviderEntityRequired: onProviderEntityRequired,
|
||||||
// FIXME: #788, TV missing provider entity
|
onPurchaseRequired: onPurchaseRequired,
|
||||||
},
|
|
||||||
onPurchaseRequired: { _ in
|
|
||||||
// FIXME: #788, TV purchase required
|
|
||||||
},
|
|
||||||
label: {
|
label: {
|
||||||
Text($0 ? Strings.Global.connect : Strings.Global.disconnect)
|
Text($0 ? Strings.Global.connect : Strings.Global.disconnect)
|
||||||
.frame(maxWidth: .infinity)
|
.frame(maxWidth: .infinity)
|
||||||
|
@ -174,6 +165,36 @@ private extension ActiveProfileView {
|
||||||
|
|
||||||
// MARK: -
|
// MARK: -
|
||||||
|
|
||||||
|
private extension ActiveProfileView {
|
||||||
|
func onProviderEntityRequired(_ profile: Profile) {
|
||||||
|
// FIXME: #788, TV missing provider entity
|
||||||
|
}
|
||||||
|
|
||||||
|
func onPurchaseRequired(_ features: Set<AppFeature>) {
|
||||||
|
// FIXME: #788, TV purchase required
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Subviews
|
||||||
|
|
||||||
|
private struct DetailRowView<Content>: View where Content: View {
|
||||||
|
let title: String
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
let content: Content
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
HStack {
|
||||||
|
Text(title)
|
||||||
|
.fontWeight(.light)
|
||||||
|
Spacer()
|
||||||
|
content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Previews
|
||||||
|
|
||||||
#Preview("Host") {
|
#Preview("Host") {
|
||||||
let profile: Profile = {
|
let profile: Profile = {
|
||||||
do {
|
do {
|
||||||
|
|
|
@ -81,12 +81,8 @@ private extension ProfileListView {
|
||||||
nextProfileId: .constant(nil),
|
nextProfileId: .constant(nil),
|
||||||
interactiveManager: interactiveManager,
|
interactiveManager: interactiveManager,
|
||||||
errorHandler: errorHandler,
|
errorHandler: errorHandler,
|
||||||
onProviderEntityRequired: { _ in
|
onProviderEntityRequired: onProviderEntityRequired,
|
||||||
// FIXME: #788, TV missing provider entity
|
onPurchaseRequired: onPurchaseRequired,
|
||||||
},
|
|
||||||
onPurchaseRequired: { _ in
|
|
||||||
// FIXME: #788, TV purchase required
|
|
||||||
},
|
|
||||||
label: { _ in
|
label: { _ in
|
||||||
toggleView(for: header)
|
toggleView(for: header)
|
||||||
}
|
}
|
||||||
|
@ -107,6 +103,18 @@ private extension ProfileListView {
|
||||||
|
|
||||||
// MARK: -
|
// MARK: -
|
||||||
|
|
||||||
|
private extension ProfileListView {
|
||||||
|
func onProviderEntityRequired(_ profile: Profile) {
|
||||||
|
// FIXME: #788, TV missing provider entity
|
||||||
|
}
|
||||||
|
|
||||||
|
func onPurchaseRequired(_ features: Set<AppFeature>) {
|
||||||
|
// FIXME: #788, TV purchase required
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Previews
|
||||||
|
|
||||||
#Preview("List") {
|
#Preview("List") {
|
||||||
ContentPreview(profileManager: .mock)
|
ContentPreview(profileManager: .mock)
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,7 @@ struct ProfileView: View, TunnelInstallationProviding {
|
||||||
var tunnel: ExtendedTunnel
|
var tunnel: ExtendedTunnel
|
||||||
|
|
||||||
@State
|
@State
|
||||||
private var showsSidePanel = false
|
var showsSidePanel = false
|
||||||
|
|
||||||
@FocusState
|
@FocusState
|
||||||
private var focusedField: Field?
|
private var focusedField: Field?
|
||||||
|
@ -185,10 +185,20 @@ private extension ProfileView {
|
||||||
|
|
||||||
// MARK: -
|
// MARK: -
|
||||||
|
|
||||||
#Preview {
|
#Preview("List") {
|
||||||
ProfileView(
|
ProfileView(
|
||||||
profileManager: .mock,
|
profileManager: .mock,
|
||||||
tunnel: .mock
|
tunnel: .mock,
|
||||||
|
showsSidePanel: true
|
||||||
|
)
|
||||||
|
.withMockEnvironment()
|
||||||
|
}
|
||||||
|
|
||||||
|
#Preview("Empty") {
|
||||||
|
ProfileView(
|
||||||
|
profileManager: ProfileManager(profiles: []),
|
||||||
|
tunnel: .mock,
|
||||||
|
showsSidePanel: true
|
||||||
)
|
)
|
||||||
.withMockEnvironment()
|
.withMockEnvironment()
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,7 +113,7 @@ private extension TunnelToggleButton {
|
||||||
if canConnect {
|
if canConnect {
|
||||||
|
|
||||||
// provider module -> check requirements
|
// provider module -> check requirements
|
||||||
if let providerModule = profile.firstProviderModule,
|
if let providerModule = profile.activeProviderModule,
|
||||||
providerModule.isProviderRequired {
|
providerModule.isProviderRequired {
|
||||||
|
|
||||||
// missing required provider -> show error
|
// missing required provider -> show error
|
||||||
|
|
Loading…
Reference in New Issue