From 3ccf5995f2560333bee15d2b6a06054126ec366d Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Mon, 31 Jul 2023 11:28:12 +1000 Subject: [PATCH] add full screen button on message info screen --- .../MessageInfoView.swift | 547 +++++++++--------- .../SessionCarouselView+SwiftUI.swift | 1 - 2 files changed, 288 insertions(+), 260 deletions(-) diff --git a/Session/Media Viewing & Editing/MessageInfoView.swift b/Session/Media Viewing & Editing/MessageInfoView.swift index cf9c15e26..9776c44b9 100644 --- a/Session/Media Viewing & Editing/MessageInfoView.swift +++ b/Session/Media Viewing & Editing/MessageInfoView.swift @@ -13,93 +13,189 @@ struct MessageInfoView: View { } var body: some View { - ZStack (alignment: .topLeading) { - if #available(iOS 14.0, *) { - Color.black.ignoresSafeArea() - } else { - Color.black - } - - ScrollView(.vertical, showsIndicators: false) { - VStack( - alignment: .leading, - spacing: 10 - ) { - // Message bubble snapshot - if let body: String = messageViewModel.body { - let (bubbleBackgroundColor, bubbleTextColor): (ThemeValue, ThemeValue) = ( - messageViewModel.variant == .standardIncoming || - messageViewModel.variant == .standardIncomingDeleted - ) ? - (.messageBubble_incomingBackground, .messageBubble_incomingText) : - (.messageBubble_outgoingBackground, .messageBubble_outgoingText) - - ZStack { - RoundedRectangle(cornerRadius: 18) - .fill(themeColor: bubbleBackgroundColor) + NavigationView { + ZStack (alignment: .topLeading) { + if #available(iOS 14.0, *) { + Color.black.ignoresSafeArea() + } else { + Color.black + } + + ScrollView(.vertical, showsIndicators: false) { + VStack( + alignment: .leading, + spacing: 10 + ) { + // Message bubble snapshot + if let body: String = messageViewModel.body { + let (bubbleBackgroundColor, bubbleTextColor): (ThemeValue, ThemeValue) = ( + messageViewModel.variant == .standardIncoming || + messageViewModel.variant == .standardIncomingDeleted + ) ? + (.messageBubble_incomingBackground, .messageBubble_incomingText) : + (.messageBubble_outgoingBackground, .messageBubble_outgoingText) - Text(body) - .foregroundColor(themeColor: bubbleTextColor) - .padding( - EdgeInsets( - top: 8, - leading: 16, - bottom: 8, - trailing: 16 + ZStack { + RoundedRectangle(cornerRadius: 18) + .fill(themeColor: bubbleBackgroundColor) + + Text(body) + .foregroundColor(themeColor: bubbleTextColor) + .padding( + EdgeInsets( + top: 8, + leading: 16, + bottom: 8, + trailing: 16 + ) ) + } + .frame( + maxWidth: .infinity, + maxHeight: .infinity, + alignment: .topLeading + ) + .fixedSize(horizontal: true, vertical: true) + .padding( + EdgeInsets( + top: 8, + leading: 30, + bottom: 4, + trailing: 30 ) - } - .frame( - maxWidth: .infinity, - maxHeight: .infinity, - alignment: .topLeading - ) - .fixedSize(horizontal: true, vertical: true) - .padding( - EdgeInsets( - top: 8, - leading: 30, - bottom: 4, - trailing: 30 ) - ) - } - - if isMessageFailed { - let (image, statusText, tintColor) = messageViewModel.state.statusIconInfo( - variant: messageViewModel.variant, - hasAtLeastOneReadReceipt: messageViewModel.hasAtLeastOneReadReceipt - ) + } - HStack(spacing: 6) { - if let image: UIImage = image?.withRenderingMode(.alwaysTemplate) { - Image(uiImage: image) - .resizable() - .scaledToFit() - .foregroundColor(themeColor: tintColor) - .frame(width: 13, height: 12) - } + if isMessageFailed { + let (image, statusText, tintColor) = messageViewModel.state.statusIconInfo( + variant: messageViewModel.variant, + hasAtLeastOneReadReceipt: messageViewModel.hasAtLeastOneReadReceipt + ) - if let statusText: String = statusText { - Text(statusText) - .font(.system(size: 11)) - .foregroundColor(themeColor: tintColor) + HStack(spacing: 6) { + if let image: UIImage = image?.withRenderingMode(.alwaysTemplate) { + Image(uiImage: image) + .resizable() + .scaledToFit() + .foregroundColor(themeColor: tintColor) + .frame(width: 13, height: 12) + } + + if let statusText: String = statusText { + Text(statusText) + .font(.system(size: 11)) + .foregroundColor(themeColor: tintColor) + } } + .padding( + EdgeInsets( + top: -8, + leading: 30, + bottom: 4, + trailing: 30 + ) + ) } - .padding( - EdgeInsets( - top: -8, - leading: 30, - bottom: 4, - trailing: 30 + + if let attachments = messageViewModel.attachments { + ZStack(alignment: .bottomTrailing) { + if attachments.count > 1 { + // Attachment carousel view + SessionCarouselView_SwiftUI(index: $index, contentInfos: [.orange, .gray, .blue, .yellow]) + .frame( + maxWidth: .infinity, + maxHeight: .infinity, + alignment: .topLeading + ) + } else { + // TODO: one attachment + } + + Button { + // TODO: full screen function + } label: { + ZStack { + Circle() + .foregroundColor(.init(white: 0, opacity: 0.4)) + Image(systemName: "arrow.up.left.and.arrow.down.right") + .font(.system(size: 13)) + .foregroundColor(.white) + } + .frame(width: 26, height: 26) + } + .padding( + EdgeInsets( + top: 0, + leading: 0, + bottom: 8, + trailing: 38 + ) + ) + } + .padding( + EdgeInsets( + top: 4, + leading: 0, + bottom: 4, + trailing: 0 + ) ) - ) - } - - if let attachments = messageViewModel.attachments { - if attachments.count > 1 { - // Attachment carousel view - SessionCarouselView_SwiftUI(index: $index, contentInfos: [.orange, .gray, .blue, .yellow]) + + // Attachment Info + ZStack { + RoundedRectangle(cornerRadius: 17) + .fill(Color(red: 27.0/255, green: 27.0/255, blue: 27.0/255)) + + VStack( + alignment: .leading, + spacing: 16 + ) { + InfoBlock(title: "ATTACHMENT_INFO_FILE_ID".localized() + ":") { + Text("12378965485235985214") + .font(.system(size: 16)) + .foregroundColor(themeColor: .textPrimary) + } + + HStack( + alignment: .center + ) { + InfoBlock(title: "ATTACHMENT_INFO_FILE_TYPE".localized() + ":") { + Text(".PNG") + .font(.system(size: 16)) + .foregroundColor(themeColor: .textPrimary) + } + + Spacer() + + InfoBlock(title: "ATTACHMENT_INFO_FILE_SIZE".localized() + ":") { + Text("6mb") + .font(.system(size: 16)) + .foregroundColor(themeColor: .textPrimary) + } + + Spacer() + } + + HStack( + alignment: .center + ) { + InfoBlock(title: "ATTACHMENT_INFO_RESOLUTION".localized() + ":") { + Text("550×550") + .font(.system(size: 16)) + .foregroundColor(themeColor: .textPrimary) + } + + Spacer() + + InfoBlock(title: "ATTACHMENT_INFO_DURATION".localized() + ":") { + Text("N/A") + .font(.system(size: 16)) + .foregroundColor(themeColor: .textPrimary) + } + + Spacer() + } + } .frame( maxWidth: .infinity, maxHeight: .infinity, @@ -107,69 +203,84 @@ struct MessageInfoView: View { ) .padding( EdgeInsets( - top: 4, - leading: 0, - bottom: 4, - trailing: 0 + top: 24, + leading: 24, + bottom: 24, + trailing: 24 ) ) - } else { - // TODO: one attachment + } + .frame(maxHeight: .infinity) + .fixedSize(horizontal: false, vertical: true) + .padding( + EdgeInsets( + top: 4, + leading: 30, + bottom: 4, + trailing: 30 + ) + ) } - - // Attachment Info + + // Message Info ZStack { RoundedRectangle(cornerRadius: 17) - .fill(Color(red: 27.0/255, green: 27.0/255, blue: 27.0/255)) + .fill(themeColor: .backgroundSecondary) VStack( alignment: .leading, spacing: 16 ) { - InfoBlock(title: "ATTACHMENT_INFO_FILE_ID".localized() + ":") { - Text("12378965485235985214") + InfoBlock(title: "MESSAGE_INFO_SENT".localized() + ":") { + Text(messageViewModel.dateForUI.fromattedForMessageInfo) .font(.system(size: 16)) .foregroundColor(themeColor: .textPrimary) } - HStack( - alignment: .center - ) { - InfoBlock(title: "ATTACHMENT_INFO_FILE_TYPE".localized() + ":") { - Text(".PNG") - .font(.system(size: 16)) - .foregroundColor(themeColor: .textPrimary) - } - - Spacer() - - InfoBlock(title: "ATTACHMENT_INFO_FILE_SIZE".localized() + ":") { - Text("6mb") - .font(.system(size: 16)) - .foregroundColor(themeColor: .textPrimary) - } - - Spacer() + InfoBlock(title: "MESSAGE_INFO_RECEIVED".localized() + ":") { + Text(messageViewModel.receivedDateForUI.fromattedForMessageInfo) + .font(.system(size: 16)) + .foregroundColor(themeColor: .textPrimary) } - - HStack( - alignment: .center - ) { - InfoBlock(title: "ATTACHMENT_INFO_RESOLUTION".localized() + ":") { - Text("550×550") + + if isMessageFailed { + let failureText: String = messageViewModel.mostRecentFailureText ?? "Message failed to send" + InfoBlock(title: "ALERT_ERROR_TITLE".localized() + ":") { + Text(failureText) .font(.system(size: 16)) - .foregroundColor(themeColor: .textPrimary) + .foregroundColor(themeColor: .danger) } - - Spacer() - - InfoBlock(title: "ATTACHMENT_INFO_DURATION".localized() + ":") { - Text("N/A") - .font(.system(size: 16)) - .foregroundColor(themeColor: .textPrimary) + } + + InfoBlock(title: "MESSAGE_INFO_FROM".localized() + ":") { + HStack( + spacing: 10 + ) { + Circle() + .frame( + width: 46, + height: 46, + alignment: .topLeading + ) + .foregroundColor(themeColor: .primary) + // ProfilePictureSwiftUI(size: .message) + + + VStack( + alignment: .leading, + spacing: 4 + ) { + if !messageViewModel.authorName.isEmpty { + Text(messageViewModel.authorName) + .bold() + .font(.system(size: 18)) + .foregroundColor(themeColor: .textPrimary) + } + Text(messageViewModel.authorId) + .font(.spaceMono(size: 16)) + .foregroundColor(themeColor: .textPrimary) + } } - - Spacer() } } .frame( @@ -196,158 +307,76 @@ struct MessageInfoView: View { trailing: 30 ) ) - } - // Message Info - ZStack { - RoundedRectangle(cornerRadius: 17) - .fill(themeColor: .backgroundSecondary) - - VStack( - alignment: .leading, - spacing: 16 - ) { - InfoBlock(title: "MESSAGE_INFO_SENT".localized() + ":") { - Text(messageViewModel.dateForUI.fromattedForMessageInfo) - .font(.system(size: 16)) - .foregroundColor(themeColor: .textPrimary) - } - - InfoBlock(title: "MESSAGE_INFO_RECEIVED".localized() + ":") { - Text(messageViewModel.receivedDateForUI.fromattedForMessageInfo) - .font(.system(size: 16)) - .foregroundColor(themeColor: .textPrimary) - } - - if isMessageFailed { - let failureText: String = messageViewModel.mostRecentFailureText ?? "Message failed to send" - InfoBlock(title: "ALERT_ERROR_TITLE".localized() + ":") { - Text(failureText) - .font(.system(size: 16)) - .foregroundColor(themeColor: .danger) - } - } - - InfoBlock(title: "MESSAGE_INFO_FROM".localized() + ":") { - HStack( - spacing: 10 + // Actions + if !actions.isEmpty { + ZStack { + RoundedRectangle(cornerRadius: 17) + .fill(themeColor: .backgroundSecondary) + + VStack( + alignment: .leading, + spacing: 0 ) { - Circle() - .frame( - width: 46, - height: 46, - alignment: .topLeading - ) - .foregroundColor(themeColor: .primary) - // ProfilePictureSwiftUI(size: .message) - - - VStack( - alignment: .leading, - spacing: 4 - ) { - if !messageViewModel.authorName.isEmpty { - Text(messageViewModel.authorName) + ForEach( + 0...(actions.count - 1), + id: \.self + ) { index in + let tintColor: ThemeValue = actions[index].isDestructive ? .danger : .textPrimary + HStack(spacing: 24) { + Image(uiImage: actions[index].icon!.withRenderingMode(.alwaysTemplate)) + .resizable() + .scaledToFit() + .foregroundColor(themeColor: tintColor) + .frame(width: 26, height: 26) + Text(actions[index].title) .bold() .font(.system(size: 18)) - .foregroundColor(themeColor: .textPrimary) + .foregroundColor(themeColor: tintColor) + } + .frame(width: .infinity, height: 60) + .onTapGesture { + actions[index].work() + } + + if index < (actions.count - 1) { + Divider() + .foregroundColor(themeColor: .borderSeparator) } - Text(messageViewModel.authorId) - .font(.spaceMono(size: 16)) - .foregroundColor(themeColor: .textPrimary) - } - } - } - } - .frame( - maxWidth: .infinity, - maxHeight: .infinity, - alignment: .topLeading - ) - .padding( - EdgeInsets( - top: 24, - leading: 24, - bottom: 24, - trailing: 24 - ) - ) - } - .frame(maxHeight: .infinity) - .fixedSize(horizontal: false, vertical: true) - .padding( - EdgeInsets( - top: 4, - leading: 30, - bottom: 4, - trailing: 30 - ) - ) - - // Actions - if !actions.isEmpty { - ZStack { - RoundedRectangle(cornerRadius: 17) - .fill(themeColor: .backgroundSecondary) - - VStack( - alignment: .leading, - spacing: 0 - ) { - ForEach( - 0...(actions.count - 1), - id: \.self - ) { index in - let tintColor: ThemeValue = actions[index].isDestructive ? .danger : .textPrimary - HStack(spacing: 24) { - Image(uiImage: actions[index].icon!.withRenderingMode(.alwaysTemplate)) - .resizable() - .scaledToFit() - .foregroundColor(themeColor: tintColor) - .frame(width: 26, height: 26) - Text(actions[index].title) - .bold() - .font(.system(size: 18)) - .foregroundColor(themeColor: tintColor) - } - .frame(width: .infinity, height: 60) - .onTapGesture { - actions[index].work() - } - - if index < (actions.count - 1) { - Divider() - .foregroundColor(themeColor: .borderSeparator) } } + .frame( + maxWidth: .infinity, + maxHeight: .infinity, + alignment: .topLeading + ) + .padding( + EdgeInsets( + top: 0, + leading: 24, + bottom: 0, + trailing: 24 + ) + ) } - .frame( - maxWidth: .infinity, - maxHeight: .infinity, - alignment: .topLeading - ) + .frame(maxHeight: .infinity) + .fixedSize(horizontal: false, vertical: true) .padding( EdgeInsets( - top: 0, - leading: 24, - bottom: 0, - trailing: 24 + top: 4, + leading: 30, + bottom: 4, + trailing: 30 ) ) } - .frame(maxHeight: .infinity) - .fixedSize(horizontal: false, vertical: true) - .padding( - EdgeInsets( - top: 4, - leading: 30, - bottom: 4, - trailing: 30 - ) - ) } } } + .navigationBarTitle( + "Message Info", + displayMode: .inline + ) } } } diff --git a/SessionUIKit/Components/SessionCarouselView+SwiftUI.swift b/SessionUIKit/Components/SessionCarouselView+SwiftUI.swift index 7ac54a699..31ed23f56 100644 --- a/SessionUIKit/Components/SessionCarouselView+SwiftUI.swift +++ b/SessionUIKit/Components/SessionCarouselView+SwiftUI.swift @@ -58,7 +58,6 @@ struct ArrowView: View { var body: some View { let imageName = self.type == .decrement ? "chevron.left" : "chevron.right" Button { - print("Tap") if self.type == .decrement { decrement() } else {