Integrate settings with about screen

Move everything to SettingsView and remove invite actions.
This commit is contained in:
Davide De Rosa 2022-08-27 22:42:52 +02:00
parent 10270b02ee
commit f36d7596d0
11 changed files with 458 additions and 512 deletions

View File

@ -175,7 +175,7 @@
0ED89C1C27DE3ABC008B36D6 /* ShortcutsView+Add.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ED89C1B27DE3ABC008B36D6 /* ShortcutsView+Add.swift */; };
0ED89C1E27DE3F8D008B36D6 /* IntentAddView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ED89C1D27DE3F8D008B36D6 /* IntentAddView.swift */; };
0EDE02C227F61C79000FBE3C /* EditableTextList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EDE02C127F61C79000FBE3C /* EditableTextList.swift */; };
0EE11CD2280D8317003BE431 /* InfoMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE11CD1280D8317003BE431 /* InfoMenu.swift */; };
0EE11CD2280D8317003BE431 /* SettingsButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE11CD1280D8317003BE431 /* SettingsButton.swift */; };
0EE8B7E327FF340F00B68621 /* VPNProtocolType+FileExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE8B7E227FF340F00B68621 /* VPNProtocolType+FileExtensions.swift */; };
0EF0FAF627DD0211007EB181 /* PaywallView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF0FAF527DD0211007EB181 /* PaywallView.swift */; };
0EF0FAF727DD159C007EB181 /* IntentDispatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA591122733DD4E0096F796 /* IntentDispatcher.swift */; };
@ -185,6 +185,7 @@
0EF2212F27E66F60001D0BD7 /* AddProfileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF2212E27E66F60001D0BD7 /* AddProfileView.swift */; };
0EF2213127E674BD001D0BD7 /* AddProviderViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF2213027E674BD001D0BD7 /* AddProviderViewModel.swift */; };
0EF8C5A828213C510053CE89 /* OrganizerView+Profiles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF8C5A728213C510053CE89 /* OrganizerView+Profiles.swift */; };
A38D607728AFCFD20005C271 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A38D607628AFCFD20005C271 /* SettingsView.swift */; };
A3A7CC462878DC8300172D7D /* ProviderServerItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3A7CC452878DC8300172D7D /* ProviderServerItem.swift */; };
A3A7CC482878DC9F00172D7D /* ProviderServerItem+ViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3A7CC472878DC9F00172D7D /* ProviderServerItem+ViewModel.swift */; };
A3A7CC4A28790BD900172D7D /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3A7CC4928790BD900172D7D /* Theme.swift */; };
@ -474,7 +475,7 @@
0EDE8DC320C86910004C739C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
0EDE8DD220C86978004C739C /* NotificationCenter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NotificationCenter.framework; path = System/Library/Frameworks/NotificationCenter.framework; sourceTree = SDKROOT; };
0EDE8DE220C86A13004C739C /* App.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = App.entitlements; sourceTree = "<group>"; };
0EE11CD1280D8317003BE431 /* InfoMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfoMenu.swift; sourceTree = "<group>"; };
0EE11CD1280D8317003BE431 /* SettingsButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsButton.swift; sourceTree = "<group>"; };
0EE8B7E227FF340F00B68621 /* VPNProtocolType+FileExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VPNProtocolType+FileExtensions.swift"; sourceTree = "<group>"; };
0EF0FAF527DD0211007EB181 /* PaywallView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaywallView.swift; sourceTree = "<group>"; };
0EF0FAF827DD212C007EB181 /* IntentActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntentActivity.swift; sourceTree = "<group>"; };
@ -483,6 +484,7 @@
0EF2212E27E66F60001D0BD7 /* AddProfileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddProfileView.swift; sourceTree = "<group>"; };
0EF2213027E674BD001D0BD7 /* AddProviderViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddProviderViewModel.swift; sourceTree = "<group>"; };
0EF8C5A728213C510053CE89 /* OrganizerView+Profiles.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "OrganizerView+Profiles.swift"; sourceTree = "<group>"; };
A38D607628AFCFD20005C271 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
A3A7CC452878DC8300172D7D /* ProviderServerItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProviderServerItem.swift; sourceTree = "<group>"; };
A3A7CC472878DC9F00172D7D /* ProviderServerItem+ViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ProviderServerItem+ViewModel.swift"; sourceTree = "<group>"; };
A3A7CC4928790BD900172D7D /* Theme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Theme.swift; sourceTree = "<group>"; };
@ -618,7 +620,6 @@
0E71ACEA27C1060D00F85C4B /* EndpointView.swift */,
0E5349C527C176C200C71BB3 /* EndpointView+OpenVPN.swift */,
0E5349C727C176D100C71BB3 /* EndpointView+WireGuard.swift */,
0EE11CD1280D8317003BE431 /* InfoMenu.swift */,
0E0BD27227B2EA2C00583AC5 /* MainView.swift */,
0E71ACE827C1055200F85C4B /* NetworkSettingsView.swift */,
0EB34BC927C6A70200B126DA /* OnDemandView.swift */,
@ -641,6 +642,8 @@
0E71ACF027C1073800F85C4B /* ProviderLocationView.swift */,
0E71ACEE27C106B400F85C4B /* ProviderPresetView.swift */,
0EBC075A27EC4FFF00208AD9 /* ReportIssueView.swift */,
0EE11CD1280D8317003BE431 /* SettingsButton.swift */,
A38D607628AFCFD20005C271 /* SettingsView.swift */,
0E0BD27827B2EBE500583AC5 /* ShortcutsView.swift */,
0ED89C1B27DE3ABC008B36D6 /* ShortcutsView+Add.swift */,
0E71ACFA27C12E5300F85C4B /* VersionView.swift */,
@ -1398,6 +1401,7 @@
0E2C172B27CB63F9007E8488 /* Reviewer.swift in Sources */,
0E71ACDD27C0295C00F85C4B /* View+Extensions.swift in Sources */,
0E021D9C284E68580077EF5D /* CoreContext.swift in Sources */,
A38D607728AFCFD20005C271 /* SettingsView.swift in Sources */,
0E34A2B627CAA8CC00C73B67 /* Core+L10n.swift in Sources */,
0E7577DF2817E22C00081CBE /* VPNToggle.swift in Sources */,
0E5467F32867A54600F74D1C /* MacBundle.swift in Sources */,
@ -1411,8 +1415,8 @@
0E5467F72867A57000F74D1C /* MacBridge.swift in Sources */,
0E9ED48127FD9BAE003B2316 /* CopySavingButton.swift in Sources */,
0E04F0062883462E00BFCE1C /* LightUtils.swift in Sources */,
0EE11CD2280D8317003BE431 /* InfoMenu.swift in Sources */,
0E44689C27B11B5300A14CE4 /* AboutView.swift in Sources */,
0EE11CD2280D8317003BE431 /* SettingsButton.swift in Sources */,
0E71ACF927C12E4800F85C4B /* CreditsView.swift in Sources */,
0ED89C1527DE0A0C008B36D6 /* Shortcut.swift in Sources */,
0E34A2B927CAA96A00C73B67 /* OpenVPN+L10n.swift in Sources */,

View File

@ -207,8 +207,8 @@ extension View {
"text.justify"
}
var themeInfoMenuImage: String {
"info.circle"
var themeSettingsImage: String {
"gearshape"
}
var themeDonateImage: String {

View File

@ -26,10 +26,14 @@
import SwiftUI
struct AboutView: View {
@Environment(\.presentationMode) private var presentationMode
// private let appName = Unlocalized.appName
private let versionString = Constants.Global.appVersionString
private let redditURL = Constants.URLs.subreddit
private let shareMessage = L10n.Global.Messages.share
private let readmeURL = Constants.URLs.readme
private let changelogURL = Constants.URLs.changelog
@ -44,17 +48,15 @@ struct AboutView: View {
var body: some View {
List {
infoSubview
githubSubview
webSubview
infoSection
supportSection
webSection
githubSection
}.themeSecondaryView()
.navigationTitle(L10n.About.title)
.toolbar {
themeCloseItem(presentationMode: presentationMode)
}
}
private var infoSubview: some View {
private var infoSection: some View {
Section {
NavigationLink {
VersionView()
@ -67,24 +69,23 @@ struct AboutView: View {
}
}
}
private var githubSubview: some View {
private var supportSection: some View {
Section {
Button(Unlocalized.About.readme) {
URL.openURL(readmeURL)
}
Button(Unlocalized.About.changelog) {
URL.openURL(changelogURL)
Button(L10n.Menu.Contextual.Support.joinCommunity) {
URL.openURL(redditURL)
}
Button(L10n.Menu.Contextual.shareTwitter, action: shareOnTwitter)
Button(L10n.Menu.Contextual.Support.writeReview, action: submitReview)
} header: {
Text(Unlocalized.About.github)
Text(L10n.Menu.All.Support.title)
}
}
private var webSubview: some View {
private var webSection: some View {
Section {
Button(L10n.About.Items.Website.caption) {
URL.openURL(readmeURL)
URL.openURL(homeURL)
}
Button(Unlocalized.About.faq) {
URL.openURL(faqURL)
@ -99,4 +100,29 @@ struct AboutView: View {
Text(L10n.About.Sections.Web.header)
}
}
private var githubSection: some View {
Section {
Button(Unlocalized.About.readme) {
URL.openURL(readmeURL)
}
Button(Unlocalized.About.changelog) {
URL.openURL(changelogURL)
}
} header: {
Text(Unlocalized.About.github)
}
}
}
extension AboutView {
private func shareOnTwitter() {
let url = Unlocalized.Social.twitterIntent(withMessage: shareMessage)
URL.openURL(url)
}
private func submitReview() {
let reviewURL = Reviewer.urlForReview(withAppId: Constants.App.appStoreId)
URL.openURL(reviewURL)
}
}

View File

@ -43,8 +43,6 @@ struct DonateView: View {
}
}
@Environment(\.presentationMode) private var presentationMode
@Environment(\.scenePhase) private var scenePhase
@ObservedObject private var productManager: ProductManager
@ -63,9 +61,7 @@ struct DonateView: View {
.disabled(pendingDonationIdentifier != nil)
}.themeSecondaryView()
.navigationTitle(L10n.Donate.title)
.toolbar {
themeCloseItem(presentationMode: presentationMode)
}.alert(item: $alertType, content: presentedAlert)
.alert(item: $alertType, content: presentedAlert)
// reloading
.onAppear {

View File

@ -1,183 +0,0 @@
//
// InfoMenu.swift
// Passepartout
//
// Created by Davide De Rosa on 4/18/22.
// Copyright (c) 2022 Davide De Rosa. All rights reserved.
//
// https://github.com/passepartoutvpn
//
// This file is part of Passepartout.
//
// Passepartout is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Passepartout is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
//
import SwiftUI
import PassepartoutLibrary
struct InfoMenu: View {
enum ModalType: Identifiable {
case donate
case share([Any])
case about
case exportProviders([URL])
// XXX: alert ids
var id: Int {
switch self {
case .donate: return 4
case .share: return 5
case .about: return 6
case .exportProviders: return 7
}
}
}
@ObservedObject private var productManager: ProductManager
@State private var modalType: ModalType?
private var isTestBuild: Bool {
Constants.App.isBeta || Constants.InApp.appType == .beta
}
private let redditURL = Constants.URLs.subreddit
private let shareMessage = L10n.Global.Messages.share
private let appName = Unlocalized.appName
init() {
productManager = .shared
}
var body: some View {
Menu {
Menu(L10n.Menu.All.Support.title) {
supportMenu
}
Menu(L10n.Menu.All.Share.title) {
shareMenu
}
if isTestBuild {
Divider()
testSection
}
Divider()
aboutButton
} label: {
themeInfoMenuImage.asSystemImage
}.sheet(item: $modalType, content: presentedModal)
}
@ViewBuilder
private func presentedModal(_ modalType: ModalType) -> some View {
switch modalType {
case .donate:
NavigationView {
DonateView()
}.themeGlobal()
case .share(let items):
ActivityView(activityItems: items)
case .about:
NavigationView {
AboutView()
}.themeGlobal()
case .exportProviders(let urls):
ActivityView(activityItems: urls)
}
}
private var isModalPresented: Binding<Bool> {
.init {
modalType != nil
} set: {
if !$0 {
modalType = nil
}
}
}
private var supportMenu: some View {
Group {
Button {
modalType = .donate
} label: {
Label(L10n.Donate.title, systemImage: themeDonateImage)
}.disabled(!productManager.canMakePayments())
Button {
URL.openURL(redditURL)
} label: {
Label(L10n.Menu.Contextual.Support.joinCommunity, systemImage: themeRedditImage)
}
Button(action: submitReview) {
Label(L10n.Menu.Contextual.Support.writeReview, systemImage: themeWriteReviewImage)
}
}
}
private var shareMenu: some View {
Group {
Button(L10n.Menu.Contextual.shareTwitter, action: shareOnTwitter)
Button(L10n.Menu.Contextual.shareGeneric, action: shareWithFriend)
}
}
private var aboutButton: some View {
Button(L10n.Menu.All.About.title("")) {
presentAbout()
}
}
private func shareOnTwitter() {
let url = Unlocalized.Social.twitterIntent(withMessage: shareMessage)
URL.openURL(url)
}
private func shareWithFriend() {
let shareMessage = "\(shareMessage) \(Constants.URLs.website)"
modalType = .share([shareMessage])
}
private func submitReview() {
let reviewURL = Reviewer.urlForReview(withAppId: Constants.App.appStoreId)
URL.openURL(reviewURL)
}
private func presentAbout() {
modalType = .about
}
}
extension InfoMenu {
private var testSection: some View {
Button("Export providers") {
guard let urls = CoreContext.shared.urlsForProviders else {
return
}
modalType = .exportProviders(urls)
}
}
}

View File

@ -68,7 +68,7 @@ struct OrganizerView: View {
}
ToolbarItem(placement: .navigation) {
if themeIdiom == .phone {
InfoMenu()
SettingsButton()
}
}
}.alert(item: $alertType, content: presentedAlert)

View File

@ -70,7 +70,7 @@ struct ProfileView: View {
}.toolbar {
ToolbarItemGroup(placement: .navigationBarTrailing) {
if themeIdiom != .phone {
InfoMenu()
SettingsButton()
}
MainMenu(
currentProfile: currentProfile,

View File

@ -0,0 +1,43 @@
//
// SettingsButton.swift
// Passepartout
//
// Created by Davide De Rosa on 4/18/22.
// Copyright (c) 2022 Davide De Rosa. All rights reserved.
//
// https://github.com/passepartoutvpn
//
// This file is part of Passepartout.
//
// Passepartout is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Passepartout is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
//
import SwiftUI
import PassepartoutLibrary
struct SettingsButton: View {
@State private var isPresented = false
var body: some View {
Button {
isPresented = true
} label: {
themeSettingsImage.asSystemImage
}.sheet(isPresented: $isPresented) {
NavigationView {
SettingsView()
}.themeGlobal()
}
}
}

View File

@ -0,0 +1,75 @@
//
// SettingsView.swift
// Passepartout
//
// Created by Davide De Rosa on 8/19/22.
// Copyright (c) 2022 Davide De Rosa. All rights reserved.
//
// https://github.com/passepartoutvpn
//
// This file is part of Passepartout.
//
// Passepartout is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Passepartout is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
//
import SwiftUI
import PassepartoutLibrary
struct SettingsView: View {
@ObservedObject private var productManager: ProductManager
@Environment(\.presentationMode) private var presentationMode
// private var isTestBuild: Bool {
// Constants.App.isBeta || Constants.InApp.appType == .beta
// }
//
// private let appName = Unlocalized.appName
private let versionString = Constants.Global.appVersionString
init() {
productManager = .shared
}
var body: some View {
List {
aboutSection
}.toolbar {
themeCloseItem(presentationMode: presentationMode)
}.themeSecondaryView()
.navigationTitle(L10n.Settings.title) // FIXME: l10n
}
private var aboutSection: some View {
Section {
NavigationLink {
AboutView()
} label: {
Text(L10n.About.title)
}
NavigationLink {
DonateView()
} label: {
Text(L10n.Donate.title)
}.disabled(!productManager.canMakePayments())
} footer: {
HStack {
Spacer()
Text(versionString)
Spacer()
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -322,6 +322,10 @@
"donate.alerts.purchase.success.message" = "This means a lot to me and I really hope you keep using and promoting this app.";
"donate.alerts.purchase.failure.message" = "Unable to perform the donation. %@";
/* MARK: SettingsView */
"settings.title" = "Settings";
/* MARK: AboutView */
"about.title" = "About";