redesign wip

This commit is contained in:
spaced4ndy
2024-05-01 20:07:09 +04:00
parent e4eb236ff5
commit 1d1b3234bb
11 changed files with 628 additions and 33 deletions
+10 -6
View File
@@ -9,6 +9,13 @@ import SwiftUI
import Intents
import SimpleXChat
enum HomeTab {
case settings
case contacts
case chats
case newChat
}
struct ContentView: View {
@EnvironmentObject var chatModel: ChatModel
@ObservedObject var alertManager = AlertManager.shared
@@ -27,7 +34,7 @@ struct ContentView: View {
@AppStorage(DEFAULT_PERFORM_LA) private var prefPerformLA = false
@AppStorage(DEFAULT_PRIVACY_PROTECT_SCREEN) private var protectScreen = false
@AppStorage(DEFAULT_NOTIFICATION_ALERT_SHOWN) private var notificationAlertShown = false
@State private var showSettings = false
@State private var homeTab: HomeTab = .chats
@State private var showWhatsNew = false
@State private var showChooseLAMode = false
@State private var showSetPasscode = false
@@ -74,7 +81,7 @@ struct ContentView: View {
callView(call)
}
if !showSettings, let la = chatModel.laRequest {
if homeTab != .settings, let la = chatModel.laRequest {
LocalAuthView(authRequest: la)
.onDisappear {
// this flag is separate from accessAuthenticated to show initializationView while we wait for authentication
@@ -97,9 +104,6 @@ struct ContentView: View {
}
}
.alert(isPresented: $alertManager.presentAlert) { alertManager.alertView! }
.sheet(isPresented: $showSettings) {
SettingsView(showSettings: $showSettings)
}
.confirmationDialog("SimpleX Lock mode", isPresented: $showChooseLAMode, titleVisibility: .visible) {
Button("System authentication") { initialEnableLA() }
Button("Passcode entry") { showSetPasscode = true }
@@ -230,7 +234,7 @@ struct ContentView: View {
private func mainView() -> some View {
ZStack(alignment: .top) {
ChatListView(showSettings: $showSettings).privacySensitive(protectScreen)
HomeView(homeTab: $homeTab).privacySensitive(protectScreen)
.onAppear {
requestNtfAuthorization()
// Local Authentication notice is to be shown on next start after onboarding is complete
@@ -10,7 +10,7 @@ import SwiftUI
struct ChatHelp: View {
@EnvironmentObject var chatModel: ChatModel
@Binding var showSettings: Bool
@Binding var homeTab: HomeTab
@State private var newChatMenuOption: NewChatMenuOption? = nil
var body: some View {
@@ -24,7 +24,7 @@ struct ChatHelp: View {
VStack(alignment: .leading, spacing: 0) {
Text("To ask any questions and to receive updates:")
Button("connect to SimpleX Chat developers.") {
showSettings = false
homeTab = .chats
DispatchQueue.main.async {
UIApplication.shared.open(simplexTeamURL)
}
@@ -63,7 +63,6 @@ struct ChatHelp: View {
struct ChatHelp_Previews: PreviewProvider {
static var previews: some View {
@State var showSettings = false
return ChatHelp(showSettings: $showSettings)
return ChatHelp(homeTab: Binding.constant(.chats))
}
}
@@ -54,7 +54,8 @@ struct ChatListView: View {
}
}
UserPicker(
showSettings: $showSettings,
// showSettings: $showSettings,
homeTab: Binding.constant(.chats),
showConnectDesktop: $showConnectDesktop,
userPickerVisible: $userPickerVisible
)
@@ -0,0 +1,382 @@
//
// ChatsView.swift
// SimpleX (iOS)
//
// Created by spaced4ndy on 01.05.2024.
// Copyright © 2024 SimpleX Chat. All rights reserved.
//
import SwiftUI
import SimpleXChat
struct ChatsView: View {
@EnvironmentObject var chatModel: ChatModel
@State private var searchMode = false
@FocusState private var searchFocussed
@State private var searchText = ""
@State private var searchShowingSimplexLink = false
@State private var searchChatFilteredBySimplexLink: String? = nil
@State private var newChatMenuOption: NewChatMenuOption? = nil // TODO remove?
@AppStorage(DEFAULT_SHOW_UNREAD_AND_FAVORITES) private var showUnreadAndFavorites = false
var body: some View {
if #available(iOS 16.0, *) {
viewBody.scrollDismissesKeyboard(.immediately)
} else {
viewBody
}
}
private var viewBody: some View {
ZStack {
NavStackCompat(
isActive: Binding(
get: { chatModel.chatId != nil },
set: { _ in }
),
destination: chatView
) {
VStack {
if chatModel.chats.isEmpty {
onboardingButtons()
}
chatsView
}
}
}
}
private var chatsView: some View {
VStack {
chatList
}
.refreshable {
AlertManager.shared.showAlert(Alert(
title: Text("Reconnect servers?"),
message: Text("Reconnect all connected servers to force message delivery. It uses additional traffic."),
primaryButton: .default(Text("Ok")) {
Task {
do {
try await reconnectAllServers()
} catch let error {
AlertManager.shared.showAlertMsg(title: "Error", message: "\(responseError(error))")
}
}
},
secondaryButton: .cancel()
))
}
.listStyle(.plain)
.navigationBarTitleDisplayMode(.inline)
.navigationBarHidden(searchMode)
.toolbar {
ToolbarItem(placement: .principal) {
HStack(spacing: 4) {
Text("Chats")
.font(.headline)
if chatModel.chats.count > 0 {
toggleFilterButton()
}
}
.frame(maxWidth: .infinity, alignment: .center)
}
}
}
private func toggleFilterButton() -> some View {
Button {
showUnreadAndFavorites = !showUnreadAndFavorites
} label: {
Image(systemName: "line.3.horizontal.decrease.circle" + (showUnreadAndFavorites ? ".fill" : ""))
.foregroundColor(.accentColor)
}
}
@ViewBuilder private var chatList: some View {
let cs = filteredChats()
ZStack {
VStack {
List {
if !chatModel.chats.isEmpty {
ChatsSearchBar(
searchMode: $searchMode,
searchFocussed: $searchFocussed,
searchText: $searchText,
searchShowingSimplexLink: $searchShowingSimplexLink,
searchChatFilteredBySimplexLink: $searchChatFilteredBySimplexLink
)
.listRowSeparator(.hidden)
.frame(maxWidth: .infinity)
}
ForEach(cs, id: \.viewId) { chat in
ChatListNavLink(chat: chat)
.padding(.trailing, -16)
.disabled(chatModel.chatRunning != true || chatModel.deletedChats.contains(chat.chatInfo.id))
}
.offset(x: -8)
}
}
.onChange(of: chatModel.chatId) { _ in
if chatModel.chatId == nil, let chatId = chatModel.chatToTop {
chatModel.chatToTop = nil
chatModel.popChat(chatId)
}
}
if cs.isEmpty && !chatModel.chats.isEmpty {
Text("No filtered chats").foregroundColor(.secondary)
}
}
}
private func unreadBadge(_ text: Text? = Text(" "), size: CGFloat = 18) -> some View {
Circle()
.frame(width: size, height: size)
.foregroundColor(.accentColor)
}
// TODO remove?
private func onboardingButtons() -> some View {
VStack(alignment: .trailing, spacing: 0) {
Path { p in
p.move(to: CGPoint(x: 8, y: 0))
p.addLine(to: CGPoint(x: 16, y: 10))
p.addLine(to: CGPoint(x: 0, y: 10))
p.addLine(to: CGPoint(x: 8, y: 0))
}
.fill(Color.accentColor)
.frame(width: 20, height: 10)
.padding(.trailing, 12)
connectButton("Tap to start a new chat") {
newChatMenuOption = .newContact
}
Spacer()
Text("You have no chats")
.foregroundColor(.secondary)
.frame(maxWidth: .infinity)
}
.padding(.trailing, 6)
.frame(maxHeight: .infinity)
}
private func connectButton(_ label: LocalizedStringKey, action: @escaping () -> Void) -> some View {
Button(action: action) {
Text(label)
.padding(.vertical, 10)
.padding(.horizontal, 20)
}
.background(Color.accentColor)
.foregroundColor(.white)
.clipShape(RoundedRectangle(cornerRadius: 16))
}
@ViewBuilder private func chatView() -> some View {
if let chatId = chatModel.chatId, let chat = chatModel.getChat(chatId) {
ChatView(chat: chat).onAppear {
loadChat(chat: chat)
}
}
}
private func filteredChats() -> [Chat] {
if let linkChatId = searchChatFilteredBySimplexLink {
return chatModel.chats.filter { $0.id == linkChatId }
} else {
let s = searchString()
return s == "" && !showUnreadAndFavorites
? chatModel.chats
: chatModel.chats.filter { chat in
let cInfo = chat.chatInfo
switch cInfo {
case let .direct(contact):
return s == ""
? filtered(chat)
: (viewNameContains(cInfo, s) ||
contact.profile.displayName.localizedLowercase.contains(s) ||
contact.fullName.localizedLowercase.contains(s))
case let .group(gInfo):
return s == ""
? (filtered(chat) || gInfo.membership.memberStatus == .memInvited)
: viewNameContains(cInfo, s)
case .local:
return s == "" || viewNameContains(cInfo, s)
case .contactRequest:
return s == "" || viewNameContains(cInfo, s)
case let .contactConnection(conn):
return s != "" && conn.localAlias.localizedLowercase.contains(s)
case .invalidJSON:
return false
}
}
}
func searchString() -> String {
searchShowingSimplexLink ? "" : searchText.trimmingCharacters(in: .whitespaces).localizedLowercase
}
func filtered(_ chat: Chat) -> Bool {
(chat.chatInfo.chatSettings?.favorite ?? false) ||
chat.chatStats.unreadChat ||
(chat.chatInfo.ntfsEnabled && chat.chatStats.unreadCount > 0)
}
func viewNameContains(_ cInfo: ChatInfo, _ s: String) -> Bool {
cInfo.chatViewName.localizedLowercase.contains(s)
}
}
}
struct ChatsSearchBar: View {
@EnvironmentObject var m: ChatModel
@Binding var searchMode: Bool
@FocusState.Binding var searchFocussed: Bool
@Binding var searchText: String
@Binding var searchShowingSimplexLink: Bool
@Binding var searchChatFilteredBySimplexLink: String?
@State private var ignoreSearchTextChange = false
@State private var showScanCodeSheet = false
@State private var alert: PlanAndConnectAlert?
@State private var sheet: PlanAndConnectActionSheet?
var body: some View {
VStack(spacing: 12) {
HStack(spacing: 12) {
HStack(spacing: 4) {
Image(systemName: "magnifyingglass")
TextField("Search or paste SimpleX link", text: $searchText)
.foregroundColor(searchShowingSimplexLink ? .secondary : .primary)
.disabled(searchShowingSimplexLink)
.focused($searchFocussed)
.frame(maxWidth: .infinity)
if !searchText.isEmpty {
Image(systemName: "xmark.circle.fill")
.onTapGesture {
searchText = ""
}
} else if !searchFocussed {
HStack(spacing: 24) {
if m.pasteboardHasStrings {
Image(systemName: "doc")
.onTapGesture {
if let str = UIPasteboard.general.string {
searchText = str
}
}
}
Image(systemName: "qrcode")
.resizable()
.scaledToFit()
.frame(width: 20, height: 20)
.onTapGesture {
showScanCodeSheet = true
}
}
.padding(.trailing, 2)
}
}
.padding(EdgeInsets(top: 7, leading: 7, bottom: 7, trailing: 7))
.foregroundColor(.secondary)
.background(Color(.tertiarySystemFill))
.cornerRadius(10.0)
if searchFocussed {
Text("Cancel")
.foregroundColor(.accentColor)
.onTapGesture {
searchText = ""
searchFocussed = false
}
}
}
Divider()
}
.sheet(isPresented: $showScanCodeSheet) {
NewChatView(selection: .connect, showQRCodeScanner: true)
.environment(\EnvironmentValues.refresh as! WritableKeyPath<EnvironmentValues, RefreshAction?>, nil) // fixes .refreshable in ChatsView affecting nested view
}
.onChange(of: searchFocussed) { sf in
withAnimation { searchMode = sf }
}
.onChange(of: searchText) { t in
if ignoreSearchTextChange {
ignoreSearchTextChange = false
} else {
if let link = strHasSingleSimplexLink(t.trimmingCharacters(in: .whitespaces)) { // if SimpleX link is pasted, show connection dialogue
searchFocussed = false
if case let .simplexLink(linkType, _, smpHosts) = link.format {
ignoreSearchTextChange = true
searchText = simplexLinkText(linkType, smpHosts)
}
searchShowingSimplexLink = true
searchChatFilteredBySimplexLink = nil
connect(link.text)
} else {
if t != "" { // if some other text is pasted, enter search mode
searchFocussed = true
}
searchShowingSimplexLink = false
searchChatFilteredBySimplexLink = nil
}
}
}
.alert(item: $alert) { a in
planAndConnectAlert(a, dismiss: true, cleanup: { searchText = "" })
}
.actionSheet(item: $sheet) { s in
planAndConnectActionSheet(s, dismiss: true, cleanup: { searchText = "" })
}
}
private func connect(_ link: String) {
planAndConnect(
link,
showAlert: { alert = $0 },
showActionSheet: { sheet = $0 },
dismiss: false,
incognito: nil,
filterKnownContact: { searchChatFilteredBySimplexLink = $0.id },
filterKnownGroup: { searchChatFilteredBySimplexLink = $0.id }
)
}
}
// TODO remove
func chatsStoppedIcon() -> some View {
Button {
AlertManager.shared.showAlertMsg(
title: "Chat is stopped",
message: "You can start chat via app Settings / Database or by restarting the app"
)
} label: {
Image(systemName: "exclamationmark.octagon.fill").foregroundColor(.red)
}
}
struct ChatsView_Previews: PreviewProvider {
static var previews: some View {
let chatModel = ChatModel()
chatModel.chats = [
Chat(
chatInfo: ChatInfo.sampleData.direct,
chatItems: [ChatItem.getSample(1, .directSnd, .now, "hello")]
),
Chat(
chatInfo: ChatInfo.sampleData.group,
chatItems: [ChatItem.getSample(1, .directSnd, .now, "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")]
),
Chat(
chatInfo: ChatInfo.sampleData.contactRequest,
chatItems: []
)
]
return Group {
ChatsView()
.environmentObject(chatModel)
ChatsView()
.environmentObject(ChatModel())
}
}
}
@@ -13,7 +13,7 @@ struct UserPicker: View {
@EnvironmentObject var m: ChatModel
@Environment(\.colorScheme) var colorScheme
@Environment(\.scenePhase) var scenePhase
@Binding var showSettings: Bool
@Binding var homeTab: HomeTab
@Binding var showConnectDesktop: Bool
@Binding var userPickerVisible: Bool
@State var scrollViewContentSize: CGSize = .zero
@@ -72,7 +72,7 @@ struct UserPicker: View {
}
Divider()
menuButton("Settings", icon: "gearshape") {
showSettings = true
homeTab = .settings
withAnimation {
userPickerVisible.toggle()
}
@@ -106,7 +106,7 @@ struct UserPicker: View {
let user = u.user
return Button(action: {
if user.activeUser {
showSettings = true
homeTab = .settings
withAnimation {
userPickerVisible.toggle()
}
@@ -181,7 +181,7 @@ struct UserPicker_Previews: PreviewProvider {
let m = ChatModel()
m.users = [UserInfo.sampleData, UserInfo.sampleData]
return UserPicker(
showSettings: Binding.constant(false),
homeTab: Binding.constant(.chats),
showConnectDesktop: Binding.constant(false),
userPickerVisible: Binding.constant(true)
)
@@ -41,7 +41,7 @@ enum DatabaseAlert: Identifiable {
struct DatabaseView: View {
@EnvironmentObject var m: ChatModel
@Binding var showSettings: Bool
@Binding var homeTab: HomeTab
@State private var runChat = false
@State private var alert: DatabaseAlert? = nil
@State private var showFileImporter = false
@@ -409,7 +409,7 @@ struct DatabaseView: View {
private func startChat() {
if m.chatDbChanged {
showSettings = false
homeTab = .chats
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
resetChatCtrl()
do {
@@ -493,6 +493,6 @@ func deleteChatAsync() async throws {
struct DatabaseView_Previews: PreviewProvider {
static var previews: some View {
DatabaseView(showSettings: Binding.constant(false), chatItemTTL: .none)
DatabaseView(homeTab: Binding.constant(.chats), chatItemTTL: .none)
}
}
+194
View File
@@ -0,0 +1,194 @@
//
// HomeView.swift
// SimpleX (iOS)
//
// Created by spaced4ndy on 01.05.2024.
// Copyright © 2024 SimpleX Chat. All rights reserved.
//
import SwiftUI
import SimpleXChat
struct HomeView: View {
@EnvironmentObject var chatModel: ChatModel
@Binding var homeTab: HomeTab
@State private var userPickerVisible = false
@State private var showConnectDesktop = false
@State private var newChatMenuOption: NewChatMenuOption? = nil
var body: some View {
ZStack(alignment: .bottomLeading) {
switch homeTab {
case .settings: settingsView()
case .contacts: contactsView()
case .chats: chatsView()
case .newChat: newChatView()
}
if userPickerVisible {
Rectangle().fill(.white.opacity(0.001)).onTapGesture {
withAnimation {
userPickerVisible.toggle()
}
}
}
UserPicker(
homeTab: $homeTab,
showConnectDesktop: $showConnectDesktop,
userPickerVisible: $userPickerVisible
)
}
.toolbar {
ToolbarItemGroup(placement: .bottomBar) {
settingsButton()
Spacer()
contactsButton()
Spacer()
chatsButton()
Spacer()
newChatButton()
}
}
.sheet(isPresented: $showConnectDesktop) {
ConnectDesktopView()
}
}
@ViewBuilder private func settingsButton() -> some View {
let user = chatModel.currentUser ?? User.sampleData
let multiUser = chatModel.users.filter({ u in u.user.activeUser || !u.user.hidden }).count > 1
Button {
if multiUser {
withAnimation {
userPickerVisible.toggle()
}
} else {
homeTab = .settings
}
} label: {
if user.image != nil {
ZStack(alignment: .topTrailing) {
ProfileImage(imageStr: user.image, size: 32, color: Color(uiColor: .quaternaryLabel))
.padding(.trailing, 4)
let allRead = chatModel.users
.filter { u in !u.user.activeUser && !u.user.hidden }
.allSatisfy { u in u.unreadCount == 0 }
if !allRead {
userUnreadBadge(size: 12)
}
}
} else {
VStack(spacing: 4) {
Image(systemName: multiUser ? "person.2.fill" : "gearshape.fill")
Text("Users")
.font(.caption)
}
}
}
.foregroundColor(homeTab == .settings ? .accentColor : .secondary)
}
private func userUnreadBadge(_ text: Text? = Text(" "), size: CGFloat = 18) -> some View {
Circle()
.frame(width: size, height: size)
.foregroundColor(.accentColor)
}
private func contactsButton() -> some View {
Button {
homeTab = .contacts
} label: {
VStack(spacing: 4) {
Image(systemName: "person.crop.circle.fill")
Text("Contacts")
.font(.caption)
}
}
.foregroundColor(homeTab == .contacts ? .accentColor : .secondary)
}
private func chatsButton() -> some View {
Button {
homeTab = .chats
} label: {
VStack(spacing: 4) {
Image(systemName: "message.fill")
Text("Chats")
.font(.caption)
}
}
.foregroundColor(homeTab == .chats ? .accentColor : .secondary)
}
@ViewBuilder private func newChatButton() -> some View {
if homeTab != .newChat {
Menu {
Button {
newChatMenuOption = .newContact
homeTab = .newChat
} label: {
Text("Add contact")
}
Button {
newChatMenuOption = .newGroup
homeTab = .newChat
} label: {
Text("Create group")
}
} label: {
newChatButtonLabel()
}
.foregroundColor(.secondary)
} else {
Button {} label: {
newChatButtonLabel()
}
.foregroundColor(.accentColor)
}
}
private func newChatButtonLabel() -> some View {
VStack(spacing: 4) {
Image(systemName: "square.and.pencil")
Text("New chat")
.font(.caption)
}
}
private func settingsView() -> some View {
SettingsView(homeTab: $homeTab)
}
private func contactsView() -> some View {
// TODO
VStack {
Text("Contacts")
}
}
private func chatsView() -> some View {
// TODO remove top bar, move search to bottom
// TODO hide toolbar when in chat
// TODO onboarding buttons (remove?)
ChatsView()
}
@ViewBuilder private func newChatView() -> some View {
// TODO doesn't fit
// TODO alerts don't work
// TODO dismiss on connect
// TODO dismiss when creating group
// TODO chat stopped (see chatsStoppedIcon in ChatsView)
switch newChatMenuOption {
case .newContact:
NewChatView(selection: .invite)
case .newGroup:
AddGroupView()
case nil:
EmptyView()
}
}
}
#Preview {
HomeView(homeTab: Binding.constant(.chats))
}
@@ -54,7 +54,7 @@ private enum MigrateFromDeviceViewAlert: Identifiable {
struct MigrateFromDevice: View {
@EnvironmentObject var m: ChatModel
@Environment(\.dismiss) var dismiss: DismissAction
@Binding var showSettings: Bool
@Binding var homeTab: HomeTab
@Binding var showProgressOnSettings: Bool
@State private var migrationState: MigrationFromState = .chatStopInProgress
@State private var useKeychain = storeDBPassphraseGroupDefault.get()
@@ -555,7 +555,7 @@ struct MigrateFromDevice: View {
} catch let error {
fatalError("Error starting chat \(responseError(error))")
}
showSettings = false
homeTab = .chats
}
} catch let error {
alert = .error(title: "Error deleting database", error: responseError(error))
@@ -579,7 +579,7 @@ struct MigrateFromDevice: View {
// Hide settings anyway if chatDbStatus is not ok, probably passphrase needs to be entered
if dismiss || m.chatDbStatus != .ok {
await MainActor.run {
showSettings = false
homeTab = .chats
}
}
}
@@ -729,6 +729,6 @@ private class MigrationChatReceiver {
struct MigrateFromDevice_Previews: PreviewProvider {
static var previews: some View {
MigrateFromDevice(showSettings: Binding.constant(true), showProgressOnSettings: Binding.constant(false))
MigrateFromDevice(homeTab: Binding.constant(.chats), showProgressOnSettings: Binding.constant(false))
}
}
@@ -154,7 +154,7 @@ struct SettingsView: View {
@Environment(\.colorScheme) var colorScheme
@EnvironmentObject var chatModel: ChatModel
@EnvironmentObject var sceneDelegate: SceneDelegate
@Binding var showSettings: Bool
@Binding var homeTab: HomeTab
@State private var showProgress: Bool = false
var body: some View {
@@ -185,7 +185,7 @@ struct SettingsView: View {
}
NavigationLink {
UserProfilesView(showSettings: $showSettings)
UserProfilesView(homeTab: $homeTab)
} label: {
settingsRow("person.crop.rectangle.stack") { Text("Your chat profiles") }
}
@@ -215,7 +215,7 @@ struct SettingsView: View {
}
NavigationLink {
MigrateFromDevice(showSettings: $showSettings, showProgressOnSettings: $showProgress)
MigrateFromDevice(homeTab: $homeTab, showProgressOnSettings: $showProgress)
.navigationTitle("Migrate device")
.navigationBarTitleDisplayMode(.large)
} label: {
@@ -276,7 +276,7 @@ struct SettingsView: View {
Section("Help") {
if let user = user {
NavigationLink {
ChatHelp(showSettings: $showSettings)
ChatHelp(homeTab: $homeTab)
.navigationTitle("Welcome \(user.displayName)!")
.frame(maxHeight: .infinity, alignment: .top)
} label: {
@@ -298,7 +298,7 @@ struct SettingsView: View {
}
settingsRow("number") {
Button("Send questions and ideas") {
showSettings = false
homeTab = .chats
DispatchQueue.main.async {
UIApplication.shared.open(simplexTeamURL)
}
@@ -352,7 +352,7 @@ struct SettingsView: View {
private func chatDatabaseRow() -> some View {
NavigationLink {
DatabaseView(showSettings: $showSettings, chatItemTTL: chatModel.chatItemTTL)
DatabaseView(homeTab: $homeTab, chatItemTTL: chatModel.chatItemTTL)
.navigationTitle("Your chat database")
} label: {
let color: Color = chatModel.chatDbEncrypted == false ? .orange : .secondary
@@ -446,9 +446,8 @@ struct SettingsView_Previews: PreviewProvider {
static var previews: some View {
let chatModel = ChatModel()
chatModel.currentUser = User.sampleData
@State var showSettings = false
return SettingsView(showSettings: $showSettings)
return SettingsView(homeTab: Binding.constant(.chats))
.environmentObject(chatModel)
}
}
@@ -8,7 +8,7 @@ import SimpleXChat
struct UserProfilesView: View {
@EnvironmentObject private var m: ChatModel
@Binding var showSettings: Bool
@Binding var homeTab: HomeTab
@Environment(\.editMode) private var editMode
@AppStorage(DEFAULT_SHOW_HIDDEN_PROFILES_NOTICE) private var showHiddenProfilesNotice = true
@AppStorage(DEFAULT_SHOW_MUTE_PROFILE_ALERT) private var showMuteProfileAlert = true
@@ -280,7 +280,7 @@ struct UserProfilesView: View {
await MainActor.run {
onboardingStageDefault.set(.step1_SimpleXInfo)
m.onboardingStage = .step1_SimpleXInfo
showSettings = false
homeTab = .chats
}
}
} else {
@@ -403,6 +403,6 @@ public func chatPasswordHash(_ pwd: String, _ salt: String) -> String {
struct UserProfilesView_Previews: PreviewProvider {
static var previews: some View {
UserProfilesView(showSettings: Binding.constant(true))
UserProfilesView(homeTab: Binding.constant(.settings))
}
}
@@ -155,6 +155,7 @@
6407BA83295DA85D0082BA18 /* CIInvalidJSONView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6407BA82295DA85D0082BA18 /* CIInvalidJSONView.swift */; };
6419EC562AB8BC8B004A607A /* ContextInvitingContactMemberView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6419EC552AB8BC8B004A607A /* ContextInvitingContactMemberView.swift */; };
6419EC582AB97507004A607A /* CIMemberCreatedContactView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6419EC572AB97507004A607A /* CIMemberCreatedContactView.swift */; };
642CE4952BE2651E00AD7757 /* HomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 642CE4942BE2651E00AD7757 /* HomeView.swift */; };
6432857C2925443C00FBE5C8 /* GroupPreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6432857B2925443C00FBE5C8 /* GroupPreferencesView.swift */; };
6440CA00288857A10062C672 /* CIEventView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6440C9FF288857A10062C672 /* CIEventView.swift */; };
6440CA03288AECA70062C672 /* AddGroupMembersView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6440CA02288AECA70062C672 /* AddGroupMembersView.swift */; };
@@ -168,6 +169,7 @@
644EFFE2292D089800525D5B /* FramedCIVoiceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 644EFFE1292D089800525D5B /* FramedCIVoiceView.swift */; };
644EFFE42937BE9700525D5B /* MarkedDeletedItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 644EFFE32937BE9700525D5B /* MarkedDeletedItemView.swift */; };
6454036F2822A9750090DDFF /* ComposeFileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6454036E2822A9750090DDFF /* ComposeFileView.swift */; };
64593F122BE28E5F00CD75D2 /* ChatsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64593F112BE28E5F00CD75D2 /* ChatsView.swift */; };
646BB38C283BEEB9001CE359 /* LocalAuthentication.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 646BB38B283BEEB9001CE359 /* LocalAuthentication.framework */; };
646BB38E283FDB6D001CE359 /* LocalAuthenticationUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 646BB38D283FDB6D001CE359 /* LocalAuthenticationUtils.swift */; };
647F090E288EA27B00644C40 /* GroupMemberInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 647F090D288EA27B00644C40 /* GroupMemberInfoView.swift */; };
@@ -450,6 +452,7 @@
6407BA82295DA85D0082BA18 /* CIInvalidJSONView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIInvalidJSONView.swift; sourceTree = "<group>"; };
6419EC552AB8BC8B004A607A /* ContextInvitingContactMemberView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContextInvitingContactMemberView.swift; sourceTree = "<group>"; };
6419EC572AB97507004A607A /* CIMemberCreatedContactView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIMemberCreatedContactView.swift; sourceTree = "<group>"; };
642CE4942BE2651E00AD7757 /* HomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeView.swift; sourceTree = "<group>"; };
6432857B2925443C00FBE5C8 /* GroupPreferencesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupPreferencesView.swift; sourceTree = "<group>"; };
6440C9FF288857A10062C672 /* CIEventView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIEventView.swift; sourceTree = "<group>"; };
6440CA02288AECA70062C672 /* AddGroupMembersView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddGroupMembersView.swift; sourceTree = "<group>"; };
@@ -463,6 +466,7 @@
644EFFE1292D089800525D5B /* FramedCIVoiceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FramedCIVoiceView.swift; sourceTree = "<group>"; };
644EFFE32937BE9700525D5B /* MarkedDeletedItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarkedDeletedItemView.swift; sourceTree = "<group>"; };
6454036E2822A9750090DDFF /* ComposeFileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeFileView.swift; sourceTree = "<group>"; };
64593F112BE28E5F00CD75D2 /* ChatsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatsView.swift; sourceTree = "<group>"; };
646BB38B283BEEB9001CE359 /* LocalAuthentication.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = LocalAuthentication.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS15.4.sdk/System/Library/Frameworks/LocalAuthentication.framework; sourceTree = DEVELOPER_DIR; };
646BB38D283FDB6D001CE359 /* LocalAuthenticationUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalAuthenticationUtils.swift; sourceTree = "<group>"; };
647F090D288EA27B00644C40 /* GroupMemberInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupMemberInfoView.swift; sourceTree = "<group>"; };
@@ -562,6 +566,7 @@
5C2E260D27A30E2400F70299 /* Views */ = {
isa = PBXGroup;
children = (
642CE4932BE2650500AD7757 /* Home */,
5CB0BA8C282711BC00B3292C /* Onboarding */,
3C714775281C080100CB4D4B /* Call */,
5C971E1F27AEBF7000C8A3CE /* Helpers */,
@@ -802,6 +807,7 @@
5C13730A28156D2700F43030 /* ContactConnectionView.swift */,
5C10D88728EED12E00E58BF0 /* ContactConnectionInfo.swift */,
18415835CBD939A9ABDC108A /* UserPicker.swift */,
64593F112BE28E5F00CD75D2 /* ChatsView.swift */,
);
path = ChatList;
sourceTree = "<group>";
@@ -899,6 +905,14 @@
path = Database;
sourceTree = "<group>";
};
642CE4932BE2650500AD7757 /* Home */ = {
isa = PBXGroup;
children = (
642CE4942BE2651E00AD7757 /* HomeView.swift */,
);
path = Home;
sourceTree = "<group>";
};
6440CA01288AEC770062C672 /* Group */ = {
isa = PBXGroup;
children = (
@@ -1212,6 +1226,7 @@
5CEBD7462A5C0A8F00665FE2 /* KeyboardPadding.swift in Sources */,
5C35CFC827B2782E00FB6C6D /* BGManager.swift in Sources */,
5CB634B129E5EFEA0066AD6B /* PasscodeView.swift in Sources */,
642CE4952BE2651E00AD7757 /* HomeView.swift in Sources */,
8C69FE7D2B8C7D2700267E38 /* AppSettings.swift in Sources */,
5C2E260F27A30FDC00F70299 /* ChatView.swift in Sources */,
5C2E260B27A30CFA00F70299 /* ChatListView.swift in Sources */,
@@ -1273,6 +1288,7 @@
18415B0585EB5A9A0A7CA8CD /* PressedButtonStyle.swift in Sources */,
1841560FD1CD447955474C1D /* UserProfilesView.swift in Sources */,
64C3B0212A0D359700E19930 /* CustomTimePicker.swift in Sources */,
64593F122BE28E5F00CD75D2 /* ChatsView.swift in Sources */,
8CC4ED902BD7B8530078AEE8 /* CallAudioDeviceManager.swift in Sources */,
18415C6C56DBCEC2CBBD2F11 /* WebRTCClient.swift in Sources */,
184152CEF68D2336FC2EBCB0 /* CallViewRenderers.swift in Sources */,