feat: implemented customizable home, allowing users to toggle visibility of elements and change their order

This commit is contained in:
CappielloAntonio 2024-03-23 21:33:11 +01:00
parent 309eca0764
commit 0e97eab744
12 changed files with 507 additions and 0 deletions

View file

@ -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,
)

View file

@ -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);
}
}
}

View file

@ -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);
}
}

View file

@ -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();
}

View file

@ -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"
}

View file

@ -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()
}
}

View file

@ -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;
}
}

View file

@ -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);

View 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>

View file

@ -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>

View 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>

View file

@ -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>