From daffe01fbd3998221c412836030887287fc65c93 Mon Sep 17 00:00:00 2001 From: Toomas Vahter Date: Wed, 29 May 2024 08:54:51 +0300 Subject: [PATCH 1/4] Show green indicator only for the winning vote when the poll is closed --- .../MessageList/Polls/PollAttachmentView.swift | 13 ++++++------- .../MessageList/Polls/PollAttachmentViewModel.swift | 8 +++++--- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollAttachmentView.swift b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollAttachmentView.swift index ccc5be19..bc45f0c7 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollAttachmentView.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollAttachmentView.swift @@ -236,9 +236,9 @@ struct PollOptionView: View { } PollVotesIndicatorView( - mostVotes: viewModel.hasMostVotes(for: option), + alternativeStyle: viewModel.poll.isClosed && viewModel.hasMostVotes(for: option), optionVotes: optionVotes ?? 0, - maxVotes: maxVotes + maxVotes: maxVotes ?? 0 ) .padding(.leading, 24) } @@ -249,9 +249,9 @@ struct PollVotesIndicatorView: View { @Injected(\.colors) var colors - let mostVotes: Bool + let alternativeStyle: Bool var optionVotes: Int - var maxVotes: Int? + var maxVotes: Int private let height: CGFloat = 4 @@ -263,7 +263,7 @@ struct PollVotesIndicatorView: View { .frame(width: reader.size.width, height: height) RoundedRectangle(cornerRadius: 8) - .fill(mostVotes ? Color(colors.alternativeActiveTint) : colors.tintColor) + .fill(alternativeStyle ? Color(colors.alternativeActiveTint) : colors.tintColor) .frame(width: reader.size.width * ratio, height: height) } } @@ -271,7 +271,6 @@ struct PollVotesIndicatorView: View { } var ratio: CGFloat { - let maxVotes = max(maxVotes ?? 1, 1) - return CGFloat(optionVotes) / CGFloat(maxVotes) + CGFloat(optionVotes) / CGFloat(max(maxVotes, 1)) } } diff --git a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollAttachmentViewModel.swift b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollAttachmentViewModel.swift index d621ad32..f4fb7c4f 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollAttachmentViewModel.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollAttachmentViewModel.swift @@ -55,7 +55,7 @@ public class PollAttachmentViewModel: ObservableObject, PollControllerDelegate { init(message: ChatMessage, poll: Poll, pollController: PollController) { self.message = message self.poll = poll - self.createdByCurrentUser = poll.createdBy?.id == InjectedValues[\.chatClient].currentUserId + createdByCurrentUser = poll.createdBy?.id == InjectedValues[\.chatClient].currentUserId self.pollController = pollController pollController.delegate = self pollController.synchronize { [weak self] _ in @@ -106,7 +106,7 @@ public class PollAttachmentViewModel: ObservableObject, PollControllerDelegate { } public func optionVotedByCurrentUser(_ option: PollOption) -> Bool { - return currentUserVote(for: option) != nil + currentUserVote(for: option) != nil } public func suggest(option: String) { @@ -118,6 +118,8 @@ public class PollAttachmentViewModel: ObservableObject, PollControllerDelegate { } /// Returns true if the specified option has more votes than any other option. + /// + /// - Note: When multiple options have the highest vote count, this function returns false. public func hasMostVotes(for option: PollOption) -> Bool { guard let allCounts = poll.voteCountsByOption else { return false } guard let optionVoteCount = allCounts[option.id], optionVoteCount > 0 else { return false } @@ -128,7 +130,7 @@ public class PollAttachmentViewModel: ObservableObject, PollControllerDelegate { return optionsByVoteCounts[optionVoteCount]?.count == 1 } - //MARK: - PollControllerDelegate + // MARK: - PollControllerDelegate public func pollController(_ pollController: PollController, didUpdatePoll poll: EntityChange) { self.poll = poll.item From 4a3928d6a2928e6c572b9948562a89494a29e075 Mon Sep 17 00:00:00 2001 From: Toomas Vahter Date: Wed, 29 May 2024 09:59:12 +0300 Subject: [PATCH 2/4] Align the checkmark to the top when there is multiple lines of text --- .../ChatChannel/MessageList/Polls/PollAttachmentView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollAttachmentView.swift b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollAttachmentView.swift index bc45f0c7..1df4fea2 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollAttachmentView.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollAttachmentView.swift @@ -201,7 +201,7 @@ struct PollOptionView: View { var body: some View { VStack(spacing: 4) { - HStack { + HStack(alignment: .top) { if !viewModel.poll.isClosed { Button { if viewModel.optionVotedByCurrentUser(option) { From a9817efdd557a1f3d1e93be69f0a363bbede202f Mon Sep 17 00:00:00 2001 From: Toomas Vahter Date: Wed, 29 May 2024 10:02:24 +0300 Subject: [PATCH 3/4] Reduce spacing between the title and subtitle --- .../ChatChannel/MessageList/Polls/PollAttachmentView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollAttachmentView.swift b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollAttachmentView.swift index 1df4fea2..b16375bf 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollAttachmentView.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollAttachmentView.swift @@ -36,7 +36,7 @@ public struct PollAttachmentView: View { public var body: some View { VStack(spacing: 16) { - VStack(alignment: .leading, spacing: 8) { + VStack(alignment: .leading, spacing: 2) { HStack { Text(poll.name) .font(fonts.bodyBold) From ff9a9e6452d9b5f4d2e94d7a9a97bc5d034b6180 Mon Sep 17 00:00:00 2001 From: Toomas Vahter Date: Wed, 29 May 2024 10:49:55 +0300 Subject: [PATCH 4/4] Use correct capitalization and strings for alerts and add plural support for view comments button --- .../Polls/PollAttachmentView.swift | 64 ++++++------------- .../MessageList/Polls/PollCommentsView.swift | 17 ++--- .../MessageList/Polls/PollResultsView.swift | 2 +- .../StreamChatSwiftUI/Generated/L10n.swift | 48 ++++++++------ .../Resources/en.lproj/Localizable.strings | 17 ++--- .../en.lproj/Localizable.stringsdict | 16 +++++ .../Utils/SwiftUI+UIAlertController.swift | 4 +- 7 files changed, 82 insertions(+), 86 deletions(-) diff --git a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollAttachmentView.swift b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollAttachmentView.swift index b16375bf..75e588a3 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollAttachmentView.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollAttachmentView.swift @@ -64,7 +64,7 @@ public struct PollAttachmentView: View { Button { viewModel.allOptionsShown = true } label: { - Text(L10n.Message.Polls.seeMoreOptions(options.count - 10)) + Text(L10n.Message.Polls.Button.seeMoreOptions(options.count - 10)) } .fullScreenCover(isPresented: $viewModel.allOptionsShown) { PollAllOptionsView(viewModel: viewModel) @@ -75,17 +75,15 @@ public struct PollAttachmentView: View { Button { viewModel.suggestOptionShown = true } label: { - Text(L10n.Message.Polls.suggestAnOption) + Text(L10n.Message.Polls.Button.suggestAnOption) } - .modifier( - SuggestOptionModifier( - title: L10n.Message.Polls.suggestAnOption, - showingAlert: $viewModel.suggestOptionShown, - text: $viewModel.suggestOptionText, - submit: { - viewModel.suggest(option: viewModel.suggestOptionText) - } - ) + .uiAlert( + title: L10n.Alert.Title.suggestAnOption, + isPresented: $viewModel.suggestOptionShown, + text: $viewModel.suggestOptionText, + placeholder: L10n.Alert.TextField.pollsNewOption, + accept: L10n.Alert.Actions.send, + action: { viewModel.suggest(option: viewModel.suggestOptionText) } ) } @@ -93,17 +91,14 @@ public struct PollAttachmentView: View { Button { viewModel.addCommentShown = true } label: { - Text(L10n.Message.Polls.addComment) + Text(L10n.Message.Polls.Button.addComment) } - .modifier( - SuggestOptionModifier( - title: L10n.Message.Polls.addComment, - showingAlert: $viewModel.addCommentShown, - text: $viewModel.commentText, - submit: { - viewModel.add(comment: viewModel.commentText) - } - ) + .uiAlert( + title: L10n.Alert.Title.addComment, + isPresented: $viewModel.addCommentShown, + text: $viewModel.commentText, + accept: L10n.Alert.Actions.send, + action: { viewModel.add(comment: viewModel.commentText) } ) } @@ -111,7 +106,7 @@ public struct PollAttachmentView: View { Button { viewModel.allCommentsShown = true } label: { - Text(L10n.Message.Polls.viewComments(viewModel.poll.answersCount)) + Text(L10n.Message.Polls.Button.viewNumberOfComments(viewModel.poll.answersCount)) } .fullScreenCover(isPresented: $viewModel.allCommentsShown) { PollCommentsView(poll: viewModel.poll, pollController: viewModel.pollController) @@ -121,7 +116,7 @@ public struct PollAttachmentView: View { Button { viewModel.pollResultsShown = true } label: { - Text(L10n.Message.Polls.viewResults) + Text(L10n.Message.Polls.Button.viewResults) } .fullScreenCover(isPresented: $viewModel.pollResultsShown) { PollResultsView(viewModel: viewModel) @@ -131,7 +126,7 @@ public struct PollAttachmentView: View { Button { viewModel.endVote() } label: { - Text(L10n.Message.Polls.endVote) + Text(L10n.Message.Polls.Button.endVote) } } } @@ -169,27 +164,6 @@ public struct PollAttachmentView: View { extension PollOption: Identifiable {} -struct SuggestOptionModifier: ViewModifier { - - var title: String - @Binding var showingAlert: Bool - @Binding var text: String - var submit: () -> Void - - func body(content: Content) -> some View { - content - .uiAlert( - title: title, - isPresented: $showingAlert, - text: $text, - placeholder: L10n.Alert.TextField.pollsNewOption, - cancel: L10n.Alert.Actions.cancel, - accept: L10n.Alert.Actions.add, - action: submit - ) - } -} - struct PollOptionView: View { @ObservedObject var viewModel: PollAttachmentViewModel diff --git a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollCommentsView.swift b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollCommentsView.swift index 869e7d0d..07094ff2 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollCommentsView.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollCommentsView.swift @@ -45,21 +45,18 @@ struct PollCommentsView: View { Button(action: { viewModel.addCommentShown = true }, label: { - Text(L10n.Message.Polls.addComment) + Text(L10n.Message.Polls.Button.addComment) .bold() .foregroundColor(colors.tintColor) }) .frame(maxWidth: .infinity) .withPollsBackground() - .modifier( - SuggestOptionModifier( - title: L10n.Message.Polls.addComment, - showingAlert: $viewModel.addCommentShown, - text: $viewModel.newCommentText, - submit: { - viewModel.add(comment: viewModel.newCommentText) - } - ) + .uiAlert( + title: L10n.Alert.Title.addComment, + isPresented: $viewModel.addCommentShown, + text: $viewModel.newCommentText, + accept: L10n.Alert.Actions.send, + action: { viewModel.add(comment: viewModel.newCommentText) } ) } .padding() diff --git a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollResultsView.swift b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollResultsView.swift index b5fca86c..d8a6c2a4 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollResultsView.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollResultsView.swift @@ -115,7 +115,7 @@ struct PollOptionResultsView: View { NavigationLink { PollOptionAllVotesView(poll: poll, option: option) } label: { - Text(L10n.Message.Polls.showAll) + Text(L10n.Message.Polls.Button.showAll) } } } diff --git a/Sources/StreamChatSwiftUI/Generated/L10n.swift b/Sources/StreamChatSwiftUI/Generated/L10n.swift index f559fd3e..b14eaa1b 100644 --- a/Sources/StreamChatSwiftUI/Generated/L10n.swift +++ b/Sources/StreamChatSwiftUI/Generated/L10n.swift @@ -13,8 +13,6 @@ internal enum L10n { internal enum Alert { internal enum Actions { - /// Add - internal static var add: String { L10n.tr("Localizable", "alert.actions.add") } /// Cancel internal static var cancel: String { L10n.tr("Localizable", "alert.actions.cancel") } /// Delete @@ -37,6 +35,8 @@ internal enum L10n { internal static var muteChannelTitle: String { L10n.tr("Localizable", "alert.actions.mute-channel-title") } /// Ok internal static var ok: String { L10n.tr("Localizable", "alert.actions.ok") } + /// Send + internal static var send: String { L10n.tr("Localizable", "alert.actions.send") } /// Are you sure you want to unmute this internal static var unmuteChannelTitle: String { L10n.tr("Localizable", "alert.actions.unmute-channel-title") } /// View info @@ -52,6 +52,12 @@ internal enum L10n { /// Enter a new option internal static var pollsNewOption: String { L10n.tr("Localizable", "alert.text-field.polls-new-option") } } + internal enum Title { + /// Add a comment + internal static var addComment: String { L10n.tr("Localizable", "alert.title.add-comment") } + /// Suggest an option + internal static var suggestAnOption: String { L10n.tr("Localizable", "alert.title.suggest-an-option") } + } } internal enum Attachment { @@ -387,30 +393,32 @@ internal enum L10n { internal static var title: String { L10n.tr("Localizable", "message.giphy-attachment.title") } } internal enum Polls { - /// Add a comment - internal static var addComment: String { L10n.tr("Localizable", "message.polls.addComment") } - /// End Vote - internal static var endVote: String { L10n.tr("Localizable", "message.polls.endVote") } - /// See %d more options - internal static func seeMoreOptions(_ p1: Int) -> String { - return L10n.tr("Localizable", "message.polls.seeMoreOptions", p1) - } - /// Show All - internal static var showAll: String { L10n.tr("Localizable", "message.polls.show-all") } - /// Suggest an option - internal static var suggestAnOption: String { L10n.tr("Localizable", "message.polls.suggestAnOption") } /// Anonymous internal static var unknownVoteAuthor: String { L10n.tr("Localizable", "message.polls.unknown-vote-author") } - /// View %d comments - internal static func viewComments(_ p1: Int) -> String { - return L10n.tr("Localizable", "message.polls.viewComments", p1) - } - /// View Results - internal static var viewResults: String { L10n.tr("Localizable", "message.polls.viewResults") } /// %d votes internal static func votes(_ p1: Int) -> String { return L10n.tr("Localizable", "message.polls.votes", p1) } + internal enum Button { + /// Add a Comment + internal static var addComment: String { L10n.tr("Localizable", "message.polls.button.addComment") } + /// End Vote + internal static var endVote: String { L10n.tr("Localizable", "message.polls.button.endVote") } + /// See %d More Options + internal static func seeMoreOptions(_ p1: Int) -> String { + return L10n.tr("Localizable", "message.polls.button.seeMoreOptions", p1) + } + /// Show All + internal static var showAll: String { L10n.tr("Localizable", "message.polls.button.show-all") } + /// Suggest an Option + internal static var suggestAnOption: String { L10n.tr("Localizable", "message.polls.button.suggestAnOption") } + /// Plural format key: "%#@comments@" + internal static func viewNumberOfComments(_ p1: Int) -> String { + return L10n.tr("Localizable", "message.polls.button.view-number-of-comments", p1) + } + /// View Results + internal static var viewResults: String { L10n.tr("Localizable", "message.polls.button.viewResults") } + } internal enum Subtitle { /// Select one internal static var selectOne: String { L10n.tr("Localizable", "message.polls.subtitle.selectOne") } diff --git a/Sources/StreamChatSwiftUI/Resources/en.lproj/Localizable.strings b/Sources/StreamChatSwiftUI/Resources/en.lproj/Localizable.strings index d7bd7580..5c18374f 100644 --- a/Sources/StreamChatSwiftUI/Resources/en.lproj/Localizable.strings +++ b/Sources/StreamChatSwiftUI/Resources/en.lproj/Localizable.strings @@ -54,24 +54,22 @@ "message.cell.edited" = "Edited"; "message.reactions.currentUser" = "You"; -"message.polls.addComment" = "Add a comment"; -"message.polls.endVote" = "End Vote"; -"message.polls.seeMoreOptions" = "See %d more options"; -"message.polls.show-all" = "Show All"; +"message.polls.button.addComment" = "Add a Comment"; +"message.polls.button.endVote" = "End Vote"; +"message.polls.button.seeMoreOptions" = "See %d More Options"; +"message.polls.button.show-all" = "Show All"; +"message.polls.button.suggestAnOption" = "Suggest an Option"; +"message.polls.button.viewResults" = "View Results"; "message.polls.subtitle.selectOne" = "Select one"; "message.polls.subtitle.selectOneOrMore" = "Select one or more"; "message.polls.subtitle.selectUpTo" = "Select up to %d"; "message.polls.subtitle.voteEnded" = "Vote ended"; -"message.polls.suggestAnOption" = "Suggest an option"; "message.polls.toolbar.comments-title" = "Poll Comments"; "message.polls.toolbar.options-title" = "Poll Options"; "message.polls.toolbar.results-title" = "Poll Results"; "message.polls.unknown-vote-author" = "Anonymous"; -"message.polls.viewComments" = "View %d comments"; -"message.polls.viewResults" = "View Results"; "message.polls.votes" = "%d votes"; -"alert.actions.add" = "Add"; "alert.actions.cancel" = "Cancel"; "alert.actions.delete" = "Delete"; "alert.actions.ok" = "Ok"; @@ -79,6 +77,7 @@ "alert.actions.delete-channel-title" = "Delete conversation"; "alert.actions.delete-channel-message" = "Are you sure you want to delete this conversation?"; "alert.actions.keep-editing" = "Keep Editing"; +"alert.actions.send" = "Send"; "alert.error.title" = "Something went wrong."; "alert.error.message" = "The operation couldn't be completed."; "alert.actions.mute-channel-title" = "Are you sure you want to mute this"; @@ -88,6 +87,8 @@ "alert.actions.leave-group-button" = "Leave"; "alert.actions.view-info-title" = "View info"; "alert.text-field.polls-new-option" = "Enter a new option"; +"alert.title.add-comment" = "Add a comment"; +"alert.title.suggest-an-option" = "Suggest an option"; "message.only-visible-to-you" = "Only visible to you"; "message.deleted-message-placeholder" = "Message deleted"; diff --git a/Sources/StreamChatSwiftUI/Resources/en.lproj/Localizable.stringsdict b/Sources/StreamChatSwiftUI/Resources/en.lproj/Localizable.stringsdict index 71663ec8..755035f6 100644 --- a/Sources/StreamChatSwiftUI/Resources/en.lproj/Localizable.stringsdict +++ b/Sources/StreamChatSwiftUI/Resources/en.lproj/Localizable.stringsdict @@ -2,6 +2,22 @@ + message.polls.button.view-number-of-comments + + NSStringLocalizedFormatKey + %#@comments@ + comments + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + d + one + View %d Comment + other + View %d Comments + + recording.presentation.name NSStringLocalizedFormatKey diff --git a/Sources/StreamChatSwiftUI/Utils/SwiftUI+UIAlertController.swift b/Sources/StreamChatSwiftUI/Utils/SwiftUI+UIAlertController.swift index 12d251a6..ffbeddc2 100644 --- a/Sources/StreamChatSwiftUI/Utils/SwiftUI+UIAlertController.swift +++ b/Sources/StreamChatSwiftUI/Utils/SwiftUI+UIAlertController.swift @@ -13,8 +13,8 @@ extension View { isPresented: Binding, message: String = "", text: Binding, - placeholder: String, - cancel: String, + placeholder: String = "", + cancel: String = L10n.Alert.Actions.cancel, accept: String, action: @escaping () -> Void ) -> some View {