ios: show what is new in the latest version (#1644)

* ios: show what is new in the latest version

* add OK button to WhatsNew

* separate state for nav buttons
This commit is contained in:
Evgeny Poberezkin
2022-12-26 14:08:01 +00:00
committed by GitHub
parent 4370012b8a
commit a02cfb4f41
7 changed files with 235 additions and 8 deletions

View File

@@ -19,6 +19,7 @@ struct ContentView: View {
@AppStorage(DEFAULT_PERFORM_LA) private var prefPerformLA = false
@AppStorage(DEFAULT_PRIVACY_PROTECT_SCREEN) private var protectScreen = true
@AppStorage(DEFAULT_NOTIFICATION_ALERT_SHOWN) private var notificationAlertShown = false
@State private var showWhatsNew = false
var body: some View {
ZStack {
@@ -61,9 +62,16 @@ struct ContentView: View {
if (!prefLANoticeShown && prefShowLANotice) {
prefLANoticeShown = true
alertManager.showAlert(laNoticeAlert())
} else if !chatModel.showCallView && CallController.shared.activeCallInvitation == nil {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
showWhatsNew = shouldShowWhatsNew()
}
}
prefShowLANotice = true
}
.sheet(isPresented: $showWhatsNew) {
WhatsNewView()
}
if chatModel.showCallView, let call = chatModel.activeCall {
ActiveCallView(call: call)
}

View File

@@ -14,6 +14,10 @@ struct ChatHelp: View {
@State private var showAddChat = false
var body: some View {
ScrollView { chatHelp() }
}
func chatHelp() -> some View {
VStack(alignment: .leading, spacing: 10) {
Text("Thank you for installing SimpleX Chat!")
@@ -44,6 +48,15 @@ struct ChatHelp: View {
Text("**Scan QR code**: to connect to your contact in person or via video call.")
}
.padding(.top, 24)
VStack(alignment: .leading, spacing: 10) {
Text("Markdown in messages")
.font(.title2)
.fontWeight(.bold)
MarkdownHelp()
}
.padding(.top, 24)
}
.padding()
}

View File

@@ -75,6 +75,7 @@ struct CreateProfile: View {
}
.onAppear() {
focusDisplayName = true
setLastVersionDefault()
}
.padding()
}

View File

@@ -0,0 +1,194 @@
//
// WhatsNewView.swift
// SimpleX (iOS)
//
// Created by Evgeny on 24/12/2022.
// Copyright © 2022 SimpleX Chat. All rights reserved.
//
import SwiftUI
private struct VersionDescription {
var version: String
var features: [FeatureDescription]
}
private struct FeatureDescription {
var icon: String
var title: LocalizedStringKey
var description: LocalizedStringKey
}
private let versionDescriptions: [VersionDescription] = [
VersionDescription(
version: "v4.2",
features: [
FeatureDescription(
icon: "checkmark.shield",
title: "Security assessment",
description: "SimpleX Chat security was [audited by Trail of Bits](https://simplex.chat/blog/20221108-simplex-chat-v4.2-security-audit-new-website.html)."
),
FeatureDescription(
icon: "person.2",
title: "Group links",
description: "Admins can create the links to join groups."
),
FeatureDescription(
icon: "checkmark",
title: "Auto-accept contact requests",
description: "With optional welcome message."
),
]
),
VersionDescription(
version: "v4.3",
features: [
FeatureDescription(
icon: "mic",
title: "Voice messages",
description: "Max 30 seconds, received instantly."
),
FeatureDescription(
icon: "trash.slash",
title: "Irreversible message deletion",
description: "Your contacts can allow full message deletion."
),
FeatureDescription(
icon: "externaldrive.connected.to.line.below",
title: "Improved server configuration",
description: "Add servers by scanning QR codes."
),
FeatureDescription(
icon: "eye.slash",
title: "Improved privacy and security",
description: "Hide app screen in the recent apps."
),
]
),
VersionDescription(
version: "v4.4",
features: [
FeatureDescription(
icon: "stopwatch",
title: "Disappearing messages",
description: "Sent messages will be deleted after set time."
),
FeatureDescription(
icon: "ellipsis.circle",
title: "Live messages",
description: "Recipients see updates as you type them."
),
FeatureDescription(
icon: "checkmark.shield",
title: "Verify connection security",
description: "Compare security codes with your contacts."
),
FeatureDescription(
icon: "camera",
title: "GIFs and stickers",
description: "Send them from gallery or custom keyboards."
)
]
)
]
private let lastVersion = versionDescriptions.last!.version
func setLastVersionDefault() {
UserDefaults.standard.set(lastVersion, forKey: DEFAULT_WHATS_NEW_VERSION)
}
func shouldShowWhatsNew() -> Bool {
let v = UserDefaults.standard.string(forKey: DEFAULT_WHATS_NEW_VERSION)
setLastVersionDefault()
return v != lastVersion
}
struct WhatsNewView: View {
@Environment(\.dismiss) var dismiss: DismissAction
@State var currentVersion = versionDescriptions.count - 1
@State var currentVersionNav = versionDescriptions.count - 1
var viaSettings = false
var body: some View {
VStack {
TabView(selection: $currentVersion) {
ForEach(0..<3) { i in
let v = versionDescriptions[i]
VStack(alignment: .leading, spacing: 16) {
Text("New in \(v.version)")
.font(.title)
.foregroundColor(.secondary)
.frame(maxWidth: .infinity)
.padding(.vertical)
ForEach(v.features, id: \.icon) { f in
featureDescription(f.icon, f.title, f.description)
}
if !viaSettings {
Spacer()
Button("Ok") {
dismiss()
}
.font(.title3)
.frame(maxWidth: .infinity, alignment: .center)
Spacer()
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
.tag(i)
}
}
.tabViewStyle(.page(indexDisplayMode: .never))
Spacer()
pagination()
}
.padding()
}
private func featureDescription(_ icon: String, _ title: LocalizedStringKey, _ description: LocalizedStringKey) -> some View {
VStack(alignment: .leading) {
HStack(alignment: .center) {
Image(systemName: icon).foregroundColor(.secondary)
Text(title).font(.title3).bold()
}
Text(description)
.multilineTextAlignment(.leading)
}
}
private func pagination() -> some View {
HStack {
if currentVersionNav > 0 {
let prev = currentVersionNav - 1
Button {
currentVersionNav = prev
withAnimation { currentVersion = prev }
} label: {
HStack {
Image(systemName: "chevron.left")
Text(versionDescriptions[prev].version)
}
}
}
Spacer()
if currentVersionNav < versionDescriptions.count - 1 {
let next = currentVersionNav + 1
Button {
currentVersionNav = next
withAnimation { currentVersion = next }
} label: {
HStack {
Text(versionDescriptions[next].version)
Image(systemName: "chevron.right")
}
}
}
}
}
}
struct NewFeaturesView_Previews: PreviewProvider {
static var previews: some View {
WhatsNewView()
}
}

View File

@@ -26,7 +26,6 @@ struct MarkdownHelp: View {
.textSelection(.enabled)
}
.frame(maxWidth: .infinity, alignment: .leading)
.padding()
}
}

View File

@@ -39,6 +39,7 @@ let DEFAULT_ACCENT_COLOR_BLUE = "accentColorBlue"
let DEFAULT_USER_INTERFACE_STYLE = "userInterfaceStyle"
let DEFAULT_CONNECT_VIA_LINK_TAB = "connectViaLinkTab"
let DEFAULT_LIVE_MESSAGE_ALERT_SHOWN = "liveMessageAlertShown"
let DEFAULT_WHATS_NEW_VERSION = "defaultWhatsNewVersion"
let appDefaults: [String: Any] = [
DEFAULT_SHOW_LA_NOTICE: false,
@@ -193,6 +194,12 @@ struct SettingsView: View {
} label: {
settingsRow("questionmark") { Text("How to use it") }
}
NavigationLink {
WhatsNewView(viaSettings: true)
.navigationBarTitleDisplayMode(.inline)
} label: {
settingsRow("plus") { Text("What's new") }
}
NavigationLink {
SimpleXInfo(onboarding: false)
.navigationBarTitle("", displayMode: .inline)
@@ -200,13 +207,14 @@ struct SettingsView: View {
} label: {
settingsRow("info") { Text("About SimpleX Chat") }
}
NavigationLink {
MarkdownHelp()
.navigationTitle("How to use markdown")
.frame(maxHeight: .infinity, alignment: .top)
} label: {
settingsRow("textformat") { Text("Markdown in messages") }
}
// NavigationLink {
// MarkdownHelp()
// .padding()
// .navigationTitle("How to use markdown")
// .frame(maxHeight: .infinity, alignment: .top)
// } label: {
// settingsRow("textformat") { Text("Markdown in messages") }
// }
settingsRow("number") {
Button("Send questions and ideas") {
showSettings = false

View File

@@ -101,6 +101,7 @@
5CB924E427A8683A00ACCCDD /* UserAddress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB924E327A8683A00ACCCDD /* UserAddress.swift */; };
5CB9250D27A9432000ACCCDD /* ChatListNavLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB9250C27A9432000ACCCDD /* ChatListNavLink.swift */; };
5CBD285A295711D700EC2CF4 /* ImageUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CBD2859295711D700EC2CF4 /* ImageUtils.swift */; };
5CBD285C29575B8E00EC2CF4 /* WhatsNewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CBD285B29575B8E00EC2CF4 /* WhatsNewView.swift */; };
5CBE6C12294487F7002D9531 /* VerifyCodeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CBE6C11294487F7002D9531 /* VerifyCodeView.swift */; };
5CBE6C142944CC12002D9531 /* ScanCodeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CBE6C132944CC12002D9531 /* ScanCodeView.swift */; };
5CC1C99227A6C7F5000D9FF6 /* QRCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CC1C99127A6C7F5000D9FF6 /* QRCode.swift */; };
@@ -325,6 +326,7 @@
5CBD285729565D2600EC2CF4 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = "fr.lproj/SimpleX--iOS--InfoPlist.strings"; sourceTree = "<group>"; };
5CBD285829565D2600EC2CF4 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/InfoPlist.strings; sourceTree = "<group>"; };
5CBD2859295711D700EC2CF4 /* ImageUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageUtils.swift; sourceTree = "<group>"; };
5CBD285B29575B8E00EC2CF4 /* WhatsNewView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WhatsNewView.swift; sourceTree = "<group>"; };
5CBE6C11294487F7002D9531 /* VerifyCodeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VerifyCodeView.swift; sourceTree = "<group>"; };
5CBE6C132944CC12002D9531 /* ScanCodeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanCodeView.swift; sourceTree = "<group>"; };
5CC1C99127A6C7F5000D9FF6 /* QRCode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCode.swift; sourceTree = "<group>"; };
@@ -592,6 +594,7 @@
5CB0BA992827FD8800B3292C /* HowItWorks.swift */,
5CB0BA91282713FD00B3292C /* CreateProfile.swift */,
5C9A5BDA2871E05400A5B906 /* SetNotificationsMode.swift */,
5CBD285B29575B8E00EC2CF4 /* WhatsNewView.swift */,
);
path = Onboarding;
sourceTree = "<group>";
@@ -1037,6 +1040,7 @@
5CEACCED27DEA495000BD591 /* MsgContentView.swift in Sources */,
5C764E89279CBCB3000C6508 /* ChatModel.swift in Sources */,
5C971E1D27AEBEF600C8A3CE /* ChatInfoView.swift in Sources */,
5CBD285C29575B8E00EC2CF4 /* WhatsNewView.swift in Sources */,
5CC1C99527A6CF7F000D9FF6 /* ShareSheet.swift in Sources */,
5C5E5D3B2824468B00B0488A /* ActiveCallView.swift in Sources */,
5C2E260727A2941F00F70299 /* SimpleXAPI.swift in Sources */,