ios: connection UI (wip)
This commit is contained in:
@@ -16,6 +16,7 @@ struct ChatListView: View {
|
||||
@State private var showAddChat = false
|
||||
@State private var userPickerVisible = false
|
||||
@State private var showConnectDesktop = false
|
||||
@State private var showCreateGroupSheet = false
|
||||
@AppStorage(DEFAULT_SHOW_UNREAD_AND_FAVORITES) private var showUnreadAndFavorites = false
|
||||
|
||||
var body: some View {
|
||||
@@ -62,11 +63,7 @@ struct ChatListView: View {
|
||||
|
||||
private var chatListView: some View {
|
||||
VStack {
|
||||
if chatModel.chats.count > 0 {
|
||||
chatList.searchable(text: $searchText)
|
||||
} else {
|
||||
chatList
|
||||
}
|
||||
chatList.searchable(text: $searchText)
|
||||
}
|
||||
.onDisappear() { withAnimation { userPickerVisible = false } }
|
||||
.refreshable {
|
||||
@@ -88,6 +85,9 @@ struct ChatListView: View {
|
||||
.offset(x: -8)
|
||||
.listStyle(.plain)
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.sheet(isPresented: $showCreateGroupSheet) {
|
||||
AddGroupView()
|
||||
}
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .navigationBarLeading) {
|
||||
let user = chatModel.currentUser ?? User.sampleData
|
||||
@@ -124,7 +124,12 @@ struct ChatListView: View {
|
||||
}
|
||||
ToolbarItem(placement: .navigationBarTrailing) {
|
||||
switch chatModel.chatRunning {
|
||||
case .some(true): NewChatButton(showAddChat: $showAddChat)
|
||||
// case .some(true): NewChatButton(showAddChat: $showAddChat)
|
||||
case .some(true):
|
||||
HStack {
|
||||
createGroupButton()
|
||||
NewChatButton2()
|
||||
}
|
||||
case .some(false): chatStoppedIcon()
|
||||
case .none: EmptyView()
|
||||
}
|
||||
@@ -132,6 +137,17 @@ struct ChatListView: View {
|
||||
}
|
||||
}
|
||||
|
||||
private func createGroupButton() -> some View {
|
||||
Button {
|
||||
showCreateGroupSheet = true
|
||||
} label: {
|
||||
Image(systemName: "person.2")
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(width: 28, height: 28)
|
||||
}
|
||||
}
|
||||
|
||||
private func toggleFilterButton() -> some View {
|
||||
Button {
|
||||
showUnreadAndFavorites = !showUnreadAndFavorites
|
||||
|
||||
53
apps/ios/Shared/Views/NewChat/NewChatButton2.swift
Normal file
53
apps/ios/Shared/Views/NewChat/NewChatButton2.swift
Normal file
@@ -0,0 +1,53 @@
|
||||
//
|
||||
// NewChatButton2.swift
|
||||
// SimpleX (iOS)
|
||||
//
|
||||
// Created by spaced4ndy on 28.11.2023.
|
||||
// Copyright © 2023 SimpleX Chat. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import SimpleXChat
|
||||
|
||||
enum NewChatSheet: Identifiable {
|
||||
case newChat(link: String, connection: PendingContactConnection)
|
||||
|
||||
var id: String {
|
||||
switch self {
|
||||
case let .newChat(link, _): return "newChat \(link)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct NewChatButton2: View {
|
||||
@State private var actionSheet: NewChatSheet?
|
||||
|
||||
var body: some View {
|
||||
Button {
|
||||
addContactAction()
|
||||
} label: {
|
||||
Image(systemName: "square.and.pencil")
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(width: 24, height: 24)
|
||||
}
|
||||
.sheet(item: $actionSheet) { sheet in
|
||||
switch sheet {
|
||||
case let .newChat(link, pcc):
|
||||
NewChatView(selection: .invite, connReqInvitation: link, contactConnection: pcc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func addContactAction() {
|
||||
Task {
|
||||
if let (connReq, pcc) = await apiAddContact(incognito: incognitoGroupDefault.get()) {
|
||||
actionSheet = .newChat(link: connReq, connection: pcc)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//#Preview {
|
||||
// NewChatButton2()
|
||||
//}
|
||||
431
apps/ios/Shared/Views/NewChat/NewChatView.swift
Normal file
431
apps/ios/Shared/Views/NewChat/NewChatView.swift
Normal file
@@ -0,0 +1,431 @@
|
||||
//
|
||||
// NewChatView.swift
|
||||
// SimpleX (iOS)
|
||||
//
|
||||
// Created by spaced4ndy on 28.11.2023.
|
||||
// Copyright © 2023 SimpleX Chat. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import SimpleXChat
|
||||
import CodeScanner
|
||||
|
||||
enum NewChatOption: Identifiable {
|
||||
case invite
|
||||
case connect
|
||||
|
||||
var id: Self { self }
|
||||
}
|
||||
|
||||
struct NewChatView: View {
|
||||
@EnvironmentObject var m: ChatModel
|
||||
@State var selection: NewChatOption
|
||||
@State var connReqInvitation: String
|
||||
@State var contactConnection: PendingContactConnection?
|
||||
@State private var creatingConnReq = false
|
||||
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
VStack(alignment: .leading) {
|
||||
Text("Start a New Chat")
|
||||
.font(.largeTitle)
|
||||
.bold()
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.padding(.vertical)
|
||||
|
||||
Picker("New chat", selection: $selection) {
|
||||
Label("Invite", systemImage: "link")
|
||||
.tag(NewChatOption.invite)
|
||||
Label("Connect", systemImage: "qrcode")
|
||||
.tag(NewChatOption.connect)
|
||||
}
|
||||
.pickerStyle(.segmented)
|
||||
|
||||
switch selection {
|
||||
case .invite: InviteView(
|
||||
contactConnection: $contactConnection,
|
||||
connReqInvitation: connReqInvitation
|
||||
)
|
||||
case .connect: ConnectView()
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
|
||||
.padding()
|
||||
.background(Color(.systemGroupedBackground))
|
||||
.onChange(of: selection) { sel in
|
||||
if case .connect = sel,
|
||||
connReqInvitation == "" && contactConnection == nil && !creatingConnReq {
|
||||
createInvitation()
|
||||
}
|
||||
}
|
||||
.onAppear { m.connReqInv = connReqInvitation }
|
||||
.onDisappear { m.connReqInv = nil }
|
||||
}
|
||||
}
|
||||
|
||||
private func createInvitation() {
|
||||
creatingConnReq = true
|
||||
Task {
|
||||
if let (connReq, pcc) = await apiAddContact(incognito: incognitoGroupDefault.get()) {
|
||||
await MainActor.run {
|
||||
connReqInvitation = connReq
|
||||
contactConnection = pcc
|
||||
m.connReqInv = connReq
|
||||
}
|
||||
} else {
|
||||
await MainActor.run {
|
||||
creatingConnReq = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct InviteView: View {
|
||||
@EnvironmentObject private var chatModel: ChatModel
|
||||
@Binding var contactConnection: PendingContactConnection?
|
||||
var connReqInvitation: String
|
||||
@AppStorage(GROUP_DEFAULT_INCOGNITO, store: groupDefaults) private var incognitoDefault = false
|
||||
|
||||
var body: some View {
|
||||
GeometryReader { geo in
|
||||
ScrollView {
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
if connReqInvitation != "" {
|
||||
HStack {
|
||||
Text("Share this unique invite link")
|
||||
.textCase(.uppercase)
|
||||
.font(.footnote)
|
||||
.foregroundColor(.secondary)
|
||||
Spacer()
|
||||
Button {
|
||||
copyLink()
|
||||
} label: {
|
||||
Text("Copy")
|
||||
.font(.footnote)
|
||||
}
|
||||
}
|
||||
.padding(.horizontal)
|
||||
|
||||
Text(simplexChatLink(connReqInvitation))
|
||||
.lineLimit(2)
|
||||
.font(.callout)
|
||||
.padding(.horizontal)
|
||||
.padding(.vertical, 8)
|
||||
.background(
|
||||
RoundedRectangle(cornerRadius: 12, style: .continuous)
|
||||
.fill(Color(uiColor: .systemBackground))
|
||||
)
|
||||
|
||||
Text("Or show this code")
|
||||
.textCase(.uppercase)
|
||||
.font(.footnote)
|
||||
.foregroundColor(.secondary)
|
||||
.padding(.horizontal)
|
||||
.padding(.top, 8)
|
||||
|
||||
VStack(alignment: .center) {
|
||||
SimpleXLinkQRCode(uri: connReqInvitation)
|
||||
.padding(.horizontal)
|
||||
.padding(.vertical, 10)
|
||||
.frame(width: geo.size.width * 0.8)
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .center)
|
||||
.background(
|
||||
RoundedRectangle(cornerRadius: 12, style: .continuous)
|
||||
.fill(Color(uiColor: .systemBackground))
|
||||
)
|
||||
|
||||
VStack(alignment: .leading) {
|
||||
IncognitoToggle(incognitoEnabled: $incognitoDefault)
|
||||
Divider()
|
||||
shareLinkButton2(connReqInvitation)
|
||||
}
|
||||
.padding(.horizontal)
|
||||
.padding(.vertical, 8)
|
||||
.frame(maxWidth: .infinity)
|
||||
.background(
|
||||
RoundedRectangle(cornerRadius: 12, style: .continuous)
|
||||
.fill(Color(uiColor: .systemBackground))
|
||||
)
|
||||
.padding(.top)
|
||||
|
||||
VStack(alignment: .center) {
|
||||
oneTimeLinkLearnMoreButton2()
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .center)
|
||||
.padding(.top)
|
||||
} else {
|
||||
Text("Creating link…")
|
||||
.textCase(.uppercase)
|
||||
.font(.footnote)
|
||||
.foregroundColor(.secondary)
|
||||
.padding(.horizontal)
|
||||
|
||||
VStack(alignment: .center) {
|
||||
ProgressView()
|
||||
.progressViewStyle(.circular)
|
||||
.scaleEffect(2)
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding(.horizontal)
|
||||
.padding(.vertical, 8)
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .center)
|
||||
.background(
|
||||
RoundedRectangle(cornerRadius: 12, style: .continuous)
|
||||
.fill(Color(uiColor: .systemBackground))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding(.vertical)
|
||||
.onAppear { chatModel.connReqInv = connReqInvitation }
|
||||
.onChange(of: incognitoDefault) { incognito in
|
||||
Task {
|
||||
do {
|
||||
if let contactConn = contactConnection,
|
||||
let conn = try await apiSetConnectionIncognito(connId: contactConn.pccConnId, incognito: incognito) {
|
||||
await MainActor.run {
|
||||
contactConnection = conn
|
||||
chatModel.updateContactConnection(conn)
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
logger.error("apiSetConnectionIncognito error: \(responseError(error))")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func copyLink() {
|
||||
UIPasteboard.general.string = simplexChatLink(connReqInvitation)
|
||||
}
|
||||
}
|
||||
|
||||
struct ConnectView: View {
|
||||
@Environment(\.dismiss) var dismiss: DismissAction
|
||||
@State private var connectionLink: String = ""
|
||||
@State private var alert: PlanAndConnectAlert?
|
||||
@State private var sheet: PlanAndConnectActionSheet?
|
||||
@State private var showScanQRCodeSheet = false
|
||||
@State private var scannedLink: String = ""
|
||||
|
||||
var body: some View {
|
||||
ScrollView {
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
(
|
||||
Text("Paste the URL your received from your contact.")
|
||||
+ Text("\n\n")
|
||||
+ Text("You'll be connected to begin a private conversation with them.")
|
||||
)
|
||||
.font(.footnote)
|
||||
.foregroundColor(.secondary)
|
||||
.padding(.horizontal)
|
||||
|
||||
HStack {
|
||||
Text("Unique invite link")
|
||||
.textCase(.uppercase)
|
||||
.font(.footnote)
|
||||
.foregroundColor(.secondary)
|
||||
Spacer()
|
||||
if (connectionLink != "") {
|
||||
Button {
|
||||
clearLink()
|
||||
} label: {
|
||||
Text("Clear")
|
||||
.font(.footnote)
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding(.horizontal)
|
||||
.padding(.top)
|
||||
|
||||
pasteLinkView()
|
||||
|
||||
Text("Or scan QR code")
|
||||
.textCase(.uppercase)
|
||||
.font(.footnote)
|
||||
.foregroundColor(.secondary)
|
||||
.padding(.horizontal)
|
||||
.padding(.top, 8)
|
||||
|
||||
VStack(alignment: .center) {
|
||||
scanQRCodeButton()
|
||||
}
|
||||
.padding(.horizontal)
|
||||
.padding(.vertical, 8)
|
||||
.frame(maxWidth: .infinity, alignment: .center)
|
||||
.background(
|
||||
RoundedRectangle(cornerRadius: 12, style: .continuous)
|
||||
.fill(Color(uiColor: .systemBackground))
|
||||
)
|
||||
|
||||
VStack(alignment: .center) {
|
||||
oneTimeLinkLearnMoreButton2()
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .center)
|
||||
.padding(.top)
|
||||
}
|
||||
}
|
||||
.padding(.vertical)
|
||||
.alert(item: $alert) { a in planAndConnectAlert(a, dismiss: true) }
|
||||
.actionSheet(item: $sheet) { s in planAndConnectActionSheet(s, dismiss: true) }
|
||||
.sheet(isPresented: $showScanQRCodeSheet) {
|
||||
if #available(iOS 16.0, *) {
|
||||
ScanConnectionCodeView(scannedLink: $scannedLink)
|
||||
.presentationDetents([.fraction(0.8)])
|
||||
} else {
|
||||
ScanConnectionCodeView(scannedLink: $scannedLink)
|
||||
}
|
||||
}
|
||||
.onChange(of: scannedLink) { link in
|
||||
connect(link)
|
||||
}
|
||||
}
|
||||
|
||||
private func clearLink() {
|
||||
connectionLink = ""
|
||||
}
|
||||
|
||||
@ViewBuilder private func pasteLinkView() -> some View {
|
||||
if connectionLink == "" {
|
||||
VStack(alignment: .center) {
|
||||
ZStack {
|
||||
Text("\n")
|
||||
.font(.callout)
|
||||
.padding(.horizontal)
|
||||
.padding(.vertical, 8)
|
||||
.opacity(0)
|
||||
Button {
|
||||
if let link = UIPasteboard.general.string {
|
||||
// TODO test pasted text is a link, alert if not
|
||||
connectionLink = link.trimmingCharacters(in: .whitespaces)
|
||||
connect(connectionLink)
|
||||
}
|
||||
} label: {
|
||||
Text("Click Here to Paste Link")
|
||||
.foregroundColor(.accentColor)
|
||||
.padding(.horizontal)
|
||||
.padding(.vertical, 8)
|
||||
}
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .center)
|
||||
.background(
|
||||
RoundedRectangle(cornerRadius: 12, style: .continuous)
|
||||
.fill(Color(uiColor: .systemBackground))
|
||||
)
|
||||
} else {
|
||||
VStack() {
|
||||
ZStack {
|
||||
Text("\n")
|
||||
.font(.callout)
|
||||
.padding(.horizontal)
|
||||
.padding(.vertical, 8)
|
||||
.opacity(0)
|
||||
Text(connectionLink)
|
||||
.lineLimit(2)
|
||||
.font(.callout)
|
||||
.padding(.horizontal)
|
||||
.padding(.vertical, 8)
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.background(
|
||||
RoundedRectangle(cornerRadius: 12, style: .continuous)
|
||||
.fill(Color(uiColor: .systemBackground))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private func connect(_ link: String) {
|
||||
planAndConnect(
|
||||
link,
|
||||
showAlert: { alert = $0 },
|
||||
showActionSheet: { sheet = $0 },
|
||||
dismiss: true,
|
||||
incognito: nil
|
||||
)
|
||||
}
|
||||
|
||||
private func scanQRCodeButton() -> some View {
|
||||
Button {
|
||||
showScanQRCodeSheet = true
|
||||
} label: {
|
||||
settingsRow("qrcode") {
|
||||
Text("Scan code")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ScanConnectionCodeView: View {
|
||||
@Environment(\.dismiss) var dismiss: DismissAction
|
||||
@Binding var scannedLink: String
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading) {
|
||||
Text("Scan QR code")
|
||||
.font(.largeTitle)
|
||||
.bold()
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.padding(.vertical)
|
||||
|
||||
CodeScannerView(codeTypes: [.qr], completion: processQRCode)
|
||||
.aspectRatio(1, contentMode: .fit)
|
||||
.cornerRadius(12)
|
||||
.padding(.top)
|
||||
|
||||
Text("If you cannot meet in person, you can **scan QR code in the video call**, or your contact can share an invitation link.")
|
||||
.padding(.top)
|
||||
}
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
|
||||
.padding()
|
||||
}
|
||||
|
||||
private func processQRCode(_ resp: Result<ScanResult, ScanError>) {
|
||||
switch resp {
|
||||
case let .success(r):
|
||||
scannedLink = r.string
|
||||
dismiss()
|
||||
case let .failure(e):
|
||||
logger.error("ConnectContactView.processQRCode QR code error: \(e.localizedDescription)")
|
||||
// TODO alert
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO move IncognitoToggle here
|
||||
|
||||
// TODO move shareLinkButton here
|
||||
func shareLinkButton2(_ connReqInvitation: String) -> some View {
|
||||
Button {
|
||||
showShareSheet(items: [simplexChatLink(connReqInvitation)])
|
||||
} label: {
|
||||
settingsRow("square.and.arrow.up") {
|
||||
Text("Share link")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO move oneTimeLinkLearnMoreButton here
|
||||
func oneTimeLinkLearnMoreButton2() -> some View {
|
||||
NavigationLink {
|
||||
AddContactLearnMore()
|
||||
.navigationTitle("One-time invitation link")
|
||||
.navigationBarTitleDisplayMode(.large)
|
||||
} label: {
|
||||
settingsRow("info.circle") {
|
||||
Text("Need Guidance?")
|
||||
.underline()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO move planAndConnect here
|
||||
|
||||
//#Preview {
|
||||
// NewChatView()
|
||||
//}
|
||||
@@ -178,6 +178,8 @@
|
||||
649BCDA22805D6EF00C3A862 /* CIImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 649BCDA12805D6EF00C3A862 /* CIImageView.swift */; };
|
||||
64AA1C6927EE10C800AC7277 /* ContextItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64AA1C6827EE10C800AC7277 /* ContextItemView.swift */; };
|
||||
64AA1C6C27F3537400AC7277 /* DeletedItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64AA1C6B27F3537400AC7277 /* DeletedItemView.swift */; };
|
||||
64AEA4ED2B15D2A400334292 /* NewChatView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64AEA4EC2B15D2A400334292 /* NewChatView.swift */; };
|
||||
64AEA4EF2B15FEE100334292 /* NewChatButton2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64AEA4EE2B15FEE100334292 /* NewChatButton2.swift */; };
|
||||
64C06EB52A0A4A7C00792D4D /* ChatItemInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64C06EB42A0A4A7C00792D4D /* ChatItemInfoView.swift */; };
|
||||
64C3B0212A0D359700E19930 /* CustomTimePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64C3B0202A0D359700E19930 /* CustomTimePicker.swift */; };
|
||||
64D0C2C029F9688300B38D5F /* UserAddressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64D0C2BF29F9688300B38D5F /* UserAddressView.swift */; };
|
||||
@@ -462,6 +464,8 @@
|
||||
649BCDA12805D6EF00C3A862 /* CIImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIImageView.swift; sourceTree = "<group>"; };
|
||||
64AA1C6827EE10C800AC7277 /* ContextItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContextItemView.swift; sourceTree = "<group>"; };
|
||||
64AA1C6B27F3537400AC7277 /* DeletedItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeletedItemView.swift; sourceTree = "<group>"; };
|
||||
64AEA4EC2B15D2A400334292 /* NewChatView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewChatView.swift; sourceTree = "<group>"; };
|
||||
64AEA4EE2B15FEE100334292 /* NewChatButton2.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewChatButton2.swift; sourceTree = "<group>"; };
|
||||
64C06EB42A0A4A7C00792D4D /* ChatItemInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatItemInfoView.swift; sourceTree = "<group>"; };
|
||||
64C3B0202A0D359700E19930 /* CustomTimePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTimePicker.swift; sourceTree = "<group>"; };
|
||||
64D0C2BF29F9688300B38D5F /* UserAddressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserAddressView.swift; sourceTree = "<group>"; };
|
||||
@@ -736,6 +740,8 @@
|
||||
5CB2085028DB64CA00D024EC /* CreateLinkView.swift */,
|
||||
5CB2085228DB7CAF00D024EC /* ConnectViaLinkView.swift */,
|
||||
64D0C2C529FAC1EC00B38D5F /* AddContactLearnMore.swift */,
|
||||
64AEA4EC2B15D2A400334292 /* NewChatView.swift */,
|
||||
64AEA4EE2B15FEE100334292 /* NewChatButton2.swift */,
|
||||
);
|
||||
path = NewChat;
|
||||
sourceTree = "<group>";
|
||||
@@ -1115,12 +1121,14 @@
|
||||
5C13730B28156D2700F43030 /* ContactConnectionView.swift in Sources */,
|
||||
644EFFE0292CFD7F00525D5B /* CIVoiceView.swift in Sources */,
|
||||
6432857C2925443C00FBE5C8 /* GroupPreferencesView.swift in Sources */,
|
||||
64AEA4EF2B15FEE100334292 /* NewChatButton2.swift in Sources */,
|
||||
5C93293129239BED0090FFF9 /* ProtocolServerView.swift in Sources */,
|
||||
5C9CC7AD28C55D7800BEF955 /* DatabaseEncryptionView.swift in Sources */,
|
||||
5CBD285A295711D700EC2CF4 /* ImageUtils.swift in Sources */,
|
||||
6419EC562AB8BC8B004A607A /* ContextInvitingContactMemberView.swift in Sources */,
|
||||
5CE4407927ADB701007B033A /* EmojiItemView.swift in Sources */,
|
||||
5C3F1D562842B68D00EC8A82 /* IntegrityErrorItemView.swift in Sources */,
|
||||
64AEA4ED2B15D2A400334292 /* NewChatView.swift in Sources */,
|
||||
5C029EAA283942EA004A9677 /* CallController.swift in Sources */,
|
||||
5CBE6C142944CC12002D9531 /* ScanCodeView.swift in Sources */,
|
||||
5CC036E029C488D500C0EF20 /* HiddenProfileView.swift in Sources */,
|
||||
|
||||
Reference in New Issue
Block a user