mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-04-26 15:18:01 +00:00
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:
committed by
GitHub
parent
4370012b8a
commit
a02cfb4f41
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -75,6 +75,7 @@ struct CreateProfile: View {
|
||||
}
|
||||
.onAppear() {
|
||||
focusDisplayName = true
|
||||
setLastVersionDefault()
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
|
||||
194
apps/ios/Shared/Views/Onboarding/WhatsNewView.swift
Normal file
194
apps/ios/Shared/Views/Onboarding/WhatsNewView.swift
Normal 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()
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,6 @@ struct MarkdownHelp: View {
|
||||
.textSelection(.enabled)
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */,
|
||||
|
||||
Reference in New Issue
Block a user