mirror of
https://github.com/Dimillian/IceCubesApp.git
synced 2025-03-28 12:35:27 +00:00
UI Adjustments
This commit is contained in:
parent
fdf15e60f6
commit
1c9cf4077d
7 changed files with 249 additions and 180 deletions
|
@ -96,7 +96,12 @@ public struct AppAccountsSelectorView: View {
|
||||||
AppAccountView(viewModel: viewModel)
|
AppAccountView(viewModel: viewModel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.listRowBackground(theme.primaryBackgroundColor)
|
#if os(visionOS)
|
||||||
|
.listRowBackground(RoundedRectangle(cornerRadius: 8)
|
||||||
|
.foregroundStyle(Material.regular))
|
||||||
|
#else
|
||||||
|
.listRowBackground(theme.primaryBackgroundColor)
|
||||||
|
#endif
|
||||||
|
|
||||||
if accountCreationEnabled {
|
if accountCreationEnabled {
|
||||||
Section {
|
Section {
|
||||||
|
@ -111,7 +116,12 @@ public struct AppAccountsSelectorView: View {
|
||||||
}
|
}
|
||||||
settingsButton
|
settingsButton
|
||||||
}
|
}
|
||||||
.listRowBackground(theme.primaryBackgroundColor)
|
#if os(visionOS)
|
||||||
|
.listRowBackground(Rectangle()
|
||||||
|
.foregroundStyle(Material.regular))
|
||||||
|
#else
|
||||||
|
.listRowBackground(theme.primaryBackgroundColor)
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.listStyle(.insetGrouped)
|
.listStyle(.insetGrouped)
|
||||||
|
|
|
@ -132,8 +132,11 @@ public struct NotificationsListView: View {
|
||||||
leading: .layoutPadding + 4,
|
leading: .layoutPadding + 4,
|
||||||
bottom: 12,
|
bottom: 12,
|
||||||
trailing: .layoutPadding))
|
trailing: .layoutPadding))
|
||||||
#if !os(visionOS)
|
#if os(visionOS)
|
||||||
.listRowBackground(theme.primaryBackgroundColor)
|
.listRowBackground(RoundedRectangle(cornerRadius: 8)
|
||||||
|
.foregroundStyle(Material.regular))
|
||||||
|
#else
|
||||||
|
.listRowBackground(theme.primaryBackgroundColor)
|
||||||
#endif
|
#endif
|
||||||
.redacted(reason: .placeholder)
|
.redacted(reason: .placeholder)
|
||||||
.allowsHitTesting(false)
|
.allowsHitTesting(false)
|
||||||
|
@ -158,7 +161,10 @@ public struct NotificationsListView: View {
|
||||||
leading: .layoutPadding + 4,
|
leading: .layoutPadding + 4,
|
||||||
bottom: 12,
|
bottom: 12,
|
||||||
trailing: .layoutPadding))
|
trailing: .layoutPadding))
|
||||||
#if !os(visionOS)
|
#if os(visionOS)
|
||||||
|
.listRowBackground(RoundedRectangle(cornerRadius: 8)
|
||||||
|
.foregroundStyle(notification.type == .mention && lockedType != .mention ? Material.thick : Material.regular))
|
||||||
|
#else
|
||||||
.listRowBackground(notification.type == .mention && lockedType != .mention ?
|
.listRowBackground(notification.type == .mention && lockedType != .mention ?
|
||||||
theme.secondaryBackgroundColor : theme.primaryBackgroundColor)
|
theme.secondaryBackgroundColor : theme.primaryBackgroundColor)
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -59,7 +59,9 @@ public struct StatusDetailView: View {
|
||||||
.foregroundColor(theme.secondaryBackgroundColor)
|
.foregroundColor(theme.secondaryBackgroundColor)
|
||||||
.frame(minHeight: reader.frame(in: .local).size.height - statusHeight)
|
.frame(minHeight: reader.frame(in: .local).size.height - statusHeight)
|
||||||
.listRowSeparator(.hidden)
|
.listRowSeparator(.hidden)
|
||||||
|
#if !os(visionOS)
|
||||||
.listRowBackground(theme.secondaryBackgroundColor)
|
.listRowBackground(theme.secondaryBackgroundColor)
|
||||||
|
#endif
|
||||||
.listRowInsets(.init())
|
.listRowInsets(.init())
|
||||||
.accessibilityHidden(true)
|
.accessibilityHidden(true)
|
||||||
|
|
||||||
|
@ -69,8 +71,10 @@ public struct StatusDetailView: View {
|
||||||
}
|
}
|
||||||
.environment(\.defaultMinListRowHeight, 1)
|
.environment(\.defaultMinListRowHeight, 1)
|
||||||
.listStyle(.plain)
|
.listStyle(.plain)
|
||||||
|
#if !os(visionOS)
|
||||||
.scrollContentBackground(.hidden)
|
.scrollContentBackground(.hidden)
|
||||||
.background(theme.primaryBackgroundColor)
|
.background(theme.primaryBackgroundColor)
|
||||||
|
#endif
|
||||||
.onChange(of: viewModel.scrollToId) { _, newValue in
|
.onChange(of: viewModel.scrollToId) { _, newValue in
|
||||||
if let newValue {
|
if let newValue {
|
||||||
viewModel.scrollToId = nil
|
viewModel.scrollToId = nil
|
||||||
|
@ -132,7 +136,9 @@ public struct StatusDetailView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.id(status.id)
|
.id(status.id)
|
||||||
|
#if !os(visionOS)
|
||||||
.listRowBackground(viewModel.highlightRowColor)
|
.listRowBackground(viewModel.highlightRowColor)
|
||||||
|
#endif
|
||||||
.listRowInsets(.init(top: 12,
|
.listRowInsets(.init(top: 12,
|
||||||
leading: .layoutPadding,
|
leading: .layoutPadding,
|
||||||
bottom: 12,
|
bottom: 12,
|
||||||
|
@ -149,7 +155,9 @@ public struct StatusDetailView: View {
|
||||||
await viewModel.fetch()
|
await viewModel.fetch()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if !os(visionOS)
|
||||||
.listRowBackground(theme.primaryBackgroundColor)
|
.listRowBackground(theme.primaryBackgroundColor)
|
||||||
|
#endif
|
||||||
.listRowSeparator(.hidden)
|
.listRowSeparator(.hidden)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,13 +177,17 @@ public struct StatusDetailView: View {
|
||||||
}
|
}
|
||||||
.frame(height: 50)
|
.frame(height: 50)
|
||||||
.listRowSeparator(.hidden)
|
.listRowSeparator(.hidden)
|
||||||
|
#if !os(visionOS)
|
||||||
.listRowBackground(theme.secondaryBackgroundColor)
|
.listRowBackground(theme.secondaryBackgroundColor)
|
||||||
|
#endif
|
||||||
.listRowInsets(.init())
|
.listRowInsets(.init())
|
||||||
}
|
}
|
||||||
|
|
||||||
private var topPaddingView: some View {
|
private var topPaddingView: some View {
|
||||||
HStack { EmptyView() }
|
HStack { EmptyView() }
|
||||||
|
#if !os(visionOS)
|
||||||
.listRowBackground(theme.primaryBackgroundColor)
|
.listRowBackground(theme.primaryBackgroundColor)
|
||||||
|
#endif
|
||||||
.listRowSeparator(.hidden)
|
.listRowSeparator(.hidden)
|
||||||
.listRowInsets(.init())
|
.listRowInsets(.init())
|
||||||
.frame(height: .layoutPadding)
|
.frame(height: .layoutPadding)
|
||||||
|
|
|
@ -31,192 +31,220 @@ struct StatusEditorAccessoryView: View {
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
@Bindable var viewModel = focusedSEVM
|
@Bindable var viewModel = focusedSEVM
|
||||||
|
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 0) {
|
||||||
|
#if os(visionOS)
|
||||||
|
HStack {
|
||||||
|
contentView
|
||||||
|
}
|
||||||
|
.frame(height: 24)
|
||||||
|
.padding(16)
|
||||||
|
.background(.ultraThinMaterial)
|
||||||
|
.cornerRadius(8)
|
||||||
|
#else
|
||||||
Divider()
|
Divider()
|
||||||
HStack {
|
HStack {
|
||||||
ScrollView(.horizontal) {
|
contentView
|
||||||
HStack(alignment: .center, spacing: 16) {
|
|
||||||
Menu {
|
|
||||||
Button {
|
|
||||||
isPhotosPickerPresented = true
|
|
||||||
} label: {
|
|
||||||
Label("status.editor.photo-library", systemImage: "photo")
|
|
||||||
}
|
|
||||||
#if !targetEnvironment(macCatalyst)
|
|
||||||
Button {
|
|
||||||
isCameraPickerPresented = true
|
|
||||||
} label: {
|
|
||||||
Label("status.editor.camera-picker", systemImage: "camera")
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
Button {
|
|
||||||
isFileImporterPresented = true
|
|
||||||
} label: {
|
|
||||||
Label("status.editor.browse-file", systemImage: "folder")
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !os(visionOS)
|
|
||||||
Button {
|
|
||||||
isGIFPickerPresented = true
|
|
||||||
} label: {
|
|
||||||
Label("GIPHY", systemImage: "party.popper")
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
} label: {
|
|
||||||
if viewModel.isMediasLoading {
|
|
||||||
ProgressView()
|
|
||||||
} else {
|
|
||||||
Image(systemName: "photo.on.rectangle.angled")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.photosPicker(isPresented: $isPhotosPickerPresented,
|
|
||||||
selection: $viewModel.mediaPickers,
|
|
||||||
maxSelectionCount: 4,
|
|
||||||
matching: .any(of: [.images, .videos]),
|
|
||||||
photoLibrary: .shared())
|
|
||||||
.fileImporter(isPresented: $isFileImporterPresented,
|
|
||||||
allowedContentTypes: [.image, .video],
|
|
||||||
allowsMultipleSelection: true)
|
|
||||||
{ result in
|
|
||||||
if let urls = try? result.get() {
|
|
||||||
viewModel.processURLs(urls: urls)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.fullScreenCover(isPresented: $isCameraPickerPresented, content: {
|
|
||||||
StatusEditorCameraPickerView(selectedImage: .init(get: {
|
|
||||||
nil
|
|
||||||
}, set: { image in
|
|
||||||
if let image {
|
|
||||||
viewModel.processCameraPhoto(image: image)
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
.background(.black)
|
|
||||||
})
|
|
||||||
.sheet(isPresented: $isGIFPickerPresented, content: {
|
|
||||||
#if !os(visionOS)
|
|
||||||
GifPickerView { url in
|
|
||||||
GPHCache.shared.downloadAssetData(url) { data, _ in
|
|
||||||
guard let data else { return }
|
|
||||||
viewModel.processGIFData(data: data)
|
|
||||||
}
|
|
||||||
isGIFPickerPresented = false
|
|
||||||
} onShouldDismissGifPicker: {
|
|
||||||
isGIFPickerPresented = false
|
|
||||||
}
|
|
||||||
.presentationDetents([.medium, .large])
|
|
||||||
#else
|
|
||||||
EmptyView()
|
|
||||||
#endif
|
|
||||||
})
|
|
||||||
.accessibilityLabel("accessibility.editor.button.attach-photo")
|
|
||||||
.disabled(viewModel.showPoll)
|
|
||||||
|
|
||||||
Button {
|
|
||||||
// all SEVM have the same visibility value
|
|
||||||
followUpSEVMs.append(StatusEditorViewModel(mode: .new(visibility: focusedSEVM.visibility)))
|
|
||||||
} label: {
|
|
||||||
Image(systemName: "arrowshape.turn.up.left.circle.fill")
|
|
||||||
}
|
|
||||||
.disabled(!canAddNewSEVM)
|
|
||||||
|
|
||||||
Button {
|
|
||||||
withAnimation {
|
|
||||||
viewModel.showPoll.toggle()
|
|
||||||
viewModel.resetPollDefaults()
|
|
||||||
}
|
|
||||||
} label: {
|
|
||||||
Image(systemName: "chart.bar")
|
|
||||||
}
|
|
||||||
.accessibilityLabel("accessibility.editor.button.poll")
|
|
||||||
.disabled(viewModel.shouldDisablePollButton)
|
|
||||||
|
|
||||||
Button {
|
|
||||||
withAnimation {
|
|
||||||
viewModel.spoilerOn.toggle()
|
|
||||||
}
|
|
||||||
isSpoilerTextFocused = viewModel.id
|
|
||||||
} label: {
|
|
||||||
Image(systemName: viewModel.spoilerOn ? "exclamationmark.triangle.fill" : "exclamationmark.triangle")
|
|
||||||
}
|
|
||||||
.accessibilityLabel("accessibility.editor.button.spoiler")
|
|
||||||
|
|
||||||
if !viewModel.mode.isInShareExtension {
|
|
||||||
Button {
|
|
||||||
isDraftsSheetDisplayed = true
|
|
||||||
} label: {
|
|
||||||
Image(systemName: "archivebox")
|
|
||||||
}
|
|
||||||
.accessibilityLabel("accessibility.editor.button.drafts")
|
|
||||||
.popover(isPresented: $isDraftsSheetDisplayed) {
|
|
||||||
if UIDevice.current.userInterfaceIdiom == .phone {
|
|
||||||
draftsListView
|
|
||||||
.presentationDetents([.medium])
|
|
||||||
} else {
|
|
||||||
draftsListView
|
|
||||||
.frame(width: 400, height: 500)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !viewModel.customEmojiContainer.isEmpty {
|
|
||||||
Button {
|
|
||||||
isCustomEmojisSheetDisplay = true
|
|
||||||
} label: {
|
|
||||||
// This is a workaround for an apparent bug in the `face.smiling` SF Symbol.
|
|
||||||
// See https://github.com/Dimillian/IceCubesApp/issues/1193
|
|
||||||
let customEmojiSheetIconName = colorScheme == .light ? "face.smiling" : "face.smiling.inverse"
|
|
||||||
Image(systemName: customEmojiSheetIconName)
|
|
||||||
}
|
|
||||||
.accessibilityLabel("accessibility.editor.button.custom-emojis")
|
|
||||||
.popover(isPresented: $isCustomEmojisSheetDisplay) {
|
|
||||||
if UIDevice.current.userInterfaceIdiom == .phone {
|
|
||||||
customEmojisSheet
|
|
||||||
} else {
|
|
||||||
customEmojisSheet
|
|
||||||
.frame(width: 400, height: 500)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
|
||||||
isLanguageSheetDisplayed.toggle()
|
|
||||||
} label: {
|
|
||||||
if let language = viewModel.selectedLanguage {
|
|
||||||
Text(language.uppercased())
|
|
||||||
} else {
|
|
||||||
Image(systemName: "globe")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.accessibilityLabel("accessibility.editor.button.language")
|
|
||||||
.popover(isPresented: $isLanguageSheetDisplayed) {
|
|
||||||
if UIDevice.current.userInterfaceIdiom == .phone {
|
|
||||||
languageSheetView
|
|
||||||
} else {
|
|
||||||
languageSheetView
|
|
||||||
.frame(width: 400, height: 500)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if preferences.isOpenAIEnabled {
|
|
||||||
AIMenu.disabled(!viewModel.canPost)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.padding(.horizontal, .layoutPadding)
|
|
||||||
}
|
|
||||||
Spacer()
|
|
||||||
characterCountView
|
|
||||||
.padding(.trailing, .layoutPadding)
|
|
||||||
}
|
}
|
||||||
.frame(height: 20)
|
.frame(height: 20)
|
||||||
.padding(.vertical, 12)
|
.padding(.vertical, 12)
|
||||||
.background(.ultraThinMaterial)
|
.background(.ultraThinMaterial)
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
.onAppear {
|
.onAppear {
|
||||||
viewModel.setInitialLanguageSelection(preference: preferences.recentlyUsedLanguages.first ?? preferences.serverPreferences?.postLanguage)
|
viewModel.setInitialLanguageSelection(preference: preferences.recentlyUsedLanguages.first ?? preferences.serverPreferences?.postLanguage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
private var contentView: some View {
|
||||||
|
#if os(visionOS)
|
||||||
|
HStack(spacing: 8) {
|
||||||
|
actionsView
|
||||||
|
characterCountView
|
||||||
|
.padding(.leading, 16)
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
ScrollView(.horizontal) {
|
||||||
|
HStack(alignment: .center, spacing: 16) {
|
||||||
|
actionsView
|
||||||
|
}
|
||||||
|
.padding(.horizontal, .layoutPadding)
|
||||||
|
}
|
||||||
|
Spacer()
|
||||||
|
characterCountView
|
||||||
|
.padding(.trailing, .layoutPadding)
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
private var actionsView: some View {
|
||||||
|
@Bindable var viewModel = focusedSEVM
|
||||||
|
Menu {
|
||||||
|
Button {
|
||||||
|
isPhotosPickerPresented = true
|
||||||
|
} label: {
|
||||||
|
Label("status.editor.photo-library", systemImage: "photo")
|
||||||
|
}
|
||||||
|
#if !targetEnvironment(macCatalyst)
|
||||||
|
Button {
|
||||||
|
isCameraPickerPresented = true
|
||||||
|
} label: {
|
||||||
|
Label("status.editor.camera-picker", systemImage: "camera")
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
Button {
|
||||||
|
isFileImporterPresented = true
|
||||||
|
} label: {
|
||||||
|
Label("status.editor.browse-file", systemImage: "folder")
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !os(visionOS)
|
||||||
|
Button {
|
||||||
|
isGIFPickerPresented = true
|
||||||
|
} label: {
|
||||||
|
Label("GIPHY", systemImage: "party.popper")
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} label: {
|
||||||
|
if viewModel.isMediasLoading {
|
||||||
|
ProgressView()
|
||||||
|
} else {
|
||||||
|
Image(systemName: "photo.on.rectangle.angled")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.photosPicker(isPresented: $isPhotosPickerPresented,
|
||||||
|
selection: $viewModel.mediaPickers,
|
||||||
|
maxSelectionCount: 4,
|
||||||
|
matching: .any(of: [.images, .videos]),
|
||||||
|
photoLibrary: .shared())
|
||||||
|
.fileImporter(isPresented: $isFileImporterPresented,
|
||||||
|
allowedContentTypes: [.image, .video],
|
||||||
|
allowsMultipleSelection: true)
|
||||||
|
{ result in
|
||||||
|
if let urls = try? result.get() {
|
||||||
|
viewModel.processURLs(urls: urls)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.fullScreenCover(isPresented: $isCameraPickerPresented, content: {
|
||||||
|
StatusEditorCameraPickerView(selectedImage: .init(get: {
|
||||||
|
nil
|
||||||
|
}, set: { image in
|
||||||
|
if let image {
|
||||||
|
viewModel.processCameraPhoto(image: image)
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
.background(.black)
|
||||||
|
})
|
||||||
|
.sheet(isPresented: $isGIFPickerPresented, content: {
|
||||||
|
#if !os(visionOS)
|
||||||
|
GifPickerView { url in
|
||||||
|
GPHCache.shared.downloadAssetData(url) { data, _ in
|
||||||
|
guard let data else { return }
|
||||||
|
viewModel.processGIFData(data: data)
|
||||||
|
}
|
||||||
|
isGIFPickerPresented = false
|
||||||
|
} onShouldDismissGifPicker: {
|
||||||
|
isGIFPickerPresented = false
|
||||||
|
}
|
||||||
|
.presentationDetents([.medium, .large])
|
||||||
|
#else
|
||||||
|
EmptyView()
|
||||||
|
#endif
|
||||||
|
})
|
||||||
|
.accessibilityLabel("accessibility.editor.button.attach-photo")
|
||||||
|
.disabled(viewModel.showPoll)
|
||||||
|
|
||||||
|
Button {
|
||||||
|
// all SEVM have the same visibility value
|
||||||
|
followUpSEVMs.append(StatusEditorViewModel(mode: .new(visibility: focusedSEVM.visibility)))
|
||||||
|
} label: {
|
||||||
|
Image(systemName: "arrowshape.turn.up.left.circle.fill")
|
||||||
|
}
|
||||||
|
.disabled(!canAddNewSEVM)
|
||||||
|
|
||||||
|
Button {
|
||||||
|
withAnimation {
|
||||||
|
viewModel.showPoll.toggle()
|
||||||
|
viewModel.resetPollDefaults()
|
||||||
|
}
|
||||||
|
} label: {
|
||||||
|
Image(systemName: "chart.bar")
|
||||||
|
}
|
||||||
|
.accessibilityLabel("accessibility.editor.button.poll")
|
||||||
|
.disabled(viewModel.shouldDisablePollButton)
|
||||||
|
|
||||||
|
Button {
|
||||||
|
withAnimation {
|
||||||
|
viewModel.spoilerOn.toggle()
|
||||||
|
}
|
||||||
|
isSpoilerTextFocused = viewModel.id
|
||||||
|
} label: {
|
||||||
|
Image(systemName: viewModel.spoilerOn ? "exclamationmark.triangle.fill" : "exclamationmark.triangle")
|
||||||
|
}
|
||||||
|
.accessibilityLabel("accessibility.editor.button.spoiler")
|
||||||
|
|
||||||
|
if !viewModel.mode.isInShareExtension {
|
||||||
|
Button {
|
||||||
|
isDraftsSheetDisplayed = true
|
||||||
|
} label: {
|
||||||
|
Image(systemName: "archivebox")
|
||||||
|
}
|
||||||
|
.accessibilityLabel("accessibility.editor.button.drafts")
|
||||||
|
.popover(isPresented: $isDraftsSheetDisplayed) {
|
||||||
|
if UIDevice.current.userInterfaceIdiom == .phone {
|
||||||
|
draftsListView
|
||||||
|
.presentationDetents([.medium])
|
||||||
|
} else {
|
||||||
|
draftsListView
|
||||||
|
.frame(width: 400, height: 500)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !viewModel.customEmojiContainer.isEmpty {
|
||||||
|
Button {
|
||||||
|
isCustomEmojisSheetDisplay = true
|
||||||
|
} label: {
|
||||||
|
// This is a workaround for an apparent bug in the `face.smiling` SF Symbol.
|
||||||
|
// See https://github.com/Dimillian/IceCubesApp/issues/1193
|
||||||
|
let customEmojiSheetIconName = colorScheme == .light ? "face.smiling" : "face.smiling.inverse"
|
||||||
|
Image(systemName: customEmojiSheetIconName)
|
||||||
|
}
|
||||||
|
.accessibilityLabel("accessibility.editor.button.custom-emojis")
|
||||||
|
.popover(isPresented: $isCustomEmojisSheetDisplay) {
|
||||||
|
if UIDevice.current.userInterfaceIdiom == .phone {
|
||||||
|
customEmojisSheet
|
||||||
|
} else {
|
||||||
|
customEmojisSheet
|
||||||
|
.frame(width: 400, height: 500)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
isLanguageSheetDisplayed.toggle()
|
||||||
|
} label: {
|
||||||
|
if let language = viewModel.selectedLanguage {
|
||||||
|
Text(language.uppercased())
|
||||||
|
} else {
|
||||||
|
Image(systemName: "globe")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.accessibilityLabel("accessibility.editor.button.language")
|
||||||
|
.popover(isPresented: $isLanguageSheetDisplayed) {
|
||||||
|
if UIDevice.current.userInterfaceIdiom == .phone {
|
||||||
|
languageSheetView
|
||||||
|
} else {
|
||||||
|
languageSheetView
|
||||||
|
.frame(width: 400, height: 500)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if preferences.isOpenAIEnabled {
|
||||||
|
AIMenu.disabled(!viewModel.canPost)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private var canAddNewSEVM: Bool {
|
private var canAddNewSEVM: Bool {
|
||||||
guard followUpSEVMs.count < 5 else { return false }
|
guard followUpSEVMs.count < 5 else { return false }
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,9 @@ struct StatusEditorCoreView: View {
|
||||||
}
|
}
|
||||||
.opacity(editorFocusState == assignedFocusState ? 1 : 0.6)
|
.opacity(editorFocusState == assignedFocusState ? 1 : 0.6)
|
||||||
}
|
}
|
||||||
|
#if !os(visionOS)
|
||||||
.background(theme.primaryBackgroundColor)
|
.background(theme.primaryBackgroundColor)
|
||||||
|
#endif
|
||||||
.focused($editorFocusState, equals: assignedFocusState)
|
.focused($editorFocusState, equals: assignedFocusState)
|
||||||
.onAppear { setupViewModel() }
|
.onAppear { setupViewModel() }
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,13 +73,21 @@ public struct StatusEditorView: View {
|
||||||
.scrollPosition(id: $scrollID, anchor: .top)
|
.scrollPosition(id: $scrollID, anchor: .top)
|
||||||
.animation(.bouncy(duration: 0.3), value: editorFocusState)
|
.animation(.bouncy(duration: 0.3), value: editorFocusState)
|
||||||
.animation(.bouncy(duration: 0.3), value: followUpSEVMs)
|
.animation(.bouncy(duration: 0.3), value: followUpSEVMs)
|
||||||
|
#if !os(visionOS)
|
||||||
.background(theme.primaryBackgroundColor)
|
.background(theme.primaryBackgroundColor)
|
||||||
|
#endif
|
||||||
.safeAreaInset(edge: .bottom) {
|
.safeAreaInset(edge: .bottom) {
|
||||||
StatusEditorAutoCompleteView(viewModel: focusedSEVM)
|
StatusEditorAutoCompleteView(viewModel: focusedSEVM)
|
||||||
}
|
}
|
||||||
|
#if os(visionOS)
|
||||||
|
.ornament(attachmentAnchor: .scene(.bottom)) {
|
||||||
|
StatusEditorAccessoryView(isSpoilerTextFocused: $isSpoilerTextFocused, focusedSEVM: focusedSEVM, followUpSEVMs: $followUpSEVMs)
|
||||||
|
}
|
||||||
|
#else
|
||||||
.safeAreaInset(edge: .bottom) {
|
.safeAreaInset(edge: .bottom) {
|
||||||
StatusEditorAccessoryView(isSpoilerTextFocused: $isSpoilerTextFocused, focusedSEVM: focusedSEVM, followUpSEVMs: $followUpSEVMs)
|
StatusEditorAccessoryView(isSpoilerTextFocused: $isSpoilerTextFocused, focusedSEVM: focusedSEVM, followUpSEVMs: $followUpSEVMs)
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
.accessibilitySortPriority(1) // Ensure that all elements inside the `ScrollView` occur earlier than the accessory views
|
.accessibilitySortPriority(1) // Ensure that all elements inside the `ScrollView` occur earlier than the accessory views
|
||||||
.navigationTitle(focusedSEVM.mode.title)
|
.navigationTitle(focusedSEVM.mode.title)
|
||||||
.navigationBarTitleDisplayMode(.inline)
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
|
|
|
@ -149,8 +149,11 @@ public struct StatusRowView: View {
|
||||||
StatusRowSwipeView(viewModel: viewModel, mode: .leading)
|
StatusRowSwipeView(viewModel: viewModel, mode: .leading)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if !os(visionOS)
|
#if os(visionOS)
|
||||||
.listRowBackground(viewModel.highlightRowColor)
|
.listRowBackground(RoundedRectangle(cornerRadius: 8)
|
||||||
|
.foregroundStyle(Material.regular))
|
||||||
|
#else
|
||||||
|
.listRowBackground(viewModel.highlightRowColor)
|
||||||
#endif
|
#endif
|
||||||
.listRowInsets(.init(top: 12,
|
.listRowInsets(.init(top: 12,
|
||||||
leading: .layoutPadding,
|
leading: .layoutPadding,
|
||||||
|
|
Loading…
Reference in a new issue