ADD: Sync Deleted Songs with Server
This commit is contained in:
parent
191c50bac3
commit
ebe09e0ba1
@ -42,4 +42,10 @@ public interface SongDao {
|
|||||||
|
|
||||||
@Query("SELECT * FROM Song WHERE serverID IN (:serverIDs)")
|
@Query("SELECT * FROM Song WHERE serverID IN (:serverIDs)")
|
||||||
List<Song> getSongsByServerIDs(List<String> serverIDs);
|
List<Song> getSongsByServerIDs(List<String> serverIDs);
|
||||||
|
|
||||||
|
@Query("DELETE FROM Song WHERE serverID IN (:serverIDs)")
|
||||||
|
void deleteSongsByServerIDs(List<String> serverIDs);
|
||||||
|
|
||||||
|
@Query("DELETE FROM SONG WHERE localID IN (:localIDs)")
|
||||||
|
void deleteSongsByLocalIDs(List<Integer> localIDs);
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,14 @@ public class SongSyncRepository {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void loadDeletedSongs(LoadDataCallback<List<Song>> callback) {
|
||||||
|
Executors.newSingleThreadExecutor().execute(() -> {
|
||||||
|
List<Song> deletedSongs = songDao.getSongsBySyncStatus(SyncStatus.DELETED);
|
||||||
|
Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||||
|
mainHandler.post(()-> callback.onResult(deletedSongs));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public void markCreatedSongsAsSynced(BatchCreateResponse createdSongs) {
|
public void markCreatedSongsAsSynced(BatchCreateResponse createdSongs) {
|
||||||
Executors.newSingleThreadExecutor().execute(() -> {
|
Executors.newSingleThreadExecutor().execute(() -> {
|
||||||
List<Integer> localIDs = createdSongs.getCreateResponses().stream().map(CreateResponse::getLocalID).collect(Collectors.toList());
|
List<Integer> localIDs = createdSongs.getCreateResponses().stream().map(CreateResponse::getLocalID).collect(Collectors.toList());
|
||||||
@ -78,6 +86,13 @@ public class SongSyncRepository {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void markDeletedSongsAsSynced(List<String> remoteDeletedSongs, List<Integer> localDeletedSongs) {
|
||||||
|
Executors.newSingleThreadExecutor().execute(() -> {
|
||||||
|
songDao.deleteSongsByServerIDs(remoteDeletedSongs);
|
||||||
|
songDao.deleteSongsByLocalIDs(localDeletedSongs);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public interface LoadDataCallback<T> {
|
public interface LoadDataCallback<T> {
|
||||||
void onResult(T result);
|
void onResult(T result);
|
||||||
}
|
}
|
||||||
|
@ -2,10 +2,7 @@ package com.stormtales.notevault.network.sync;
|
|||||||
|
|
||||||
import com.stormtales.notevault.network.auth.LoginRequest;
|
import com.stormtales.notevault.network.auth.LoginRequest;
|
||||||
import com.stormtales.notevault.network.auth.LoginResponse;
|
import com.stormtales.notevault.network.auth.LoginResponse;
|
||||||
import com.stormtales.notevault.network.sync.models.BatchCreateResponse;
|
import com.stormtales.notevault.network.sync.models.*;
|
||||||
import com.stormtales.notevault.network.sync.models.BatchModifyResponse;
|
|
||||||
import com.stormtales.notevault.network.sync.models.SongCreateBatchRequest;
|
|
||||||
import com.stormtales.notevault.network.sync.models.SongModifyBatchRequest;
|
|
||||||
import retrofit2.Call;
|
import retrofit2.Call;
|
||||||
import retrofit2.http.Body;
|
import retrofit2.http.Body;
|
||||||
import retrofit2.http.POST;
|
import retrofit2.http.POST;
|
||||||
@ -17,4 +14,7 @@ public interface SongSyncAPI {
|
|||||||
|
|
||||||
@POST("/sync/songs/modify")
|
@POST("/sync/songs/modify")
|
||||||
Call<BatchModifyResponse> syncModifiedSongs(@Body SongModifyBatchRequest songModifyBatchRequest);
|
Call<BatchModifyResponse> syncModifiedSongs(@Body SongModifyBatchRequest songModifyBatchRequest);
|
||||||
|
|
||||||
|
@POST("/sync/songs/delete")
|
||||||
|
Call<BatchModifyResponse> syncDeletedSongs(@Body SongBatchDeleteRequest songBatchDeleteRequest);
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,8 @@ import com.stormtales.notevault.network.sync.models.BatchCreateResponse;
|
|||||||
import com.stormtales.notevault.network.sync.models.BatchModifyResponse;
|
import com.stormtales.notevault.network.sync.models.BatchModifyResponse;
|
||||||
import com.stormtales.notevault.ui.gallery.GalleryViewModel;
|
import com.stormtales.notevault.ui.gallery.GalleryViewModel;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class SongSyncModule {
|
public class SongSyncModule {
|
||||||
private SongRepository songRepository;
|
private SongRepository songRepository;
|
||||||
private SongSyncRepository songSyncRepository;
|
private SongSyncRepository songSyncRepository;
|
||||||
@ -38,6 +40,15 @@ public class SongSyncModule {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void syncDeletedSongs() {
|
||||||
|
songSyncRepository.loadDeletedSongs(result -> {
|
||||||
|
songSyncService.syncDeletedSong(result, (remoteDeletedSongs, localDeletedSongs) -> {
|
||||||
|
songSyncRepository.markDeletedSongsAsSynced(remoteDeletedSongs, localDeletedSongs);
|
||||||
|
syncViewModel.finishDeleteSongSyncinc();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public interface FinishSongCreateSyncingCallback {
|
public interface FinishSongCreateSyncingCallback {
|
||||||
void finishSongSyncing(BatchCreateResponse response);
|
void finishSongSyncing(BatchCreateResponse response);
|
||||||
}
|
}
|
||||||
|
@ -58,4 +58,37 @@ public class SongSyncService {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void syncDeletedSong(List<Song> songs, SyncDeletedSongsCallback callback) {
|
||||||
|
List<String> deleteRequests = new ArrayList<>();
|
||||||
|
List<Integer> deletedNotSyncedSongs = new ArrayList<>();
|
||||||
|
for(Song song : songs) {
|
||||||
|
if(song.getServerID() == null) {
|
||||||
|
deletedNotSyncedSongs.add(song.getLocalID());
|
||||||
|
} else {
|
||||||
|
deleteRequests.add(song.getServerID());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SongBatchDeleteRequest songBatchDeleteRequest = new SongBatchDeleteRequest(deleteRequests);
|
||||||
|
songSyncAPI.syncDeletedSongs(songBatchDeleteRequest).enqueue(new Callback<BatchModifyResponse>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call<BatchModifyResponse> call, Response<BatchModifyResponse> response) {
|
||||||
|
if(response.isSuccessful() && response.body() != null) {
|
||||||
|
callback.finishSongSyncing(response.body().getModifiedServerObjects(), deletedNotSyncedSongs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<BatchModifyResponse> call, Throwable throwable) {
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public interface SyncDeletedSongsCallback {
|
||||||
|
void finishSongSyncing(List<String> remoteDeletedSongs, List<Integer> localDeletedSongs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,19 @@
|
|||||||
|
package com.stormtales.notevault.network.sync.models;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class SongBatchDeleteRequest {
|
||||||
|
private List<String> songs;
|
||||||
|
|
||||||
|
public SongBatchDeleteRequest(List<String> songs) {
|
||||||
|
this.songs = songs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getSongs() {
|
||||||
|
return songs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSongs(List<String> songs) {
|
||||||
|
this.songs = songs;
|
||||||
|
}
|
||||||
|
}
|
@ -24,6 +24,8 @@ public class GalleryFragment extends Fragment {
|
|||||||
private Button sync_created_songs_btn;
|
private Button sync_created_songs_btn;
|
||||||
private ProgressBar progress_sync_modified_songs;
|
private ProgressBar progress_sync_modified_songs;
|
||||||
private Button sync_modified_songs_btn;
|
private Button sync_modified_songs_btn;
|
||||||
|
private ProgressBar progress_sync_deleted_songs;
|
||||||
|
private Button sync_deleted_songs_btn;
|
||||||
|
|
||||||
|
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater,
|
public View onCreateView(@NonNull LayoutInflater inflater,
|
||||||
@ -36,10 +38,15 @@ public class GalleryFragment extends Fragment {
|
|||||||
progress_sync_created_songs = binding.progressSyncCreatedSongs;
|
progress_sync_created_songs = binding.progressSyncCreatedSongs;
|
||||||
sync_created_songs_btn = binding.syncCreatedBtn;
|
sync_created_songs_btn = binding.syncCreatedBtn;
|
||||||
sync_created_songs_btn.setOnClickListener(v -> onSyncCreatedSongs());
|
sync_created_songs_btn.setOnClickListener(v -> onSyncCreatedSongs());
|
||||||
|
|
||||||
progress_sync_modified_songs = binding.progressSyncModifiedSongs;
|
progress_sync_modified_songs = binding.progressSyncModifiedSongs;
|
||||||
sync_modified_songs_btn = binding.syncModifiedBtn;
|
sync_modified_songs_btn = binding.syncModifiedBtn;
|
||||||
sync_modified_songs_btn.setOnClickListener(v -> onSyncModifiedSogs());
|
sync_modified_songs_btn.setOnClickListener(v -> onSyncModifiedSogs());
|
||||||
|
|
||||||
|
progress_sync_deleted_songs = binding.progressSyncDeletedSongs;
|
||||||
|
sync_deleted_songs_btn = binding.syncDeletedBtn;
|
||||||
|
sync_deleted_songs_btn.setOnClickListener(v -> onSyncDeletedSongs());
|
||||||
|
|
||||||
galleryViewModel.setSongSyncModule(new SongSyncModule(getContext(), galleryViewModel));
|
galleryViewModel.setSongSyncModule(new SongSyncModule(getContext(), galleryViewModel));
|
||||||
|
|
||||||
galleryViewModel.getIsCreatedSongSyncing().observe(getViewLifecycleOwner(), isCreatedSyncinc -> {
|
galleryViewModel.getIsCreatedSongSyncing().observe(getViewLifecycleOwner(), isCreatedSyncinc -> {
|
||||||
@ -61,9 +68,23 @@ public class GalleryFragment extends Fragment {
|
|||||||
sync_modified_songs_btn.setEnabled(true);
|
sync_modified_songs_btn.setEnabled(true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
galleryViewModel.getIsDeletedSongSyncing().observe(getViewLifecycleOwner(), isDeletedSyncinc -> {
|
||||||
|
if(isDeletedSyncinc) {
|
||||||
|
progress_sync_deleted_songs.setIndeterminate(true);
|
||||||
|
sync_deleted_songs_btn.setEnabled(false);
|
||||||
|
} else {
|
||||||
|
progress_sync_deleted_songs.setIndeterminate(false);
|
||||||
|
sync_deleted_songs_btn.setEnabled(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onSyncDeletedSongs() {
|
||||||
|
galleryViewModel.startDeletedSongSyncing();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroyView() {
|
public void onDestroyView() {
|
||||||
|
@ -10,6 +10,7 @@ public class GalleryViewModel extends ViewModel {
|
|||||||
|
|
||||||
private final MutableLiveData<Boolean> isCreatedSongSyncing;
|
private final MutableLiveData<Boolean> isCreatedSongSyncing;
|
||||||
private final MutableLiveData<Boolean> isModifiedSongSyncing;
|
private final MutableLiveData<Boolean> isModifiedSongSyncing;
|
||||||
|
private final MutableLiveData<Boolean> isDeletedSongSyncing;
|
||||||
private SongSyncModule songSyncModule;
|
private SongSyncModule songSyncModule;
|
||||||
|
|
||||||
public GalleryViewModel() {
|
public GalleryViewModel() {
|
||||||
@ -19,6 +20,9 @@ public class GalleryViewModel extends ViewModel {
|
|||||||
|
|
||||||
isModifiedSongSyncing = new MutableLiveData<>();
|
isModifiedSongSyncing = new MutableLiveData<>();
|
||||||
isModifiedSongSyncing.setValue(false);
|
isModifiedSongSyncing.setValue(false);
|
||||||
|
|
||||||
|
isDeletedSongSyncing = new MutableLiveData<>();
|
||||||
|
isDeletedSongSyncing.setValue(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MutableLiveData<Boolean> getIsCreatedSongSyncing() {
|
public MutableLiveData<Boolean> getIsCreatedSongSyncing() {
|
||||||
@ -53,4 +57,18 @@ public class GalleryViewModel extends ViewModel {
|
|||||||
public void finishModifiedSongSyncinc() {
|
public void finishModifiedSongSyncinc() {
|
||||||
this.isModifiedSongSyncing.setValue(false);
|
this.isModifiedSongSyncing.setValue(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MutableLiveData<Boolean> getIsDeletedSongSyncing() {
|
||||||
|
return isDeletedSongSyncing;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void startDeletedSongSyncing() {
|
||||||
|
if(this.songSyncModule == null) throw new RuntimeException("SongSyncModule is not initialized");
|
||||||
|
this.isDeletedSongSyncing.setValue(true);
|
||||||
|
this.songSyncModule.syncDeletedSongs();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void finishDeleteSongSyncinc() {
|
||||||
|
this.isDeletedSongSyncing.setValue(false);
|
||||||
|
}
|
||||||
}
|
}
|
@ -103,6 +103,49 @@
|
|||||||
android:layout_marginEnd="16dp" />
|
android:layout_marginEnd="16dp" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
<!-- Deleted Songs Sync Section -->
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<!-- Label -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/sync_deleted_songs"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Sync Client Side Deleted Songs"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textColor="@android:color/black"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
android:layout_marginEnd="8dp" />
|
||||||
|
|
||||||
|
<!-- Progress Bar -->
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/progress_sync_deleted_songs"
|
||||||
|
style="?android:attr/progressBarStyleHorizontal"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="44dp"
|
||||||
|
android:indeterminate="true"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/sync_deleted_songs"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/sync_deleted_btn"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/sync_deleted_songs"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/sync_deleted_songs" />
|
||||||
|
|
||||||
|
<!-- Sync Button -->
|
||||||
|
<Button
|
||||||
|
android:id="@+id/sync_deleted_btn"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Sync"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/sync_deleted_songs"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/sync_deleted_songs"
|
||||||
|
android:layout_marginEnd="16dp" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
Loading…
Reference in New Issue
Block a user