From 007f6a8501d3ee7407315721b79304d87e645373 Mon Sep 17 00:00:00 2001 From: Fawkes100 Date: Sun, 19 Jan 2025 13:41:09 +0100 Subject: [PATCH] ADD: Handle Modified NoteSheeds --- .../notevault/data/dao/SongDao.java | 9 +++ .../notevault/data/entities/NoteSheet.java | 12 ++++ .../data/repositories/SongSyncRepository.java | 61 ++++++++++++++++--- .../notevault/network/sync/SongSyncAPI.java | 6 +- .../network/sync/SongSyncModule.java | 39 ++++++++---- .../network/sync/SongSyncService.java | 42 +++++++++++-- .../sync/models/NoteSheetModifyRequest.java | 27 ++++++++ .../sync/models/SongModifyBatchResponse.java | 16 +++++ .../sync/models/SongModifyRequest.java | 16 ++++- .../sync/models/SongModifyResponse.java | 25 ++++++++ 10 files changed, 224 insertions(+), 29 deletions(-) create mode 100644 app/src/main/java/com/stormtales/notevault/network/sync/models/NoteSheetModifyRequest.java create mode 100644 app/src/main/java/com/stormtales/notevault/network/sync/models/SongModifyBatchResponse.java create mode 100644 app/src/main/java/com/stormtales/notevault/network/sync/models/SongModifyResponse.java diff --git a/app/src/main/java/com/stormtales/notevault/data/dao/SongDao.java b/app/src/main/java/com/stormtales/notevault/data/dao/SongDao.java index 00d31ae..e108bee 100644 --- a/app/src/main/java/com/stormtales/notevault/data/dao/SongDao.java +++ b/app/src/main/java/com/stormtales/notevault/data/dao/SongDao.java @@ -60,4 +60,13 @@ public interface SongDao { @Query("SELECT localID FROM Song WHERE serverID IN (:serverIDs)") List getLocalSongIDsByServerIDs(List serverIDs); + + @Query("SELECT * FROM NoteSheet WHERE serverFileName IN (:serverFileNames)") + List getNoteSheetsByServerFileNames(List serverFileNames); + + @Query("SELECT * FROM NoteSheet WHERE syncStatus = :status") + List getNoteSheetsBySyncStatus(SyncStatus status); + + @Query("SELECT * FROM NoteSheet WHERE songID IN (:localSongIDs)") + List getNoteSheetFilesBySongIDs(List localSongIDs); } diff --git a/app/src/main/java/com/stormtales/notevault/data/entities/NoteSheet.java b/app/src/main/java/com/stormtales/notevault/data/entities/NoteSheet.java index 12309d7..8a38119 100644 --- a/app/src/main/java/com/stormtales/notevault/data/entities/NoteSheet.java +++ b/app/src/main/java/com/stormtales/notevault/data/entities/NoteSheet.java @@ -2,6 +2,7 @@ package com.stormtales.notevault.data.entities; import androidx.room.Entity; import androidx.room.PrimaryKey; +import com.stormtales.notevault.data.sync.SyncStatus; import java.util.Objects; @@ -14,9 +15,12 @@ public class NoteSheet { private String serverFileName; private String hash; + private SyncStatus syncStatus; + public NoteSheet(String localFileName, String hash) { this.localFileName = localFileName; this.hash = hash; + this.syncStatus = SyncStatus.CREATED; } public int getLocalID() { @@ -70,4 +74,12 @@ public class NoteSheet { public void setSongID(int songID) { this.songID = songID; } + + public SyncStatus getSyncStatus() { + return syncStatus; + } + + public void setSyncStatus(SyncStatus syncStatus) { + this.syncStatus = syncStatus; + } } diff --git a/app/src/main/java/com/stormtales/notevault/data/repositories/SongSyncRepository.java b/app/src/main/java/com/stormtales/notevault/data/repositories/SongSyncRepository.java index f9c52b8..ae1cb12 100644 --- a/app/src/main/java/com/stormtales/notevault/data/repositories/SongSyncRepository.java +++ b/app/src/main/java/com/stormtales/notevault/data/repositories/SongSyncRepository.java @@ -3,20 +3,20 @@ package com.stormtales.notevault.data.repositories; import android.content.Context; import android.os.Handler; import android.os.Looper; +import androidx.recyclerview.widget.AsyncListUtil; import com.stormtales.notevault.data.MusicDatabase; import com.stormtales.notevault.data.dao.SongDao; import com.stormtales.notevault.data.entities.NoteSheet; import com.stormtales.notevault.data.entities.Song; import com.stormtales.notevault.data.sync.SyncStatus; -import com.stormtales.notevault.network.sync.models.BatchCreateResponse; -import com.stormtales.notevault.network.sync.models.BatchModifyResponse; -import com.stormtales.notevault.network.sync.models.CreateResponse; -import com.stormtales.notevault.network.sync.models.UploadResponse; +import com.stormtales.notevault.network.sync.models.*; import java.io.File; import java.time.LocalDateTime; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.stream.Collectors; @@ -36,11 +36,16 @@ public class SongSyncRepository { }); } - public void loadModifiedSongs(LoadDataCallback> callback) { + public void loadModifiedSongs(LoadDataCallback>> callback) { Executors.newSingleThreadExecutor().execute(() -> { + Map> result = new HashMap<>(); List modifiedSongs = songDao.getSongsBySyncStatus(SyncStatus.MODIFIED); + for(Song song : modifiedSongs) { + List noteSheets = songDao.getNoteSheetsBySong(song.getLocalID()); + result.put(song, noteSheets); + } Handler mainHandler = new Handler(Looper.getMainLooper()); - mainHandler.post(()-> callback.onResult(modifiedSongs)); + mainHandler.post(()-> callback.onResult(result)); }); } @@ -78,13 +83,27 @@ public class SongSyncRepository { } } - public void markModifiedSongsAsSynced(BatchModifyResponse response) { + public void markModifiedSongsAsSynced(SongModifyBatchResponse modifyBatchResponse) { Executors.newSingleThreadExecutor().execute(() -> { - List requestedSongs = songDao.getSongsByServerIDs(response.getModifiedServerObjects()); + List serverIDs = modifyBatchResponse.getModifiedServerObjects().stream().map(SongModifyResponse::getServerID).collect(Collectors.toList()); + List requestedSongs = songDao.getSongsByServerIDs(serverIDs); for(Song song : requestedSongs) { song.setSyncStatus(SyncStatus.SYNCED); song.setSyncTime(LocalDateTime.now()); + + + for(SongModifyResponse modifyResponse : modifyBatchResponse.getModifiedServerObjects()) { + if(modifyResponse.getServerID().equals(song.getServerID())) { + List outdatedNoteSheets = songDao.getNoteSheetsByServerFileNames(modifyResponse.getOutdated_note_sheets()); + for(NoteSheet noteSheet : outdatedNoteSheets) { + noteSheet.setSyncStatus(SyncStatus.MODIFIED); + } + songDao.updateNoteSheets(outdatedNoteSheets); + } + } } + + songDao.updateSongs(requestedSongs); }); } @@ -96,9 +115,9 @@ public class SongSyncRepository { }); } - public void getNoteSheetFilesBySongIDs(List songIDs, LoadDataCallback> callback) { + public void getNoteSheetFilesBySongIDs(LoadDataCallback> callback) { Executors.newSingleThreadExecutor().execute(() -> { - List noteSheets = songDao.getNoteSheetsBySongIDs(songIDs); + List noteSheets = songDao.getNoteSheetsBySyncStatus(SyncStatus.CREATED); Handler mainHandler = new Handler(Looper.getMainLooper()); mainHandler.post(()-> callback.onResult(noteSheets)); }); @@ -114,6 +133,7 @@ public class SongSyncRepository { for(NoteSheet noteSheet : uploadedNoteSheets) { if(new File(noteSheet.getLocalFileName()).getName().equals(uploadResponse.getLocalFile())) { noteSheet.setServerFileName(uploadResponse.getServerFile()); + noteSheet.setSyncStatus(SyncStatus.SYNCED); break; } } @@ -122,6 +142,27 @@ public class SongSyncRepository { }); } + public void loadModifiedNoteSheets(LoadDataCallback> callback) { + Executors.newSingleThreadExecutor().execute(() -> { + List noteSheets = songDao.getNoteSheetsBySyncStatus(SyncStatus.MODIFIED); + Handler mainHandler = new Handler(Looper.getMainLooper()); + mainHandler.post(()-> callback.onResult(noteSheets)); + }); + } + + public void markModifiedNoteSheetsAsSynced(List uploadResponses) { + Executors.newSingleThreadExecutor().execute(() -> { + List serverFileNames = uploadResponses.stream().map(UploadResponse::getServerFile).collect(Collectors.toList()); + + + List noteSheets = songDao.getNoteSheetsByServerFileNames(serverFileNames); + for(NoteSheet noteSheet : noteSheets) { + noteSheet.setSyncStatus(SyncStatus.SYNCED); + } + songDao.updateNoteSheets(noteSheets); + }); + } + public interface LoadDataCallback { void onResult(T result); } diff --git a/app/src/main/java/com/stormtales/notevault/network/sync/SongSyncAPI.java b/app/src/main/java/com/stormtales/notevault/network/sync/SongSyncAPI.java index ba93d7b..a463ed3 100644 --- a/app/src/main/java/com/stormtales/notevault/network/sync/SongSyncAPI.java +++ b/app/src/main/java/com/stormtales/notevault/network/sync/SongSyncAPI.java @@ -17,7 +17,7 @@ public interface SongSyncAPI { Call syncCreatedSongs(@Body SongCreateBatchRequest songCreateBatchRequest); @POST("/sync/songs/modify") - Call syncModifiedSongs(@Body SongModifyBatchRequest songModifyBatchRequest); + Call syncModifiedSongs(@Body SongModifyBatchRequest songModifyBatchRequest); @POST("/sync/songs/delete") Call syncDeletedSongs(@Body SongBatchDeleteRequest songBatchDeleteRequest); @@ -25,4 +25,8 @@ public interface SongSyncAPI { @Multipart @POST("/sync/songs/note_sheet/upload") Call uploadNoteSheet(@Part("serverID")RequestBody serverID, @Part("fileName") RequestBody fileName, @Part MultipartBody.Part image); + + @Multipart + @POST("/sync/songs/note_sheet/update") + Call updateNoteSheet(@Part("server_filename") RequestBody server_filename, @Part MultipartBody.Part image); } diff --git a/app/src/main/java/com/stormtales/notevault/network/sync/SongSyncModule.java b/app/src/main/java/com/stormtales/notevault/network/sync/SongSyncModule.java index 4e4abee..bb99c96 100644 --- a/app/src/main/java/com/stormtales/notevault/network/sync/SongSyncModule.java +++ b/app/src/main/java/com/stormtales/notevault/network/sync/SongSyncModule.java @@ -6,6 +6,7 @@ import com.stormtales.notevault.data.repositories.SongRepository; import com.stormtales.notevault.data.repositories.SongSyncRepository; import com.stormtales.notevault.network.sync.models.BatchCreateResponse; import com.stormtales.notevault.network.sync.models.BatchModifyResponse; +import com.stormtales.notevault.network.sync.models.SongModifyBatchResponse; import com.stormtales.notevault.network.sync.models.UploadResponse; import com.stormtales.notevault.ui.gallery.GalleryViewModel; @@ -33,23 +34,39 @@ public class SongSyncModule { if(response.getCreateResponses().isEmpty()) { syncViewModel.finishCreateSongSyncing(); } else { - List songIDs = result.stream().map(Song::getLocalID).collect(Collectors.toList()); - songSyncRepository.getNoteSheetFilesBySongIDs(songIDs, noteSheets -> { - songSyncService.uploadNoteSheetsOfCreatedSongs(noteSheets, response, uploadResponses -> { - songSyncRepository.markCreatedNoteSheetsAsSynced(uploadResponses); - syncViewModel.finishCreateSongSyncing(); - }); - }); + uploadCreatedNoteSheets(result, response); } }); }); } + public void uploadCreatedNoteSheets(List result, BatchCreateResponse response) { + List songIDs = result.stream().map(Song::getLocalID).collect(Collectors.toList()); + songSyncRepository.getNoteSheetFilesBySongIDs(noteSheets -> { + songSyncService.uploadNoteSheetsOfCreatedSongs(noteSheets, response, uploadResponses -> { + songSyncRepository.markCreatedNoteSheetsAsSynced(uploadResponses); + syncViewModel.finishCreateSongSyncing(); + }); + }); + } + public void syncModifiedSongs() { songSyncRepository.loadModifiedSongs(result -> { - songSyncService.syncModifiedSongs(result, response -> { + songSyncService.syncModifiedSongs(result, (FinishSongSyncingCallback) response -> { songSyncRepository.markModifiedSongsAsSynced(response); - syncViewModel.finishModifiedSongSyncinc(); + uploadModifiedNoteSheets(); + }); + }); + } + + public void uploadModifiedNoteSheets() { + songSyncRepository.loadModifiedNoteSheets(modifiedNoteSheets -> { + songSyncService.uploadModifiedNoteSheets(modifiedNoteSheets, new SongSyncService.UploadNoteSheetCallback() { + @Override + public void finishUploadNoteSheets(List uploadResponses) { + songSyncRepository.markModifiedNoteSheetsAsSynced(uploadResponses); + syncViewModel.finishModifiedSongSyncinc(); + } }); }); } @@ -67,7 +84,7 @@ public class SongSyncModule { void finishSongSyncing(BatchCreateResponse response); } - public interface FinishSongSyncingCallback { - void finishSongSyncing(BatchModifyResponse response); + public interface FinishSongSyncingCallback { + void finishSongSyncing(T response); } } diff --git a/app/src/main/java/com/stormtales/notevault/network/sync/SongSyncService.java b/app/src/main/java/com/stormtales/notevault/network/sync/SongSyncService.java index 7d1eeda..63bff7d 100644 --- a/app/src/main/java/com/stormtales/notevault/network/sync/SongSyncService.java +++ b/app/src/main/java/com/stormtales/notevault/network/sync/SongSyncService.java @@ -1,6 +1,7 @@ package com.stormtales.notevault.network.sync; import android.content.Context; +import android.util.Log; import com.stormtales.notevault.data.entities.NoteSheet; import com.stormtales.notevault.data.entities.Song; import com.stormtales.notevault.network.NetworkModule; @@ -17,6 +18,7 @@ import retrofit2.Response; import java.io.File; import java.util.ArrayList; import java.util.List; +import java.util.Map; public class SongSyncService { private final SongSyncAPI songSyncAPI; @@ -79,20 +81,20 @@ public class SongSyncService { } } - public void syncModifiedSongs(List songs, SongSyncModule.FinishSongSyncingCallback callback) { + public void syncModifiedSongs(Map> songs, SongSyncModule.FinishSongSyncingCallback callback) { List modifyRequests = new ArrayList<>(); - for(Song song : songs) { - modifyRequests.add(new SongModifyRequest(song)); + for(Map.Entry> entry: songs.entrySet()) { + modifyRequests.add(new SongModifyRequest(entry.getKey(), entry.getValue())); } SongModifyBatchRequest songModifyBatchRequest = new SongModifyBatchRequest(modifyRequests); - songSyncAPI.syncModifiedSongs(songModifyBatchRequest).enqueue(new Callback() { + songSyncAPI.syncModifiedSongs(songModifyBatchRequest).enqueue(new Callback() { @Override - public void onResponse(Call call, Response response) { + public void onResponse(Call call, Response response) { callback.finishSongSyncing(response.body()); } @Override - public void onFailure(Call call, Throwable throwable) { + public void onFailure(Call call, Throwable throwable) { } }); @@ -125,6 +127,34 @@ public class SongSyncService { }); } + public void uploadModifiedNoteSheets(List modifiedNoteSheets, UploadNoteSheetCallback callback) { + List uploadResponses = new ArrayList<>(); + for(NoteSheet noteSheet : modifiedNoteSheets) { + RequestBody server_filename = RequestBody.create(MediaType.parse("text/plain"), noteSheet.getServerFileName()); + + RequestBody requestFile = RequestBody.create(MediaType.parse("image/**"), new File(noteSheet.getLocalFileName())); + MultipartBody.Part image = MultipartBody.Part.createFormData("image", noteSheet.getLocalFileName(), requestFile); + + songSyncAPI.updateNoteSheet(server_filename, image).enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + if(response.isSuccessful() && response.body() != null) { + uploadResponses.add(response.body()); + if(uploadResponses.size() == modifiedNoteSheets.size()) { + callback.finishUploadNoteSheets(uploadResponses); + } + } else { + Log.d("SongSyncService", "Something went wrong"); + } + } + + @Override + public void onFailure(Call call, Throwable throwable) { + Log.e("SongSyncService", "Upload failed: " + throwable.getMessage(), throwable); + } + }); + } + } public interface SyncDeletedSongsCallback { diff --git a/app/src/main/java/com/stormtales/notevault/network/sync/models/NoteSheetModifyRequest.java b/app/src/main/java/com/stormtales/notevault/network/sync/models/NoteSheetModifyRequest.java new file mode 100644 index 0000000..f5d9603 --- /dev/null +++ b/app/src/main/java/com/stormtales/notevault/network/sync/models/NoteSheetModifyRequest.java @@ -0,0 +1,27 @@ +package com.stormtales.notevault.network.sync.models; + +public class NoteSheetModifyRequest { + private String serverFileName; + private String clientHash; + + public NoteSheetModifyRequest(String serverFileName, String clientHash) { + this.serverFileName = serverFileName; + this.clientHash = clientHash; + } + + public String getServerFileName() { + return serverFileName; + } + + public void setServerFileName(String serverFileName) { + this.serverFileName = serverFileName; + } + + public String getClientHash() { + return clientHash; + } + + public void setClientHash(String clientHash) { + this.clientHash = clientHash; + } +} diff --git a/app/src/main/java/com/stormtales/notevault/network/sync/models/SongModifyBatchResponse.java b/app/src/main/java/com/stormtales/notevault/network/sync/models/SongModifyBatchResponse.java new file mode 100644 index 0000000..e475605 --- /dev/null +++ b/app/src/main/java/com/stormtales/notevault/network/sync/models/SongModifyBatchResponse.java @@ -0,0 +1,16 @@ +package com.stormtales.notevault.network.sync.models; + +import java.util.List; + +public class SongModifyBatchResponse { + + private List modifiedServerObjects; + + public List getModifiedServerObjects() { + return modifiedServerObjects; + } + + public void setModifiedServerObjects(List modifiedServerObjects) { + this.modifiedServerObjects = modifiedServerObjects; + } +} diff --git a/app/src/main/java/com/stormtales/notevault/network/sync/models/SongModifyRequest.java b/app/src/main/java/com/stormtales/notevault/network/sync/models/SongModifyRequest.java index 910b929..607f6b7 100644 --- a/app/src/main/java/com/stormtales/notevault/network/sync/models/SongModifyRequest.java +++ b/app/src/main/java/com/stormtales/notevault/network/sync/models/SongModifyRequest.java @@ -1,7 +1,11 @@ package com.stormtales.notevault.network.sync.models; +import com.stormtales.notevault.data.entities.NoteSheet; import com.stormtales.notevault.data.entities.Song; +import java.util.List; +import java.util.stream.Collectors; + public class SongModifyRequest { private String serverID; @@ -9,6 +13,7 @@ public class SongModifyRequest { private String composer; private String genre; private int year; + private List noteSheets; public SongModifyRequest(String serverID, String title, String composer, String genre, int year) { this.serverID = serverID; @@ -18,12 +23,13 @@ public class SongModifyRequest { this.year = year; } - public SongModifyRequest(Song song) { + public SongModifyRequest(Song song, List noteSheets) { this.serverID = song.getServerID(); this.title = song.getTitle(); this.composer = song.getComposer(); this.genre = song.getGenre(); this.year = song.getYear(); + this.noteSheets = noteSheets.stream().map(noteSheet -> new NoteSheetModifyRequest(noteSheet.getServerFileName(), noteSheet.getHash())).collect(Collectors.toList()); } public String getServerID() { @@ -65,4 +71,12 @@ public class SongModifyRequest { public void setYear(int year) { this.year = year; } + + public List getNoteSheets() { + return noteSheets; + } + + public void setNoteSheets(List noteSheets) { + this.noteSheets = noteSheets; + } } diff --git a/app/src/main/java/com/stormtales/notevault/network/sync/models/SongModifyResponse.java b/app/src/main/java/com/stormtales/notevault/network/sync/models/SongModifyResponse.java new file mode 100644 index 0000000..b798c33 --- /dev/null +++ b/app/src/main/java/com/stormtales/notevault/network/sync/models/SongModifyResponse.java @@ -0,0 +1,25 @@ +package com.stormtales.notevault.network.sync.models; + +import java.util.List; + +public class SongModifyResponse { + + private String serverID; + private List outdated_note_sheets; + + public List getOutdated_note_sheets() { + return outdated_note_sheets; + } + + public void setOutdated_note_sheets(List outdated_note_sheets) { + this.outdated_note_sheets = outdated_note_sheets; + } + + public String getServerID() { + return serverID; + } + + public void setServerID(String serverID) { + this.serverID = serverID; + } +}