nextNoteVault #23
@ -4,6 +4,7 @@ import androidx.lifecycle.LiveData;
 | 
			
		||||
import androidx.room.*;
 | 
			
		||||
import com.stormtales.notevault.data.entities.NoteSheet;
 | 
			
		||||
import com.stormtales.notevault.data.entities.Song;
 | 
			
		||||
import com.stormtales.notevault.data.sync.SyncStatus;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
@ -29,4 +30,13 @@ public interface SongDao {
 | 
			
		||||
 | 
			
		||||
    @Query("SELECT localFileName FROM NoteSheet WHERE songID = :songID")
 | 
			
		||||
    List<String> getNoteSheetFilesBySongID(int songID);
 | 
			
		||||
 | 
			
		||||
    @Query("SELECT * FROM Song WHERE syncStatus = :syncStatus")
 | 
			
		||||
    List<Song> getSongsBySyncStatus(SyncStatus syncStatus);
 | 
			
		||||
 | 
			
		||||
    @Update
 | 
			
		||||
    void updateSongs(List<Song> songs);
 | 
			
		||||
 | 
			
		||||
    @Query("SELECT * FROM Song WHERE localID IN (:localIDs)")
 | 
			
		||||
    List<Song> getSongsByLocalIDs(List<Integer> localIDs);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,64 @@
 | 
			
		||||
package com.stormtales.notevault.data.repositories;
 | 
			
		||||
 | 
			
		||||
import android.content.Context;
 | 
			
		||||
import android.os.Handler;
 | 
			
		||||
import android.os.Looper;
 | 
			
		||||
import com.stormtales.notevault.data.MusicDatabase;
 | 
			
		||||
import com.stormtales.notevault.data.dao.SongDao;
 | 
			
		||||
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.CreateResponse;
 | 
			
		||||
 | 
			
		||||
import java.time.LocalDateTime;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.concurrent.ExecutorService;
 | 
			
		||||
import java.util.concurrent.Executors;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
 | 
			
		||||
public class SongSyncRepository {
 | 
			
		||||
    private SongDao songDao;
 | 
			
		||||
    public SongSyncRepository(Context context) {
 | 
			
		||||
        MusicDatabase database = MusicDatabase.getDatabase(context);
 | 
			
		||||
        songDao = database.getSongTable();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void loadCreatedSongs(LoadDataCallback<List<Song>> callback) {
 | 
			
		||||
        Executors.newSingleThreadExecutor().execute(() -> {
 | 
			
		||||
            List<Song> createdSongs = songDao.getSongsBySyncStatus(SyncStatus.CREATED);
 | 
			
		||||
            Handler mainHandler = new Handler(Looper.getMainLooper());
 | 
			
		||||
            mainHandler.post(()-> callback.onResult(createdSongs));
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void markCreatedSongsAsSynced(BatchCreateResponse createdSongs) {
 | 
			
		||||
        Executors.newSingleThreadExecutor().execute(() -> {
 | 
			
		||||
            List<Integer> localIDs = createdSongs.getCreateResponses().stream().map(CreateResponse::getLocalID).collect(Collectors.toList());
 | 
			
		||||
            List<Song> requestedSongs = songDao.getSongsByLocalIDs(localIDs);
 | 
			
		||||
 | 
			
		||||
            for(Song song : requestedSongs) {
 | 
			
		||||
                song.setSyncTime(LocalDateTime.now());
 | 
			
		||||
                song.setSyncStatus(SyncStatus.SYNCED);
 | 
			
		||||
 | 
			
		||||
                for(CreateResponse createResponse : createdSongs.getCreateResponses()) {
 | 
			
		||||
                    if(createResponse.getLocalID() == song.getLocalID()) {
 | 
			
		||||
                        song.setServerID(createResponse.getServerID());
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            songDao.updateSongs(requestedSongs);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void markSongsAsSynced(List<Song> songs) {
 | 
			
		||||
        for(Song song : songs) {
 | 
			
		||||
            song.setSyncStatus(SyncStatus.SYNCED);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public interface LoadDataCallback<T> {
 | 
			
		||||
        void onResult(T result);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,15 @@
 | 
			
		||||
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.SongCreateBatchRequest;
 | 
			
		||||
import retrofit2.Call;
 | 
			
		||||
import retrofit2.http.Body;
 | 
			
		||||
import retrofit2.http.POST;
 | 
			
		||||
 | 
			
		||||
public interface SongSyncAPI {
 | 
			
		||||
 | 
			
		||||
    @POST("/sync/songs/create")
 | 
			
		||||
    Call<BatchCreateResponse> syncCreatedSongs(@Body SongCreateBatchRequest songCreateBatchRequest);
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,40 @@
 | 
			
		||||
package com.stormtales.notevault.network.sync;
 | 
			
		||||
 | 
			
		||||
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.ui.gallery.GalleryViewModel;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class SongSyncModule {
 | 
			
		||||
    private SongRepository songRepository;
 | 
			
		||||
    private SongSyncRepository songSyncRepository;
 | 
			
		||||
    private SongSyncService songSyncService;
 | 
			
		||||
    private GalleryViewModel syncViewModel;
 | 
			
		||||
 | 
			
		||||
    public SongSyncModule(Context context, GalleryViewModel syncViewModel) {
 | 
			
		||||
        this.songRepository = new SongRepository(context);
 | 
			
		||||
        this.songSyncRepository = new SongSyncRepository(context);
 | 
			
		||||
        this.songSyncService = new SongSyncService(context);
 | 
			
		||||
        this.syncViewModel = syncViewModel;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void syncCreatedSongs(FinishSongSyncingCallback callback) {
 | 
			
		||||
        songSyncRepository.loadCreatedSongs(result -> {
 | 
			
		||||
            songSyncService.syncCreatedSongs(result, new FinishSongSyncingCallback() {
 | 
			
		||||
                @Override
 | 
			
		||||
                public void finishSongSyncing(BatchCreateResponse response) {
 | 
			
		||||
                    songSyncRepository.markCreatedSongsAsSynced(response);
 | 
			
		||||
                    callback.finishSongSyncing(response);
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public interface FinishSongSyncingCallback {
 | 
			
		||||
        void finishSongSyncing(BatchCreateResponse response);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,44 @@
 | 
			
		||||
package com.stormtales.notevault.network.sync;
 | 
			
		||||
 | 
			
		||||
import android.content.Context;
 | 
			
		||||
import com.stormtales.notevault.data.entities.Song;
 | 
			
		||||
import com.stormtales.notevault.network.NetworkModule;
 | 
			
		||||
import com.stormtales.notevault.network.auth.AuthAPI;
 | 
			
		||||
import com.stormtales.notevault.network.sync.models.BatchCreateResponse;
 | 
			
		||||
import com.stormtales.notevault.network.sync.models.SongCreateBatchRequest;
 | 
			
		||||
import com.stormtales.notevault.network.sync.models.SongCreateRequest;
 | 
			
		||||
import com.stormtales.notevault.ui.gallery.GalleryViewModel;
 | 
			
		||||
import retrofit2.Call;
 | 
			
		||||
import retrofit2.Callback;
 | 
			
		||||
import retrofit2.Response;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class SongSyncService {
 | 
			
		||||
    private final SongSyncAPI songSyncAPI;
 | 
			
		||||
    private GalleryViewModel syncStatusViewModel;
 | 
			
		||||
 | 
			
		||||
    public SongSyncService(Context context) {
 | 
			
		||||
        songSyncAPI = NetworkModule.getRetrofitInstance(context).create(SongSyncAPI.class);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void syncCreatedSongs(List<Song> songs, SongSyncModule.FinishSongSyncingCallback callback) {
 | 
			
		||||
        List<SongCreateRequest> createRequests = new ArrayList<>();
 | 
			
		||||
        for(Song song : songs) {
 | 
			
		||||
            createRequests.add(new SongCreateRequest(song));
 | 
			
		||||
        }
 | 
			
		||||
        SongCreateBatchRequest songCreateBatchRequest = new SongCreateBatchRequest(createRequests);
 | 
			
		||||
        songSyncAPI.syncCreatedSongs(songCreateBatchRequest).enqueue(new Callback<BatchCreateResponse>() {
 | 
			
		||||
            @Override
 | 
			
		||||
            public void onResponse(Call<BatchCreateResponse> call, Response<BatchCreateResponse> response) {
 | 
			
		||||
                callback.finishSongSyncing(response.body());
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            @Override
 | 
			
		||||
            public void onFailure(Call<BatchCreateResponse> call, Throwable throwable) {
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,15 @@
 | 
			
		||||
package com.stormtales.notevault.network.sync.models;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class BatchCreateResponse {
 | 
			
		||||
    private List<CreateResponse> createResponses;
 | 
			
		||||
 | 
			
		||||
    public List<CreateResponse> getCreateResponses() {
 | 
			
		||||
        return createResponses;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setCreateResponses(List<CreateResponse> createResponses) {
 | 
			
		||||
        this.createResponses = createResponses;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,22 @@
 | 
			
		||||
package com.stormtales.notevault.network.sync.models;
 | 
			
		||||
 | 
			
		||||
public class CreateResponse {
 | 
			
		||||
    private int localID;
 | 
			
		||||
    private String serverID;
 | 
			
		||||
 | 
			
		||||
    public int getLocalID() {
 | 
			
		||||
        return localID;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setLocalID(int localID) {
 | 
			
		||||
        this.localID = localID;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getServerID() {
 | 
			
		||||
        return serverID;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setServerID(String serverID) {
 | 
			
		||||
        this.serverID = serverID;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,20 @@
 | 
			
		||||
package com.stormtales.notevault.network.sync.models;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class SongCreateBatchRequest {
 | 
			
		||||
 | 
			
		||||
    private List<SongCreateRequest> songs;
 | 
			
		||||
 | 
			
		||||
    public SongCreateBatchRequest(List<SongCreateRequest> songs) {
 | 
			
		||||
        this.songs = songs;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public List<SongCreateRequest> getSongs() {
 | 
			
		||||
        return songs;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setSongs(List<SongCreateRequest> songs) {
 | 
			
		||||
        this.songs = songs;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,67 @@
 | 
			
		||||
package com.stormtales.notevault.network.sync.models;
 | 
			
		||||
 | 
			
		||||
import com.stormtales.notevault.data.entities.Song;
 | 
			
		||||
 | 
			
		||||
public class SongCreateRequest {
 | 
			
		||||
    private int localID;
 | 
			
		||||
    private String title;
 | 
			
		||||
    private String composer;
 | 
			
		||||
    private String genre;
 | 
			
		||||
    private int year;
 | 
			
		||||
 | 
			
		||||
    public SongCreateRequest(int localID, String title, String composer, String genre, int year) {
 | 
			
		||||
        this.localID = localID;
 | 
			
		||||
        this.title = title;
 | 
			
		||||
        this.composer = composer;
 | 
			
		||||
        this.genre = genre;
 | 
			
		||||
        this.year = year;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public SongCreateRequest(Song song) {
 | 
			
		||||
        this.localID = song.getLocalID();
 | 
			
		||||
        this.title = song.getTitle();
 | 
			
		||||
        this.composer = song.getComposer();
 | 
			
		||||
        this.genre = song.getGenre();
 | 
			
		||||
        this.year = song.getYear();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int getLocalID() {
 | 
			
		||||
        return localID;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setLocalID(int localID) {
 | 
			
		||||
        this.localID = localID;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getTitle() {
 | 
			
		||||
        return title;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setTitle(String title) {
 | 
			
		||||
        this.title = title;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getComposer() {
 | 
			
		||||
        return composer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setComposer(String composer) {
 | 
			
		||||
        this.composer = composer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getGenre() {
 | 
			
		||||
        return genre;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setGenre(String genre) {
 | 
			
		||||
        this.genre = genre;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int getYear() {
 | 
			
		||||
        return year;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setYear(int year) {
 | 
			
		||||
        this.year = year;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -4,26 +4,48 @@ import android.os.Bundle;
 | 
			
		||||
import android.view.LayoutInflater;
 | 
			
		||||
import android.view.View;
 | 
			
		||||
import android.view.ViewGroup;
 | 
			
		||||
import android.widget.Button;
 | 
			
		||||
import android.widget.ProgressBar;
 | 
			
		||||
import android.widget.TextView;
 | 
			
		||||
import androidx.annotation.NonNull;
 | 
			
		||||
import androidx.fragment.app.Fragment;
 | 
			
		||||
import androidx.lifecycle.ViewModelProvider;
 | 
			
		||||
import com.stormtales.notevault.data.repositories.SongRepository;
 | 
			
		||||
import com.stormtales.notevault.databinding.FragmentGalleryBinding;
 | 
			
		||||
import com.stormtales.notevault.network.sync.SongSyncModule;
 | 
			
		||||
import com.stormtales.notevault.network.sync.SongSyncService;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
public class GalleryFragment extends Fragment {
 | 
			
		||||
 | 
			
		||||
    GalleryViewModel galleryViewModel;
 | 
			
		||||
    private FragmentGalleryBinding binding;
 | 
			
		||||
    private ProgressBar progress_sync_created_songs;
 | 
			
		||||
    private Button sync_created_songs_btn;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public View onCreateView(@NonNull LayoutInflater inflater,
 | 
			
		||||
                             ViewGroup container, Bundle savedInstanceState) {
 | 
			
		||||
        GalleryViewModel galleryViewModel =
 | 
			
		||||
                new ViewModelProvider(this).get(GalleryViewModel.class);
 | 
			
		||||
        galleryViewModel = new ViewModelProvider(this).get(GalleryViewModel.class);
 | 
			
		||||
 | 
			
		||||
        binding = FragmentGalleryBinding.inflate(inflater, container, false);
 | 
			
		||||
        View root = binding.getRoot();
 | 
			
		||||
 | 
			
		||||
        final TextView textView = binding.textGallery;
 | 
			
		||||
        galleryViewModel.getText().observe(getViewLifecycleOwner(), textView::setText);
 | 
			
		||||
        progress_sync_created_songs = binding.progressSyncCreatedSongs;
 | 
			
		||||
        sync_created_songs_btn = binding.syncCreatedBtn;
 | 
			
		||||
        sync_created_songs_btn.setOnClickListener(v -> onSyncCreatedSongs());
 | 
			
		||||
 | 
			
		||||
        galleryViewModel.setSongSyncModule(new SongSyncModule(getContext(), galleryViewModel));
 | 
			
		||||
 | 
			
		||||
        galleryViewModel.getIsCreatedSongSyncing().observe(getViewLifecycleOwner(), isCreatedSyncinc -> {
 | 
			
		||||
            if(isCreatedSyncinc) {
 | 
			
		||||
                progress_sync_created_songs.setIndeterminate(true);
 | 
			
		||||
                sync_created_songs_btn.setEnabled(false);
 | 
			
		||||
            } else {
 | 
			
		||||
                progress_sync_created_songs.setIndeterminate(false);
 | 
			
		||||
                sync_created_songs_btn.setEnabled(true);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        return root;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -32,4 +54,8 @@ public class GalleryFragment extends Fragment {
 | 
			
		||||
        super.onDestroyView();
 | 
			
		||||
        binding = null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void onSyncCreatedSongs() {
 | 
			
		||||
        galleryViewModel.startCreateSongSyncing();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -3,17 +3,34 @@ package com.stormtales.notevault.ui.gallery;
 | 
			
		||||
import androidx.lifecycle.LiveData;
 | 
			
		||||
import androidx.lifecycle.MutableLiveData;
 | 
			
		||||
import androidx.lifecycle.ViewModel;
 | 
			
		||||
import com.stormtales.notevault.data.repositories.SongRepository;
 | 
			
		||||
import com.stormtales.notevault.network.sync.SongSyncModule;
 | 
			
		||||
 | 
			
		||||
public class GalleryViewModel extends ViewModel {
 | 
			
		||||
 | 
			
		||||
    private final MutableLiveData<String> mText;
 | 
			
		||||
    private final MutableLiveData<Boolean> isCreatedSongSyncing;
 | 
			
		||||
    private SongSyncModule songSyncModule;
 | 
			
		||||
 | 
			
		||||
    public GalleryViewModel() {
 | 
			
		||||
        mText = new MutableLiveData<>();
 | 
			
		||||
        mText.setValue("This is gallery fragment");
 | 
			
		||||
 | 
			
		||||
        isCreatedSongSyncing = new MutableLiveData<>();
 | 
			
		||||
        isCreatedSongSyncing.setValue(false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public LiveData<String> getText() {
 | 
			
		||||
        return mText;
 | 
			
		||||
    public MutableLiveData<Boolean> getIsCreatedSongSyncing() {
 | 
			
		||||
        return isCreatedSongSyncing;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void startCreateSongSyncing() {
 | 
			
		||||
        if(this.songSyncModule == null) throw new RuntimeException("SongSyncModule is not initialized");
 | 
			
		||||
        this.isCreatedSongSyncing.setValue(true);
 | 
			
		||||
 | 
			
		||||
        this.songSyncModule.syncCreatedSongs(batchResponse -> {
 | 
			
		||||
            this.isCreatedSongSyncing.setValue(false);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setSongSyncModule(SongSyncModule songSyncModule) {
 | 
			
		||||
        this.songSyncModule = songSyncModule;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -6,18 +6,55 @@
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="match_parent"
 | 
			
		||||
        tools:context=".ui.gallery.GalleryFragment">
 | 
			
		||||
 | 
			
		||||
    <TextView
 | 
			
		||||
            android:id="@+id/text_gallery"
 | 
			
		||||
    <LinearLayout
 | 
			
		||||
            android:orientation="vertical"
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:layout_marginStart="8dp"
 | 
			
		||||
            android:layout_marginTop="8dp"
 | 
			
		||||
            android:layout_marginEnd="8dp"
 | 
			
		||||
            android:textAlignment="center"
 | 
			
		||||
            android:textSize="20sp"
 | 
			
		||||
            app:layout_constraintEnd_toEndOf="parent"
 | 
			
		||||
            app:layout_constraintStart_toStartOf="parent"
 | 
			
		||||
            app:layout_constraintTop_toTopOf="parent"
 | 
			
		||||
            app:layout_constraintBottom_toBottomOf="parent"/>
 | 
			
		||||
            android:layout_height="match_parent">
 | 
			
		||||
        <androidx.constraintlayout.widget.ConstraintLayout
 | 
			
		||||
                android:layout_width="match_parent"
 | 
			
		||||
                android:layout_height="match_parent"
 | 
			
		||||
                tools:context=".ui.gallery.GalleryFragment">
 | 
			
		||||
 | 
			
		||||
            <!-- Label -->
 | 
			
		||||
            <TextView
 | 
			
		||||
                    android:id="@+id/sync_created_songs"
 | 
			
		||||
                    android:layout_width="wrap_content"
 | 
			
		||||
                    android:layout_height="wrap_content"
 | 
			
		||||
                    android:text="Sync Client Side Created 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_marginStart="16dp"
 | 
			
		||||
                    android:layout_marginEnd="8dp" />
 | 
			
		||||
 | 
			
		||||
            <!-- Progress Bar -->
 | 
			
		||||
            <ProgressBar
 | 
			
		||||
                    android:id="@+id/progress_sync_created_songs"
 | 
			
		||||
                    style="?android:attr/progressBarStyleHorizontal"
 | 
			
		||||
                    android:layout_width="0dp"
 | 
			
		||||
                    android:layout_height="44dp"
 | 
			
		||||
                    android:progress="0"
 | 
			
		||||
                    android:layout_marginEnd="15dp"
 | 
			
		||||
                    android:layout_marginStart="15dp"
 | 
			
		||||
                    app:layout_constraintStart_toEndOf="@id/sync_created_songs"
 | 
			
		||||
                    app:layout_constraintEnd_toStartOf="@id/sync_created_btn"
 | 
			
		||||
                    app:layout_constraintTop_toTopOf="@id/sync_created_songs"
 | 
			
		||||
                    app:layout_constraintBottom_toBottomOf="@id/sync_created_songs" />
 | 
			
		||||
 | 
			
		||||
            <!-- Sync Button -->
 | 
			
		||||
            <Button
 | 
			
		||||
                    android:id="@+id/sync_created_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_created_songs"
 | 
			
		||||
                    app:layout_constraintBottom_toBottomOf="@id/sync_created_songs"
 | 
			
		||||
                    android:layout_marginEnd="16dp" />
 | 
			
		||||
 | 
			
		||||
        </androidx.constraintlayout.widget.ConstraintLayout>
 | 
			
		||||
 | 
			
		||||
    </LinearLayout>
 | 
			
		||||
</androidx.constraintlayout.widget.ConstraintLayout>
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user