@@ -32,142 +32,151 @@ struct ComposeContentToolbarView: View {
3232
3333 var body : some View {
3434 HStack ( spacing: . zero) {
35- ForEach ( ComposeContentToolbarView . ViewModel. Action. allCases, id: \. self) { action in
36- let basicHandler = {
37- logger. log ( level: . debug, " \( ( #file as NSString ) . lastPathComponent, privacy: . public) [ \( #line, privacy: . public) ], \( #function, privacy: . public) : \( String ( describing: action) ) " )
38- viewModel. delegate? . composeContentToolbarView ( viewModel, toolbarItemDidPressed: action)
39- }
35+ let makeBasicHandler : ( ViewModel . Action ) -> ( ) -> Void = { action in {
36+ logger. log ( level: . debug, " \( ( #file as NSString ) . lastPathComponent, privacy: . public) [ \( #line, privacy: . public) ], \( #function, privacy: . public) : \( String ( describing: action) ) " )
37+ viewModel. delegate? . composeContentToolbarView ( viewModel, toolbarItemDidPressed: action)
38+ } }
4039
41- switch action {
42- case . attachment:
43- Menu {
44- ForEach ( ComposeContentToolbarView . ViewModel. AttachmentAction. allCases, id: \. self) { attachmentAction in
45- Button {
46- logger. log ( level: . debug, " \( ( #file as NSString ) . lastPathComponent, privacy: . public) [ \( #line, privacy: . public) ], \( #function, privacy: . public) , \( attachmentAction. title) " )
47- viewModel. delegate? . composeContentToolbarView ( viewModel, attachmentMenuDidPressed: attachmentAction)
48- } label: {
49- Label {
50- Text ( attachmentAction. title)
51- } icon: {
52- Image ( uiImage: attachmentAction. image)
53- }
54- }
55- }
40+ // MARK: Attachment
41+ Menu {
42+ ForEach ( ComposeContentToolbarView . ViewModel. AttachmentAction. allCases, id: \. self) { attachmentAction in
43+ Button {
44+ logger. log ( level: . debug, " \( ( #file as NSString ) . lastPathComponent, privacy: . public) [ \( #line, privacy: . public) ], \( #function, privacy: . public) , \( attachmentAction. title) " )
45+ viewModel. delegate? . composeContentToolbarView ( viewModel, attachmentMenuDidPressed: attachmentAction)
5646 } label: {
57- ComposeContentToolbarAction (
58- label: L10n . Scene. Compose. Accessibility. appendAttachment,
59- image: Asset . Scene. Compose. media
60- )
61- }
62- . disabled ( !viewModel. isAttachmentButtonEnabled)
63- case . visibility:
64- Menu {
65- Picker ( selection: $viewModel. visibility) {
66- ForEach ( viewModel. allVisibilities, id: \. self) { visibility in
67- Label {
68- Text ( visibility. title)
69- } icon: {
70- visibility. image. swiftUIImage
71- }
72- }
73- } label: {
74- Text ( viewModel. visibility. title)
47+ Label {
48+ Text ( attachmentAction. title)
49+ } icon: {
50+ Image ( uiImage: attachmentAction. image)
7551 }
76- } label: {
77- ComposeContentToolbarAction (
78- label: L10n . Scene. Compose. Keyboard. selectVisibilityEntry ( viewModel. visibility. title) ,
79- image: viewModel. visibility. image
80- )
81- }
82- . disabled ( !viewModel. isVisibilityButtonEnabled)
83- case . poll:
84- Button ( action: basicHandler) {
85- ComposeContentToolbarAction (
86- label: viewModel. isPollActive
87- ? L10n . Scene. Compose. Accessibility. removePoll
88- : L10n . Scene. Compose. Accessibility. appendPoll,
89- image: viewModel. isPollActive
90- ? Asset . Scene. Compose. pollFill
91- : Asset . Scene. Compose. poll
92- )
9352 }
94- . disabled ( !viewModel. isPollButtonEnabled)
95- case . language:
96- Menu {
97- Section { } // workaround a bug where the “Suggested” section doesn’t appear
98- if !viewModel. suggestedLanguages. isEmpty {
99- Section ( L10n . Scene. Compose. Language. suggested) {
100- ForEach ( viewModel. suggestedLanguages. compactMap ( Language . init ( id: ) ) ) { lang in
101- Toggle ( isOn: languageBinding ( for: lang. id) ) {
102- Text ( lang. label)
103- }
104- }
105- }
106- }
107- let recent = viewModel. recentLanguages. filter { !viewModel. suggestedLanguages. contains ( $0) }
108- if !recent. isEmpty {
109- Section ( L10n . Scene. Compose. Language. recent) {
110- ForEach ( recent. compactMap ( Language . init ( id: ) ) ) { lang in
111- Toggle ( isOn: languageBinding ( for: lang. id) ) {
112- Text ( lang. label)
113- }
114- }
115- }
53+ }
54+ } label: {
55+ ComposeContentToolbarAction (
56+ label: L10n . Scene. Compose. Accessibility. appendAttachment,
57+ image: Asset . Scene. Compose. media
58+ )
59+ }
60+ . disabled ( !viewModel. isAttachmentButtonEnabled)
61+ . frame ( width: Self . toolbarHeight, height: Self . toolbarHeight)
62+
63+ // MARK: Poll
64+ Button ( action: makeBasicHandler ( . poll) ) {
65+ ComposeContentToolbarAction (
66+ label: viewModel. isPollActive
67+ ? L10n . Scene. Compose. Accessibility. removePoll
68+ : L10n . Scene. Compose. Accessibility. appendPoll,
69+ image: viewModel. isPollActive
70+ ? Asset . Scene. Compose. pollFill
71+ : Asset . Scene. Compose. poll
72+ )
73+ }
74+ . disabled ( !viewModel. isPollButtonEnabled)
75+ . frame ( width: Self . toolbarHeight, height: Self . toolbarHeight)
76+
77+ // MARK: Emoji
78+ Button ( action: makeBasicHandler ( . emoji) ) {
79+ ComposeContentToolbarAction (
80+ label: L10n . Scene. Compose. Accessibility. customEmojiPicker,
81+ image: viewModel. isEmojiActive ? Asset . Scene. Compose. emojiFill : Asset . Scene. Compose. emoji
82+ )
83+ }
84+ . frame ( width: Self . toolbarHeight, height: Self . toolbarHeight)
85+
86+ // MARK: Content Warning
87+ Button ( action: makeBasicHandler ( . contentWarning) ) {
88+ ComposeContentToolbarAction (
89+ label: viewModel. isContentWarningActive
90+ ? L10n . Scene. Compose. Accessibility. disableContentWarning
91+ : L10n . Scene. Compose. Accessibility. enableContentWarning,
92+ image: viewModel. isContentWarningActive
93+ ? Asset . Scene. Compose. chatWarningFill
94+ : Asset . Scene. Compose. chatWarning
95+ )
96+ }
97+ . frame ( width: Self . toolbarHeight, height: Self . toolbarHeight)
98+
99+ // MARK: Visibility
100+ Menu {
101+ Picker ( selection: $viewModel. visibility) {
102+ ForEach ( viewModel. allVisibilities, id: \. self) { visibility in
103+ Label {
104+ Text ( visibility. title)
105+ } icon: {
106+ visibility. image. swiftUIImage
116107 }
117- if !( recent + viewModel. suggestedLanguages) . contains ( viewModel. language) {
118- Toggle ( isOn: languageBinding ( for: viewModel. language) ) {
119- Text ( Language ( id: viewModel. language) ? . label ?? AttributedString ( " \( viewModel. language) " ) )
108+ }
109+ } label: {
110+ Text ( viewModel. visibility. title)
111+ }
112+ } label: {
113+ ComposeContentToolbarAction (
114+ label: L10n . Scene. Compose. Keyboard. selectVisibilityEntry ( viewModel. visibility. title) ,
115+ image: viewModel. visibility. image
116+ )
117+ }
118+ . disabled ( !viewModel. isVisibilityButtonEnabled)
119+ . frame ( width: Self . toolbarHeight, height: Self . toolbarHeight)
120+
121+ // MARK: Language
122+ Menu {
123+ Section { } // workaround a bug where the “Suggested” section doesn’t appear
124+ if !viewModel. suggestedLanguages. isEmpty {
125+ Section ( L10n . Scene. Compose. Language. suggested) {
126+ ForEach ( viewModel. suggestedLanguages. compactMap ( Language . init ( id: ) ) ) { lang in
127+ Toggle ( isOn: languageBinding ( for: lang. id) ) {
128+ Text ( lang. label)
120129 }
121130 }
122- Button ( L10n . Scene. Compose. Language. other) {
123- showingLanguagePicker = true
124- }
125- } label: {
126- ComposeContentToolbarAction (
127- label: L10n . Scene. Compose. Language. title,
128- icon: LanguagePickerIcon ( language: viewModel. language, showBadge: {
129- if let suggested = viewModel. highConfidenceSuggestedLanguage {
130- return !didChangeLanguage && suggested != viewModel. language
131- }
132- return false
133- } ( ) )
134- ) . accessibilityValue ( Text ( Language ( id: viewModel. language) ? . label ?? AttributedString ( " \( viewModel. language) " ) ) )
135131 }
136- . popover ( isPresented: $showingLanguagePicker) {
137- let picker = LanguagePicker { newLanguage in
138- viewModel. language = newLanguage
139- didChangeLanguage = true
140- showingLanguagePicker = false
141- }
142- if verticalSizeClass == . regular && horizontalSizeClass == . regular {
143- // explicitly size picker when it’s a popover
144- picker. frame ( width: 400 , height: 500 )
145- } else {
146- picker
132+ }
133+ let recent = viewModel. recentLanguages. filter { !viewModel. suggestedLanguages. contains ( $0) }
134+ if !recent. isEmpty {
135+ Section ( L10n . Scene. Compose. Language. recent) {
136+ ForEach ( recent. compactMap ( Language . init ( id: ) ) ) { lang in
137+ Toggle ( isOn: languageBinding ( for: lang. id) ) {
138+ Text ( lang. label)
139+ }
147140 }
148141 }
149-
150- case . emoji:
151- Button ( action: basicHandler) {
152- ComposeContentToolbarAction (
153- label: L10n . Scene. Compose. Accessibility. customEmojiPicker,
154- image: viewModel. isEmojiActive ? Asset . Scene. Compose. emojiFill : Asset . Scene. Compose. emoji
155- )
156- }
157- case . contentWarning:
158- Button ( action: basicHandler) {
159- ComposeContentToolbarAction (
160- label: viewModel. isContentWarningActive
161- ? L10n . Scene. Compose. Accessibility. disableContentWarning
162- : L10n . Scene. Compose. Accessibility. enableContentWarning,
163- image: viewModel. isContentWarningActive
164- ? Asset . Scene. Compose. chatWarningFill
165- : Asset . Scene. Compose. chatWarning
166- )
142+ }
143+ if !( recent + viewModel. suggestedLanguages) . contains ( viewModel. language) {
144+ Toggle ( isOn: languageBinding ( for: viewModel. language) ) {
145+ Text ( Language ( id: viewModel. language) ? . label ?? AttributedString ( " \( viewModel. language) " ) )
167146 }
168147 }
169- } . frame ( width: 48 , height: 48 )
148+ Button ( L10n . Scene. Compose. Language. other) {
149+ showingLanguagePicker = true
150+ }
151+ } label: {
152+ ComposeContentToolbarAction (
153+ label: L10n . Scene. Compose. Language. title,
154+ icon: LanguagePickerIcon ( language: viewModel. language, showBadge: {
155+ if let suggested = viewModel. highConfidenceSuggestedLanguage {
156+ return !didChangeLanguage && suggested != viewModel. language
157+ }
158+ return false
159+ } ( ) )
160+ ) . accessibilityValue ( Text ( Language ( id: viewModel. language) ? . label ?? AttributedString ( " \( viewModel. language) " ) ) )
161+ }
162+ . frame ( width: Self . toolbarHeight, height: Self . toolbarHeight)
163+ . popover ( isPresented: $showingLanguagePicker) {
164+ let picker = LanguagePicker { newLanguage in
165+ viewModel. language = newLanguage
166+ didChangeLanguage = true
167+ showingLanguagePicker = false
168+ }
169+ if verticalSizeClass == . regular, horizontalSizeClass == . regular {
170+ // explicitly size picker when it’s a popover
171+ picker. frame ( width: 400 , height: 500 )
172+ } else {
173+ picker
174+ }
175+ }
176+
170177 Spacer ( )
178+
179+ // MARK: Character count
171180 let count : Int = {
172181 if viewModel. isContentWarningActive {
173182 return viewModel. contentWeightedLength + viewModel. contentWarningWeightedLength
0 commit comments