ios: create group with profile image (#849)

* ios: create group with profile image

* update libs
This commit is contained in:
Evgeny Poberezkin
2022-07-28 11:49:36 +01:00
committed by GitHub
parent 7b9164f95a
commit ee6f6462cf
7 changed files with 108 additions and 57 deletions

View File

@@ -559,8 +559,8 @@ private func sendCommandOkResp(_ cmd: ChatCommand) async throws {
throw r
}
func apiNewGroup(_ gp: GroupProfile) throws -> GroupInfo {
let r = chatSendCmdSync(.newGroup(groupProfile: gp))
func apiNewGroup(_ p: GroupProfile) throws -> GroupInfo {
let r = chatSendCmdSync(.newGroup(groupProfile: p))
if case let .groupCreated(groupInfo) = r { return groupInfo }
throw r
}

View File

@@ -12,25 +12,50 @@ import SimpleXChat
struct AddGroupView: View {
@Binding var openedSheet: NewChatAction?
@EnvironmentObject var m: ChatModel
@State private var displayName: String = ""
@State private var fullName: String = ""
@State private var profile = GroupProfile(displayName: "", fullName: "")
@FocusState private var focusDisplayName
@FocusState private var focusFullName
@State private var showChooseSource = false
@State private var showImagePicker = false
@State private var showTakePhoto = false
@State private var chosenImage: UIImage? = nil
var body: some View {
VStack(alignment: .leading) {
Text("Create group")
Text("Create secret group")
.font(.largeTitle)
.padding(.vertical, 4)
Text("The group is fully decentralized it is visible only to the members.")
.padding(.bottom, 4)
Text("Enter group details")
.padding(.bottom)
ZStack(alignment: .center) {
ZStack(alignment: .topTrailing) {
profileImageView(profile.image)
if profile.image != nil {
Button {
profile.image = nil
} label: {
Image(systemName: "multiply")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 12)
}
}
}
editImageButton { showChooseSource = true }
}
.frame(maxWidth: .infinity, alignment: .center)
.padding(.bottom, 4)
ZStack(alignment: .topLeading) {
if !validDisplayName(displayName) {
if !validDisplayName(profile.displayName) {
Image(systemName: "exclamationmark.circle")
.foregroundColor(.red)
.padding(.top, 4)
}
textField("Display name", text: $displayName)
textField("Group display name", text: $profile.displayName)
.focused($focusDisplayName)
.submitLabel(.next)
.onSubmit {
@@ -38,7 +63,7 @@ struct AddGroupView: View {
else { focusDisplayName = true }
}
}
textField("Full name (optional)", text: $fullName)
textField("Group full name (optional)", text: $profile.fullName)
.focused($focusFullName)
.submitLabel(.go)
.onSubmit {
@@ -58,9 +83,39 @@ struct AddGroupView: View {
.frame(maxWidth: .infinity, alignment: .trailing)
}
.onAppear() {
focusDisplayName = true
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
focusDisplayName = true
}
}
.padding()
.confirmationDialog("Group image", isPresented: $showChooseSource, titleVisibility: .visible) {
Button("Take picture") {
showTakePhoto = true
}
Button("Choose from library") {
showImagePicker = true
}
}
.fullScreenCover(isPresented: $showTakePhoto) {
ZStack {
Color.black.edgesIgnoringSafeArea(.all)
CameraImagePicker(image: $chosenImage)
}
}
.sheet(isPresented: $showImagePicker) {
LibraryImagePicker(image: $chosenImage) {
didSelectItem in showImagePicker = false
}
}
.onChange(of: chosenImage) { image in
if let image = image {
profile.image = resizeImageToStrSize(cropToSquare(image), maxDataSize: 12500)
} else {
profile.image = nil
}
}
.contentShape(Rectangle())
.onTapGesture { hideKeyboard() }
}
func textField(_ placeholder: LocalizedStringKey, text: Binding<String>) -> some View {
@@ -73,12 +128,8 @@ struct AddGroupView: View {
func createGroup() {
hideKeyboard()
let groupProfile = GroupProfile(
displayName: displayName,
fullName: fullName
)
do {
let groupInfo = try apiNewGroup(groupProfile)
let groupInfo = try apiNewGroup(profile)
m.addChat(Chat(chatInfo: .group(groupInfo: groupInfo), chatItems: []))
openedSheet = nil
DispatchQueue.main.async {
@@ -88,7 +139,7 @@ struct AddGroupView: View {
openedSheet = nil
AlertManager.shared.showAlert(
Alert(
title: Text("Failed to create group"),
title: Text("Error creating group"),
message: Text(responseError(error))
)
)
@@ -100,7 +151,7 @@ struct AddGroupView: View {
}
func canCreateProfile() -> Bool {
displayName != "" && validDisplayName(displayName)
profile.displayName != "" && validDisplayName(profile.displayName)
}
}

View File

@@ -34,7 +34,7 @@ struct NewChatButton: View {
Button("Create link / QR code") { addContactAction() }
Button("Paste received link") { actionSheet = .pasteLink }
Button("Scan QR code") { actionSheet = .scanQRCode }
Button("Create group") { actionSheet = .createGroup }
Button("Create secret group") { actionSheet = .createGroup }
}
.sheet(item: $actionSheet) { sheet in
switch sheet {

View File

@@ -113,7 +113,7 @@ struct CreateProfile: View {
}
func validDisplayName(_ name: String) -> Bool {
name.firstIndex(of: " ") == nil
name.firstIndex(of: " ") == nil && name.first != "@" && name.first != "#"
}
struct CreateProfile_Previews: PreviewProvider {

View File

@@ -130,23 +130,6 @@ struct UserProfile: View {
.padding(.bottom)
}
func profileImageView(_ imageStr: String?) -> some View {
ProfileImage(imageStr: imageStr)
.aspectRatio(1, contentMode: .fit)
.frame(maxWidth: 192, maxHeight: 192)
}
func editImageButton(action: @escaping () -> Void) -> some View {
Button {
action()
} label: {
Image(systemName: "camera")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 48)
}
}
func startEditingImage(_ user: User) {
profile = user.profile
editProfile = true
@@ -170,6 +153,23 @@ struct UserProfile: View {
}
}
func profileImageView(_ imageStr: String?) -> some View {
ProfileImage(imageStr: imageStr)
.aspectRatio(1, contentMode: .fit)
.frame(maxWidth: 192, maxHeight: 192)
}
func editImageButton(action: @escaping () -> Void) -> some View {
Button {
action()
} label: {
Image(systemName: "camera")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 48)
}
}
struct UserProfile_Previews: PreviewProvider {
static var previews: some View {
let chatModel1 = ChatModel()

View File

@@ -50,6 +50,11 @@
5C971E1D27AEBEF600C8A3CE /* ChatInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C971E1C27AEBEF600C8A3CE /* ChatInfoView.swift */; };
5C971E2127AEBF8300C8A3CE /* ChatInfoImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C971E2027AEBF8300C8A3CE /* ChatInfoImage.swift */; };
5C9A5BDB2871E05400A5B906 /* SetNotificationsMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C9A5BDA2871E05400A5B906 /* SetNotificationsMode.swift */; };
5C9C2D9F28929B6900CC63B1 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C9C2D9A28929B6900CC63B1 /* libffi.a */; };
5C9C2DA028929B6900CC63B1 /* libHSsimplex-chat-3.1.0-FNUbBjLYHjnDjt6ldpTolw.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C9C2D9B28929B6900CC63B1 /* libHSsimplex-chat-3.1.0-FNUbBjLYHjnDjt6ldpTolw.a */; };
5C9C2DA128929B6900CC63B1 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C9C2D9C28929B6900CC63B1 /* libgmp.a */; };
5C9C2DA228929B6900CC63B1 /* libHSsimplex-chat-3.1.0-FNUbBjLYHjnDjt6ldpTolw-ghc8.10.7.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C9C2D9D28929B6900CC63B1 /* libHSsimplex-chat-3.1.0-FNUbBjLYHjnDjt6ldpTolw-ghc8.10.7.a */; };
5C9C2DA328929B6900CC63B1 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C9C2D9E28929B6900CC63B1 /* libgmpxx.a */; };
5C9D13A3282187BB00AB8B43 /* WebRTC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C9D13A2282187BB00AB8B43 /* WebRTC.swift */; };
5C9FD96E27A5D6ED0075386C /* SendMessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C9FD96D27A5D6ED0075386C /* SendMessageView.swift */; };
5CA059DC279559F40002BEB4 /* Tests_iOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CA059DB279559F40002BEB4 /* Tests_iOS.swift */; };
@@ -57,11 +62,6 @@
5CA059EB279559F40002BEB4 /* SimpleXApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CA059C3279559F40002BEB4 /* SimpleXApp.swift */; };
5CA059ED279559F40002BEB4 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CA059C4279559F40002BEB4 /* ContentView.swift */; };
5CA059EF279559F40002BEB4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5CA059C5279559F40002BEB4 /* Assets.xcassets */; };
5CAB35F828870432009BAA9E /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CAB35F328870432009BAA9E /* libgmpxx.a */; };
5CAB35F928870432009BAA9E /* libHSsimplex-chat-3.0.0-LLJFvekvxJh78JPfTQjcLF-ghc8.10.7.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CAB35F428870432009BAA9E /* libHSsimplex-chat-3.0.0-LLJFvekvxJh78JPfTQjcLF-ghc8.10.7.a */; };
5CAB35FA28870432009BAA9E /* libHSsimplex-chat-3.0.0-LLJFvekvxJh78JPfTQjcLF.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CAB35F528870432009BAA9E /* libHSsimplex-chat-3.0.0-LLJFvekvxJh78JPfTQjcLF.a */; };
5CAB35FB28870432009BAA9E /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CAB35F628870432009BAA9E /* libffi.a */; };
5CAB35FC28870432009BAA9E /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CAB35F728870432009BAA9E /* libgmp.a */; };
5CB0BA882826CB3A00B3292C /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 5CB0BA862826CB3A00B3292C /* InfoPlist.strings */; };
5CB0BA8B2826CB3A00B3292C /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 5CB0BA892826CB3A00B3292C /* Localizable.strings */; };
5CB0BA8E2827126500B3292C /* OnboardingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB0BA8D2827126500B3292C /* OnboardingView.swift */; };
@@ -229,6 +229,11 @@
5C971E1C27AEBEF600C8A3CE /* ChatInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatInfoView.swift; sourceTree = "<group>"; };
5C971E2027AEBF8300C8A3CE /* ChatInfoImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatInfoImage.swift; sourceTree = "<group>"; };
5C9A5BDA2871E05400A5B906 /* SetNotificationsMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetNotificationsMode.swift; sourceTree = "<group>"; };
5C9C2D9A28929B6900CC63B1 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
5C9C2D9B28929B6900CC63B1 /* libHSsimplex-chat-3.1.0-FNUbBjLYHjnDjt6ldpTolw.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-3.1.0-FNUbBjLYHjnDjt6ldpTolw.a"; sourceTree = "<group>"; };
5C9C2D9C28929B6900CC63B1 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
5C9C2D9D28929B6900CC63B1 /* libHSsimplex-chat-3.1.0-FNUbBjLYHjnDjt6ldpTolw-ghc8.10.7.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-3.1.0-FNUbBjLYHjnDjt6ldpTolw-ghc8.10.7.a"; sourceTree = "<group>"; };
5C9C2D9E28929B6900CC63B1 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
5C9D13A2282187BB00AB8B43 /* WebRTC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebRTC.swift; sourceTree = "<group>"; };
5C9FD96A27A56D4D0075386C /* JSON.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSON.swift; sourceTree = "<group>"; };
5C9FD96D27A5D6ED0075386C /* SendMessageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendMessageView.swift; sourceTree = "<group>"; };
@@ -239,11 +244,6 @@
5CA059D7279559F40002BEB4 /* Tests iOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Tests iOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
5CA059DB279559F40002BEB4 /* Tests_iOS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tests_iOS.swift; sourceTree = "<group>"; };
5CA059DD279559F40002BEB4 /* Tests_iOSLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tests_iOSLaunchTests.swift; sourceTree = "<group>"; };
5CAB35F328870432009BAA9E /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
5CAB35F428870432009BAA9E /* libHSsimplex-chat-3.0.0-LLJFvekvxJh78JPfTQjcLF-ghc8.10.7.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-3.0.0-LLJFvekvxJh78JPfTQjcLF-ghc8.10.7.a"; sourceTree = "<group>"; };
5CAB35F528870432009BAA9E /* libHSsimplex-chat-3.0.0-LLJFvekvxJh78JPfTQjcLF.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-3.0.0-LLJFvekvxJh78JPfTQjcLF.a"; sourceTree = "<group>"; };
5CAB35F628870432009BAA9E /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
5CAB35F728870432009BAA9E /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
5CB0BA872826CB3A00B3292C /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/InfoPlist.strings; sourceTree = "<group>"; };
5CB0BA8A2826CB3A00B3292C /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = "<group>"; };
5CB0BA8D2827126500B3292C /* OnboardingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingView.swift; sourceTree = "<group>"; };
@@ -337,13 +337,13 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
5CAB35F828870432009BAA9E /* libgmpxx.a in Frameworks */,
5CAB35FC28870432009BAA9E /* libgmp.a in Frameworks */,
5CAB35FB28870432009BAA9E /* libffi.a in Frameworks */,
5C9C2DA028929B6900CC63B1 /* libHSsimplex-chat-3.1.0-FNUbBjLYHjnDjt6ldpTolw.a in Frameworks */,
5C9C2DA128929B6900CC63B1 /* libgmp.a in Frameworks */,
5CE2BA93284534B000EC33A6 /* libiconv.tbd in Frameworks */,
5CAB35FA28870432009BAA9E /* libHSsimplex-chat-3.0.0-LLJFvekvxJh78JPfTQjcLF.a in Frameworks */,
5C9C2DA228929B6900CC63B1 /* libHSsimplex-chat-3.1.0-FNUbBjLYHjnDjt6ldpTolw-ghc8.10.7.a in Frameworks */,
5C9C2D9F28929B6900CC63B1 /* libffi.a in Frameworks */,
5CE2BA94284534BB00EC33A6 /* libz.tbd in Frameworks */,
5CAB35F928870432009BAA9E /* libHSsimplex-chat-3.0.0-LLJFvekvxJh78JPfTQjcLF-ghc8.10.7.a in Frameworks */,
5C9C2DA328929B6900CC63B1 /* libgmpxx.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -399,11 +399,11 @@
5C764E5C279C70B7000C6508 /* Libraries */ = {
isa = PBXGroup;
children = (
5CAB35F628870432009BAA9E /* libffi.a */,
5CAB35F728870432009BAA9E /* libgmp.a */,
5CAB35F328870432009BAA9E /* libgmpxx.a */,
5CAB35F428870432009BAA9E /* libHSsimplex-chat-3.0.0-LLJFvekvxJh78JPfTQjcLF-ghc8.10.7.a */,
5CAB35F528870432009BAA9E /* libHSsimplex-chat-3.0.0-LLJFvekvxJh78JPfTQjcLF.a */,
5C9C2D9A28929B6900CC63B1 /* libffi.a */,
5C9C2D9C28929B6900CC63B1 /* libgmp.a */,
5C9C2D9E28929B6900CC63B1 /* libgmpxx.a */,
5C9C2D9D28929B6900CC63B1 /* libHSsimplex-chat-3.1.0-FNUbBjLYHjnDjt6ldpTolw-ghc8.10.7.a */,
5C9C2D9B28929B6900CC63B1 /* libHSsimplex-chat-3.1.0-FNUbBjLYHjnDjt6ldpTolw.a */,
);
path = Libraries;
sourceTree = "<group>";

View File

@@ -95,7 +95,7 @@ public enum ChatCommand {
case let .apiVerifyToken(token, nonce, code): return "/_ntf verify \(token.cmdString) \(nonce) \(code)"
case let .apiDeleteToken(token): return "/_ntf delete \(token.cmdString)"
case let .apiGetNtfMessage(nonce, encNtfInfo): return "/_ntf message \(nonce) \(encNtfInfo)"
case let .newGroup(groupProfile): return "/group \(groupProfile.displayName) \(groupProfile.fullName)"
case let .newGroup(groupProfile): return "/_group \(encodeJSON(groupProfile))"
case let .apiAddMember(groupId, contactId, memberRole): return "/_add #\(groupId) \(contactId) \(memberRole)"
case let .apiJoinGroup(groupId): return "/_join #\(groupId)"
case let .apiRemoveMember(groupId, memberId): return "/_remove #\(groupId) \(memberId)"