diff --git a/Bremer.xcodeproj/project.pbxproj b/Bremer.xcodeproj/project.pbxproj index ab10689..c747c4d 100644 --- a/Bremer.xcodeproj/project.pbxproj +++ b/Bremer.xcodeproj/project.pbxproj @@ -35,7 +35,6 @@ 38FB93612A9A16FA00967B01 /* SettingViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38FB93602A9A16FA00967B01 /* SettingViewModel.swift */; }; 38FB93632A9A257C00967B01 /* SettingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38FB93622A9A257C00967B01 /* SettingView.swift */; }; 38FB93672AA2DCA400967B01 /* SearchDetailAlertView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38FB93662AA2DCA400967B01 /* SearchDetailAlertView.swift */; }; - 38FB936F2AA2DE5D00967B01 /* RenameAudioAlertView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38FB936E2AA2DE5D00967B01 /* RenameAudioAlertView.swift */; }; 5DA23E753A5913DC36665E82 /* Pods_Bremer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9ABE7FFD426EF8354B37CD27 /* Pods_Bremer.framework */; }; /* End PBXBuildFile section */ @@ -74,7 +73,6 @@ 38FB93602A9A16FA00967B01 /* SettingViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingViewModel.swift; sourceTree = ""; }; 38FB93622A9A257C00967B01 /* SettingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingView.swift; sourceTree = ""; }; 38FB93662AA2DCA400967B01 /* SearchDetailAlertView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchDetailAlertView.swift; sourceTree = ""; }; - 38FB936E2AA2DE5D00967B01 /* RenameAudioAlertView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RenameAudioAlertView.swift; sourceTree = ""; }; 70A47812EFF9D6BB89E5CF8A /* Pods_BremerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_BremerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 74CD6B89272147713072414F /* Pods_Bremer_BremerUITests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Bremer_BremerUITests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 9ABE7FFD426EF8354B37CD27 /* Pods_Bremer.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Bremer.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -129,15 +127,14 @@ 38ECE1D02A4B31110044E913 /* LoginWebView.swift */, 3847F0202A6447C700DDB350 /* PlaylistView.swift */, 3847F0222A64FAA900DDB350 /* SearchView.swift */, - 38006C442A7FEE640027A05C /* TagView.swift */, 38006C422A7E42240027A05C /* AudioPlayerView.swift */, - 382AB95F2A8BBC5A00928393 /* ToastView.swift */, + 38006C442A7FEE640027A05C /* TagView.swift */, 382AB9612A90DC4300928393 /* LatestRecentlyPlayedView.swift */, 382AB96F2A93B9D900928393 /* LocalView.swift */, 38FB93622A9A257C00967B01 /* SettingView.swift */, + 38317EDC2AAC12C0003193B7 /* RenameAudioView.swift */, 38317EDB2AABF9AA003193B7 /* Component */, 38FB93702AA2DE7500967B01 /* Alert */, - 38317EDC2AAC12C0003193B7 /* RenameAudioView.swift */, ); path = View; sourceTree = ""; @@ -158,6 +155,7 @@ 38317EDB2AABF9AA003193B7 /* Component */ = { isa = PBXGroup; children = ( + 382AB95F2A8BBC5A00928393 /* ToastView.swift */, 38317ED92AA8BA15003193B7 /* NameAlertView.swift */, 3847F0282A6C121100DDB350 /* LoginButton.swift */, ); @@ -208,7 +206,6 @@ isa = PBXGroup; children = ( 38FB93662AA2DCA400967B01 /* SearchDetailAlertView.swift */, - 38FB936E2AA2DE5D00967B01 /* RenameAudioAlertView.swift */, ); path = Alert; sourceTree = ""; @@ -365,7 +362,6 @@ 38006C412A7E3FCC0027A05C /* ApiModel.swift in Sources */, 382AB9662A93B88800928393 /* PlaylistAudioViewModel.swift in Sources */, 382AB9622A90DC4300928393 /* LatestRecentlyPlayedView.swift in Sources */, - 38FB936F2AA2DE5D00967B01 /* RenameAudioAlertView.swift in Sources */, 3847F0292A6C121100DDB350 /* LoginButton.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/BremerApp/View/Alert/RenameAudioAlertView.swift b/BremerApp/View/Alert/RenameAudioAlertView.swift deleted file mode 100644 index 8108c8f..0000000 --- a/BremerApp/View/Alert/RenameAudioAlertView.swift +++ /dev/null @@ -1,46 +0,0 @@ -// -// RenameAudioAlertView.swift -// Bremer -// -// Created by yhornisse on 2023/09/02. -// - - -import SwiftUI - -struct RenameAudioAlertView : View { - @State - var audioInfo : AudioInfo - var onOk: (_ audioInfo: AudioInfo) -> Void - var onError: (_ message: String) -> Void - - var body : some View { - TextField("曲名", text: $audioInfo.audioName) - TextField("歌手名", text: $audioInfo.artistName) - TextField("アルバム名", text: $audioInfo.albumName) - TextField("ローカルパス(変更不可)", text: $audioInfo.localPath) - .disabled(true) // TODO 効かないがいずれ治す - Button("OK", role: .cancel){ - if audioInfo.audioName.isEmpty { - self.onError("名前の変更に失敗しました") - return - } - if audioInfo.albumName.isEmpty { - self.onError("名前の変更に失敗しました") - return - } - self.onOk(audioInfo) - clear() - } - Button("キャンセル", role: .destructive){ - clear() - } - } - - func clear() { - self.audioInfo.audioName = "" - self.audioInfo.artistName = "" - self.audioInfo.albumName = "" - } -} - diff --git a/BremerApp/View/Component/NameAlertView.swift b/BremerApp/View/Component/NameAlertView.swift index caa69b6..749d00b 100644 --- a/BremerApp/View/Component/NameAlertView.swift +++ b/BremerApp/View/Component/NameAlertView.swift @@ -20,6 +20,9 @@ var body : some View { TextField("\(label)名", text: $input) + Button("キャンセル", role: .destructive){ + self.input = "" + } Button("OK", role: .cancel){ if input.isEmpty { self.onError("\(label)の\(act)に失敗しました") @@ -28,8 +31,5 @@ self.onOk(input) self.input = "" } - Button("キャンセル", role: .destructive){ - self.input = "" - } } } diff --git a/BremerApp/View/LatestRecentlyPlayedView.swift b/BremerApp/View/LatestRecentlyPlayedView.swift index d8eca1a..00ebd35 100644 --- a/BremerApp/View/LatestRecentlyPlayedView.swift +++ b/BremerApp/View/LatestRecentlyPlayedView.swift @@ -13,8 +13,6 @@ @State private var showedLoginView = false @State - private var showedUpdateAudioDialog = false - @State private var audioTargetSlug = "" @State private var audioInfo = AudioInfo() @@ -22,6 +20,8 @@ private var errorAlertTitle = "" @State private var showedErrorAlert = false + @State + private var showedUpdateView = false @EnvironmentObject private var audioPlayerViewModel : AudioPlayerViewModel @EnvironmentObject @@ -67,7 +67,7 @@ self.audioInfo.artistName = audio.artist ?? "" self.audioInfo.albumName = audio.album ?? "" self.audioInfo.localPath = audio.localPath - self.showedUpdateAudioDialog = true + self.showedUpdateView = true } label: { Text("変更") } @@ -83,19 +83,14 @@ .sheet(isPresented: $showedLoginView) { LoginWebView() } - .alert("更新", isPresented: $showedUpdateAudioDialog) { - RenameAudioAlertView(audioInfo: self.audioInfo) {(audioInfo: AudioInfo) in + .sheet(isPresented: $showedUpdateView) { + RenameAudioView(audioInfo: self.audioInfo){(audioInfo : AudioInfo) in latestRecentlyPlayedAudioViewModel.updateAudio( - slug: audioTargetSlug, + slug: self.audioTargetSlug, audioName: audioInfo.audioName, artistName: audioInfo.artistName, albumName: audioInfo.albumName) - } onError: {(message: String) in - self.errorAlertTitle = message - self.showedErrorAlert = true } - } message: { - Text("新しい名前を入力してください") } .alert(errorAlertTitle, isPresented: $showedErrorAlert, actions: { Button(action: { diff --git a/BremerApp/View/PlaylistView.swift b/BremerApp/View/PlaylistView.swift index e0810c6..d62e27e 100644 --- a/BremerApp/View/PlaylistView.swift +++ b/BremerApp/View/PlaylistView.swift @@ -175,7 +175,8 @@ .swipeActions(edge: .trailing) { Button { // TODO 再生中の時は削除する必要ある - self.playlistAudioViewModel.deleteAudioInPlaylist(playlistSlug: slug, audioSlug: audio.slug) + self.playlistAudioViewModel.deleteAudioInPlaylist( + playlistSlug: slug, audioSlug: audio.slug) } label: { Text("削除") } @@ -236,11 +237,9 @@ @State private var toastMessage = "" @State - private var showedUpdateAudioDialog = false - @State var showedSearchAudioDialog = false @State - var shouldShowSecondView = false + var showedUpdateView = false var body : some View { NavigationView { @@ -294,8 +293,7 @@ self.audioInfo.artistName = audio.artist ?? "" self.audioInfo.albumName = audio.album ?? "" self.audioInfo.localPath = audio.localPath - // self.showedUpdateAudioDialog = true - self.shouldShowSecondView = true + self.showedUpdateView = true }) { Text("変更") } @@ -327,7 +325,7 @@ .sheet(isPresented: $showedLoginView) { LoginWebView() } - .sheet(isPresented: $shouldShowSecondView) { + .sheet(isPresented: $showedUpdateView) { RenameAudioView(audioInfo: self.audioInfo){(audioInfo : AudioInfo) in searchAudioViewModel.updateAudio( slug: self.audioTargetSlug, diff --git a/BremerApp/View/RenameAudioView.swift b/BremerApp/View/RenameAudioView.swift index 07e8a2c..2732dc4 100644 --- a/BremerApp/View/RenameAudioView.swift +++ b/BremerApp/View/RenameAudioView.swift @@ -34,13 +34,25 @@ .textSelection(.enabled) } Spacer() - HStack { - Button("保存") { + HStack(spacing: 40) { + Button(action: { onOk(audioInfo) dismiss() + }) { + Image(systemName: "arrow.triangle.2.circlepath") + .resizable() + .scaledToFill() + .frame(width: 60, height: 60) + .clipShape(Rectangle()) } - Button("キャンセル") { + Button(action: { dismiss() + }) { + Image(systemName: "xmark.circle") + .resizable() + .scaledToFill() + .frame(width: 60, height: 60) + .clipShape(Rectangle()) } } } diff --git a/BremerApp/View/SearchView.swift b/BremerApp/View/SearchView.swift index 7e94bf1..b6e0418 100644 --- a/BremerApp/View/SearchView.swift +++ b/BremerApp/View/SearchView.swift @@ -23,18 +23,14 @@ @State private var showedDeleteAudioDialog = false @State + private var showedUpdateView = false + @State private var audioTargetSlug = "" @State + private var audioInfo = AudioInfo() + @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 = "" @@ -87,11 +83,11 @@ .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 + self.audioInfo.audioName = audio.name + self.audioInfo.artistName = audio.artist ?? "" + self.audioInfo.albumName = audio.album ?? "" + self.audioInfo.localPath = audio.localPath + self.showedUpdateView = true } label: { Text("変更") } @@ -104,37 +100,6 @@ .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, @@ -172,6 +137,15 @@ searchAudioViewModel.searchAudio(keyword: searchText) } } + .sheet(isPresented: $showedUpdateView) { + RenameAudioView(audioInfo: self.audioInfo){(audioInfo : AudioInfo) in + searchAudioViewModel.updateAudio( + slug: self.audioTargetSlug, + audioName: audioInfo.audioName, + artistName: audioInfo.artistName, + albumName: audioInfo.albumName) + } + } .scrollDismissesKeyboard(.immediately) .onReceive(NotificationCenter.default.publisher(for: AVAudioSession.routeChangeNotification), perform: { param in audioPlayerViewModel.onChangeAudioSessionRoute(param) diff --git a/BremerApp/View/TagView.swift b/BremerApp/View/TagView.swift index d734b9f..e91b1c6 100644 --- a/BremerApp/View/TagView.swift +++ b/BremerApp/View/TagView.swift @@ -172,6 +172,11 @@ .tint(.red) } } + .onMove {src, dst in + self.audioPlayerViewModel.reorderAudioList(from: src, to: dst, usedBy: "tag") + self.tagAudioViewModel.reorderTagAudiolist(from: src, to: dst) + self.tagAudioViewModel.save(slug: self.slug) + } } .listStyle(.plain) .keyboardType(.default) @@ -211,7 +216,7 @@ @State private var showedLoginView = false @State - private var showedUpdateAudioDialog = false + private var showedUpdateView = false @State private var showedErrorAlert = false @State @@ -276,7 +281,7 @@ self.audioInfo.artistName = audio.artist ?? "" self.audioInfo.albumName = audio.album ?? "" self.audioInfo.localPath = audio.localPath - self.showedUpdateAudioDialog = true + self.showedUpdateView = true } label: { Text("変更") } @@ -289,20 +294,6 @@ .onSubmit(of: .search) { searchAudioViewModel.searchAudio(keyword: searchText) } - .alert("更新", isPresented: $showedUpdateAudioDialog) { - RenameAudioAlertView(audioInfo: self.audioInfo) {(audioInfo: AudioInfo) in - searchAudioViewModel.updateAudio( - slug: audioTargetSlug, - audioName: audioInfo.audioName, - artistName: audioInfo.artistName, - albumName: audioInfo.albumName) - } onError: {(message: String) in - self.errorAlertTitle = message - self.showedErrorAlert = true - } - } message: { - Text("新しい名前を入力してください") - } } if showedToast { VStack { @@ -322,6 +313,15 @@ .sheet(isPresented: $showedLoginView) { LoginWebView() } + .sheet(isPresented: $showedUpdateView) { + RenameAudioView(audioInfo: self.audioInfo){(audioInfo : AudioInfo) in + searchAudioViewModel.updateAudio( + slug: self.audioTargetSlug, + audioName: audioInfo.audioName, + artistName: audioInfo.artistName, + albumName: audioInfo.albumName) + } + } .scrollDismissesKeyboard(.immediately) .toolbar { ToolbarItem(placement: .navigationBarTrailing) { diff --git a/BremerApp/ViewModel/AudioPlayerViewModel.swift b/BremerApp/ViewModel/AudioPlayerViewModel.swift index 870d5b9..c4fdec9 100644 --- a/BremerApp/ViewModel/AudioPlayerViewModel.swift +++ b/BremerApp/ViewModel/AudioPlayerViewModel.swift @@ -158,14 +158,12 @@ if !self.audioQueue.contains(where: { $0.slug == audio.slug }) { self.audioQueue.append(audio) } - let file = FileManager.default.temporaryDirectory - .appendingPathComponent(UUID().uuidString) - .appendingPathExtension("tmp") + let file = "\(NSTemporaryDirectory())/\(UUID().uuidString).tmp" try FileManager.default.copyItem( - at: location, - to: file + atPath: location.path, + toPath: file ) - self.audioFileCache[audio.slug] = file + self.audioFileCache[audio.slug] = URL(string: file)! if let onDownload = onDownload { onDownload() } diff --git a/BremerApp/ViewModel/BremerApi.swift b/BremerApp/ViewModel/BremerApi.swift index ec85434..7df1e36 100644 --- a/BremerApp/ViewModel/BremerApi.swift +++ b/BremerApp/ViewModel/BremerApi.swift @@ -15,6 +15,7 @@ case is BremerConnectionError: return "Connection error" default: + print(error) return error.localizedDescription } } @@ -23,7 +24,7 @@ let cookie = UserDefaults.standard.string(forKey: "JSESSIONID") if cookie == nil { return Future { promise in - promise(.failure(BremerConnectionError())) + promise(.failure(BremerLoginError())) }.eraseToAnyPublisher() } var request:URLRequest = URLRequest(url: url) @@ -59,7 +60,7 @@ let cookie = UserDefaults.standard.string(forKey: "JSESSIONID") if cookie == nil { return Future { promise in - promise(.failure(BremerConnectionError())) + promise(.failure(BremerLoginError())) }.eraseToAnyPublisher() } var request:URLRequest = URLRequest(url: url) @@ -83,7 +84,7 @@ let cookie = UserDefaults.standard.string(forKey: "JSESSIONID") if cookie == nil { return Future { promise in - promise(.failure(BremerConnectionError())) + promise(.failure(BremerLoginError())) }.eraseToAnyPublisher() } var request:URLRequest = URLRequest(url: url) diff --git a/BremerApp/ViewModel/TagAudioViewModel.swift b/BremerApp/ViewModel/TagAudioViewModel.swift index 0975479..9a29b99 100644 --- a/BremerApp/ViewModel/TagAudioViewModel.swift +++ b/BremerApp/ViewModel/TagAudioViewModel.swift @@ -83,10 +83,30 @@ .store(in: &disposables) } - func reorderPlaylist(from: IndexSet, to: Int) { + func reorderTagAudiolist(from: IndexSet, to: Int) { self.result.move(fromOffsets: from, toOffset: to) } + func save(slug: String) { + sendApi(url: URL(string: "\(bremerApiBaseUrl)/tag/audio/\(slug)" + .addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!)!, + httpMethod: "PUT", + requestBody: TagAudioRequest(audioSlugs: result.map{ $0.slug })) + .sink { completion in + switch completion { + case .finished: + break + case .failure(let error): + self.hasError = true + self.messageText = getApiFailureTextByError(error) + } + } receiveValue: { (response : Any) in + self.hasError = false + self.messageText = "" + } + .store(in: &disposables) + } + func deleteAudioInTag(tagSlug: String, audio: Audio) { self.result.removeAll(where: { $0.slug == audio.slug }) sendApi(url: URL(string: "\(bremerApiBaseUrl)/tag/audio/\(tagSlug)"