From bd862eae0ec0f46c69c39b60eaad850b67054193 Mon Sep 17 00:00:00 2001 From: kate-signal Date: Mon, 27 Oct 2025 09:48:15 -0400 Subject: [PATCH] More Polls UI polish --- .../CellViews/CVPollView.swift | 9 ++++--- .../arrow/arrow-up-30.imageset/Contents.json | 15 +++++++++++ .../arrow-up-30.imageset/arrow-up-30.pdf | Bin 0 -> 4514 bytes .../x/x-26.imageset/Contents.json | 15 +++++++++++ .../Symbols.xcassets/x/x-26.imageset/x26.pdf | Bin 0 -> 4499 bytes .../Polls/NewPollViewController.swift | 25 ++++++++++++++++-- .../Polls/PollDetailsViewController.swift | 12 +++++++-- SignalUI/Appearance/Theme+Icons.swift | 6 +++++ 8 files changed, 74 insertions(+), 8 deletions(-) create mode 100644 Signal/Symbols.xcassets/arrow/arrow-up-30.imageset/Contents.json create mode 100644 Signal/Symbols.xcassets/arrow/arrow-up-30.imageset/arrow-up-30.pdf create mode 100644 Signal/Symbols.xcassets/x/x-26.imageset/Contents.json create mode 100644 Signal/Symbols.xcassets/x/x-26.imageset/x26.pdf diff --git a/Signal/ConversationView/CellViews/CVPollView.swift b/Signal/ConversationView/CellViews/CVPollView.swift index 6ec90b440e..a150030e25 100644 --- a/Signal/ConversationView/CellViews/CVPollView.swift +++ b/Signal/ConversationView/CellViews/CVPollView.swift @@ -607,11 +607,10 @@ public class CVPollView: ManualStackView { let checkMark = UIImageView(image: UIImage(named: Theme.iconName(.checkmark))) checkbox.addSubview(spinningEllipse, withLayoutBlock: { [weak self] _ in guard let self else { return } - spinningEllipse.frame = checkbox.bounds spinView(view: spinningEllipse) checkMark.frame = CGRect( - x: (checkbox.bounds.width - 15) / 2, - y: (checkbox.bounds.height - 15) / 2, + x: (spinningEllipse.frame.width - 15) / 2, + y: (spinningEllipse.frame.height - 15) / 2, width: 15, height: 15 ) @@ -638,7 +637,9 @@ public class CVPollView: ManualStackView { switch localUserVoteState { case .vote: - checkbox.addSubview(UIImageView(image: UIImage(named: Theme.iconName(.checkCircleFill)))) + let checkMarkCircle = UIImageView(image: UIImage(named: Theme.iconName(.checkCircleFill))) + checkbox.addSubview(checkMarkCircle) + checkbox.tintColor = configurator.colorConfigurator.checkboxSelectedColor case .pendingVote, .pendingUnvote: displayPendingUI(type: localUserVoteState) diff --git a/Signal/Symbols.xcassets/arrow/arrow-up-30.imageset/Contents.json b/Signal/Symbols.xcassets/arrow/arrow-up-30.imageset/Contents.json new file mode 100644 index 0000000000..47d67eb539 --- /dev/null +++ b/Signal/Symbols.xcassets/arrow/arrow-up-30.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "arrow-up-30.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "template" + } +} diff --git a/Signal/Symbols.xcassets/arrow/arrow-up-30.imageset/arrow-up-30.pdf b/Signal/Symbols.xcassets/arrow/arrow-up-30.imageset/arrow-up-30.pdf new file mode 100644 index 0000000000000000000000000000000000000000..37a620b10545bb7a9b2f4f5658f33923665ad6d5 GIT binary patch literal 4514 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 literal 0 HcmV?d00001 diff --git a/Signal/src/ViewControllers/Polls/NewPollViewController.swift b/Signal/src/ViewControllers/Polls/NewPollViewController.swift index c92c2c6eb6..4855d7ccd0 100644 --- a/Signal/src/ViewControllers/Polls/NewPollViewController.swift +++ b/Signal/src/ViewControllers/Polls/NewPollViewController.swift @@ -190,6 +190,11 @@ struct NewPollView: View { .onAppear { focusQuestionField = true } + .onSubmit { + if let nextBlankRow = findFirstBlankRow() { + focusedItemID = nextBlankRow.id + } + } } header: { Text( OWSLocalizedString( @@ -212,6 +217,11 @@ struct NewPollView: View { option.text = "" } } + .onSubmit { + if let nextBlankRow = findFirstBlankRow() { + focusedItemID = nextBlankRow.id + } + } .focused($focusedItemID, equals: option.id) } .onMove(perform: { from, to in @@ -254,9 +264,10 @@ struct NewPollView: View { Button(action: { viewModel.onDismiss() }) { - Image(Theme.iconName(.xBold)) + Image(Theme.iconName(.x26)) } .accessibilityLabel(CommonStrings.cancelButton) + .foregroundColor(Color.Signal.label) } else { Button(CommonStrings.cancelButton, action: { viewModel.onDismiss() @@ -273,7 +284,8 @@ struct NewPollView: View { Button(action: { sendButtonPressed(sendButtonEnabled: sendButtonEnabled) }) { - Image(Theme.iconName(.arrowUp)) + Image(Theme.iconName(.arrowUp30)) + .foregroundColor(.white) } .accessibilityLabel(MessageStrings.sendButton) .tint(Color.Signal.ultramarine) @@ -292,6 +304,15 @@ struct NewPollView: View { } } + private func findFirstBlankRow() -> NewOption? { + for option in pollOptions { + if option.text.isEmpty { + return option + } + } + return nil + } + private func sendButtonPressed(sendButtonEnabled: Bool) { if sendButtonEnabled { viewModel.onSend( diff --git a/Signal/src/ViewControllers/Polls/PollDetailsViewController.swift b/Signal/src/ViewControllers/Polls/PollDetailsViewController.swift index 3a017f84f3..79282b5f2a 100644 --- a/Signal/src/ViewControllers/Polls/PollDetailsViewController.swift +++ b/Signal/src/ViewControllers/Polls/PollDetailsViewController.swift @@ -76,6 +76,13 @@ struct PollDetailsView: View { Text(poll.question) .font(.body) .foregroundColor(Color.Signal.label) + } header: { + Text( + OWSLocalizedString( + "POLL_QUESTION_LABEL", + comment: "Header for the poll question text box when making a new poll" + ) + ) } if !poll.isEnded, poll.ownerIsLocalUser { @@ -137,14 +144,15 @@ struct PollDetailsView: View { } .navigationTitle(titleString) .toolbar { - ToolbarItem(placement: .topBarLeading) { + ToolbarItem(placement: .topBarTrailing) { if #available(iOS 26.0, *) { Button(action: { viewModel.onDismiss() }) { - Image(Theme.iconName(.xBold)) + Image(Theme.iconName(.x26)) } .accessibilityLabel(CommonStrings.doneButton) + .foregroundColor(Color.Signal.label) } else { Button(CommonStrings.doneButton, action: { viewModel.onDismiss() diff --git a/SignalUI/Appearance/Theme+Icons.swift b/SignalUI/Appearance/Theme+Icons.swift index 52697a4697..4688a50832 100644 --- a/SignalUI/Appearance/Theme+Icons.swift +++ b/SignalUI/Appearance/Theme+Icons.swift @@ -69,11 +69,13 @@ public enum ThemeIcon: UInt { case checkCircleFill case xCircle case xBold + case x26 case checkmark case checkmarkBold case circle case arrowDown case arrowUp + case arrowUp30 case arrowRight case chevronUp case chevronDown @@ -339,6 +341,8 @@ public extension Theme { return "x-circle" case .xBold: return "x-bold" + case .x26: + return "x-26" case .checkmark: return "check" case .checkmarkBold: @@ -349,6 +353,8 @@ public extension Theme { return "arrow-down" case .arrowUp: return "arrow-up" + case .arrowUp30: + return "arrow-up-30" case .arrowRight: return "arrow-right" case .chevronUp: