MNN/apps/iOS/MNNLLMChat/MNNLLMiOS/MainTab/MainTabView.swift

186 lines
7.3 KiB
Swift
Raw Normal View History

2025-06-20 17:39:06 +08:00
//
// MNNLLMiOSApp.swift
// MainTabView
//
// Created by () on 2025/06/20.
//
import SwiftUI
struct MainTabView: View {
@State private var showHistory = false
@State private var selectedHistory: ChatHistory? = nil
@State private var histories: [ChatHistory] = ChatHistoryManager.shared.getAllHistory()
@State private var showHistoryButton = true
2025-06-24 17:11:07 +08:00
@State private var showSettings = false
@State private var showWebView = false
@State private var webViewURL: URL?
@StateObject private var modelListViewModel = ModelListViewModel()
@State private var selectedTab: Int = 0
@State private var titles = ["本地模型", "模型市场", "Benchmark"]
2025-06-20 17:39:06 +08:00
var body: some View {
2025-06-25 17:12:04 +08:00
ZStack {
NavigationView {
TabView(selection: $selectedTab) {
LocalModelListView(viewModel: modelListViewModel)
.tabItem {
Image(systemName: "house.fill")
Text("本地模型")
}
.tag(0)
ModelListView(viewModel: modelListViewModel)
.tabItem {
Image(systemName: "cart.fill")
Text("模型市场")
}
.tag(1)
BenchmarkView()
.tabItem {
Image(systemName: "clock.fill")
Text("Benchmark")
}
.tag(2)
}
2025-06-25 17:12:04 +08:00
.background(NavigationLink(destination: chatDestination, isActive: chatIsActiveBinding) { EmptyView() })
.navigationTitle(titles[selectedTab])
.navigationBarTitleDisplayMode(.inline)
.navigationBarHidden(false)
.onAppear(perform: setupNavigationBarAppearance)
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
if showHistoryButton {
Button(action: {
showHistory = true
showHistoryButton = false
histories = ChatHistoryManager.shared.getAllHistory()
}) {
Image(systemName: "sidebar.left")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 20, height: 20)
}
}
2025-06-25 17:12:04 +08:00
}
2025-06-26 16:06:25 +08:00
2025-06-25 17:12:04 +08:00
ToolbarItem(placement: .navigationBarTrailing) {
2025-06-25 17:45:26 +08:00
if selectedTab == 1 {
Button(action: {
showSettings.toggle()
}) {
Image(systemName: "gear")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 20, height: 20)
}
} else {
Button(action: {
if let url = URL(string: "https://github.com/alibaba/MNN") {
UIApplication.shared.open(url)
}
}) {
Image(systemName: "star")
.aspectRatio(contentMode: .fit)
.frame(width: 20, height: 20)
}
}
}
}
}
2025-06-25 17:12:04 +08:00
if showHistory {
Color.black.opacity(0.5)
.edgesIgnoringSafeArea(.all)
.onTapGesture {
withAnimation {
2025-06-25 17:12:04 +08:00
showHistory = false
}
}
}
2025-06-25 17:12:04 +08:00
SideMenuView(isOpen: $showHistory, selectedHistory: $selectedHistory, histories: $histories)
.edgesIgnoringSafeArea(.all)
}
.onChange(of: showHistory) { newValue in
if !newValue {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
withAnimation {
showHistoryButton = true
}
2025-06-20 17:39:06 +08:00
}
}
2025-06-25 17:12:04 +08:00
}
.sheet(isPresented: $showWebView) {
if let url = webViewURL {
WebView(url: url)
2025-06-24 17:11:07 +08:00
}
}
2025-06-25 17:12:04 +08:00
.actionSheet(isPresented: $showSettings) {
ActionSheet(title: Text("Settings"), buttons: [
.default(Text("Report an Issue")) {
webViewURL = URL(string: "https://github.com/alibaba/MNN/issues")
showWebView = true
},
.default(Text("Go to MNN Homepage")) {
webViewURL = URL(string: "https://github.com/alibaba/MNN")
showWebView = true
},
.default(Text(ModelSource.modelScope.description)) {
ModelSourceManager.shared.updateSelectedSource(.modelScope)
},
.default(Text(ModelSource.modeler.description)) {
ModelSourceManager.shared.updateSelectedSource(.modeler)
},
.default(Text(ModelSource.huggingFace.description)) {
ModelSourceManager.shared.updateSelectedSource(.huggingFace)
},
.cancel()
])
}
}
@ViewBuilder
private var chatDestination: some View {
if let model = modelListViewModel.selectedModel {
LLMChatView(modelInfo: model)
} else if let history = selectedHistory {
let modelInfo = ModelInfo(
modelId: history.modelId,
createdAt: "",
downloads: 0,
tags: [],
isDownloaded: true
)
LLMChatView(modelInfo: modelInfo, history: history)
} else {
EmptyView()
2025-06-24 17:11:07 +08:00
}
2025-06-20 17:39:06 +08:00
}
private var chatIsActiveBinding: Binding<Bool> {
Binding<Bool>(
get: { modelListViewModel.selectedModel != nil || selectedHistory != nil },
set: { isActive in
if !isActive {
2025-06-26 16:06:25 +08:00
if let model = modelListViewModel.selectedModel {
modelListViewModel.recordModelUsage(modelId: model.modelId)
}
modelListViewModel.selectedModel = nil
selectedHistory = nil
}
}
)
}
private func setupNavigationBarAppearance() {
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = .white
appearance.shadowColor = .clear // Optional: remove the shadow
UINavigationBar.appearance().standardAppearance = appearance
UINavigationBar.appearance().compactAppearance = appearance
UINavigationBar.appearance().scrollEdgeAppearance = appearance
}
2025-06-20 17:39:06 +08:00
}