nextNoteVault #23
@ -163,6 +163,16 @@ public class SongSyncRepository {
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void markSongsAsRemotelyModified(List<String> serverIDs) {
 | 
			
		||||
        Executors.newSingleThreadExecutor().execute(() -> {
 | 
			
		||||
            List<Song> songs = songDao.getSongsByServerIDs(serverIDs);
 | 
			
		||||
            for(Song song : songs) {
 | 
			
		||||
                song.setSyncStatus(SyncStatus.REMOTE_MODIFIED);
 | 
			
		||||
            }
 | 
			
		||||
            songDao.updateSongs(songs);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public interface LoadDataCallback<T> {
 | 
			
		||||
        void onResult(T result);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -6,10 +6,9 @@ import com.stormtales.notevault.network.sync.models.*;
 | 
			
		||||
import okhttp3.MultipartBody;
 | 
			
		||||
import okhttp3.RequestBody;
 | 
			
		||||
import retrofit2.Call;
 | 
			
		||||
import retrofit2.http.Body;
 | 
			
		||||
import retrofit2.http.Multipart;
 | 
			
		||||
import retrofit2.http.POST;
 | 
			
		||||
import retrofit2.http.Part;
 | 
			
		||||
import retrofit2.http.*;
 | 
			
		||||
 | 
			
		||||
import java.time.LocalDateTime;
 | 
			
		||||
 | 
			
		||||
public interface SongSyncAPI {
 | 
			
		||||
 | 
			
		||||
@ -29,4 +28,7 @@ public interface SongSyncAPI {
 | 
			
		||||
    @Multipart
 | 
			
		||||
    @POST("/sync/songs/note_sheet/update")
 | 
			
		||||
    Call<UploadResponse> updateNoteSheet(@Part("server_filename") RequestBody server_filename, @Part MultipartBody.Part image);
 | 
			
		||||
 | 
			
		||||
    @GET("/sync/songs/fetch")
 | 
			
		||||
    Call<FetchResponse> fetchRemoteModifiedSongs(@Query(value = "last_client_sync") String last_client_sync);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -4,12 +4,10 @@ import android.content.Context;
 | 
			
		||||
import com.stormtales.notevault.data.entities.Song;
 | 
			
		||||
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.network.sync.models.*;
 | 
			
		||||
import com.stormtales.notevault.ui.gallery.GalleryViewModel;
 | 
			
		||||
 | 
			
		||||
import java.time.LocalDateTime;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
@ -80,6 +78,17 @@ public class SongSyncModule {
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void fetchRemoteModifiedSongs() {
 | 
			
		||||
        //Todo: Determine Last Client Sync; for testing use LocalDateTime.MIN
 | 
			
		||||
        songSyncService.fetchRemoteModifiedSongs(LocalDateTime.now().minusDays(35), new SongSyncRepository.LoadDataCallback<FetchResponse>() {
 | 
			
		||||
            @Override
 | 
			
		||||
            public void onResult(FetchResponse result) {
 | 
			
		||||
                songSyncRepository.markSongsAsRemotelyModified(result.getServerIDs());
 | 
			
		||||
                syncViewModel.finishFetching();
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public interface FinishSongCreateSyncingCallback {
 | 
			
		||||
        void finishSongSyncing(BatchCreateResponse response);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -4,6 +4,7 @@ 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.data.repositories.SongSyncRepository;
 | 
			
		||||
import com.stormtales.notevault.network.NetworkModule;
 | 
			
		||||
import com.stormtales.notevault.network.auth.AuthAPI;
 | 
			
		||||
import com.stormtales.notevault.network.sync.models.*;
 | 
			
		||||
@ -16,6 +17,8 @@ import retrofit2.Callback;
 | 
			
		||||
import retrofit2.Response;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.time.LocalDateTime;
 | 
			
		||||
import java.time.format.DateTimeFormatter;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
@ -156,6 +159,23 @@ public class SongSyncService {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void fetchRemoteModifiedSongs(LocalDateTime lastClientSync, SongSyncRepository.LoadDataCallback<FetchResponse> callback) {
 | 
			
		||||
        String formattedTime = lastClientSync.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
 | 
			
		||||
        songSyncAPI.fetchRemoteModifiedSongs(formattedTime).enqueue(new Callback<FetchResponse>() {
 | 
			
		||||
            @Override
 | 
			
		||||
            public void onResponse(Call<FetchResponse> call, Response<FetchResponse> response) {
 | 
			
		||||
                if(response.isSuccessful() && response.body() != null) {
 | 
			
		||||
                    callback.onResult(response.body());
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            @Override
 | 
			
		||||
            public void onFailure(Call<FetchResponse> call, Throwable throwable) {
 | 
			
		||||
                Log.d("SongSyncService", "Fetch failed: " + throwable.getMessage(), throwable);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public interface SyncDeletedSongsCallback {
 | 
			
		||||
        void finishSongSyncing(List<String> remoteDeletedSongs, List<Integer> localDeletedSongs);
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,15 @@
 | 
			
		||||
package com.stormtales.notevault.network.sync.models;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class FetchResponse {
 | 
			
		||||
    private List<String> serverIDs;
 | 
			
		||||
 | 
			
		||||
    public List<String> getServerIDs() {
 | 
			
		||||
        return serverIDs;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setServerIDs(List<String> serverIDs) {
 | 
			
		||||
        this.serverIDs = serverIDs;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -27,6 +27,9 @@ public class GalleryFragment extends Fragment {
 | 
			
		||||
    private ProgressBar progress_sync_deleted_songs;
 | 
			
		||||
    private Button sync_deleted_songs_btn;
 | 
			
		||||
 | 
			
		||||
    private ProgressBar progress_fetching_songs;
 | 
			
		||||
    private Button sync_fetching_songs_btn;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public View onCreateView(@NonNull LayoutInflater inflater,
 | 
			
		||||
                             ViewGroup container, Bundle savedInstanceState) {
 | 
			
		||||
@ -47,6 +50,10 @@ public class GalleryFragment extends Fragment {
 | 
			
		||||
        sync_deleted_songs_btn = binding.syncDeletedBtn;
 | 
			
		||||
        sync_deleted_songs_btn.setOnClickListener(v -> onSyncDeletedSongs());
 | 
			
		||||
 | 
			
		||||
        progress_fetching_songs = binding.progressFetchSongs;
 | 
			
		||||
        sync_fetching_songs_btn = binding.fetchSongsBtn;
 | 
			
		||||
        sync_fetching_songs_btn.setOnClickListener(v -> onFetchRemoteModifiedSongs());
 | 
			
		||||
 | 
			
		||||
        galleryViewModel.setSongSyncModule(new SongSyncModule(getContext(), galleryViewModel));
 | 
			
		||||
 | 
			
		||||
        galleryViewModel.getIsCreatedSongSyncing().observe(getViewLifecycleOwner(), isCreatedSyncinc -> {
 | 
			
		||||
@ -78,9 +85,23 @@ public class GalleryFragment extends Fragment {
 | 
			
		||||
                sync_deleted_songs_btn.setEnabled(true);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        galleryViewModel.getIsFetchingActive().observe(getViewLifecycleOwner(), isFetchingActiveSyncinc -> {
 | 
			
		||||
            if(isFetchingActiveSyncinc) {
 | 
			
		||||
                progress_fetching_songs.setIndeterminate(true);
 | 
			
		||||
                sync_fetching_songs_btn.setEnabled(false);
 | 
			
		||||
            } else {
 | 
			
		||||
                progress_fetching_songs.setIndeterminate(false);
 | 
			
		||||
                sync_fetching_songs_btn.setEnabled(true);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        return root;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void onFetchRemoteModifiedSongs() {
 | 
			
		||||
        galleryViewModel.startFetchingActive();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void onSyncDeletedSongs() {
 | 
			
		||||
        galleryViewModel.startDeletedSongSyncing();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -11,6 +11,7 @@ public class GalleryViewModel extends ViewModel {
 | 
			
		||||
    private final MutableLiveData<Boolean> isCreatedSongSyncing;
 | 
			
		||||
    private final MutableLiveData<Boolean> isModifiedSongSyncing;
 | 
			
		||||
    private final MutableLiveData<Boolean> isDeletedSongSyncing;
 | 
			
		||||
    private final MutableLiveData<Boolean> isFetchingActive;
 | 
			
		||||
    private SongSyncModule songSyncModule;
 | 
			
		||||
 | 
			
		||||
    public GalleryViewModel() {
 | 
			
		||||
@ -23,6 +24,9 @@ public class GalleryViewModel extends ViewModel {
 | 
			
		||||
 | 
			
		||||
        isDeletedSongSyncing = new MutableLiveData<>();
 | 
			
		||||
        isDeletedSongSyncing.setValue(false);
 | 
			
		||||
 | 
			
		||||
        isFetchingActive = new MutableLiveData<>();
 | 
			
		||||
        isFetchingActive.setValue(false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public MutableLiveData<Boolean> getIsCreatedSongSyncing() {
 | 
			
		||||
@ -71,4 +75,18 @@ public class GalleryViewModel extends ViewModel {
 | 
			
		||||
    public void finishDeleteSongSyncinc() {
 | 
			
		||||
        this.isDeletedSongSyncing.setValue(false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void startFetchingActive() {
 | 
			
		||||
        if(this.songSyncModule == null) throw new RuntimeException("SongSyncModule is not initialized");
 | 
			
		||||
        this.isFetchingActive.setValue(true);
 | 
			
		||||
        this.songSyncModule.fetchRemoteModifiedSongs();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void finishFetching() {
 | 
			
		||||
        this.isFetchingActive.setValue(false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public MutableLiveData<Boolean> getIsFetchingActive() {
 | 
			
		||||
        return isFetchingActive;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -147,5 +147,48 @@
 | 
			
		||||
                    android:layout_marginEnd="16dp" />
 | 
			
		||||
 | 
			
		||||
        </androidx.constraintlayout.widget.ConstraintLayout>
 | 
			
		||||
        <androidx.constraintlayout.widget.ConstraintLayout
 | 
			
		||||
                android:layout_width="match_parent"
 | 
			
		||||
                android:layout_height="wrap_content">
 | 
			
		||||
 | 
			
		||||
            <!-- Label -->
 | 
			
		||||
            <TextView
 | 
			
		||||
                    android:id="@+id/fetch_songs"
 | 
			
		||||
                    android:layout_width="wrap_content"
 | 
			
		||||
                    android:layout_height="wrap_content"
 | 
			
		||||
                    android:text="Fetch Remote Modified 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_fetch_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/fetch_songs"
 | 
			
		||||
                    app:layout_constraintEnd_toStartOf="@id/fetch_songs_btn"
 | 
			
		||||
                    app:layout_constraintTop_toTopOf="@id/fetch_songs"
 | 
			
		||||
                    app:layout_constraintBottom_toBottomOf="@id/fetch_songs"/>
 | 
			
		||||
 | 
			
		||||
            <!-- Sync Button -->
 | 
			
		||||
            <Button
 | 
			
		||||
                    android:id="@+id/fetch_songs_btn"
 | 
			
		||||
                    android:layout_width="wrap_content"
 | 
			
		||||
                    android:layout_height="wrap_content"
 | 
			
		||||
                    android:text="Sync"
 | 
			
		||||
                    app:layout_constraintEnd_toEndOf="parent"
 | 
			
		||||
                    app:layout_constraintTop_toTopOf="@id/fetch_songs"
 | 
			
		||||
                    app:layout_constraintBottom_toBottomOf="@id/fetch_songs"
 | 
			
		||||
                    android:layout_marginEnd="16dp" />
 | 
			
		||||
 | 
			
		||||
        </androidx.constraintlayout.widget.ConstraintLayout>
 | 
			
		||||
    </LinearLayout>
 | 
			
		||||
</androidx.constraintlayout.widget.ConstraintLayout>
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user