Skip to content

Commit

Permalink
add group settings view
Browse files Browse the repository at this point in the history
  • Loading branch information
nakajima committed Feb 6, 2024
1 parent 7d4316a commit e5118ca
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 14 deletions.
8 changes: 8 additions & 0 deletions XMTPiOSExample/XMTPiOSExample.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
A6606A1A2B5EE80000E2ED4D /* XMTPiOS in Frameworks */ = {isa = PBXBuildFile; productRef = A6606A192B5EE80000E2ED4D /* XMTPiOS */; };
A67CCEC129355B4B00131F5C /* AccountManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A67CCEC029355B4B00131F5C /* AccountManager.swift */; };
A683860C293EA862006336FF /* MessageListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A683860B293EA862006336FF /* MessageListView.swift */; };
A685CC662B72B114008ACECE /* Util.swift in Sources */ = {isa = PBXBuildFile; fileRef = A685CC652B72B114008ACECE /* Util.swift */; };
A685CC682B72B306008ACECE /* GroupSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A685CC672B72B306008ACECE /* GroupSettingsView.swift */; };
A687810729679BC700042FAB /* Account.swift in Sources */ = {isa = PBXBuildFile; fileRef = A687810629679BC700042FAB /* Account.swift */; };
A687810C29679BFC00042FAB /* WalletConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = A687810B29679BFC00042FAB /* WalletConnection.swift */; };
A687810E29679C0D00042FAB /* WalletConnectionMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = A687810D29679C0D00042FAB /* WalletConnectionMethod.swift */; };
Expand Down Expand Up @@ -82,6 +84,8 @@
A65F0703297B5D4E00C3C76E /* Persistence.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Persistence.swift; sourceTree = "<group>"; };
A67CCEC029355B4B00131F5C /* AccountManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountManager.swift; sourceTree = "<group>"; };
A683860B293EA862006336FF /* MessageListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageListView.swift; sourceTree = "<group>"; };
A685CC652B72B114008ACECE /* Util.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Util.swift; sourceTree = "<group>"; };
A685CC672B72B306008ACECE /* GroupSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupSettingsView.swift; sourceTree = "<group>"; };
A687810629679BC700042FAB /* Account.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Account.swift; sourceTree = "<group>"; };
A687810B29679BFC00042FAB /* WalletConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletConnection.swift; sourceTree = "<group>"; };
A687810D29679C0D00042FAB /* WalletConnectionMethod.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletConnectionMethod.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -157,6 +161,7 @@
A6281996292DC826004B9117 /* Assets.xcassets */,
A6281998292DC826004B9117 /* XMTPiOSExample.entitlements */,
A6281999292DC826004B9117 /* Preview Content */,
A685CC652B72B114008ACECE /* Util.swift */,
);
path = XMTPiOSExample;
sourceTree = "<group>";
Expand Down Expand Up @@ -201,6 +206,7 @@
A6557A3229411F4F00CC4C7B /* NewConversationView.swift */,
A6C0F3832AC1E4B5008C6AA7 /* LoginView.swift */,
A68807142B6C53E0004340BD /* GroupDetailView.swift */,
A685CC672B72B306008ACECE /* GroupSettingsView.swift */,
);
path = Views;
sourceTree = "<group>";
Expand Down Expand Up @@ -350,6 +356,8 @@
A687810729679BC700042FAB /* Account.swift in Sources */,
A6557A312941166E00CC4C7B /* MessageCellView.swift in Sources */,
A60FC8C1293AD171001697E3 /* ConversationDetailView.swift in Sources */,
A685CC682B72B306008ACECE /* GroupSettingsView.swift in Sources */,
A685CC662B72B114008ACECE /* Util.swift in Sources */,
A60FC8C3293AD18A001697E3 /* PreviewClientProvider.swift in Sources */,
A6281995292DC825004B9117 /* ContentView.swift in Sources */,
A687810C29679BFC00042FAB /* WalletConnection.swift in Sources */,
Expand Down
20 changes: 20 additions & 0 deletions XMTPiOSExample/XMTPiOSExample/Util.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// Util.swift
// XMTPiOSExample
//
// Created by Pat Nakajima on 2/6/24.
//

import Foundation

enum Util {
static func abbreviate(address: String) -> String {
if address.count > 6 {
let start = address.index(address.startIndex, offsetBy: 6)
let end = address.index(address.endIndex, offsetBy: -5)
return address.replacingCharacters(in: start ... end, with: "...")
} else {
return address
}
}
}
14 changes: 2 additions & 12 deletions XMTPiOSExample/XMTPiOSExample/Views/ConversationListView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ struct ConversationListView: View {
VStack(alignment: .leading) {
switch item {
case .conversation(let conversation):
Text(abbreviate(address: conversation.peerAddress))
Text(Util.abbreviate(address: conversation.peerAddress))
case .group(let group):
Text(group.members.map { abbreviate(address: $0) }.joined(separator: ", "))
Text(group.members.sorted().map { Util.abbreviate(address: $0) }.joined(separator: ", "))
}

Text(item.createdAt.formatted())
Expand Down Expand Up @@ -101,16 +101,6 @@ struct ConversationListView: View {
}
}

func abbreviate(address: String) -> String {
if address.count > 6 {
let start = address.index(address.startIndex, offsetBy: 6)
let end = address.index(address.endIndex, offsetBy: -5)
return address.replacingCharacters(in: start ... end, with: "...")
} else {
return address
}
}

func loadConversations() async {
do {
let conversations = try await client.conversations.list().map {
Expand Down
9 changes: 9 additions & 0 deletions XMTPiOSExample/XMTPiOSExample/Views/GroupDetailView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ struct GroupDetailView: View {
var group: XMTPiOS.Group

@State private var messages: [DecodedMessage] = []
@State private var isShowingSettings = false

var body: some View {
VStack {
Expand All @@ -34,6 +35,14 @@ struct GroupDetailView: View {
}
.navigationTitle("Group Chat")
.navigationBarTitleDisplayMode(.inline)
.toolbar {
Button(action: { isShowingSettings.toggle() }) {
Label("Settings", systemImage: "gearshape")
}
.sheet(isPresented: $isShowingSettings) {
GroupSettingsView(client: client, group: group)
}
}
}

func loadMessages() async {
Expand Down
122 changes: 122 additions & 0 deletions XMTPiOSExample/XMTPiOSExample/Views/GroupSettingsView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
//
// GroupSettingsView.swift
// XMTPiOSExample
//
// Created by Pat Nakajima on 2/6/24.
//

import SwiftUI
import XMTPiOS

struct GroupSettingsView: View {
var client: XMTPiOS.Client
var group: XMTPiOS.Group

@Environment(\.dismiss) var dismiss
@EnvironmentObject var coordinator: EnvironmentCoordinator

@State private var groupMembers: [String] = []
@State private var newGroupMember = ""
@State private var isAddingMember = false
@State private var groupError = ""

init(client: Client, group: XMTPiOS.Group) {
self.client = client
self.group = group
}

var body: some View {
NavigationStack {
List {
Section("Members") {
ForEach(groupMembers, id: \.self) { member in
HStack {
Text(Util.abbreviate(address: member))
Spacer()
if client.address.lowercased() == member.lowercased() {
Text("You")
.foregroundStyle(.secondary)
}
}
.swipeActions {
if client.address.lowercased() == member.lowercased() {
Button("Leave", role: .destructive) {
Task {
try await group.removeMembers(addresses: [client.address])
coordinator.path = NavigationPath()
dismiss()
}
}
} else {
Button("Remove", role: .destructive) {
Task {
try await group.removeMembers(addresses: [member])
await syncGroupMembers()
}
}
}
}
}

HStack {
TextField("Add member", text: $newGroupMember)
Button("Add") {
if newGroupMember.lowercased() == client.address {
self.groupError = "You cannot add yourself to a group"
return
}

isAddingMember = true

Task {
do {
if try await self.client.canMessageV3(address: newGroupMember) {
try await group.addMembers(addresses: [newGroupMember])
try await syncGroupMembers()

await MainActor.run {
self.groupError = ""
self.newGroupMember = ""
self.isAddingMember = false
}
} else {
await MainActor.run {
self.groupError = "Member address not registered"
self.isAddingMember = false
}
}
} catch {
self.groupError = error.localizedDescription
self.isAddingMember = false
}
}
}
.opacity(isAddingMember ? 0 : 1)
.overlay {
if isAddingMember {
ProgressView()
}
}
}
}

if groupError != "" {
Text(groupError)
.foregroundStyle(.red)
.font(.subheadline)
}
}
.navigationTitle("Group Settings")
.task {
await syncGroupMembers()
}
}
}

private func syncGroupMembers() async {
try? await group.sync()
await MainActor.run {
self.groupMembers = group.members
}
}
}
5 changes: 3 additions & 2 deletions XMTPiOSExample/XMTPiOSExample/Views/MessageCellView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -87,18 +87,19 @@ struct MessageGroupMembershipChangedView: View {
Text(label)
.font(.caption)
.foregroundStyle(.secondary)
.padding(.vertical)
}

var label: String {
do {
let changes: GroupMembershipChanges = try message.content()

if !changes.membersAdded.isEmpty {
return "Added \(changes.membersAdded.map(\.accountAddress).joined(separator: ", "))"
return "Added \(changes.membersAdded.map(\.accountAddress).map { Util.abbreviate(address: $0) }.joined(separator: ", "))"
}

if !changes.membersRemoved.isEmpty {
return "Removed \(changes.membersRemoved.map(\.accountAddress).joined(separator: ", "))"
return "Removed \(changes.membersRemoved.map(\.accountAddress).map { Util.abbreviate(address: $0) }.joined(separator: ", "))"
}

return changes.debugDescription
Expand Down
5 changes: 5 additions & 0 deletions XMTPiOSExample/XMTPiOSExample/Views/MessageListView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ struct MessageListView: View {
var body: some View {
ScrollViewReader { proxy in
ScrollView {
if messages.isEmpty {
Text("No messages yet.")
.foregroundStyle(.secondary)
}

VStack {
ForEach(Array(messages.sorted(by: { $0.sent < $1.sent }).enumerated()), id: \.0) { i, message in
MessageCellView(myAddress: myAddress, message: message, isGroup: isGroup)
Expand Down

0 comments on commit e5118ca

Please sign in to comment.