// // SearchView.swift // Bremer // // Created by yhornisse on 2023/07/17. // import SwiftUI import AVFoundation struct SearchView : View { @State private var searchText : String = "" @State private var showedLoginView = false @State private var showedUpdateAudioDialog = false @State private var showedErrorAlert = false @State private var showedSearchAudioDialog = false @State private var showedDeleteAudioDialog = false @State private var audioTargetSlug = "" @State private var audioTargetName = "" @State private var audioName = "" @State var artistName = "" @State private var albumName = "" @State private var localPath = "" @State private var tagName = "" @State private var errorAlertTitle = "" @EnvironmentObject private var audioPlayerViewModel : AudioPlayerViewModel @EnvironmentObject private var settingViewModel : SettingViewModel @ObservedObject private var searchAudioViewModel = SearchAudioViewModel() var body : some View { NavigationView { VStack { if settingViewModel.getSetting().baseUrl == "" { Text("Base URLを設定してください") } else if !searchAudioViewModel.messageText.isEmpty { if (searchAudioViewModel.hasError) { VStack { Text(searchAudioViewModel.messageText) .foregroundColor(.red) if searchAudioViewModel.messageText == "ログインしてください" { LoginButton(action: { self.showedLoginView = true }) } } } else { Text(searchAudioViewModel.messageText) } } List { ForEach(searchAudioViewModel.result, id:\.slug) { audio in Button(action: { audioPlayerViewModel.playAudioList( audioList: searchAudioViewModel.result, audio: audio, usedBy: "search") }) { Text("\(audio.name) - \(audio.album ?? "")") .font(.system(size: 14)) .frame(height: 35, alignment: .center) .aspectRatio(contentMode: .fit) } .swipeActions(edge: .trailing) { Button { self.audioTargetSlug = audio.slug self.audioTargetName = audio.name self.showedDeleteAudioDialog = true } label : { Text("削除") } .tint(.red) Button { self.audioTargetSlug = audio.slug self.audioName = audio.name self.artistName = audio.artist ?? "" self.albumName = audio.album ?? "" self.localPath = audio.localPath self.showedUpdateAudioDialog = true } label: { Text("変更") } .tint(.green) } } } .listStyle(.plain) .searchable(text: $searchText, prompt: "検索キーワード") .onSubmit(of: .search) { searchAudioViewModel.searchAudio(keyword: searchText) } .alert("更新", isPresented: $showedUpdateAudioDialog) { TextField("曲名", text: $audioName) TextField("歌手名", text: $artistName) TextField("アルバム名", text: $albumName) TextField("ローカルパス(変更不可)", text: $localPath) .disabled(true) // TODO 効かないがいずれ治す Button("OK", role: .cancel){ if audioName.isEmpty { self.errorAlertTitle = "名前の変更に失敗しました" self.showedErrorAlert = true return } if albumName.isEmpty { self.errorAlertTitle = "名前の変更に失敗しました" self.showedErrorAlert = true return } searchAudioViewModel.updateAudio( slug: audioTargetSlug, audioName: audioName, artistName: artistName, albumName: albumName) } Button("キャンセル", role: .destructive){ self.audioName = "" self.artistName = "" self.albumName = "" } } message: { Text("新しい名前を入力してください") } .confirmationDialog( "音楽削除", isPresented: $showedDeleteAudioDialog, actions: { Button("OK", role: .destructive){ searchAudioViewModel.deleteAudio(audioTargetSlug) } Button("キャンセル", role: .cancel){ self.audioTargetSlug = "" self.audioTargetName = "" } }, message: { Text( "本当に \(audioTargetName) を削除しますか?\n一度消すとアプリからは戻せません!") }) Spacer() Divider() AudioPlayerView(audioPlayerViewModel: audioPlayerViewModel) } .toolbar { ToolbarItem(placement: .navigationBarTrailing) { Button(action: { self.showedSearchAudioDialog = true }) { Image(systemName: "text.magnifyingglass") } } } } .onAppear { searchAudioViewModel.bremerApiBaseUrl = settingViewModel.getSetting().baseApiUrl() } .sheet(isPresented: $showedLoginView) { LoginWebView() .onDisappear { searchAudioViewModel.searchAudio(keyword: searchText) } } .scrollDismissesKeyboard(.immediately) .onReceive(NotificationCenter.default.publisher(for: AVAudioSession.routeChangeNotification), perform: { param in audioPlayerViewModel.onChangeAudioSessionRoute(param) }) .onReceive(NotificationCenter.default.publisher(for: AVAudioSession.interruptionNotification), perform: { param in audioPlayerViewModel.onInterrupted(param) }) .alert("詳細検索", isPresented: $showedSearchAudioDialog) { SearchDetailAlertView(searchAction: searchAudioViewModel.searchAudio) } message: { Text("新しい名前を入力してください") } } }