nextNoteVault #23
@ -42,4 +42,10 @@ public interface SongDao {
 | 
			
		||||
 | 
			
		||||
    @Query("SELECT * FROM Song WHERE serverID IN (: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) {
 | 
			
		||||
        Executors.newSingleThreadExecutor().execute(() -> {
 | 
			
		||||
            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> {
 | 
			
		||||
        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.LoginResponse;
 | 
			
		||||
import com.stormtales.notevault.network.sync.models.BatchCreateResponse;
 | 
			
		||||
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 com.stormtales.notevault.network.sync.models.*;
 | 
			
		||||
import retrofit2.Call;
 | 
			
		||||
import retrofit2.http.Body;
 | 
			
		||||
import retrofit2.http.POST;
 | 
			
		||||
@ -17,4 +14,7 @@ public interface SongSyncAPI {
 | 
			
		||||
 | 
			
		||||
    @POST("/sync/songs/modify")
 | 
			
		||||
    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.ui.gallery.GalleryViewModel;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class SongSyncModule {
 | 
			
		||||
    private SongRepository songRepository;
 | 
			
		||||
    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 {
 | 
			
		||||
        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 ProgressBar progress_sync_modified_songs;
 | 
			
		||||
    private Button sync_modified_songs_btn;
 | 
			
		||||
    private ProgressBar progress_sync_deleted_songs;
 | 
			
		||||
    private Button sync_deleted_songs_btn;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public View onCreateView(@NonNull LayoutInflater inflater,
 | 
			
		||||
@ -36,10 +38,15 @@ public class GalleryFragment extends Fragment {
 | 
			
		||||
        progress_sync_created_songs = binding.progressSyncCreatedSongs;
 | 
			
		||||
        sync_created_songs_btn = binding.syncCreatedBtn;
 | 
			
		||||
        sync_created_songs_btn.setOnClickListener(v -> onSyncCreatedSongs());
 | 
			
		||||
 | 
			
		||||
        progress_sync_modified_songs = binding.progressSyncModifiedSongs;
 | 
			
		||||
        sync_modified_songs_btn = binding.syncModifiedBtn;
 | 
			
		||||
        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.getIsCreatedSongSyncing().observe(getViewLifecycleOwner(), isCreatedSyncinc -> {
 | 
			
		||||
@ -61,9 +68,23 @@ public class GalleryFragment extends Fragment {
 | 
			
		||||
                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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void onSyncDeletedSongs() {
 | 
			
		||||
        galleryViewModel.startDeletedSongSyncing();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onDestroyView() {
 | 
			
		||||
 | 
			
		||||
@ -10,6 +10,7 @@ public class GalleryViewModel extends ViewModel {
 | 
			
		||||
 | 
			
		||||
    private final MutableLiveData<Boolean> isCreatedSongSyncing;
 | 
			
		||||
    private final MutableLiveData<Boolean> isModifiedSongSyncing;
 | 
			
		||||
    private final MutableLiveData<Boolean> isDeletedSongSyncing;
 | 
			
		||||
    private SongSyncModule songSyncModule;
 | 
			
		||||
 | 
			
		||||
    public GalleryViewModel() {
 | 
			
		||||
@ -19,6 +20,9 @@ public class GalleryViewModel extends ViewModel {
 | 
			
		||||
 | 
			
		||||
        isModifiedSongSyncing = new MutableLiveData<>();
 | 
			
		||||
        isModifiedSongSyncing.setValue(false);
 | 
			
		||||
 | 
			
		||||
        isDeletedSongSyncing = new MutableLiveData<>();
 | 
			
		||||
        isDeletedSongSyncing.setValue(false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public MutableLiveData<Boolean> getIsCreatedSongSyncing() {
 | 
			
		||||
@ -53,4 +57,18 @@ public class GalleryViewModel extends ViewModel {
 | 
			
		||||
    public void finishModifiedSongSyncinc() {
 | 
			
		||||
        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" />
 | 
			
		||||
 | 
			
		||||
        </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>
 | 
			
		||||
</androidx.constraintlayout.widget.ConstraintLayout>
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user