|
|
@@ -2,43 +2,81 @@ import SwiftUI
|
|
|
|
|
|
struct ModelSelectorMenu: View {
|
|
|
@ObservedObject var viewModel: HomeViewModel
|
|
|
+ @State private var isHovered = false
|
|
|
+ @State private var isPresented = false
|
|
|
|
|
|
var body: some View {
|
|
|
- Menu {
|
|
|
- ForEach(viewModel.availableModels) { model in
|
|
|
- Button {
|
|
|
- viewModel.selectedModel = model
|
|
|
- } label: {
|
|
|
- if model.isPremium {
|
|
|
- Label(model.name, systemImage: "crown.fill")
|
|
|
- } else {
|
|
|
- Text(model.name)
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
+ Button {
|
|
|
+ isPresented.toggle()
|
|
|
} label: {
|
|
|
labelContent
|
|
|
}
|
|
|
- .menuStyle(.borderlessButton)
|
|
|
+ .buttonStyle(.plain)
|
|
|
.fixedSize()
|
|
|
+ .onHover { isHovered = $0 }
|
|
|
+ .popover(isPresented: $isPresented, arrowEdge: .bottom) {
|
|
|
+ modelPickerList
|
|
|
+ .frame(minWidth: 196)
|
|
|
+ }
|
|
|
.accessibilityLabel("Selected model, \(viewModel.selectedModel.name)")
|
|
|
+ .accessibilityHint("Opens model picker")
|
|
|
}
|
|
|
|
|
|
private var labelContent: some View {
|
|
|
- HStack(spacing: 5) {
|
|
|
+ HStack(spacing: 6) {
|
|
|
Text(viewModel.selectedModel.name)
|
|
|
- .font(.system(size: 13, weight: .semibold))
|
|
|
+ .font(.system(size: 12, weight: .semibold))
|
|
|
.foregroundStyle(AppTheme.textPrimary)
|
|
|
+ .lineLimit(1)
|
|
|
|
|
|
Image(systemName: "chevron.down")
|
|
|
- .font(.system(size: 9, weight: .bold))
|
|
|
+ .font(.system(size: 9, weight: .semibold))
|
|
|
.foregroundStyle(AppTheme.textSecondary)
|
|
|
}
|
|
|
.padding(.horizontal, 12)
|
|
|
- .padding(.vertical, 7)
|
|
|
+ .padding(.vertical, 8)
|
|
|
.background(
|
|
|
RoundedRectangle(cornerRadius: 10, style: .continuous)
|
|
|
- .fill(AppTheme.chatToolbarPillBackground)
|
|
|
+ .fill(isHovered ? AppTheme.controlBackground : Color.white)
|
|
|
)
|
|
|
+ .overlay(
|
|
|
+ RoundedRectangle(cornerRadius: 10, style: .continuous)
|
|
|
+ .stroke(AppTheme.chatActionButtonBorder, lineWidth: 1)
|
|
|
+ )
|
|
|
+ .contentShape(RoundedRectangle(cornerRadius: 10, style: .continuous))
|
|
|
+ }
|
|
|
+
|
|
|
+ private var modelPickerList: some View {
|
|
|
+ VStack(alignment: .leading, spacing: 2) {
|
|
|
+ ForEach(viewModel.availableModels) { model in
|
|
|
+ Button {
|
|
|
+ viewModel.selectedModel = model
|
|
|
+ isPresented = false
|
|
|
+ } label: {
|
|
|
+ HStack(spacing: 8) {
|
|
|
+ if model.isPremium {
|
|
|
+ Label(model.name, systemImage: "crown.fill")
|
|
|
+ } else {
|
|
|
+ Text(model.name)
|
|
|
+ }
|
|
|
+
|
|
|
+ Spacer(minLength: 12)
|
|
|
+
|
|
|
+ if viewModel.selectedModel == model {
|
|
|
+ Image(systemName: "checkmark")
|
|
|
+ .font(.system(size: 11, weight: .bold))
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .font(.system(size: 13))
|
|
|
+ .foregroundStyle(AppTheme.textPrimary)
|
|
|
+ .padding(.horizontal, 12)
|
|
|
+ .padding(.vertical, 7)
|
|
|
+ .frame(maxWidth: .infinity, alignment: .leading)
|
|
|
+ .contentShape(Rectangle())
|
|
|
+ }
|
|
|
+ .buttonStyle(.plain)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .padding(.vertical, 6)
|
|
|
}
|
|
|
}
|