mirror of
https://github.com/antebudimir/tempus.git
synced 2025-12-31 09:33:33 +00:00
feat: implemented customizable home, allowing users to toggle visibility of elements and change their order
This commit is contained in:
parent
309eca0764
commit
0e97eab744
12 changed files with 507 additions and 0 deletions
|
|
@ -0,0 +1,11 @@
|
|||
package com.cappielloantonio.tempo.model
|
||||
|
||||
import androidx.annotation.Keep
|
||||
|
||||
@Keep
|
||||
data class HomeSector(
|
||||
val id: String,
|
||||
val sectorTitle: String,
|
||||
var isVisible: Boolean,
|
||||
val order: Int,
|
||||
)
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
package com.cappielloantonio.tempo.ui.adapter;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.cappielloantonio.tempo.databinding.ItemHorizontalHomeSectorBinding;
|
||||
import com.cappielloantonio.tempo.databinding.ItemHorizontalPlaylistDialogTrackBinding;
|
||||
import com.cappielloantonio.tempo.glide.CustomGlideRequest;
|
||||
import com.cappielloantonio.tempo.model.HomeSector;
|
||||
import com.cappielloantonio.tempo.subsonic.models.Child;
|
||||
import com.cappielloantonio.tempo.util.Constants;
|
||||
import com.cappielloantonio.tempo.util.MusicUtil;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class HomeSectorHorizontalAdapter extends RecyclerView.Adapter<HomeSectorHorizontalAdapter.ViewHolder> {
|
||||
private List<HomeSector> sectors;
|
||||
|
||||
public HomeSectorHorizontalAdapter() {
|
||||
this.sectors = Collections.emptyList();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
ItemHorizontalHomeSectorBinding view = ItemHorizontalHomeSectorBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false);
|
||||
return new ViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(ViewHolder holder, int position) {
|
||||
HomeSector sector = sectors.get(position);
|
||||
|
||||
holder.item.homeSectorTitleCheckBox.setText(sector.getSectorTitle());
|
||||
holder.item.homeSectorTitleCheckBox.setChecked(sector.isVisible());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return sectors.size();
|
||||
}
|
||||
|
||||
public List<HomeSector> getItems() {
|
||||
return this.sectors;
|
||||
}
|
||||
|
||||
public void setItems(List<HomeSector> sectors) {
|
||||
this.sectors = sectors;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public HomeSector getItem(int id) {
|
||||
return sectors.get(id);
|
||||
}
|
||||
|
||||
public class ViewHolder extends RecyclerView.ViewHolder {
|
||||
ItemHorizontalHomeSectorBinding item;
|
||||
|
||||
ViewHolder(ItemHorizontalHomeSectorBinding item) {
|
||||
super(item.getRoot());
|
||||
|
||||
this.item = item;
|
||||
|
||||
this.item.homeSectorTitleCheckBox.setOnCheckedChangeListener((buttonView, isChecked) -> onCheck(isChecked));
|
||||
}
|
||||
|
||||
private void onCheck(boolean isChecked) {
|
||||
sectors.get(getBindingAdapterPosition()).setVisible(isChecked);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
package com.cappielloantonio.tempo.ui.dialog;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.cappielloantonio.tempo.R;
|
||||
import com.cappielloantonio.tempo.databinding.DialogHomeRearrangementBinding;
|
||||
import com.cappielloantonio.tempo.ui.adapter.HomeSectorHorizontalAdapter;
|
||||
import com.cappielloantonio.tempo.viewmodel.HomeRearrangementViewModel;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Objects;
|
||||
|
||||
public class HomeRearrangementDialog extends DialogFragment {
|
||||
private DialogHomeRearrangementBinding bind;
|
||||
private HomeRearrangementViewModel homeRearrangementViewModel;
|
||||
private HomeSectorHorizontalAdapter homeSectorHorizontalAdapter;
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
bind = DialogHomeRearrangementBinding.inflate(getLayoutInflater());
|
||||
|
||||
homeRearrangementViewModel = new ViewModelProvider(requireActivity()).get(HomeRearrangementViewModel.class);
|
||||
|
||||
return new MaterialAlertDialogBuilder(requireContext())
|
||||
.setView(bind.getRoot())
|
||||
.setTitle(R.string.home_rearrangement_dialog_title)
|
||||
.setPositiveButton(R.string.home_rearrangement_dialog_positive_button, (dialog, id) -> { })
|
||||
.setNeutralButton(R.string.home_rearrangement_dialog_neutral_button, (dialog, id) -> { })
|
||||
.setNegativeButton(R.string.home_rearrangement_dialog_negative_button, (dialog, id) -> dialog.cancel())
|
||||
.create();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
|
||||
setButtonAction();
|
||||
initSectorView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
homeRearrangementViewModel.closeDialog();
|
||||
bind = null;
|
||||
}
|
||||
|
||||
private void setButtonAction() {
|
||||
androidx.appcompat.app.AlertDialog alertDialog = (androidx.appcompat.app.AlertDialog) Objects.requireNonNull(getDialog());
|
||||
|
||||
alertDialog.getButton(androidx.appcompat.app.AlertDialog.BUTTON_POSITIVE).setOnClickListener(v -> {
|
||||
homeRearrangementViewModel.saveHomeSectorList(homeSectorHorizontalAdapter.getItems());
|
||||
dismiss();
|
||||
});
|
||||
|
||||
alertDialog.getButton(androidx.appcompat.app.AlertDialog.BUTTON_NEUTRAL).setOnClickListener(v -> {
|
||||
homeRearrangementViewModel.resetHomeSectorList();
|
||||
dismiss();
|
||||
});
|
||||
}
|
||||
|
||||
private void initSectorView() {
|
||||
bind.homeSectorItemRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext()));
|
||||
bind.homeSectorItemRecyclerView.setHasFixedSize(true);
|
||||
|
||||
homeSectorHorizontalAdapter = new HomeSectorHorizontalAdapter();
|
||||
bind.homeSectorItemRecyclerView.setAdapter(homeSectorHorizontalAdapter);
|
||||
homeSectorHorizontalAdapter.setItems(homeRearrangementViewModel.getHomeSectorList());
|
||||
|
||||
new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP | ItemTouchHelper.DOWN, 0) {
|
||||
int originalPosition = -1;
|
||||
int fromPosition = -1;
|
||||
int toPosition = -1;
|
||||
|
||||
@Override
|
||||
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
|
||||
if (originalPosition == -1) originalPosition = viewHolder.getBindingAdapterPosition();
|
||||
|
||||
fromPosition = viewHolder.getBindingAdapterPosition();
|
||||
toPosition = target.getBindingAdapterPosition();
|
||||
|
||||
Collections.swap(homeSectorHorizontalAdapter.getItems(), fromPosition, toPosition);
|
||||
Objects.requireNonNull(recyclerView.getAdapter()).notifyItemMoved(fromPosition, toPosition);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearView(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
|
||||
super.clearView(recyclerView, viewHolder);
|
||||
|
||||
homeRearrangementViewModel.orderSectorLiveListAfterSwap(homeSectorHorizontalAdapter.getItems());
|
||||
|
||||
originalPosition = -1;
|
||||
fromPosition = -1;
|
||||
toPosition = -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
|
||||
|
||||
}
|
||||
}
|
||||
).attachToRecyclerView(bind.homeSectorItemRecyclerView);
|
||||
}
|
||||
}
|
||||
|
|
@ -32,6 +32,7 @@ import com.cappielloantonio.tempo.helper.recyclerview.DotsIndicatorDecoration;
|
|||
import com.cappielloantonio.tempo.helper.recyclerview.GridItemDecoration;
|
||||
import com.cappielloantonio.tempo.interfaces.ClickCallback;
|
||||
import com.cappielloantonio.tempo.model.Download;
|
||||
import com.cappielloantonio.tempo.model.HomeSector;
|
||||
import com.cappielloantonio.tempo.service.DownloaderManager;
|
||||
import com.cappielloantonio.tempo.service.MediaManager;
|
||||
import com.cappielloantonio.tempo.service.MediaService;
|
||||
|
|
@ -48,6 +49,8 @@ import com.cappielloantonio.tempo.ui.adapter.ShareHorizontalAdapter;
|
|||
import com.cappielloantonio.tempo.ui.adapter.SimilarTrackAdapter;
|
||||
import com.cappielloantonio.tempo.ui.adapter.SongHorizontalAdapter;
|
||||
import com.cappielloantonio.tempo.ui.adapter.YearAdapter;
|
||||
import com.cappielloantonio.tempo.ui.dialog.BatteryOptimizationDialog;
|
||||
import com.cappielloantonio.tempo.ui.dialog.HomeRearrangementDialog;
|
||||
import com.cappielloantonio.tempo.util.Constants;
|
||||
import com.cappielloantonio.tempo.util.DownloadUtil;
|
||||
import com.cappielloantonio.tempo.util.MappingUtil;
|
||||
|
|
@ -56,7 +59,9 @@ import com.cappielloantonio.tempo.util.Preferences;
|
|||
import com.cappielloantonio.tempo.util.UIUtil;
|
||||
import com.cappielloantonio.tempo.viewmodel.HomeViewModel;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
import com.google.common.reflect.TypeToken;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
|
@ -119,6 +124,9 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
|||
initRecentAddedAlbumView();
|
||||
initGridView();
|
||||
initSharesView();
|
||||
initHomeReorganizer();
|
||||
|
||||
reorder();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -303,6 +311,8 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
|||
}
|
||||
|
||||
private void initDiscoverSongSlideView() {
|
||||
if (!homeViewModel.checkHomeSectorVisibility(Constants.HOME_SECTOR_DISCOVERY)) return;
|
||||
|
||||
bind.discoverSongViewPager.setOrientation(ViewPager2.ORIENTATION_HORIZONTAL);
|
||||
|
||||
discoverSongAdapter = new DiscoverSongAdapter(this);
|
||||
|
|
@ -329,6 +339,8 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
|||
}
|
||||
|
||||
private void initSimilarSongView() {
|
||||
if (!homeViewModel.checkHomeSectorVisibility(Constants.HOME_SECTOR_MADE_FOR_YOU)) return;
|
||||
|
||||
bind.similarTracksRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false));
|
||||
bind.similarTracksRecyclerView.setHasFixedSize(true);
|
||||
|
||||
|
|
@ -356,6 +368,8 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
|||
}
|
||||
|
||||
private void initArtistBestOf() {
|
||||
if (!homeViewModel.checkHomeSectorVisibility(Constants.HOME_SECTOR_BEST_OF)) return;
|
||||
|
||||
bind.bestOfArtistRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false));
|
||||
bind.bestOfArtistRecyclerView.setHasFixedSize(true);
|
||||
|
||||
|
|
@ -381,6 +395,8 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
|||
}
|
||||
|
||||
private void initArtistRadio() {
|
||||
if (!homeViewModel.checkHomeSectorVisibility(Constants.HOME_SECTOR_RADIO_STATION)) return;
|
||||
|
||||
bind.radioArtistRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false));
|
||||
bind.radioArtistRecyclerView.setHasFixedSize(true);
|
||||
|
||||
|
|
@ -408,6 +424,8 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
|||
}
|
||||
|
||||
private void initGridView() {
|
||||
if (!homeViewModel.checkHomeSectorVisibility(Constants.HOME_SECTOR_TOP_SONGS)) return;
|
||||
|
||||
bind.gridTracksRecyclerView.setLayoutManager(new GridLayoutManager(requireContext(), 3));
|
||||
bind.gridTracksRecyclerView.addItemDecoration(new GridItemDecoration(3, 8, false));
|
||||
bind.gridTracksRecyclerView.setHasFixedSize(true);
|
||||
|
|
@ -432,6 +450,8 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
|||
}
|
||||
|
||||
private void initStarredTracksView() {
|
||||
if (!homeViewModel.checkHomeSectorVisibility(Constants.HOME_SECTOR_STARRED_TRACKS)) return;
|
||||
|
||||
bind.starredTracksRecyclerView.setHasFixedSize(true);
|
||||
|
||||
starredSongAdapter = new SongHorizontalAdapter(this, true, false);
|
||||
|
|
@ -467,6 +487,8 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
|||
}
|
||||
|
||||
private void initStarredAlbumsView() {
|
||||
if (!homeViewModel.checkHomeSectorVisibility(Constants.HOME_SECTOR_STARRED_ALBUMS)) return;
|
||||
|
||||
bind.starredAlbumsRecyclerView.setHasFixedSize(true);
|
||||
|
||||
starredAlbumAdapter = new AlbumHorizontalAdapter(this, false);
|
||||
|
|
@ -502,6 +524,8 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
|||
}
|
||||
|
||||
private void initStarredArtistsView() {
|
||||
if (!homeViewModel.checkHomeSectorVisibility(Constants.HOME_SECTOR_STARRED_ARTISTS)) return;
|
||||
|
||||
bind.starredArtistsRecyclerView.setHasFixedSize(true);
|
||||
|
||||
starredArtistAdapter = new ArtistHorizontalAdapter(this);
|
||||
|
|
@ -539,6 +563,8 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
|||
}
|
||||
|
||||
private void initNewReleasesView() {
|
||||
if (!homeViewModel.checkHomeSectorVisibility(Constants.HOME_SECTOR_NEW_RELEASES)) return;
|
||||
|
||||
bind.newReleasesRecyclerView.setHasFixedSize(true);
|
||||
|
||||
newReleasesAlbumAdapter = new AlbumHorizontalAdapter(this, false);
|
||||
|
|
@ -574,6 +600,8 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
|||
}
|
||||
|
||||
private void initYearSongView() {
|
||||
if (!homeViewModel.checkHomeSectorVisibility(Constants.HOME_SECTOR_FLASHBACK)) return;
|
||||
|
||||
bind.yearsRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false));
|
||||
bind.yearsRecyclerView.setHasFixedSize(true);
|
||||
|
||||
|
|
@ -599,6 +627,8 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
|||
}
|
||||
|
||||
private void initMostPlayedAlbumView() {
|
||||
if (!homeViewModel.checkHomeSectorVisibility(Constants.HOME_SECTOR_MOST_PLAYED)) return;
|
||||
|
||||
bind.mostPlayedAlbumsRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false));
|
||||
bind.mostPlayedAlbumsRecyclerView.setHasFixedSize(true);
|
||||
|
||||
|
|
@ -625,6 +655,8 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
|||
}
|
||||
|
||||
private void initRecentPlayedAlbumView() {
|
||||
if (!homeViewModel.checkHomeSectorVisibility(Constants.HOME_SECTOR_LAST_PLAYED)) return;
|
||||
|
||||
bind.recentlyPlayedAlbumsRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false));
|
||||
bind.recentlyPlayedAlbumsRecyclerView.setHasFixedSize(true);
|
||||
|
||||
|
|
@ -650,6 +682,8 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
|||
}
|
||||
|
||||
private void initRecentAddedAlbumView() {
|
||||
if (!homeViewModel.checkHomeSectorVisibility(Constants.HOME_SECTOR_RECENTLY_ADDED)) return;
|
||||
|
||||
bind.recentlyAddedAlbumsRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false));
|
||||
bind.recentlyAddedAlbumsRecyclerView.setHasFixedSize(true);
|
||||
|
||||
|
|
@ -675,6 +709,8 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
|||
}
|
||||
|
||||
private void initSharesView() {
|
||||
if (!homeViewModel.checkHomeSectorVisibility(Constants.HOME_SECTOR_SHARED)) return;
|
||||
|
||||
bind.sharesRecyclerView.setHasFixedSize(true);
|
||||
|
||||
shareHorizontalAdapter = new ShareHorizontalAdapter(this);
|
||||
|
|
@ -710,6 +746,13 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
|||
);
|
||||
}
|
||||
|
||||
private void initHomeReorganizer() {
|
||||
bind.homeSectorRearrangementButton.setOnClickListener(v -> {
|
||||
HomeRearrangementDialog dialog = new HomeRearrangementDialog();
|
||||
dialog.show(requireActivity().getSupportFragmentManager(), null);
|
||||
});
|
||||
}
|
||||
|
||||
private void refreshSharesView() {
|
||||
final Handler handler = new Handler();
|
||||
final Runnable runnable = () -> {
|
||||
|
|
@ -735,6 +778,75 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
|||
});
|
||||
}
|
||||
|
||||
public void reorder() {
|
||||
if (bind != null && homeViewModel.getHomeSectorList() != null) {
|
||||
bind.homeLinearLayoutContainer.removeAllViews();
|
||||
|
||||
for (HomeSector sector : homeViewModel.getHomeSectorList()) {
|
||||
if (!sector.isVisible()) continue;
|
||||
|
||||
switch (sector.getId()) {
|
||||
case Constants.HOME_SECTOR_DISCOVERY:
|
||||
bind.homeLinearLayoutContainer.addView(bind.homeDiscoverSector);
|
||||
break;
|
||||
case Constants.HOME_SECTOR_MADE_FOR_YOU:
|
||||
bind.homeLinearLayoutContainer.addView(bind.homeSimilarTracksSector);
|
||||
bind.homeLinearLayoutContainer.addView(bind.homeSimilarTracksPlaceholder.getRoot());
|
||||
break;
|
||||
case Constants.HOME_SECTOR_BEST_OF:
|
||||
bind.homeLinearLayoutContainer.addView(bind.homeBestOfArtistSector);
|
||||
bind.homeLinearLayoutContainer.addView(bind.homeBestOfArtistPlaceholder.getRoot());
|
||||
break;
|
||||
case Constants.HOME_SECTOR_RADIO_STATION:
|
||||
bind.homeLinearLayoutContainer.addView(bind.homeRadioArtistSector);
|
||||
bind.homeLinearLayoutContainer.addView(bind.homeRadioArtistPlaceholder.getRoot());
|
||||
break;
|
||||
case Constants.HOME_SECTOR_TOP_SONGS:
|
||||
bind.homeLinearLayoutContainer.addView(bind.homeGridTracksSector);
|
||||
break;
|
||||
case Constants.HOME_SECTOR_STARRED_TRACKS:
|
||||
bind.homeLinearLayoutContainer.addView(bind.starredTracksSector);
|
||||
bind.homeLinearLayoutContainer.addView(bind.starredTracksPlaceholder.getRoot());
|
||||
break;
|
||||
case Constants.HOME_SECTOR_STARRED_ALBUMS:
|
||||
bind.homeLinearLayoutContainer.addView(bind.starredAlbumsSector);
|
||||
bind.homeLinearLayoutContainer.addView(bind.starredAlbumsPlaceholder.getRoot());
|
||||
break;
|
||||
case Constants.HOME_SECTOR_STARRED_ARTISTS:
|
||||
bind.homeLinearLayoutContainer.addView(bind.starredArtistsSector);
|
||||
bind.homeLinearLayoutContainer.addView(bind.starredArtistsPlaceholder.getRoot());
|
||||
break;
|
||||
case Constants.HOME_SECTOR_NEW_RELEASES:
|
||||
bind.homeLinearLayoutContainer.addView(bind.homeNewReleasesSector);
|
||||
bind.homeLinearLayoutContainer.addView(bind.homeNewReleasesPlaceholder.getRoot());
|
||||
break;
|
||||
case Constants.HOME_SECTOR_FLASHBACK:
|
||||
bind.homeLinearLayoutContainer.addView(bind.homeFlashbackSector);
|
||||
bind.homeLinearLayoutContainer.addView(bind.homeFlashbackPlaceholder.getRoot());
|
||||
break;
|
||||
case Constants.HOME_SECTOR_MOST_PLAYED:
|
||||
bind.homeLinearLayoutContainer.addView(bind.homeMostPlayedAlbumsSector);
|
||||
bind.homeLinearLayoutContainer.addView(bind.homeMostPlayedAlbumsPlaceholder.getRoot());
|
||||
break;
|
||||
case Constants.HOME_SECTOR_LAST_PLAYED:
|
||||
bind.homeLinearLayoutContainer.addView(bind.homeRecentlyPlayedAlbumsSector);
|
||||
bind.homeLinearLayoutContainer.addView(bind.homeRecentlyPlayedAlbumsPlaceholder.getRoot());
|
||||
break;
|
||||
case Constants.HOME_SECTOR_RECENTLY_ADDED:
|
||||
bind.homeLinearLayoutContainer.addView(bind.homeRecentlyAddedAlbumsSector);
|
||||
bind.homeLinearLayoutContainer.addView(bind.homeRecentlyAddedAlbumsPlaceholder.getRoot());
|
||||
break;
|
||||
case Constants.HOME_SECTOR_SHARED:
|
||||
bind.homeLinearLayoutContainer.addView(bind.sharesSector);
|
||||
bind.homeLinearLayoutContainer.addView(bind.sharesPlaceholder.getRoot());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bind.homeLinearLayoutContainer.addView(bind.homeSectorRearrangementButton);
|
||||
}
|
||||
}
|
||||
|
||||
private void initializeMediaBrowser() {
|
||||
mediaBrowserListenableFuture = new MediaBrowser.Builder(requireContext(), new SessionToken(requireContext(), new ComponentName(requireContext(), MediaService.class))).buildAsync();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -91,4 +91,19 @@ object Constants {
|
|||
|
||||
const val PLAYABLE_MEDIA_LIMIT = 100
|
||||
const val PRE_PLAYABLE_MEDIA = 15
|
||||
|
||||
const val HOME_SECTOR_DISCOVERY = "HOME_SECTOR_DISCOVERY"
|
||||
const val HOME_SECTOR_MADE_FOR_YOU = "HOME_SECTOR_MADE_FOR_YOU"
|
||||
const val HOME_SECTOR_BEST_OF = "HOME_SECTOR_BEST_OF"
|
||||
const val HOME_SECTOR_RADIO_STATION = "HOME_SECTOR_RADIO_STATION"
|
||||
const val HOME_SECTOR_TOP_SONGS = "HOME_SECTOR_TOP_SONGS"
|
||||
const val HOME_SECTOR_STARRED_TRACKS = "HOME_SECTOR_STARRED_TRACKS"
|
||||
const val HOME_SECTOR_STARRED_ALBUMS = "HOME_SECTOR_STARRED_ALBUMS"
|
||||
const val HOME_SECTOR_STARRED_ARTISTS = "HOME_SECTOR_STARRED_ARTISTS"
|
||||
const val HOME_SECTOR_NEW_RELEASES = "HOME_SECTOR_NEW_RELEASES"
|
||||
const val HOME_SECTOR_FLASHBACK = "HOME_SECTOR_FLASHBACK"
|
||||
const val HOME_SECTOR_MOST_PLAYED = "HOME_SECTOR_MOST_PLAYED"
|
||||
const val HOME_SECTOR_LAST_PLAYED = "HOME_SECTOR_LAST_PLAYED"
|
||||
const val HOME_SECTOR_RECENTLY_ADDED = "HOME_SECTOR_RECENTLY_ADDED"
|
||||
const val HOME_SECTOR_SHARED = "HOME_SECTOR_SHARED"
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package com.cappielloantonio.tempo.util
|
||||
|
||||
import com.cappielloantonio.tempo.App
|
||||
import com.cappielloantonio.tempo.model.HomeSector
|
||||
import com.cappielloantonio.tempo.subsonic.models.OpenSubsonicExtension
|
||||
import com.google.gson.Gson
|
||||
|
||||
|
|
@ -54,6 +55,7 @@ object Preferences {
|
|||
private const val MIN_STAR_RATING = "min_star_rating"
|
||||
private const val ALWAYS_ON_DISPLAY = "always_on_display"
|
||||
private const val AUDIO_QUALITY_PER_ITEM = "audio_quality_per_item"
|
||||
private const val HOME_SECTOR_LIST = "home_sector_list"
|
||||
|
||||
|
||||
@JvmStatic
|
||||
|
|
@ -384,4 +386,14 @@ object Preferences {
|
|||
fun showAudioQuality(): Boolean {
|
||||
return App.getInstance().preferences.getBoolean(AUDIO_QUALITY_PER_ITEM, false)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getHomeSectorList(): String? {
|
||||
return App.getInstance().preferences.getString(HOME_SECTOR_LIST, null)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun setHomeSectorList(extension: List<HomeSector>?) {
|
||||
App.getInstance().preferences.edit().putString(HOME_SECTOR_LIST, Gson().toJson(extension)).apply()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
package com.cappielloantonio.tempo.viewmodel;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.AndroidViewModel;
|
||||
|
||||
import com.cappielloantonio.tempo.R;
|
||||
import com.cappielloantonio.tempo.model.HomeSector;
|
||||
import com.cappielloantonio.tempo.util.Constants;
|
||||
import com.cappielloantonio.tempo.util.Preferences;
|
||||
import com.google.common.reflect.TypeToken;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class HomeRearrangementViewModel extends AndroidViewModel {
|
||||
private List<HomeSector> sectors = new ArrayList<>();
|
||||
|
||||
public HomeRearrangementViewModel(@NonNull Application application) {
|
||||
super(application);
|
||||
}
|
||||
|
||||
public List<HomeSector> getHomeSectorList() {
|
||||
if (sectors != null && !sectors.isEmpty()) return sectors;
|
||||
|
||||
if (Preferences.getHomeSectorList() != null && !Preferences.getHomeSectorList().equals("null")) {
|
||||
sectors = new Gson().fromJson(
|
||||
Preferences.getHomeSectorList(),
|
||||
new TypeToken<List<HomeSector>>() {
|
||||
}.getType()
|
||||
);
|
||||
} else {
|
||||
sectors = fillStandardHomeSectorList();
|
||||
}
|
||||
|
||||
return sectors;
|
||||
}
|
||||
|
||||
public void orderSectorLiveListAfterSwap(List<HomeSector> sectors) {
|
||||
this.sectors = sectors;
|
||||
}
|
||||
|
||||
public void saveHomeSectorList(List<HomeSector> sectors) {
|
||||
Preferences.setHomeSectorList(sectors);
|
||||
}
|
||||
|
||||
public void resetHomeSectorList() {
|
||||
Preferences.setHomeSectorList(null);
|
||||
}
|
||||
|
||||
public void closeDialog() {
|
||||
sectors = null;
|
||||
}
|
||||
|
||||
private List<HomeSector> fillStandardHomeSectorList() {
|
||||
List<HomeSector> sectors = new ArrayList<>();
|
||||
|
||||
sectors.add(new HomeSector(Constants.HOME_SECTOR_DISCOVERY, getApplication().getString(R.string.home_title_discovery), true, 1));
|
||||
sectors.add(new HomeSector(Constants.HOME_SECTOR_MADE_FOR_YOU, getApplication().getString(R.string.home_title_made_for_you), true, 2));
|
||||
sectors.add(new HomeSector(Constants.HOME_SECTOR_BEST_OF, getApplication().getString(R.string.home_title_best_of), true, 3));
|
||||
sectors.add(new HomeSector(Constants.HOME_SECTOR_RADIO_STATION, getApplication().getString(R.string.home_title_radio_station), true, 4));
|
||||
sectors.add(new HomeSector(Constants.HOME_SECTOR_TOP_SONGS, getApplication().getString(R.string.home_title_top_songs), true, 5));
|
||||
sectors.add(new HomeSector(Constants.HOME_SECTOR_STARRED_TRACKS, getApplication().getString(R.string.home_title_starred_tracks), true, 6));
|
||||
sectors.add(new HomeSector(Constants.HOME_SECTOR_STARRED_ALBUMS, getApplication().getString(R.string.home_title_starred_albums), true, 7));
|
||||
sectors.add(new HomeSector(Constants.HOME_SECTOR_STARRED_ARTISTS, getApplication().getString(R.string.home_title_starred_artists), true, 8));
|
||||
sectors.add(new HomeSector(Constants.HOME_SECTOR_NEW_RELEASES, getApplication().getString(R.string.home_title_new_releases), true, 9));
|
||||
sectors.add(new HomeSector(Constants.HOME_SECTOR_FLASHBACK, getApplication().getString(R.string.home_title_flashback), true, 10));
|
||||
sectors.add(new HomeSector(Constants.HOME_SECTOR_MOST_PLAYED, getApplication().getString(R.string.home_title_most_played), true, 11));
|
||||
sectors.add(new HomeSector(Constants.HOME_SECTOR_LAST_PLAYED, getApplication().getString(R.string.home_title_last_played), true, 12));
|
||||
sectors.add(new HomeSector(Constants.HOME_SECTOR_RECENTLY_ADDED, getApplication().getString(R.string.home_title_recently_added), true, 13));
|
||||
sectors.add(new HomeSector(Constants.HOME_SECTOR_SHARED, getApplication().getString(R.string.home_title_shares), true, 14));
|
||||
|
||||
return sectors;
|
||||
}
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@ import androidx.lifecycle.MutableLiveData;
|
|||
import com.cappielloantonio.tempo.interfaces.StarCallback;
|
||||
import com.cappielloantonio.tempo.model.Chronology;
|
||||
import com.cappielloantonio.tempo.model.Favorite;
|
||||
import com.cappielloantonio.tempo.model.HomeSector;
|
||||
import com.cappielloantonio.tempo.repository.AlbumRepository;
|
||||
import com.cappielloantonio.tempo.repository.ArtistRepository;
|
||||
import com.cappielloantonio.tempo.repository.ChronologyRepository;
|
||||
|
|
@ -22,6 +23,8 @@ import com.cappielloantonio.tempo.subsonic.models.ArtistID3;
|
|||
import com.cappielloantonio.tempo.subsonic.models.Child;
|
||||
import com.cappielloantonio.tempo.subsonic.models.Share;
|
||||
import com.cappielloantonio.tempo.util.Preferences;
|
||||
import com.google.common.reflect.TypeToken;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
|
|
@ -59,10 +62,13 @@ public class HomeViewModel extends AndroidViewModel {
|
|||
private final MutableLiveData<List<Child>> artistBestOf = new MutableLiveData<>(null);
|
||||
private final MutableLiveData<List<Share>> shares = new MutableLiveData<>(null);
|
||||
|
||||
private List<HomeSector> sectors;
|
||||
|
||||
public HomeViewModel(@NonNull Application application) {
|
||||
super(application);
|
||||
|
||||
setHomeSectorList();
|
||||
|
||||
songRepository = new SongRepository();
|
||||
albumRepository = new AlbumRepository();
|
||||
artistRepository = new ArtistRepository();
|
||||
|
|
@ -266,6 +272,26 @@ public class HomeViewModel extends AndroidViewModel {
|
|||
sharingRepository.getShares().observe(owner, this.shares::postValue);
|
||||
}
|
||||
|
||||
private void setHomeSectorList() {
|
||||
if (Preferences.getHomeSectorList() != null && !Preferences.getHomeSectorList().equals("null")) {
|
||||
sectors = new Gson().fromJson(
|
||||
Preferences.getHomeSectorList(),
|
||||
new TypeToken<List<HomeSector>>() {
|
||||
}.getType()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public List<HomeSector> getHomeSectorList() {
|
||||
return sectors;
|
||||
}
|
||||
|
||||
public boolean checkHomeSectorVisibility(String sectorId) {
|
||||
return sectors != null && sectors.stream().filter(sector -> sector.getId().equals(sectorId))
|
||||
.findAny()
|
||||
.orElse(null) != null;
|
||||
}
|
||||
|
||||
public void setOfflineFavorite() {
|
||||
ArrayList<Favorite> favorites = getFavorites();
|
||||
ArrayList<Favorite> favoritesToSave = getFavoritesToSave(favorites);
|
||||
|
|
|
|||
23
app/src/main/res/layout/dialog_home_rearrangement.xml
Normal file
23
app/src/main/res/layout/dialog_home_rearrangement.xml
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:text="@string/home_rearrangement_dialog_subtitle" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/home_sector_item_recycler_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipToPadding="false"
|
||||
android:nestedScrollingEnabled="false"
|
||||
android:paddingHorizontal="18dp" />
|
||||
</LinearLayout>
|
||||
|
|
@ -787,6 +787,14 @@
|
|||
android:id="@+id/shares_placeholder"
|
||||
layout="@layout/item_placeholder_horizontal"
|
||||
android:visibility="gone" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/home_sector_rearrangement_button"
|
||||
style="@style/Widget.Material3.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:text="@string/home_option_reorganize"/>
|
||||
</LinearLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
|
|
|
|||
26
app/src/main/res/layout/item_horizontal_home_sector.xml
Normal file
26
app/src/main/res/layout/item_horizontal_home_sector.xml
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:clipChildren="false"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/home_sector_title_check_box"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/home_sector_rearranger_image_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_drag_handle"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/home_sector_title_check_box"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/home_sector_title_check_box" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
@ -87,6 +87,11 @@
|
|||
<string name="filter_title_expanded">Filter Genres</string>
|
||||
<string name="genre_catalogue_title">Genre Catalogue</string>
|
||||
<string name="genre_catalogue_title_expanded">Browse Genres</string>
|
||||
<string name="home_rearrangement_dialog_negative_button">Cancel</string>
|
||||
<string name="home_rearrangement_dialog_neutral_button">Reset</string>
|
||||
<string name="home_rearrangement_dialog_positive_button">Save</string>
|
||||
<string name="home_rearrangement_dialog_title">Rearrange home</string>
|
||||
<string name="home_rearrangement_dialog_subtitle">Please note that in order for the changes made to take effect, it is necessary to restart the application.</string>
|
||||
<string name="home_subtitle_best_of">Top songs of your favorite artists</string>
|
||||
<string name="home_subtitle_made_for_you">Start mix from a song you liked</string>
|
||||
<string name="home_subtitle_new_internet_radio_station">Add a new radio</string>
|
||||
|
|
@ -121,6 +126,7 @@
|
|||
<string name="home_title_starred_tracks">★ Starred tracks</string>
|
||||
<string name="home_title_starred_tracks_see_all_button">See all</string>
|
||||
<string name="home_title_top_songs">Your top songs</string>
|
||||
<string name="home_option_reorganize">Reorganize</string>
|
||||
<string name="label_dot_separator" translatable="false">•</string>
|
||||
<string name="label_placeholder" translatable="false">--</string>
|
||||
<string name="library_title_album">Albums</string>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue