Newer
Older
bremer-ios-app / BremerApp / View / SearchView.swift
yhornisse on 10 Sep 2023 7 KB Initial Commit
//
//  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("新しい名前を入力してください")
        }
    }
}