From 7d4d30afe29f2908334b592ffd6cef335eec29ef Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin Date: Wed, 4 Sep 2024 10:36:40 +0100 Subject: [PATCH] ios: different user picker layout --- .../Shared/Views/Call/IncomingCallView.swift | 1 + .../Shared/Views/ChatList/UserPicker.swift | 235 +++++++++++------- .../Views/UserSettings/SettingsView.swift | 27 +- 3 files changed, 167 insertions(+), 96 deletions(-) diff --git a/apps/ios/Shared/Views/Call/IncomingCallView.swift b/apps/ios/Shared/Views/Call/IncomingCallView.swift index 4960281d72..5479a9fada 100644 --- a/apps/ios/Shared/Views/Call/IncomingCallView.swift +++ b/apps/ios/Shared/Views/Call/IncomingCallView.swift @@ -38,6 +38,7 @@ struct IncomingCallView: View { } HStack { ProfilePreview(profileOf: invitation.contact, color: .white) + .padding(.vertical, 6) Spacer() callButton("Reject", "phone.down.fill", .red) { diff --git a/apps/ios/Shared/Views/ChatList/UserPicker.swift b/apps/ios/Shared/Views/ChatList/UserPicker.swift index d32d4acf73..d23729929e 100644 --- a/apps/ios/Shared/Views/ChatList/UserPicker.swift +++ b/apps/ios/Shared/Views/ChatList/UserPicker.swift @@ -16,78 +16,98 @@ struct UserPicker: View { var body: some View { let v = List { - VStack(alignment: .leading, spacing: 6) { - if let currentUser = activeUser ?? m.currentUser { - HStack(alignment: .top) { - ProfileImage(imageStr: currentUser.image, size: 52) - .onTapGesture { - activeSheet = .currentProfile - } - Spacer() - let usersToPreview = m.users.filter({ u in !u.user.hidden && u.user.userId != currentUser.userId }) - ZStack(alignment: .leading) { - ZStack(alignment: .trailing) { - let ps = HStack(spacing: 20) { - Color.clear.frame(width: 48, height: 32) - ForEach(usersToPreview) { u in - userView(u) - } - Color.clear.frame(width: 32, height: 32) - } - - if usersToPreview.count > 3 { - let s = ScrollView(.horizontal) { ps }.frame(width: 284) - if #available(iOS 16.0, *) { - s.scrollIndicators(.hidden) - } else { - s - } - } else { - ps - } - HStack(spacing: 0) { - LinearGradient( - colors: [.clear, theme.colors.background.asGroupedBackground(theme.base.mode)], - startPoint: .leading, - endPoint: .trailing - ) - .frame(width: 32, height: 35) - Button { - activeSheet = .chatProfiles - } label: { - Image(systemName: "ellipsis.circle.fill") - .resizable() - .scaledToFit() - .frame(width: 31, height: 31) - .padding(.top, 4) - .foregroundColor(Color(uiColor: .quaternaryLabel)) - .modifier(ThemedBackground(grouped: true)) - } - } - } - .padding(.top, 10) - - LinearGradient( - colors: [.clear, theme.colors.background.asGroupedBackground(theme.base.mode)], - startPoint: .trailing, - endPoint: .leading - ) - .frame(width: 32, height: 35) - } - } - - Text(currentUser.displayName) - .fontWeight(.bold) - .font(.headline) - } - } - .listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0)) - .listRowBackground(Color.clear) - .listRowSeparator(.hidden) - .padding(.horizontal, 12) +// VStack(alignment: .leading, spacing: 6) { +// if let currentUser = activeUser ?? m.currentUser { +// HStack(alignment: .top) { +// ProfileImage(imageStr: currentUser.image, size: 52) +// .onTapGesture { +// activeSheet = .currentProfile +// } +// Spacer() +// let usersToPreview = m.users.filter({ u in !u.user.hidden && u.user.userId != currentUser.userId }) +// ZStack(alignment: .leading) { +// ZStack(alignment: .trailing) { +// let ps = HStack(spacing: 20) { +// Color.clear.frame(width: 48, height: 32) +// ForEach(usersToPreview) { u in +// userView(u) +// } +// Color.clear.frame(width: 32, height: 32) +// } +// +// if usersToPreview.count > 3 { +// let s = ScrollView(.horizontal) { ps }.frame(width: 284) +// if #available(iOS 16.0, *) { +// s.scrollIndicators(.hidden) +// } else { +// s +// } +// } else { +// ps +// } +// HStack(spacing: 0) { +// LinearGradient( +// colors: [.clear, theme.colors.background.asGroupedBackground(theme.base.mode)], +// startPoint: .leading, +// endPoint: .trailing +// ) +// .frame(width: 32, height: 35) +// Button { +// activeSheet = .chatProfiles +// } label: { +// Image(systemName: "ellipsis.circle.fill") +// .resizable() +// .scaledToFit() +// .frame(width: 31, height: 31) +// .padding(.top, 4) +// .foregroundColor(Color(uiColor: .quaternaryLabel)) +// .modifier(ThemedBackground(grouped: true)) +// } +// } +// } +// .padding(.top, 10) +// +// LinearGradient( +// colors: [.clear, theme.colors.background.asGroupedBackground(theme.base.mode)], +// startPoint: .trailing, +// endPoint: .leading +// ) +// .frame(width: 32, height: 35) +// } +// } +// +// Text(currentUser.displayName) +// .fontWeight(.bold) +// .font(.headline) +// } +// } +// .listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0)) +// .listRowBackground(Color.clear) +// .listRowSeparator(.hidden) +// .padding(.horizontal, 12) Section { - if (m.currentUser != nil) { + let otherUsers = m.users.filter { u in !u.user.hidden && u.user.userId != m.currentUser?.userId } + if otherUsers.isEmpty { + openSheetOnTap(title: "Create chat profile", image: "person.crop.circle.fill.badge.plus") { + activeSheet = .chatProfiles + } + } else { + userPickerRow(otherUsers) + } + } + + + Section { + if let user = m.currentUser { + openSheetOnTap(label: { + ProfilePreview(profileOf: user) + .foregroundColor(.primary) + .padding(.leading, -8) + }) { + activeSheet = .currentProfile + } + openSheetOnTap(title: m.userAddress == nil ? "Create public address" : "Your public address", image: "qrcode") { activeSheet = .address } @@ -95,14 +115,14 @@ struct UserPicker: View { openSheetOnTap(title: "Chat preferences", image: "switch.2") { activeSheet = .chatPreferences } - - openSheetOnTap(title: "Use from desktop", image: "desktopcomputer") { - activeSheet = .useFromDesktop - } } } Section { + openSheetOnTap(title: "Use from desktop", image: "desktopcomputer") { + activeSheet = .useFromDesktop + } + HStack { openSheetOnTap(title: "Settings", image: "gearshape") { activeSheet = .settings @@ -148,20 +168,58 @@ struct UserPicker: View { .modifier(ThemedBackground(grouped: true)) if #available(iOS 16.0, *) { - v.presentationDetents([.height(400)]) + v.presentationDetents([.height(425)]) } else { v } } + + private func userPickerRow(_ users: [UserInfo]) -> some View { + HStack(spacing: 6) { + let s = ScrollView(.horizontal) { + HStack(spacing: 20) { + ForEach(users) { u in + if !u.user.hidden && u.user.userId != m.currentUser?.userId { + userView(u, size: 28) + } + } + } + .padding(.trailing, 14) + } + ZStack(alignment: .topTrailing) { + if #available(iOS 16.0, *) { + s.scrollIndicators(.hidden) + } else { + s + } + LinearGradient( + colors: [.clear, theme.colors.background], + startPoint: .leading, + endPoint: .trailing + ) + .frame(width: 28, height: 31) + .allowsHitTesting(false) + } + .padding(.top, -3) // to fit unread badge + Spacer() + Image(systemName: "chevron.right") + .foregroundColor(theme.colors.secondary) + .onTapGesture { + activeSheet = .chatProfiles + } + } + .padding(.leading, -4) + } - private func userView(_ u: UserInfo) -> some View { + private func userView(_ u: UserInfo, size: CGFloat) -> some View { ZStack(alignment: .topTrailing) { - ProfileImage(imageStr: u.user.image, size: 32, color: Color(uiColor: .quaternaryLabel)) + ProfileImage(imageStr: u.user.image, size: size, color: Color(uiColor: .quaternaryLabel)) .padding([.top, .trailing], 3) if (u.unreadCount > 0) { - unreadBadge() + unreadBadge(size: 10) } } + .frame(width: size) .onTapGesture { activeUser = m.currentUser @@ -183,27 +241,30 @@ struct UserPicker: View { } } - private func openSheetOnTap(title: LocalizedStringKey, image: String, setActive: @escaping () -> Void) -> some View { - Button(action: setActive) { + private func openSheetOnTap(title: LocalizedStringKey, image: String, action: @escaping () -> Void) -> some View { + openSheetOnTap(label: { Label { Text(title).foregroundColor(.primary) } icon: { Image(systemName: image) .resizable() + .scaledToFit() .symbolRenderingMode(.monochrome) .foregroundColor(theme.colors.secondary) .frame(maxWidth: 20, maxHeight: 20) } - } - .frame(maxWidth: .infinity, alignment: .leading) - .padding(.leading, 16).padding(.vertical, 8).padding(.trailing, 32) - .contentShape(Rectangle()) - .padding(.leading, -19).padding(.vertical, -8).padding(.trailing, -32) + }, action: action) } - private func unreadBadge() -> some View { + private func openSheetOnTap(label: () -> V, action: @escaping () -> Void) -> some View { + Button(action: action, label: label) + .frame(maxWidth: .infinity, alignment: .leading) + .contentShape(Rectangle()) + } + + private func unreadBadge(size: CGFloat) -> some View { Circle() - .frame(width: 12, height: 12) + .frame(width: size, height: size) .foregroundColor(theme.colors.primary) } } diff --git a/apps/ios/Shared/Views/UserSettings/SettingsView.swift b/apps/ios/Shared/Views/UserSettings/SettingsView.swift index b9d4d5ac5b..82c4f20d67 100644 --- a/apps/ios/Shared/Views/UserSettings/SettingsView.swift +++ b/apps/ios/Shared/Views/UserSettings/SettingsView.swift @@ -504,17 +504,26 @@ struct ProfilePreview: View { HStack { ProfileImage(imageStr: profileOf.image, size: 44, color: color) .padding(.trailing, 6) - .padding(.vertical, 6) - VStack(alignment: .leading) { - Text(profileOf.displayName) - .fontWeight(.bold) - .font(.title2) - if profileOf.fullName != "" && profileOf.fullName != profileOf.displayName { - Text(profileOf.fullName) - } - } + profileName().lineLimit(1) +// VStack(alignment: .leading, spacing: 0) { +// var t = Text(profileOf.displayName).fontWeight(.semibold).font(.title3) +// if profileOf.fullName != "" && profileOf.fullName != profileOf.displayName { +// t = t + Text(" (" + profileOf.fullName + ")") +//// .font(.callout) +// } +// t +// } } } + + private func profileName() -> Text { + var t = Text(profileOf.displayName).fontWeight(.semibold).font(.title2) + if profileOf.fullName != "" && profileOf.fullName != profileOf.displayName { + t = t + Text(" (" + profileOf.fullName + ")") +// .font(.callout) + } + return t + } } struct SettingsView_Previews: PreviewProvider {