From f806d3f7dd2dbe0b8c21d01381200d3bfbe02d14 Mon Sep 17 00:00:00 2001 From: Niko Strijbol Date: Fri, 27 Oct 2023 19:06:35 +0200 Subject: [PATCH 1/5] More code clean up --- .../be/ugent/zeus/hydra/MainActivity.java | 10 +-- .../hydra/common/utils/FragmentUtils.java | 39 +++++++++++ .../zeus/hydra/resto/SingleDayFragment.java | 3 +- .../zeus/hydra/resto/menu/RestoFragment.java | 70 ++++++++----------- .../ecological/EcologicalFragment.java | 29 ++------ .../ecological/EcologicalSandwich.java | 2 + .../sandwich/regular/RegularFragment.java | 29 ++------ .../zeus/hydra/schamper/SchamperFragment.java | 23 +----- .../ugent/zeus/hydra/urgent/MusicService.java | 11 ++- .../hydra/urgent/player/InternalPlayer.java | 2 - .../zeus/hydra/urgent/player/Player.java | 59 ++++------------ .../urgent/player/PlayerSessionCallback.java | 3 +- .../be/ugent/zeus/hydra/wpi/WpiActivity.java | 3 +- .../wpi/account/CombinedUserRequest.java | 3 - .../zeus/hydra/wpi/cammie/CammieActivity.java | 3 +- .../hydra/wpi/cammie/ChatDialogFragment.java | 2 +- .../zeus/hydra/wpi/cammie/MoveRequest.java | 3 +- .../wpi/door/NfcIntentReceiverActivity.java | 5 +- .../tab/create/CreateTransactionRequest.java | 3 +- .../hydra/wpi/tab/create/FormActivity.java | 12 ++-- .../hydra/wpi/tab/create/TransactionForm.java | 2 +- .../wpi/tab/create/TransactionViewModel.java | 3 +- .../wpi/tab/list/TransactionFragment.java | 1 - .../wpi/tab/list/TransactionViewHolder.java | 2 +- .../AcceptableRequestsViewHolder.java | 2 +- .../zeus/hydra/wpi/tap/barcode/Barcode.java | 4 +- .../ugent/zeus/hydra/wpi/tap/cart/Cart.java | 2 +- .../zeus/hydra/wpi/tap/cart/CartActivity.java | 2 +- .../zeus/hydra/wpi/tap/cart/CartProduct.java | 10 ++- .../wpi/tap/cart/CartProductAdapter.java | 1 - .../wpi/tap/cart/CartProductViewHolder.java | 5 +- .../hydra/wpi/tap/cart/CartViewModel.java | 1 - .../wpi/tap/cart/CreateOrderRequest.java | 1 - .../wpi/tap/cart/ExistingCartRequest.java | 10 +-- .../zeus/hydra/wpi/tap/cart/OrderResult.java | 2 +- .../tap/cart/ProductPickerDialogFragment.java | 1 - .../zeus/hydra/wpi/tap/cart/StorageCart.java | 2 +- .../ugent/zeus/hydra/wpi/tap/order/Order.java | 3 +- .../hydra/wpi/tap/order/OrderViewHolder.java | 3 +- .../hydra/wpi/tap/product/ProductAdapter.java | 7 -- .../wpi/tap/product/ProductFragment.java | 69 +++++++++--------- .../wpi/tap/product/ProductViewHolder.java | 5 +- 42 files changed, 187 insertions(+), 265 deletions(-) diff --git a/app/src/main/java/be/ugent/zeus/hydra/MainActivity.java b/app/src/main/java/be/ugent/zeus/hydra/MainActivity.java index a8df6b213..c28bde09a 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/MainActivity.java +++ b/app/src/main/java/be/ugent/zeus/hydra/MainActivity.java @@ -74,13 +74,13 @@ *

* The logic for handling the navigation drawer is not immediately obvious to those who do not work with it regularly. * Proceed with caution. - * + *

*

Navigation

*

* One of the main responsibilities of this activity is managing navigation between the drawer, the fragments and the * fragments between each other. The navigation is built in two main components: navigation forward and navigating * backwards. Each component itself is not that difficult. Together the provide an intuitive navigation. - * + *

*

Forward navigation

*

* When the user navigates to a new fragment in this activity, the back stack (of the {@link #getSupportFragmentManager()} @@ -112,7 +112,7 @@ *

* The third and last scenario is the easiest: nothing should be done when the activity is first started or recreated. * The fragments should not be added to the back stack. - * + *

*

Backwards navigation

*

* The logic above makes the backwards navigation quite simple, and can be summarized as: @@ -149,7 +149,7 @@ * After this method call, the fragment can behave as if the arguments were directly set on the fragment itself. *

* This function will only be called when creating a fragment, not when popping from the back stack. - * + *

*

Common views and removal

*

* The activity provides some common views: @@ -172,7 +172,7 @@ *

* The reason fragments cannot fully rely on the default lifecycle methods, such as {@link Fragment#onStop()}, is that * the fragment is not always removed immediately by the activity when it is hidden (this as to do with performance). - * + *

*

Arguments

*

* The activity has one public argument: which child fragment to load. The preferred way of using it is diff --git a/app/src/main/java/be/ugent/zeus/hydra/common/utils/FragmentUtils.java b/app/src/main/java/be/ugent/zeus/hydra/common/utils/FragmentUtils.java index 00c607e15..7842b3696 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/common/utils/FragmentUtils.java +++ b/app/src/main/java/be/ugent/zeus/hydra/common/utils/FragmentUtils.java @@ -24,10 +24,21 @@ import android.app.Activity; import android.os.Bundle; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import androidx.annotation.IdRes; +import androidx.annotation.MenuRes; import androidx.annotation.NonNull; +import androidx.core.view.MenuProvider; import androidx.fragment.app.Fragment; +import java.util.function.Function; + +import be.ugent.zeus.hydra.R; import be.ugent.zeus.hydra.common.ui.BaseActivity; +import be.ugent.zeus.hydra.common.ui.RefreshViewModel; +import org.jetbrains.annotations.NotNull; /** * @author Niko Strijbol @@ -53,4 +64,32 @@ public static Bundle requireArguments(Fragment fragment) { return arguments; } } + + // TODO: this is an experimental abstraction, since there isn't a lot of benefit vs just doing it + public static void registerMenuProvider(@NonNull Fragment fragment, @MenuRes int menuRes, @IdRes int[] icons, Function onSelected) { + BaseActivity activity = requireBaseActivity(fragment); + + activity.addMenuProvider(new MenuProvider() { + @Override + public void onCreateMenu(@NonNull @NotNull Menu menu, @NonNull @NotNull MenuInflater menuInflater) { + menuInflater.inflate(menuRes, menu); + activity.tintToolbarIcons(menu, icons); + } + + @Override + public boolean onMenuItemSelected(@NonNull @NotNull MenuItem menuItem) { + return onSelected.apply(menuItem); + } + }, fragment.getViewLifecycleOwner()); + } + + public static void registerRefreshMenu(@NonNull Fragment fragment, @NonNull RefreshViewModel viewModel) { + registerMenuProvider(fragment, R.menu.menu_resto, new int[]{R.id.action_refresh}, menuItem -> { + if (menuItem.getItemId() == R.id.action_refresh) { + viewModel.onRefresh(); + return true; + } + return false; + }); + } } diff --git a/app/src/main/java/be/ugent/zeus/hydra/resto/SingleDayFragment.java b/app/src/main/java/be/ugent/zeus/hydra/resto/SingleDayFragment.java index af8ed56c2..091a329a9 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/resto/SingleDayFragment.java +++ b/app/src/main/java/be/ugent/zeus/hydra/resto/SingleDayFragment.java @@ -28,6 +28,7 @@ import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.core.os.BundleCompat; import androidx.fragment.app.Fragment; import be.ugent.zeus.hydra.common.reporting.BaseEvents; @@ -65,7 +66,7 @@ public static SingleDayFragment newInstance(RestoMenu menu, boolean showAllergen @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - data = requireArguments().getParcelable(ARG_DATA_MENU); + data = BundleCompat.getParcelable(requireArguments(), ARG_DATA_MENU, RestoMenu.class); } @Override diff --git a/app/src/main/java/be/ugent/zeus/hydra/resto/menu/RestoFragment.java b/app/src/main/java/be/ugent/zeus/hydra/resto/menu/RestoFragment.java index a670ae633..7ad06af49 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/resto/menu/RestoFragment.java +++ b/app/src/main/java/be/ugent/zeus/hydra/resto/menu/RestoFragment.java @@ -66,6 +66,7 @@ import com.google.android.material.textfield.MaterialAutoCompleteTextView; import com.google.android.material.textfield.TextInputLayout; +import static be.ugent.zeus.hydra.common.utils.FragmentUtils.registerMenuProvider; import static be.ugent.zeus.hydra.common.utils.FragmentUtils.requireBaseActivity; /** @@ -107,12 +108,6 @@ public class RestoFragment extends Fragment implements @Nullable private LocalDate startDate; - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setHasOptionsMenu(true); - } - @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { @@ -139,6 +134,32 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat super.onViewCreated(view, savedInstanceState); Log.d(TAG, "receiveResto: on view created"); + registerMenuProvider(this, R.menu.menu_resto, new int[]{R.id.action_history}, menuItem -> { + int itemId = menuItem.getItemId(); + if (itemId == R.id.action_refresh) { + Toast toast = Toast.makeText(requireContext(), R.string.resto_extra_refresh_started, Toast.LENGTH_SHORT); + toast.show(); + metaViewModel.onRefresh(); + menuViewModel.onRefresh(); + return true; + } else if (itemId == R.id.resto_show_website) { + NetworkUtils.maybeLaunchBrowser(requireContext(), URL); + return true; + } else if (itemId == R.id.action_history) { + startActivity(new Intent(requireContext(), HistoryActivity.class)); + return true; + } else if (itemId == R.id.resto_order_online) { + String url = ORDER_URL + requireContext().getString(R.string.value_info_endpoint); + NetworkUtils.maybeLaunchBrowser(requireContext(), url); + return true; + } else if (itemId == R.id.resto_show_allergens) { + menuItem.setChecked(!menuItem.isChecked()); + pageAdapter.setShowAllergens(menuItem.isChecked()); + return true; + } + return false; + }); + requireBaseActivity(this).requireToolbar().setDisplayShowTitleEnabled(false); exposedDropdown = requireActivity().findViewById(R.id.exposed_dropdown); exposedDropdown.setEnabled(false); @@ -196,7 +217,7 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat private void receiveResto(@NonNull List restos) { SelectedResto selectedResto = new SelectedResto(requireContext()); selectedResto.setData(restos); - + // Set the things. List wrappers = selectedResto.getAsWrappers(); ArrayAdapter items = new ArrayAdapter<>(requireBaseActivity(this).requireToolbar().getThemedContext(), R.layout.x_simple_spinner_dropdown_item); @@ -249,39 +270,6 @@ private void receiveData(@NonNull List data) { } } - @Override - public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { - inflater.inflate(R.menu.menu_resto, menu); - requireBaseActivity(this).tintToolbarIcons(menu, R.id.action_history); - } - - @Override - public boolean onOptionsItemSelected(@NonNull MenuItem item) { - int itemId = item.getItemId(); - if (itemId == R.id.action_refresh) { - Toast toast = Toast.makeText(requireContext(), R.string.resto_extra_refresh_started, Toast.LENGTH_SHORT); - toast.show(); - metaViewModel.onRefresh(); - menuViewModel.onRefresh(); - return true; - } else if (itemId == R.id.resto_show_website) { - NetworkUtils.maybeLaunchBrowser(requireContext(), URL); - return true; - } else if (itemId == R.id.action_history) { - startActivity(new Intent(requireContext(), HistoryActivity.class)); - return true; - } else if (itemId == R.id.resto_order_online) { - String url = ORDER_URL + requireContext().getString(R.string.value_info_endpoint); - NetworkUtils.maybeLaunchBrowser(requireContext(), url); - return true; - } else if (itemId == R.id.resto_show_allergens) { - item.setChecked(!item.isChecked()); - pageAdapter.setShowAllergens(item.isChecked()); - return true; - } - return super.onOptionsItemSelected(item); - } - public void onRestoSelected(@NonNull AdapterView parent, View view, int position, long id) { // Get the item we selected. SelectedResto.Wrapper wrapper = (SelectedResto.Wrapper) parent.getItemAtPosition(position); @@ -362,7 +350,7 @@ public void onDestroyView() { private void hideExternalViews() { bottomNavigation.setVisibility(View.GONE); - bottomNavigation.setOnNavigationItemSelectedListener(null); + bottomNavigation.setOnItemSelectedListener(null); exposedDropdownWrapper.setVisibility(View.GONE); requireBaseActivity(this).requireToolbar().setDisplayShowTitleEnabled(true); exposedDropdownProgress.setVisibility(View.GONE); diff --git a/app/src/main/java/be/ugent/zeus/hydra/resto/sandwich/ecological/EcologicalFragment.java b/app/src/main/java/be/ugent/zeus/hydra/resto/sandwich/ecological/EcologicalFragment.java index d7322aea0..bfadfd49e 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/resto/sandwich/ecological/EcologicalFragment.java +++ b/app/src/main/java/be/ugent/zeus/hydra/resto/sandwich/ecological/EcologicalFragment.java @@ -24,7 +24,9 @@ import android.os.Bundle; import android.util.Log; -import android.view.*; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; @@ -40,7 +42,7 @@ import be.ugent.zeus.hydra.common.utils.ColourUtils; import com.google.android.material.snackbar.Snackbar; -import static be.ugent.zeus.hydra.common.utils.FragmentUtils.requireBaseActivity; +import static be.ugent.zeus.hydra.common.utils.FragmentUtils.registerRefreshMenu; /** * Activity that shows a list of regular sandwiches. @@ -54,27 +56,6 @@ public class EcologicalFragment extends Fragment { private final EcologicalAdapter adapter = new EcologicalAdapter(); private EcologicalViewModel viewModel; - @Override - public void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setHasOptionsMenu(true); - } - - @Override - public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { - inflater.inflate(R.menu.menu_refresh, menu); - requireBaseActivity(this).tintToolbarIcons(menu, R.id.action_refresh); - } - - @Override - public boolean onOptionsItemSelected(@NonNull MenuItem item) { - if (item.getItemId() == R.id.action_refresh) { - viewModel.onRefresh(); - return true; - } - return super.onOptionsItemSelected(item); - } - @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { @@ -99,6 +80,8 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat viewModel.getData().observe(getViewLifecycleOwner(), new AdapterObserver<>(adapter)); viewModel.getRefreshing().observe(getViewLifecycleOwner(), swipeRefreshLayout::setRefreshing); swipeRefreshLayout.setOnRefreshListener(viewModel); + + registerRefreshMenu(this, viewModel); } private void onError(Throwable throwable) { diff --git a/app/src/main/java/be/ugent/zeus/hydra/resto/sandwich/ecological/EcologicalSandwich.java b/app/src/main/java/be/ugent/zeus/hydra/resto/sandwich/ecological/EcologicalSandwich.java index 387d9d74d..591bd94cf 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/resto/sandwich/ecological/EcologicalSandwich.java +++ b/app/src/main/java/be/ugent/zeus/hydra/resto/sandwich/ecological/EcologicalSandwich.java @@ -24,6 +24,7 @@ import android.os.Parcel; import android.os.Parcelable; +import androidx.annotation.NonNull; import java.time.LocalDate; import java.util.List; @@ -105,6 +106,7 @@ public int hashCode() { return Objects.hash(name, ingredients, start, end, vegan); } + @NonNull @Override public String toString() { return name; diff --git a/app/src/main/java/be/ugent/zeus/hydra/resto/sandwich/regular/RegularFragment.java b/app/src/main/java/be/ugent/zeus/hydra/resto/sandwich/regular/RegularFragment.java index 24738a438..fcd472ebb 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/resto/sandwich/regular/RegularFragment.java +++ b/app/src/main/java/be/ugent/zeus/hydra/resto/sandwich/regular/RegularFragment.java @@ -24,7 +24,9 @@ import android.os.Bundle; import android.util.Log; -import android.view.*; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; @@ -40,7 +42,7 @@ import be.ugent.zeus.hydra.common.utils.ColourUtils; import com.google.android.material.snackbar.Snackbar; -import static be.ugent.zeus.hydra.common.utils.FragmentUtils.requireBaseActivity; +import static be.ugent.zeus.hydra.common.utils.FragmentUtils.registerRefreshMenu; /** * Activity that shows a list of regular sandwiches. @@ -54,12 +56,6 @@ public class RegularFragment extends Fragment { private final RegularAdapter adapter = new RegularAdapter(); private RegularViewModel viewModel; - @Override - public void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setHasOptionsMenu(true); - } - @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { @@ -84,6 +80,8 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat viewModel.getData().observe(getViewLifecycleOwner(), new AdapterObserver<>(adapter)); viewModel.getRefreshing().observe(getViewLifecycleOwner(), swipeRefreshLayout::setRefreshing); swipeRefreshLayout.setOnRefreshListener(viewModel); + + registerRefreshMenu(this, viewModel); } private void onError(Throwable throwable) { @@ -92,19 +90,4 @@ private void onError(Throwable throwable) { .setAction(getString(R.string.action_again), v -> viewModel.onRefresh()) .show(); } - - @Override - public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { - inflater.inflate(R.menu.menu_refresh, menu); - requireBaseActivity(this).tintToolbarIcons(menu, R.id.action_refresh); - } - - @Override - public boolean onOptionsItemSelected(@NonNull MenuItem item) { - if (item.getItemId() == R.id.action_refresh) { - viewModel.onRefresh(); - return true; - } - return super.onOptionsItemSelected(item); - } } diff --git a/app/src/main/java/be/ugent/zeus/hydra/schamper/SchamperFragment.java b/app/src/main/java/be/ugent/zeus/hydra/schamper/SchamperFragment.java index 826a03376..f8fd729de 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/schamper/SchamperFragment.java +++ b/app/src/main/java/be/ugent/zeus/hydra/schamper/SchamperFragment.java @@ -43,6 +43,7 @@ import be.ugent.zeus.hydra.common.utils.ColourUtils; import com.google.android.material.snackbar.Snackbar; +import static be.ugent.zeus.hydra.common.utils.FragmentUtils.registerRefreshMenu; import static be.ugent.zeus.hydra.common.utils.FragmentUtils.requireBaseActivity; /** @@ -68,7 +69,6 @@ public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); helper = CustomTabsHelper.initHelper(getActivity(), null); helper.setShareMenu(); - setHasOptionsMenu(true); } @Override @@ -90,25 +90,8 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat viewModel.getData().observe(getViewLifecycleOwner(), new AdapterObserver<>(adapter)); viewModel.getRefreshing().observe(getViewLifecycleOwner(), swipeRefreshLayout::setRefreshing); swipeRefreshLayout.setOnRefreshListener(viewModel); - } - - @Override - public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { - super.onCreateOptionsMenu(menu, inflater); - inflater.inflate(R.menu.menu_refresh, menu); - BaseActivity activity = requireBaseActivity(this); - activity.tintToolbarIcons(menu, R.id.action_refresh); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - - if (item.getItemId() == R.id.action_refresh) { - viewModel.onRefresh(); - return true; - } - - return super.onOptionsItemSelected(item); + + registerRefreshMenu(this, viewModel); } private void onError(Throwable throwable) { diff --git a/app/src/main/java/be/ugent/zeus/hydra/urgent/MusicService.java b/app/src/main/java/be/ugent/zeus/hydra/urgent/MusicService.java index 59e5982af..b34430b59 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/urgent/MusicService.java +++ b/app/src/main/java/be/ugent/zeus/hydra/urgent/MusicService.java @@ -25,7 +25,6 @@ import android.annotation.SuppressLint; import android.app.Notification; import android.app.PendingIntent; -import android.content.Context; import android.content.Intent; import android.content.pm.ServiceInfo; import android.net.wifi.WifiManager; @@ -57,11 +56,11 @@ * It is highly recommended to read the Android documentation first, before working on these classes. For example, * the term media session is strictly used to denote the media session managed by Android itself, through the * {@link MediaSessionCompat} class. - * + *

*

Service

* The service is responsible for keeping the stream alive and managing the various background permissions and * restrictions imposed by Android. It is not responsible for controlling the audio. - * + *

*

Audio controls

* The main responsibility of this service is keeping an instance of {@link Player} alive. The service will start the * player, construct a media session and connect everything up. Afterwards, control is given up to the media session. @@ -113,7 +112,7 @@ public void onCreate() { notificationManager = NotificationManagerCompat.from(this); // Create the WiFi lock we we will use later. - WifiManager manager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE); + WifiManager manager = ContextCompat.getSystemService(getApplicationContext(), WifiManager.class); if (manager != null) { this.wifiLock = manager.createWifiLock(WifiManager.WIFI_MODE_FULL, WIFI_LOCK_TAG); } @@ -262,7 +261,7 @@ public void onPause() { if (wifiLock != null && wifiLock.isHeld()) { wifiLock.release(); } - stopForeground(false); + ServiceCompat.stopForeground(this, 0); } @Override @@ -272,7 +271,7 @@ public void onStop() { wifiLock.release(); } Reporting.getTracker(this).log(new MusicStopEvent()); - stopForeground(true); + ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_REMOVE); foreground = false; } diff --git a/app/src/main/java/be/ugent/zeus/hydra/urgent/player/InternalPlayer.java b/app/src/main/java/be/ugent/zeus/hydra/urgent/player/InternalPlayer.java index 1c26db983..e57c39659 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/urgent/player/InternalPlayer.java +++ b/app/src/main/java/be/ugent/zeus/hydra/urgent/player/InternalPlayer.java @@ -22,7 +22,6 @@ package be.ugent.zeus.hydra.urgent.player; -import android.annotation.SuppressLint; import android.content.Context; import android.media.AudioAttributes; import android.media.MediaPlayer; @@ -181,7 +180,6 @@ void setVolume(float volume) { } void setAudioAttributes(@NonNull AudioAttributesCompat attributes) { - @SuppressLint("WrongConstant") AudioAttributes audioAttributes = new AudioAttributes.Builder() .setContentType(attributes.getContentType()) .setFlags(attributes.getFlags()) diff --git a/app/src/main/java/be/ugent/zeus/hydra/urgent/player/Player.java b/app/src/main/java/be/ugent/zeus/hydra/urgent/player/Player.java index a2ec2887a..e1be9d0a7 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/urgent/player/Player.java +++ b/app/src/main/java/be/ugent/zeus/hydra/urgent/player/Player.java @@ -22,20 +22,17 @@ package be.ugent.zeus.hydra.urgent.player; -import android.annotation.TargetApi; import android.content.Context; -import android.media.AudioAttributes; -import android.media.AudioFocusRequest; import android.media.AudioManager; -import android.os.Build; import android.support.v4.media.MediaMetadataCompat; import android.support.v4.media.session.MediaSessionCompat; import android.util.Log; import androidx.annotation.Nullable; -import androidx.annotation.RequiresApi; +import androidx.core.content.ContextCompat; import androidx.media.AudioAttributesCompat; +import androidx.media.AudioFocusRequestCompat; +import androidx.media.AudioManagerCompat; -import java.util.Objects; import java.util.stream.IntStream; import static be.ugent.zeus.hydra.urgent.player.MediaStateListener.State.*; @@ -45,17 +42,17 @@ *
* Android has various restrictions and permissions on background playing, audio playback, wifi usage, etc. These things * are not managed by this class, but by the {@link be.ugent.zeus.hydra.urgent.MusicService}. - * + *

*

Playback

* This class does not actually control the actual playback. That is done by the {@link InternalPlayer}. This class * exists to manage the state of said player, meaning it will ensure the internal player is in the correct state * before calling methods, such as play or pause. - * + *

*

Control

* The player should not be controlled directly by other code. Instead, Android's media sessions should be used. This * class will ensure all necessary callbacks (such as {@link SessionPlayerCallback} and {@link PlayerSessionCallback}) * are correctly set and attached. - * + *

*

Relation to {@link be.ugent.zeus.hydra.urgent.MusicService}

* While the service will start this player and connect it to the media session, it will not control it. After the * connection is made, this class will take over control (and this class will be in turn controlled by the media @@ -98,7 +95,7 @@ public class Player { /** * Internal request. */ - private AudioFocusRequest audioFocusRequest; + private AudioFocusRequestCompat audioFocusRequest; /** * The volume we want. This is changed as a response to audio focus things. */ @@ -211,7 +208,7 @@ public void setPlayWhenReady(boolean playWhenReady) { playOrSchedulePlay(); } else { cancelOrStopPlay(); - abandonAudioFocus(); + AudioManagerCompat.abandonAudioFocusRequest(audioManager, getAudioFocusRequest()); } } @@ -241,15 +238,7 @@ public void destroy() { } private void requestAudioFocus() { - int result; - if (Build.VERSION.SDK_INT >= 26) { - result = requestAudioFocusOreo(); - } else { - result = audioManager.requestAudioFocus(focusChangeListener, - audioAttributes.getLegacyStreamType(), - AudioManager.AUDIOFOCUS_GAIN); - } - + int result = AudioManagerCompat.requestAudioFocus(audioManager, getAudioFocusRequest()); // Call the listener whenever focus is granted - even the first time! if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { shouldPlayWhenReady = true; @@ -259,34 +248,14 @@ private void requestAudioFocus() { } } - private void abandonAudioFocus() { - if (Build.VERSION.SDK_INT >= 26) { - abandonAudioFocusOreo(); - } else { - audioManager.abandonAudioFocus(focusChangeListener); - } - } - - @RequiresApi(Build.VERSION_CODES.O) - private int requestAudioFocusOreo() { - return audioManager.requestAudioFocus(getAudioFocusRequest()); - } - - @RequiresApi(Build.VERSION_CODES.O) - private void abandonAudioFocusOreo() { - audioManager.abandonAudioFocusRequest(getAudioFocusRequest()); - } - - @TargetApi(Build.VERSION_CODES.O) - private AudioFocusRequest buildFocusRequest() { - return new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN) - .setAudioAttributes((AudioAttributes) Objects.requireNonNull(audioAttributes.unwrap())) + private AudioFocusRequestCompat buildFocusRequest() { + return new AudioFocusRequestCompat.Builder(AudioManagerCompat.AUDIOFOCUS_GAIN) + .setAudioAttributes(audioAttributes) .setOnAudioFocusChangeListener(focusChangeListener) .build(); } - @RequiresApi(Build.VERSION_CODES.O) - private AudioFocusRequest getAudioFocusRequest() { + private AudioFocusRequestCompat getAudioFocusRequest() { if (audioFocusRequest == null) { audioFocusRequest = buildFocusRequest(); } @@ -329,7 +298,7 @@ public Builder withCallback2(PlayerSessionServiceCallback serviceCallback) { public Player build() { // Create some classes we need for the Player. - AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); + AudioManager audioManager = ContextCompat.getSystemService(context, AudioManager.class); AudioAttributesCompat attributes = new AudioAttributesCompat.Builder() .setUsage(AudioAttributesCompat.USAGE_MEDIA) .setContentType(AudioAttributesCompat.CONTENT_TYPE_MUSIC) diff --git a/app/src/main/java/be/ugent/zeus/hydra/urgent/player/PlayerSessionCallback.java b/app/src/main/java/be/ugent/zeus/hydra/urgent/player/PlayerSessionCallback.java index 4226d7320..2cbcfc447 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/urgent/player/PlayerSessionCallback.java +++ b/app/src/main/java/be/ugent/zeus/hydra/urgent/player/PlayerSessionCallback.java @@ -24,6 +24,7 @@ import android.os.Bundle; import android.os.Handler; +import android.os.Looper; import android.support.v4.media.session.MediaSessionCompat; import android.util.Log; import androidx.annotation.NonNull; @@ -45,7 +46,7 @@ class PlayerSessionCallback extends MediaSessionCompat.Callback { private final Player player; private final BecomingNoisyReceiver receiver; private final PlayerSessionServiceCallback serviceCallback; - private final Handler handler = new Handler(); + private final Handler handler = new Handler(Looper.getMainLooper()); private Runnable nextUpdate; diff --git a/app/src/main/java/be/ugent/zeus/hydra/wpi/WpiActivity.java b/app/src/main/java/be/ugent/zeus/hydra/wpi/WpiActivity.java index 10fdce779..07997c99b 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/wpi/WpiActivity.java +++ b/app/src/main/java/be/ugent/zeus/hydra/wpi/WpiActivity.java @@ -27,6 +27,7 @@ import android.content.Intent; import android.os.Bundle; import android.os.Handler; +import android.os.Looper; import android.text.TextUtils; import android.util.Log; import android.view.*; @@ -145,7 +146,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { // is much faster than the actual lock. // In the other case, just do it. if (enabled && (!binding.doorOpen.isEnabled() || !binding.doorClose.isEnabled())) { - new Handler().postDelayed(() -> { + new Handler(Looper.getMainLooper()).postDelayed(() -> { binding.doorOpen.setEnabled(true); binding.doorClose.setEnabled(true); }, 3000); diff --git a/app/src/main/java/be/ugent/zeus/hydra/wpi/account/CombinedUserRequest.java b/app/src/main/java/be/ugent/zeus/hydra/wpi/account/CombinedUserRequest.java index 9ca6efcbe..3534e283d 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/wpi/account/CombinedUserRequest.java +++ b/app/src/main/java/be/ugent/zeus/hydra/wpi/account/CombinedUserRequest.java @@ -24,11 +24,8 @@ import android.content.Context; import android.os.Bundle; -import android.util.Pair; import androidx.annotation.NonNull; -import java.util.function.Function; - import be.ugent.zeus.hydra.common.request.Request; import be.ugent.zeus.hydra.common.request.Result; import be.ugent.zeus.hydra.wpi.tab.user.TabUser; diff --git a/app/src/main/java/be/ugent/zeus/hydra/wpi/cammie/CammieActivity.java b/app/src/main/java/be/ugent/zeus/hydra/wpi/cammie/CammieActivity.java index 1d05bdd7b..d4e6fbd5c 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/wpi/cammie/CammieActivity.java +++ b/app/src/main/java/be/ugent/zeus/hydra/wpi/cammie/CammieActivity.java @@ -25,6 +25,7 @@ import android.content.Intent; import android.os.Bundle; import android.os.Handler; +import android.os.Looper; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; @@ -78,7 +79,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { // we add a delay of about 1 second. // In the other case, just do it. if (enabled && !binding.moveNorthWest.isEnabled()) { - new Handler().postDelayed(() -> toggleButtons(true), 1000); + new Handler(Looper.getMainLooper()).postDelayed(() -> toggleButtons(true), 1000); } else { toggleButtons(enabled); } diff --git a/app/src/main/java/be/ugent/zeus/hydra/wpi/cammie/ChatDialogFragment.java b/app/src/main/java/be/ugent/zeus/hydra/wpi/cammie/ChatDialogFragment.java index a046db38b..d3a85a621 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/wpi/cammie/ChatDialogFragment.java +++ b/app/src/main/java/be/ugent/zeus/hydra/wpi/cammie/ChatDialogFragment.java @@ -61,7 +61,7 @@ public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { .setTitle(R.string.wpi_cammie_chat_dialog_title) .setView(R.layout.fragment_wpi_cammie_chat) .setPositiveButton(R.string.action_send, (dialog, which) -> { - // This will also dismiss the dialog unfortunately. + // This will also dismiss the dialog, unfortunately. buttonPressed = true; TextInputEditText input = (TextInputEditText) DialogCompat.requireViewById((Dialog) dialog, R.id.message_entry); vm.sendMessage(input.getEditableText().toString()); diff --git a/app/src/main/java/be/ugent/zeus/hydra/wpi/cammie/MoveRequest.java b/app/src/main/java/be/ugent/zeus/hydra/wpi/cammie/MoveRequest.java index 0a9fc0789..0e343fe11 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/wpi/cammie/MoveRequest.java +++ b/app/src/main/java/be/ugent/zeus/hydra/wpi/cammie/MoveRequest.java @@ -92,8 +92,9 @@ public Result execute(@NonNull Bundle args) { .addQueryParameter("posY", String.valueOf(command.y)) .build(); - Log.d(TAG, "execute: doing door request to: " + url.toString()); + Log.d(TAG, "execute: doing door request to: " + url); + //noinspection KotlinInternalInJava Request request = new Request.Builder() .url(url) .get() diff --git a/app/src/main/java/be/ugent/zeus/hydra/wpi/door/NfcIntentReceiverActivity.java b/app/src/main/java/be/ugent/zeus/hydra/wpi/door/NfcIntentReceiverActivity.java index 7df2e6cc1..c2ded35d4 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/wpi/door/NfcIntentReceiverActivity.java +++ b/app/src/main/java/be/ugent/zeus/hydra/wpi/door/NfcIntentReceiverActivity.java @@ -32,6 +32,7 @@ import android.util.Log; import android.view.Window; import androidx.annotation.Nullable; +import androidx.core.content.IntentCompat; import androidx.lifecycle.ViewModelProvider; import be.ugent.zeus.hydra.R; @@ -80,9 +81,9 @@ private void handleRequest(Intent intent) { return; } - Parcelable[] rawMessages = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES); + Parcelable[] rawMessages = IntentCompat.getParcelableArrayExtra(intent, NfcAdapter.EXTRA_NDEF_MESSAGES, Parcelable.class); // We only expect one message, so we only listen for one message. - if (rawMessages.length != 1) { + if (rawMessages == null || rawMessages.length != 1) { return; } diff --git a/app/src/main/java/be/ugent/zeus/hydra/wpi/tab/create/CreateTransactionRequest.java b/app/src/main/java/be/ugent/zeus/hydra/wpi/tab/create/CreateTransactionRequest.java index f1848d320..c15424eea 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/wpi/tab/create/CreateTransactionRequest.java +++ b/app/src/main/java/be/ugent/zeus/hydra/wpi/tab/create/CreateTransactionRequest.java @@ -24,7 +24,6 @@ import android.content.Context; import android.os.Bundle; -import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.WorkerThread; @@ -55,7 +54,7 @@ public class CreateTransactionRequest extends OkHttpRequest { private final TransactionForm form; private final Context context; - public CreateTransactionRequest(@NonNull Context context, @NonNull TransactionForm form) { + CreateTransactionRequest(@NonNull Context context, @NonNull TransactionForm form) { super(context); this.context = context.getApplicationContext(); this.form = form; diff --git a/app/src/main/java/be/ugent/zeus/hydra/wpi/tab/create/FormActivity.java b/app/src/main/java/be/ugent/zeus/hydra/wpi/tab/create/FormActivity.java index f018adddf..37014711e 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/wpi/tab/create/FormActivity.java +++ b/app/src/main/java/be/ugent/zeus/hydra/wpi/tab/create/FormActivity.java @@ -29,13 +29,14 @@ import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.core.os.BundleCompat; import androidx.lifecycle.ViewModelProvider; -import com.google.android.material.dialog.MaterialAlertDialogBuilder; - import java.math.BigDecimal; import java.text.NumberFormat; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; import java.util.stream.Collectors; import be.ugent.zeus.hydra.R; @@ -45,6 +46,7 @@ import be.ugent.zeus.hydra.common.ui.BaseActivity; import be.ugent.zeus.hydra.common.ui.SimpleTextWatcher; import be.ugent.zeus.hydra.databinding.ActivityWpiTabTransactionFormBinding; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; /** * Form where the user can create a new transaction. @@ -65,14 +67,14 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { setContentView(ActivityWpiTabTransactionFormBinding::inflate); if (savedInstanceState != null && savedInstanceState.containsKey(KEY_FORM_OBJECT)) { - formObject = savedInstanceState.getParcelable(KEY_FORM_OBJECT); + formObject = BundleCompat.getParcelable(savedInstanceState, KEY_FORM_OBJECT, TransactionForm.class); } else { formObject = new TransactionForm(); } TransactionViewModel model = new ViewModelProvider(this).get(TransactionViewModel.class); - ArrayAdapter autocompleteAdapter = new ArrayAdapter(this, android.R.layout.simple_dropdown_item_1line); + ArrayAdapter autocompleteAdapter = new ArrayAdapter<>(this, android.R.layout.simple_dropdown_item_1line); binding.formMember.setAdapter(autocompleteAdapter); model.getRequestResult().observe(this, EventObserver.with(booleanResult -> { diff --git a/app/src/main/java/be/ugent/zeus/hydra/wpi/tab/create/TransactionForm.java b/app/src/main/java/be/ugent/zeus/hydra/wpi/tab/create/TransactionForm.java index a37fdf567..b7621303f 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/wpi/tab/create/TransactionForm.java +++ b/app/src/main/java/be/ugent/zeus/hydra/wpi/tab/create/TransactionForm.java @@ -118,7 +118,7 @@ protected TransactionForm(Parcel in) { this.description = in.readString(); } - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public static final Parcelable.Creator CREATOR = new Parcelable.Creator<>() { @Override public TransactionForm createFromParcel(Parcel source) { return new TransactionForm(source); diff --git a/app/src/main/java/be/ugent/zeus/hydra/wpi/tab/create/TransactionViewModel.java b/app/src/main/java/be/ugent/zeus/hydra/wpi/tab/create/TransactionViewModel.java index 429e5ce60..c28f90d28 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/wpi/tab/create/TransactionViewModel.java +++ b/app/src/main/java/be/ugent/zeus/hydra/wpi/tab/create/TransactionViewModel.java @@ -24,7 +24,6 @@ import android.app.Application; import androidx.annotation.NonNull; -import androidx.lifecycle.AndroidViewModel; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; @@ -47,7 +46,7 @@ * * @author Niko Strijbol */ -public class TransactionViewModel extends RequestViewModel> { +class TransactionViewModel extends RequestViewModel> { private final MutableLiveData networkState; private final MutableLiveData>> requestResult; diff --git a/app/src/main/java/be/ugent/zeus/hydra/wpi/tab/list/TransactionFragment.java b/app/src/main/java/be/ugent/zeus/hydra/wpi/tab/list/TransactionFragment.java index 4b15c3da1..1053a65e9 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/wpi/tab/list/TransactionFragment.java +++ b/app/src/main/java/be/ugent/zeus/hydra/wpi/tab/list/TransactionFragment.java @@ -30,7 +30,6 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; -import androidx.lifecycle.Observer; import androidx.lifecycle.ViewModelProvider; import androidx.recyclerview.widget.RecyclerView; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; diff --git a/app/src/main/java/be/ugent/zeus/hydra/wpi/tab/list/TransactionViewHolder.java b/app/src/main/java/be/ugent/zeus/hydra/wpi/tab/list/TransactionViewHolder.java index 77e6a0390..9afd33863 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/wpi/tab/list/TransactionViewHolder.java +++ b/app/src/main/java/be/ugent/zeus/hydra/wpi/tab/list/TransactionViewHolder.java @@ -39,7 +39,7 @@ * * @author Niko Strijbol */ -class TransactionViewHolder extends DataViewHolder { +public class TransactionViewHolder extends DataViewHolder { private final ImageView thumbnail; private final TextView title; diff --git a/app/src/main/java/be/ugent/zeus/hydra/wpi/tab/requests/AcceptableRequestsViewHolder.java b/app/src/main/java/be/ugent/zeus/hydra/wpi/tab/requests/AcceptableRequestsViewHolder.java index 7014f3ec3..a5f3e48aa 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/wpi/tab/requests/AcceptableRequestsViewHolder.java +++ b/app/src/main/java/be/ugent/zeus/hydra/wpi/tab/requests/AcceptableRequestsViewHolder.java @@ -40,7 +40,7 @@ * @author Niko Strijbol * @see TabRequestRequest#acceptableRequests(Context) */ -class AcceptableRequestsViewHolder extends DataViewHolder { +public class AcceptableRequestsViewHolder extends DataViewHolder { private final TextView summary; private final TextView description; diff --git a/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/barcode/Barcode.java b/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/barcode/Barcode.java index 9c7cca4a8..f53a31778 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/barcode/Barcode.java +++ b/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/barcode/Barcode.java @@ -22,10 +22,10 @@ package be.ugent.zeus.hydra.wpi.tap.barcode; -import com.squareup.moshi.Json; - import java.util.Objects; +import com.squareup.moshi.Json; + /** * A Tap barcode. * diff --git a/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/cart/Cart.java b/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/cart/Cart.java index 545209b3c..5f4e80907 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/cart/Cart.java +++ b/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/cart/Cart.java @@ -48,7 +48,7 @@ * * @author Niko Strijbol */ -class Cart { +public class Cart { private static final String TAG = "Cart"; private final List orders; diff --git a/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/cart/CartActivity.java b/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/cart/CartActivity.java index c242316c7..df1458a48 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/cart/CartActivity.java +++ b/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/cart/CartActivity.java @@ -236,7 +236,7 @@ private void onBarcodeScan(String barcode) { new MaterialAlertDialogBuilder(CartActivity.this) .setMessage(getString(R.string.wpi_tap_product_not_found, barcode)) .setPositiveButton(R.string.action_share, (dialog, which) -> startActivity(shareIntent)) - .setNegativeButton(android.R.string.no, null) + .setNegativeButton(android.R.string.cancel, null) .show(); return; } diff --git a/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/cart/CartProduct.java b/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/cart/CartProduct.java index 3c1b60104..e4ef29548 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/cart/CartProduct.java +++ b/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/cart/CartProduct.java @@ -23,28 +23,26 @@ package be.ugent.zeus.hydra.wpi.tap.cart; import java.math.BigDecimal; -import java.util.Locale; import java.util.Objects; -import be.ugent.zeus.hydra.common.network.Endpoints; import be.ugent.zeus.hydra.wpi.tap.product.Product; /** * Represents a product (or more than one) in the user's cart. - * + *

* Various details about the product are also saved, but this is to reduce - * the amount of network requests we need to make. + * the number of network requests we need to make. * * @author Niko Strijbol */ -class CartProduct { +public class CartProduct { private final int amount; private final int productId; private final String name; private final int price; private final String thumbnail; - public CartProduct(Product product, int amount) { + CartProduct(Product product, int amount) { this(amount, product.getId(), product.getName(), product.getPrice(), product.getImageUrl()); } diff --git a/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/cart/CartProductAdapter.java b/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/cart/CartProductAdapter.java index c3a9baba8..88c59a117 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/cart/CartProductAdapter.java +++ b/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/cart/CartProductAdapter.java @@ -27,7 +27,6 @@ import be.ugent.zeus.hydra.R; import be.ugent.zeus.hydra.common.ui.recyclerview.adapters.DiffAdapter; -import be.ugent.zeus.hydra.common.ui.recyclerview.adapters.EqualsItemCallback; import be.ugent.zeus.hydra.common.utils.ViewUtils; /** diff --git a/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/cart/CartProductViewHolder.java b/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/cart/CartProductViewHolder.java index f4e6faccf..e92329366 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/cart/CartProductViewHolder.java +++ b/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/cart/CartProductViewHolder.java @@ -22,9 +22,6 @@ package be.ugent.zeus.hydra.wpi.tap.cart; -import static androidx.recyclerview.widget.RecyclerView.NO_POSITION; - -import android.util.Log; import android.view.*; import android.widget.ImageView; import android.widget.TextView; @@ -37,6 +34,8 @@ import be.ugent.zeus.hydra.common.ui.recyclerview.viewholders.DataViewHolder; import be.ugent.zeus.hydra.feed.cards.PriorityUtils; +import static androidx.recyclerview.widget.RecyclerView.NO_POSITION; + /** * View holder for the products in the Tap cart. * diff --git a/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/cart/CartViewModel.java b/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/cart/CartViewModel.java index 5359f3464..4e7101422 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/cart/CartViewModel.java +++ b/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/cart/CartViewModel.java @@ -23,7 +23,6 @@ package be.ugent.zeus.hydra.wpi.tap.cart; import android.app.Application; -import android.util.Log; import androidx.annotation.NonNull; import androidx.lifecycle.*; diff --git a/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/cart/CreateOrderRequest.java b/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/cart/CreateOrderRequest.java index 86770787d..98fa2b03d 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/cart/CreateOrderRequest.java +++ b/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/cart/CreateOrderRequest.java @@ -24,7 +24,6 @@ import android.content.Context; import android.os.Bundle; -import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.WorkerThread; diff --git a/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/cart/ExistingCartRequest.java b/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/cart/ExistingCartRequest.java index 1a7cd88e5..3d87adc70 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/cart/ExistingCartRequest.java +++ b/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/cart/ExistingCartRequest.java @@ -28,9 +28,6 @@ import androidx.annotation.NonNull; import androidx.preference.PreferenceManager; -import com.squareup.moshi.JsonAdapter; -import com.squareup.moshi.Moshi; - import java.io.IOException; import java.time.OffsetDateTime; import java.util.ArrayList; @@ -39,6 +36,8 @@ import be.ugent.zeus.hydra.common.network.InstanceProvider; import be.ugent.zeus.hydra.common.request.Request; import be.ugent.zeus.hydra.common.request.Result; +import com.squareup.moshi.JsonAdapter; +import com.squareup.moshi.Moshi; /** * Get an existing cart if there is one available. @@ -64,11 +63,6 @@ public static void saveCartStorage(@NonNull Context context, @NonNull StorageCar .putString(PREF_CART_STORAGE, raw) .apply(); } - - public static boolean hasExistingCart(@NonNull Context context) { - SharedPreferences p = PreferenceManager.getDefaultSharedPreferences(context); - return p.contains(PREF_CART_STORAGE); - } @NonNull @Override diff --git a/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/cart/OrderResult.java b/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/cart/OrderResult.java index cc8a3846d..7b2df2f2d 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/cart/OrderResult.java +++ b/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/cart/OrderResult.java @@ -33,7 +33,7 @@ * * @author Niko Strijbol */ -class OrderResult { +public class OrderResult { private Integer id; @Json(name = "user_id") private int userId; diff --git a/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/cart/ProductPickerDialogFragment.java b/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/cart/ProductPickerDialogFragment.java index 56c2697fa..0d7d35652 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/cart/ProductPickerDialogFragment.java +++ b/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/cart/ProductPickerDialogFragment.java @@ -22,7 +22,6 @@ package be.ugent.zeus.hydra.wpi.tap.cart; -import android.app.Dialog; import android.content.Context; import android.graphics.Rect; import android.os.Bundle; diff --git a/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/cart/StorageCart.java b/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/cart/StorageCart.java index 206cf9707..9626a929a 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/cart/StorageCart.java +++ b/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/cart/StorageCart.java @@ -33,7 +33,7 @@ * * @author Niko Strijbol */ -class StorageCart { +public class StorageCart { private final List> productIdsAndAmounts; private final OffsetDateTime lastEdited; diff --git a/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/order/Order.java b/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/order/Order.java index 87ed291aa..401c4b366 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/order/Order.java +++ b/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/order/Order.java @@ -24,13 +24,12 @@ import androidx.annotation.Nullable; -import com.squareup.moshi.Json; - import java.math.BigDecimal; import java.time.OffsetDateTime; import java.util.List; import be.ugent.zeus.hydra.wpi.tap.product.Product; +import com.squareup.moshi.Json; /** * Represents an order on Tap. diff --git a/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/order/OrderViewHolder.java b/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/order/OrderViewHolder.java index 2a200e3d3..914aaac65 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/order/OrderViewHolder.java +++ b/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/order/OrderViewHolder.java @@ -26,7 +26,6 @@ import android.widget.Button; import android.widget.TextView; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import java.text.NumberFormat; import java.util.Currency; @@ -45,7 +44,7 @@ * * @author Niko Strijbol */ -class OrderViewHolder extends DataViewHolder { +public class OrderViewHolder extends DataViewHolder { private final TextView orderDescription; private final TextView orderDate; diff --git a/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/product/ProductAdapter.java b/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/product/ProductAdapter.java index f5323ef83..4ad96f6d9 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/product/ProductAdapter.java +++ b/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/product/ProductAdapter.java @@ -22,22 +22,15 @@ package be.ugent.zeus.hydra.wpi.tap.product; -import android.view.View; import android.view.ViewGroup; import androidx.annotation.NonNull; -import java.util.List; import java.util.Locale; -import java.util.function.BiPredicate; import java.util.function.Consumer; -import java.util.function.Function; import be.ugent.zeus.hydra.R; -import be.ugent.zeus.hydra.common.ui.customtabs.ActivityHelper; -import be.ugent.zeus.hydra.common.ui.recyclerview.adapters.DiffAdapter; import be.ugent.zeus.hydra.common.ui.recyclerview.adapters.SearchableAdapter; import be.ugent.zeus.hydra.common.utils.ViewUtils; -import be.ugent.zeus.hydra.news.NewsArticle; /** * @author Niko Strijbol diff --git a/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/product/ProductFragment.java b/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/product/ProductFragment.java index 0e1cfefed..b238cd3d0 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/product/ProductFragment.java +++ b/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/product/ProductFragment.java @@ -33,6 +33,7 @@ import androidx.core.content.pm.ShortcutInfoCompat; import androidx.core.content.pm.ShortcutManagerCompat; import androidx.core.graphics.drawable.IconCompat; +import androidx.core.view.MenuProvider; import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProvider; import androidx.preference.PreferenceManager; @@ -51,6 +52,7 @@ import be.ugent.zeus.hydra.wpi.tap.cart.CartActivity; import com.google.android.material.floatingactionbutton.FloatingActionButton; import com.google.android.material.snackbar.Snackbar; +import org.jetbrains.annotations.NotNull; import static be.ugent.zeus.hydra.wpi.WpiActivity.ACTIVITY_DO_REFRESH; import static be.ugent.zeus.hydra.wpi.tap.product.ProductData.PREF_SHOW_ONLY_IN_STOCK; @@ -72,7 +74,6 @@ public class ProductFragment extends Fragment { @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setHasOptionsMenu(true); if (savedInstanceState != null) { favouriteProductId = savedInstanceState.getInt(SAVED_FAVOURITE, -1); } @@ -123,7 +124,7 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat fab.hide(); } else { Optional product = pf.first.stream().filter(p -> p.getId() == pf.second).findFirst(); - if (!product.isPresent()) { + if (product.isEmpty()) { // Oops. fab.hide(); requireActivity().invalidateOptionsMenu(); @@ -143,42 +144,42 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat maybeUpdateShortcut(); } }); - } - - @Override - public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { - inflater.inflate(R.menu.menu_wpi_products, menu); - // Set saved preference for stock stuff. - MenuItem item = menu.findItem(R.id.action_filter_stock); - SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(requireContext()); - boolean show = preferences.getBoolean(PREF_SHOW_ONLY_IN_STOCK, false); - item.setChecked(show); + requireActivity().addMenuProvider(new MenuProvider() { + @Override + public void onCreateMenu(@NonNull @NotNull Menu menu, @NonNull @NotNull MenuInflater menuInflater) { + menuInflater.inflate(R.menu.menu_wpi_products, menu); - // Hide or show based on whether the user has a favourite item or not. - MenuItem pinItem = menu.findItem(R.id.action_pin_favourite); - pinItem.setVisible(favouriteProductId != -1); - - super.onCreateOptionsMenu(menu, inflater); - } + // Set saved preference for stock stuff. + MenuItem item = menu.findItem(R.id.action_filter_stock); + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(requireContext()); + boolean show = preferences.getBoolean(PREF_SHOW_ONLY_IN_STOCK, false); + item.setChecked(show); - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == R.id.action_filter_stock) { - boolean checked = !item.isChecked(); - SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(requireContext()); - preferences.edit() - .putBoolean(PREF_SHOW_ONLY_IN_STOCK, checked) - .apply(); - item.setChecked(checked); - viewModel.requestRefresh(); - return true; - } else if (item.getItemId() == R.id.action_pin_favourite) { - createOrUpdatePinnedShortcut(); - return true; - } + // Hide or show based on whether the user has a favourite item or not. + MenuItem pinItem = menu.findItem(R.id.action_pin_favourite); + pinItem.setVisible(favouriteProductId != -1); + } - return super.onOptionsItemSelected(item); + @Override + public boolean onMenuItemSelected(@NonNull @NotNull MenuItem item) { + if (item.getItemId() == R.id.action_filter_stock) { + boolean checked = !item.isChecked(); + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(requireContext()); + preferences.edit() + .putBoolean(PREF_SHOW_ONLY_IN_STOCK, checked) + .apply(); + item.setChecked(checked); + viewModel.requestRefresh(); + return true; + } else if (item.getItemId() == R.id.action_pin_favourite) { + createOrUpdatePinnedShortcut(); + return true; + } + + return false; + } + }, getViewLifecycleOwner()); } private void onError(Throwable throwable) { diff --git a/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/product/ProductViewHolder.java b/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/product/ProductViewHolder.java index fb81705d7..61669eb67 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/product/ProductViewHolder.java +++ b/app/src/main/java/be/ugent/zeus/hydra/wpi/tap/product/ProductViewHolder.java @@ -25,11 +25,8 @@ import android.view.View; import android.widget.ImageView; import android.widget.TextView; - import androidx.annotation.Nullable; -import org.w3c.dom.Text; - import java.text.NumberFormat; import java.util.Currency; import java.util.function.Consumer; @@ -43,7 +40,7 @@ * * @author Niko Strijbol */ -class ProductViewHolder extends DataViewHolder { +public class ProductViewHolder extends DataViewHolder { private final ImageView thumbnail; private final TextView title; From 88efd4b6e7549e99740f0326efce0d6d2a8bfd10 Mon Sep 17 00:00:00 2001 From: Niko Strijbol Date: Fri, 27 Oct 2023 19:10:43 +0200 Subject: [PATCH 2/5] Enable JDK 17 source code --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 8dc646a02..aa28d290b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -104,8 +104,8 @@ android { compileOptions { coreLibraryDesugaringEnabled true - sourceCompatibility JavaVersion.VERSION_11 - targetCompatibility JavaVersion.VERSION_11 + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 } buildTypes { From 496ce955600ce2768f1a5c6e6f6618ca85597522 Mon Sep 17 00:00:00 2001 From: Niko Strijbol Date: Thu, 30 Nov 2023 18:58:23 +0100 Subject: [PATCH 3/5] Use new Java language features Migrate code to use: - record classes - enhanced switch statements - more --- app/build.gradle | 8 +- app/src/main/AndroidManifest.xml | 2 +- .../be/ugent/zeus/hydra/MainActivity.java | 18 +- .../zeus/hydra/association/Association.java | 101 +++----- .../EventPage.java => AssociationList.java} | 39 ++- .../{common => }/AssociationMap.java | 55 +++-- .../hydra/association/AssociationRequest.java | 125 ++++++++++ .../AssociationVisibilityStorage.java | 16 +- .../hydra/association/{event => }/Event.java | 139 ++++------- .../{event => }/EventDetailsActivity.java | 74 +++--- .../association/{common => }/EventFilter.java | 20 +- .../association/{common => }/EventItem.java | 97 ++++---- .../zeus/hydra/association/EventList.java} | 18 +- .../zeus/hydra/association/EventPage.java} | 18 +- .../{common => }/EventRequest.java | 22 +- .../common/AssociationRequestBuilder.java | 154 ------------ .../common/EventListConverter.java | 67 ----- .../hydra/association/event/EventSorter.java | 41 ---- ...nsAdapter.java => AssociationAdapter.java} | 2 +- .../list/AssociationViewHolder.java | 2 +- .../list/DateHeaderViewHolder.java | 4 +- .../hydra/association/list/EventAdapter.java | 6 +- .../hydra/association/list/EventFragment.java | 45 ++-- .../association/list/EventListConverter.java | 66 ----- .../association/list/EventViewHolder.java | 17 +- .../association/list/EventViewModel.java | 17 +- ...ssociationSelectionPreferenceFragment.java | 8 +- .../preference/AssociationViewHolder.java | 2 +- .../preference/AssociationsViewModel.java | 11 +- .../SearchableAssociationsAdapter.java | 4 +- .../zeus/hydra/common/ArticleViewer.java | 23 +- .../hydra/common/ExtendedSparseArray.java | 2 +- .../common/arch/data/RequestLiveData.java | 12 +- .../common/arch/observers/ErrorObserver.java | 2 +- .../arch/observers/PartialErrorObserver.java | 2 +- .../common/converter/PairJsonAdapter.java | 3 +- .../zeus/hydra/common/database/Database.java | 4 +- .../common/network/InstanceProvider.java | 14 +- .../common/network/JsonOkHttpRequest.java | 18 +- .../hydra/common/network/OkHttpRequest.java | 4 +- .../zeus/hydra/common/reporting/Event.java | 18 +- .../zeus/hydra/common/request/Request.java | 10 +- .../zeus/hydra/common/request/Result.java | 8 +- .../hydra/common/scanner/BarcodeScanner.java | 8 +- .../hydra/common/ui/RefreshViewModel.java | 2 +- .../hydra/common/ui/RequestViewModel.java | 4 +- .../common/ui/SingleRefreshViewModel.java | 6 +- .../common/ui/customtabs/ActivityHelper.java | 19 -- .../ui/customtabs/CustomTabsHelper.java | 2 +- .../ui/customtabs/HasTabActivityHelper.java | 30 +-- .../ui/customtabs/NoTabActivityHelper.java | 15 -- .../common/ui/recyclerview/ResultStarter.java | 2 +- .../recyclerview/adapters/AdapterUpdate.java | 2 +- .../ui/recyclerview/adapters/DataAdapter.java | 8 +- .../recyclerview/adapters/DataContainer.java | 8 +- .../ui/recyclerview/adapters/DiffUpdate.java | 2 +- .../ui/recyclerview/adapters/DumbUpdate.java | 2 +- .../adapters/MultiSelectAdapter.java | 30 +-- .../MultiSelectSearchableAdapter.java | 6 +- .../adapters/SearchableAdapter.java | 11 - .../viewholders/DateHeaderViewHolder.java | 2 +- .../common/ui/widgets/DisplayableMenu.java | 52 ++-- .../hydra/common/ui/widgets/MenuTable.java | 2 +- .../zeus/hydra/common/utils/DateUtils.java | 18 +- .../ugent/zeus/hydra/feed/FeedCollection.java | 2 +- .../ugent/zeus/hydra/feed/FeedException.java | 8 +- .../ugent/zeus/hydra/feed/FeedLiveData.java | 17 +- .../ugent/zeus/hydra/feed/FeedViewModel.java | 2 +- .../hydra/feed/HideableHomeFeedRequest.java | 10 +- .../zeus/hydra/feed/HomeFeedAdapter.java | 40 ++- .../zeus/hydra/feed/HomeFeedFragment.java | 22 +- .../zeus/hydra/feed/HomeFeedRequest.java | 2 +- .../be/ugent/zeus/hydra/feed/cards/Card.java | 12 +- .../zeus/hydra/feed/cards/CardViewHolder.java | 8 +- .../cards/debug/DebugCardViewHolder.java} | 23 +- .../hydra/feed/cards/debug/WaitRequest.java | 2 +- .../feed/cards/dismissal/CardDismissal.java | 6 +- .../feed/cards/dismissal/CardIdentifier.java | 5 +- .../feed/cards/dismissal/DismissalDao.java | 2 +- .../hydra/feed/cards/event/EventCard.java | 16 +- .../feed/cards/event/EventCardViewHolder.java | 16 +- .../hydra/feed/cards/event/EventRequest.java | 16 +- .../hydra/feed/cards/library/LibraryCard.java | 6 +- .../feed/cards/library/LibraryRequest.java | 5 +- .../feed/cards/library/LibraryViewHolder.java | 6 +- .../hydra/feed/cards/news/NewsItemCard.java | 13 +- .../feed/cards/news/NewsItemViewHolder.java | 14 +- .../hydra/feed/cards/news/NewsRequest.java | 4 +- .../feed/cards/resto/RestoCardViewHolder.java | 31 +-- .../feed/cards/resto/RestoKindCommand.java | 27 +-- .../hydra/feed/cards/resto/RestoMenuCard.java | 22 +- .../hydra/feed/cards/resto/RestoRequest.java | 4 +- .../feed/cards/schamper/SchamperCard.java | 16 +- .../feed/cards/schamper/SchamperRequest.java | 4 +- .../cards/schamper/SchamperViewHolder.java | 19 +- .../LimitingSpecialEventRequest.java | 18 +- .../cards/specialevent/SpecialEventCard.java | 16 +- .../SpecialEventCardViewHolder.java | 10 +- .../hydra/feed/cards/urgent/UrgentCard.java | 6 +- .../feed/cards/urgent/UrgentRequest.java | 2 +- .../feed/cards/urgent/UrgentViewHolder.java | 2 +- .../hydra/feed/commands/CommandResult.java | 6 +- .../commands/DisableAssociationCommand.java | 4 +- .../feed/commands/DisableIndividualCard.java | 8 +- .../feed/commands/DisableTypeCommand.java | 2 +- .../hydra/feed/commands/DismissalEvent.java | 4 +- .../zeus/hydra/feed/commands/FeedCommand.java | 4 +- .../hydra/feed/operations/FeedOperation.java | 2 +- .../feed/operations/RemoveOperation.java | 4 +- .../feed/operations/RequestOperation.java | 8 +- .../feed/preferences/DeleteViewModel.java | 2 +- .../preferences/HomeFeedSelectFragment.java | 26 +- .../hydra/feed/preferences/HomeFragment.java | 4 +- .../ugent/zeus/hydra/info/InfoFragment.java | 6 +- .../be/ugent/zeus/hydra/info/InfoItem.java | 117 ++------- .../be/ugent/zeus/hydra/info/InfoRequest.java | 8 +- .../be/ugent/zeus/hydra/info/InfoType.java | 14 +- .../ugent/zeus/hydra/info/InfoViewHolder.java | 8 +- .../ugent/zeus/hydra/info/InfoViewModel.java | 2 +- .../be/ugent/zeus/hydra/library/Library.java | 228 ++++++------------ .../library/details/FavouriteViewModel.java | 8 +- .../hydra/library/details/HoursViewModel.java | 2 +- .../details/LibraryDetailActivity.java | 70 +++--- .../hydra/library/details/OpeningHours.java | 85 +------ .../library/details/OpeningHoursRequest.java | 8 +- ...pository.java => FavouriteRepository.java} | 10 +- ...vouritesTable.java => FavouriteTable.java} | 4 +- .../library/favourites/LibraryFavourite.java | 8 +- .../zeus/hydra/library/list/LibraryList.java | 59 ++--- .../library/list/LibraryListAdapter.java | 4 +- .../library/list/LibraryListFragment.java | 8 +- .../library/list/LibraryListRequest.java | 4 +- .../hydra/library/list/LibraryLiveData.java | 11 +- .../hydra/library/list/LibraryViewHolder.java | 10 +- .../hydra/library/list/LibraryViewModel.java | 2 +- .../be/ugent/zeus/hydra/news/NewsArticle.java | 97 ++------ .../ugent/zeus/hydra/news/NewsFragment.java | 8 +- .../zeus/hydra/news/NewsItemViewHolder.java | 16 +- .../be/ugent/zeus/hydra/news/NewsRequest.java | 4 +- .../be/ugent/zeus/hydra/news/NewsStream.java | 52 +--- .../ugent/zeus/hydra/news/NewsViewModel.java | 4 +- .../hydra/onboarding/OnboardingActivity.java | 2 +- .../zeus/hydra/preferences/ThemeFragment.java | 35 +-- .../ugent/zeus/hydra/resto/RestoChoice.java | 34 +-- .../be/ugent/zeus/hydra/resto/RestoMeal.java | 82 +------ .../be/ugent/zeus/hydra/resto/RestoMenu.java | 127 +++++----- .../hydra/resto/RestoPreferenceFragment.java | 20 +- .../zeus/hydra/resto/SingleDayFragment.java | 21 +- .../zeus/hydra/resto/extrafood/ExtraFood.java | 46 +--- .../resto/extrafood/ExtraFoodActivity.java | 6 +- .../extrafood/ExtraFoodPagerAdapter.java | 20 +- .../resto/extrafood/ExtraFoodRequest.java | 4 +- .../resto/extrafood/ExtraFoodViewModel.java | 18 +- .../zeus/hydra/resto/extrafood/Food.java | 47 +--- .../hydra/resto/extrafood/FoodFragment.java | 6 +- .../hydra/resto/extrafood/FoodViewHolder.java | 4 +- .../zeus/hydra/resto/history/DayRequest.java | 4 +- .../hydra/resto/history/HistoryActivity.java | 41 ++-- .../resto/history/SingleDayLiveData.java | 14 +- .../resto/history/SingleDayViewModel.java | 4 +- .../zeus/hydra/resto/menu/LegendFragment.java | 4 +- .../zeus/hydra/resto/menu/MenuFilter.java | 2 +- .../hydra/resto/menu/MenuPagerAdapter.java | 2 +- .../zeus/hydra/resto/menu/MenuRequest.java | 4 +- .../zeus/hydra/resto/menu/MenuViewModel.java | 2 +- .../zeus/hydra/resto/menu/RestoFragment.java | 39 ++- .../zeus/hydra/resto/meta/MetaRequest.java | 4 +- .../zeus/hydra/resto/meta/MetaViewModel.java | 2 +- .../be/ugent/zeus/hydra/resto/meta/Resto.java | 87 ++----- .../zeus/hydra/resto/meta/RestoMeta.java | 26 +- .../meta/selectable/SelectableLiveData.java | 8 +- .../selectable/SelectableMetaRequest.java | 6 +- .../selectable/SelectableMetaViewModel.java | 2 +- .../resto/meta/selectable/SelectedResto.java | 100 ++------ .../zeus/hydra/resto/salad/SaladActivity.java | 8 +- .../zeus/hydra/resto/salad/SaladBowl.java | 49 +--- .../zeus/hydra/resto/salad/SaladHolder.java | 6 +- .../zeus/hydra/resto/salad/SaladRequest.java | 15 +- .../hydra/resto/salad/SaladViewModel.java | 2 +- .../resto/sandwich/SandwichPagerAdapter.java | 34 +-- .../ecological/EcologicalFragment.java | 8 +- .../ecological/EcologicalRequest.java | 6 +- .../ecological/EcologicalSandwich.java | 86 ++----- .../ecological/EcologicalViewHolder.java | 10 +- .../ecological/EcologicalViewModel.java | 2 +- .../sandwich/regular/RegularFragment.java | 8 +- .../resto/sandwich/regular/RegularHolder.java | 6 +- .../sandwich/regular/RegularRequest.java | 6 +- .../sandwich/regular/RegularSandwich.java | 63 +---- .../sandwich/regular/RegularViewModel.java | 2 +- .../be/ugent/zeus/hydra/schamper/Article.java | 120 +++------ .../schamper/SchamperArticlesRequest.java | 4 +- .../zeus/hydra/schamper/SchamperFragment.java | 14 +- .../hydra/schamper/SchamperViewHolder.java | 16 +- .../hydra/schamper/SchamperViewModel.java | 2 +- .../zeus/hydra/specialevent/SpecialEvent.java | 138 +---------- .../specialevent/SpecialEventRequest.java | 4 +- .../specialevent/SpecialEventWrapper.java | 39 +-- .../ugent/zeus/hydra/urgent/MusicService.java | 4 +- .../hydra/urgent/ProgrammeInformation.java | 46 +--- .../zeus/hydra/urgent/UrgentFragment.java | 2 +- .../ugent/zeus/hydra/urgent/UrgentInfo.java | 45 +--- .../zeus/hydra/urgent/UrgentInfoRequest.java | 2 +- .../urgent/player/UrgentTrackProvider.java | 20 +- .../be/ugent/zeus/hydra/wpi/WpiActivity.java | 14 +- .../be/ugent/zeus/hydra/wpi/WpiViewModel.java | 2 +- .../zeus/hydra/wpi/account/CombinedUser.java | 86 +------ .../wpi/account/CombinedUserRequest.java | 25 +- .../wpi/account/CombinedUserViewModel.java | 2 +- .../hydra/wpi/door/DoorRequestResult.java | 26 +- .../hydra/wpi/tab/create/FormActivity.java | 6 +- .../zeus/hydra/wpi/tab/create/Member.java | 27 +-- .../hydra/wpi/tab/create/MemberRequest.java | 4 +- .../hydra/wpi/tab/create/TransactionForm.java | 6 - .../wpi/tab/create/TransactionViewModel.java | 8 +- .../zeus/hydra/wpi/tab/list/Transaction.java | 37 +-- .../wpi/tab/list/TransactionAdapter.java | 2 +- .../wpi/tab/list/TransactionFragment.java | 10 +- .../wpi/tab/list/TransactionRequest.java | 4 +- .../wpi/tab/list/TransactionViewHolder.java | 14 +- .../wpi/tab/list/TransactionViewModel.java | 4 +- .../AcceptableRequestsViewHolder.java | 6 +- .../tab/requests/RequestActionRequest.java | 2 +- .../hydra/wpi/tab/requests/TabRequest.java | 3 +- .../wpi/tab/requests/TabRequestRequest.java | 4 +- .../wpi/tab/requests/TabRequestsAdapter.java | 2 +- .../zeus/hydra/wpi/tab/user/TabUser.java | 38 +-- .../hydra/wpi/tab/user/TabUserRequest.java | 4 +- .../EventList.java => wpi/tap/TapUtils.java} | 47 ++-- .../zeus/hydra/wpi/tap/barcode/Barcode.java | 48 +--- .../hydra/wpi/tap/barcode/BarcodeRequest.java | 4 +- .../ugent/zeus/hydra/wpi/tap/cart/Cart.java | 29 ++- .../zeus/hydra/wpi/tap/cart/CartActivity.java | 18 +- .../hydra/wpi/tap/cart/CartInteraction.java | 9 +- .../zeus/hydra/wpi/tap/cart/CartProduct.java | 75 ++---- .../wpi/tap/cart/CartProductViewHolder.java | 18 +- .../zeus/hydra/wpi/tap/cart/CartRequest.java | 9 +- .../hydra/wpi/tap/cart/CartViewModel.java | 2 +- .../wpi/tap/cart/CreateOrderRequest.java | 2 +- .../wpi/tap/cart/ExistingCartRequest.java | 8 +- .../zeus/hydra/wpi/tap/cart/OrderResult.java | 49 +--- .../hydra/wpi/tap/cart/ProductIdAmount.java} | 22 +- .../zeus/hydra/wpi/tap/cart/StorageCart.java | 36 +-- .../wpi/tap/order/CancelOrderRequest.java | 2 +- .../ugent/zeus/hydra/wpi/tap/order/Order.java | 52 ++-- .../hydra/wpi/tap/order/OrderAdapter.java | 2 +- .../hydra/wpi/tap/order/OrderRequest.java | 2 +- .../hydra/wpi/tap/order/OrderViewHolder.java | 6 +- .../zeus/hydra/wpi/tap/product/Product.java | 91 ++----- .../hydra/wpi/tap/product/ProductAdapter.java | 2 +- .../hydra/wpi/tap/product/ProductData.java | 4 +- .../wpi/tap/product/ProductFragment.java | 18 +- .../hydra/wpi/tap/product/ProductRequest.java | 4 +- .../wpi/tap/product/ProductViewHolder.java | 12 +- .../wpi/tap/product/ProductViewModel.java | 4 +- .../zeus/hydra/wpi/tap/user/TapUser.java | 80 ++---- .../hydra/wpi/tap/user/TapUserRequest.java | 4 +- .../main/res/layout/activity_event_detail.xml | 2 +- .../common/barcode/OpenBarcodeScanner.java | 7 +- .../resto/meta/RestoLocationActivity.java | 14 +- .../common/barcode/GoogleBarcodeScanner.java | 15 +- .../common/reporting/FirebaseTracker.java | 4 +- .../resto/meta/RestoLocationActivity.java | 16 +- .../be/ugent/zeus/hydra/MainActivityTest.java | 4 +- .../hydra/association/AssociationTest.java | 20 +- .../{common => }/AssociationsRequestTest.java | 8 +- .../EventDetailsActivityDeviceTest.java | 37 +-- .../{event => }/EventDetailsActivityTest.java | 12 +- .../{list => }/EventListConverterTest.java | 16 +- .../association/{event => }/EventTest.java | 49 ++-- .../association/event/EventSorterTest.java | 60 ----- .../association/list/EventViewHolderTest.java | 23 +- .../list/MemoryAssociationMap.java | 65 ----- .../preference/AssociationViewHolderTest.java | 2 +- .../ugent/zeus/hydra/common/MockParcel.java | 1 + .../be/ugent/zeus/hydra/common/ModelTest.java | 6 +- .../network/AbstractJsonRequestTest.java | 67 +---- .../common/network/JsonOkHttpRequestTest.java | 67 ++--- .../recyclerview/adapters/DiffUpdateTest.java | 14 +- .../recyclerview/adapters/DumbUpdateTest.java | 4 +- .../common/utils/ExtendedSparseArrayTest.java | 4 +- .../hydra/common/utils/FriendlyDateTest.java | 24 +- .../common/utils/FullFriendlyDateTest.java | 24 +- .../zeus/hydra/feed/CardDismissalTest.java | 2 - .../zeus/hydra/feed/CardIdentifierTest.java | 2 - .../cards/dismissal/DismissalDaoTest.java | 24 +- .../cards/event/EventCardViewHolderTest.java | 8 +- .../AbstractFeedViewHolderTest.java | 6 +- .../cards/news/NewsItemViewHolderTest.java | 8 +- .../cards/resto/RestoCardViewHolderTest.java | 69 ------ .../schamper/SchamperViewHolderTest.java | 65 ----- .../SpecialEventCardViewHolderTest.java | 65 ----- .../cards/urgent/UrgentViewHolderTest.java | 2 +- .../commands/DisableIndividualCardTest.java | 2 +- .../feed/commands/MemoryDismissalDao.java | 10 +- .../feed/specialevent/SpecialEventTest.java | 43 ---- .../ugent/zeus/hydra/info/InfoItemTest.java | 48 +--- .../zeus/hydra/info/InfoViewHolderTest.java | 2 +- .../ugent/zeus/hydra/library/LibraryTest.java | 23 +- .../details/OpeningHoursRequestTest.java | 6 +- .../library/favourites/FavouriteDaoTest.java | 25 +- .../hydra/library/list/LibraryListTest.java | 16 +- .../library/list/LibraryViewHolderTest.java | 6 +- .../hydra/news/NewsItemViewHolderTest.java | 8 +- .../resto/extrafood/FoodViewHolderTest.java | 2 +- .../hydra/resto/history/DayRequestTest.java | 2 +- .../zeus/hydra/resto/menu/MenuFilterTest.java | 38 ++- .../hydra/resto/menu/MenuRequestTest.java | 2 +- .../ecological/EcologicalRequestTest.java | 2 +- .../ecological/EcologicalViewHolderTest.java | 2 +- .../sandwich/regular/RegularRequestTest.java | 2 +- .../regular/RegularViewHolderTest.java | 2 +- .../zeus/hydra/schamper/ArticleTest.java | 17 +- .../schamper/SchamperViewHolderTest.java | 4 +- .../be/ugent/zeus/hydra/testing/Assert.java | 40 ++- .../be/ugent/zeus/hydra/testing/Utils.java | 4 +- app/src/test/resources/robolectric.properties | 3 +- build.gradle | 4 + .../materialintro/app/IntroActivity.java | 42 +--- .../materialintro/slide/FragmentSlide.java | 17 +- .../materialintro/util/AnimUtils.java | 2 - 321 files changed, 2052 insertions(+), 4637 deletions(-) rename app/src/main/java/be/ugent/zeus/hydra/association/{event/EventPage.java => AssociationList.java} (63%) rename app/src/main/java/be/ugent/zeus/hydra/association/{common => }/AssociationMap.java (55%) create mode 100644 app/src/main/java/be/ugent/zeus/hydra/association/AssociationRequest.java rename app/src/main/java/be/ugent/zeus/hydra/association/{common => }/AssociationVisibilityStorage.java (92%) rename app/src/main/java/be/ugent/zeus/hydra/association/{event => }/Event.java (59%) rename app/src/main/java/be/ugent/zeus/hydra/association/{event => }/EventDetailsActivity.java (79%) rename app/src/main/java/be/ugent/zeus/hydra/association/{common => }/EventFilter.java (85%) rename app/src/main/java/be/ugent/zeus/hydra/association/{common => }/EventItem.java (50%) rename app/src/{test/java/be/ugent/zeus/hydra/association/event/EventPageTest.java => main/java/be/ugent/zeus/hydra/association/EventList.java} (76%) rename app/src/{test/java/be/ugent/zeus/hydra/association/event/EventListTest.java => main/java/be/ugent/zeus/hydra/association/EventPage.java} (76%) rename app/src/main/java/be/ugent/zeus/hydra/association/{common => }/EventRequest.java (84%) delete mode 100644 app/src/main/java/be/ugent/zeus/hydra/association/common/AssociationRequestBuilder.java delete mode 100644 app/src/main/java/be/ugent/zeus/hydra/association/common/EventListConverter.java delete mode 100644 app/src/main/java/be/ugent/zeus/hydra/association/event/EventSorter.java rename app/src/main/java/be/ugent/zeus/hydra/association/list/{AssociationsAdapter.java => AssociationAdapter.java} (96%) delete mode 100644 app/src/main/java/be/ugent/zeus/hydra/association/list/EventListConverter.java rename app/src/{test/java/be/ugent/zeus/hydra/association/list/EventItemTest.java => main/java/be/ugent/zeus/hydra/feed/cards/debug/DebugCardViewHolder.java} (71%) rename app/src/main/java/be/ugent/zeus/hydra/library/favourites/{FavouritesRepository.java => FavouriteRepository.java} (84%) rename app/src/main/java/be/ugent/zeus/hydra/library/favourites/{FavouritesTable.java => FavouriteTable.java} (96%) rename app/src/main/java/be/ugent/zeus/hydra/{association/event/EventList.java => wpi/tap/TapUtils.java} (58%) rename app/src/{test/java/be/ugent/zeus/hydra/feed/specialevent/SpecialEventWrapperTest.java => main/java/be/ugent/zeus/hydra/wpi/tap/cart/ProductIdAmount.java} (67%) rename app/src/test/java/be/ugent/zeus/hydra/association/{common => }/AssociationsRequestTest.java (86%) rename app/src/test/java/be/ugent/zeus/hydra/association/{event => }/EventDetailsActivityDeviceTest.java (63%) rename app/src/test/java/be/ugent/zeus/hydra/association/{event => }/EventDetailsActivityTest.java (84%) rename app/src/test/java/be/ugent/zeus/hydra/association/{list => }/EventListConverterTest.java (86%) rename app/src/test/java/be/ugent/zeus/hydra/association/{event => }/EventTest.java (73%) delete mode 100644 app/src/test/java/be/ugent/zeus/hydra/association/event/EventSorterTest.java delete mode 100644 app/src/test/java/be/ugent/zeus/hydra/association/list/MemoryAssociationMap.java delete mode 100644 app/src/test/java/be/ugent/zeus/hydra/feed/cards/resto/RestoCardViewHolderTest.java delete mode 100644 app/src/test/java/be/ugent/zeus/hydra/feed/cards/schamper/SchamperViewHolderTest.java delete mode 100644 app/src/test/java/be/ugent/zeus/hydra/feed/cards/specialevent/SpecialEventCardViewHolderTest.java delete mode 100644 app/src/test/java/be/ugent/zeus/hydra/feed/specialevent/SpecialEventTest.java diff --git a/app/build.gradle b/app/build.gradle index aa28d290b..67012df0c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -120,7 +120,7 @@ android { debug { // Disable crashlytics in debug builds if necessary. ext.enableCrashlytics = Boolean.parseBoolean(props.getProperty("hydra.debug.reporting")) - testCoverageEnabled true +// testCoverageEnabled true } } @@ -199,6 +199,9 @@ dependencies { implementation 'dev.chrisbanes.insetter:insetter:0.6.1' implementation 'com.github.niqdev:ipcam-view:2.4.0' + annotationProcessor 'io.soabase.record-builder:record-builder-processor:37' + compileOnly 'io.soabase.record-builder:record-builder-core:37' + // Dependencies for the Play Store version. storeImplementation 'com.google.android.gms:play-services-maps:18.2.0' storeImplementation 'com.google.firebase:firebase-analytics:21.4.0' @@ -230,9 +233,10 @@ dependencies { testImplementation 'nl.jqno.equalsverifier:equalsverifier:3.15.2' testImplementation 'com.shazam:shazamcrest:0.11' testImplementation 'org.skyscreamer:jsonassert:1.5.1' - testImplementation 'org.jeasy:easy-random-core:5.0.0' + testImplementation 'org.jeasy:easy-random-core:6.0.0-SNAPSHOT' testImplementation 'org.apache.commons:commons-lang3:3.13.0' testImplementation 'commons-validator:commons-validator:1.7' + testImplementation 'com.google.guava:guava:32.1.3-jre' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index ddbb5717f..05c72e8b2 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -118,7 +118,7 @@ diff --git a/app/src/main/java/be/ugent/zeus/hydra/MainActivity.java b/app/src/main/java/be/ugent/zeus/hydra/MainActivity.java index c28bde09a..706c996df 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/MainActivity.java +++ b/app/src/main/java/be/ugent/zeus/hydra/MainActivity.java @@ -683,24 +683,14 @@ public interface OnBackPressed { private static final class TutorialEndEvent implements Event { @Nullable @Override - public String getEventName() { + public String eventName() { return Reporting.getEvents().tutorialComplete(); } } /** - * Groups an update for the navigation drawer. - */ - private static class DrawerUpdate { - @NavigationSource - final int navigationSource; - final Fragment fragment; - final MenuItem menuItem; - - private DrawerUpdate(int navigationSource, Fragment fragment, MenuItem menuItem) { - this.navigationSource = navigationSource; - this.fragment = fragment; - this.menuItem = menuItem; + * Groups an update for the navigation drawer. + */ + private record DrawerUpdate(@NavigationSource int navigationSource, Fragment fragment, MenuItem menuItem) { } - } } diff --git a/app/src/main/java/be/ugent/zeus/hydra/association/Association.java b/app/src/main/java/be/ugent/zeus/hydra/association/Association.java index 4e6d5dbf2..43e00aaeb 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/association/Association.java +++ b/app/src/main/java/be/ugent/zeus/hydra/association/Association.java @@ -26,8 +26,8 @@ import android.os.Parcelable; import androidx.annotation.Nullable; +import java.util.Collections; import java.util.List; -import java.util.Objects; /** * Represents an association registered with the DSA. @@ -35,40 +35,38 @@ * @author feliciaan * @author Niko Strijbol */ -public final class Association implements Parcelable { - - private String abbreviation; - private String name; - private List path; - @Nullable - private String description; - private String email; - @Nullable - private String logo; - @Nullable - private String website; - - public Association() { - // Moshi uses this! - } - - /** @noinspection ProtectedMemberInFinalClass*/ - protected Association(Parcel in) { - abbreviation = in.readString(); - name = in.readString(); - path = in.createStringArrayList(); - description = in.readString(); - email = in.readString(); - logo = in.readString(); - website = in.readString(); +public record Association( + String abbreviation, + String name, + List path, + @Nullable String description, + @Nullable String email, + @Nullable String logo, + @Nullable String website +) implements Parcelable { + + private Association(Parcel in) { + this( + in.readString(), + in.readString(), + in.createStringArrayList(), + in.readString(), + in.readString(), + in.readString(), + in.readString() + ); } public static Association unknown(String name) { - Association association = new Association(); - association.abbreviation = "unknown"; - association.name = name; - association.description = "Onbekende vereniging"; - return association; + return new Association( + "unknown", + name, + Collections.emptyList(), + "Onbekende vereniging", + null, + null, + null + ); } @Override @@ -98,43 +96,4 @@ public Association[] newArray(int size) { return new Association[size]; } }; - - @Nullable - public String getDescription() { - return description; - } - - @Nullable - public String getWebsite() { - return website; - } - - /** - * @return A name for this association. If a full name is available, that is returned. If not, the display name is. - */ - public String getName() { - return name; - } - - public String getAbbreviation() { - return abbreviation; - } - - @Nullable - public String getImageLink() { - return logo; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - Association that = (Association) o; - return Objects.equals(abbreviation, that.abbreviation); - } - - @Override - public int hashCode() { - return Objects.hash(abbreviation); - } } diff --git a/app/src/main/java/be/ugent/zeus/hydra/association/event/EventPage.java b/app/src/main/java/be/ugent/zeus/hydra/association/AssociationList.java similarity index 63% rename from app/src/main/java/be/ugent/zeus/hydra/association/event/EventPage.java rename to app/src/main/java/be/ugent/zeus/hydra/association/AssociationList.java index 5d5619a4a..b7088fc75 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/association/event/EventPage.java +++ b/app/src/main/java/be/ugent/zeus/hydra/association/AssociationList.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 The Hydra authors + * Copyright (c) 2023 Niko Strijbol * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,33 +20,28 @@ * SOFTWARE. */ -package be.ugent.zeus.hydra.association.event; +package be.ugent.zeus.hydra.association; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import java.util.Collections; import java.util.List; import java.util.Objects; /** - * @author Niko Strijbol + * Top-level response object for the DSA API. + *

+ * This is basically an object with an association list inside it. + * While the list won't be null most of the time, we do not control this API, + * so we assume is can be null to have a more robust app. */ -public final class EventPage { - - /** @noinspection unused*/ - private List entries; - - public List getEntries() { - return entries; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - EventPage eventPage = (EventPage) o; - return Objects.equals(entries, eventPage.entries); - } - +public record AssociationList( + @Nullable List associations +) { + @NonNull @Override - public int hashCode() { - return Objects.hash(entries); + public List associations() { + return Objects.requireNonNullElse(associations, Collections.emptyList()); } } diff --git a/app/src/main/java/be/ugent/zeus/hydra/association/common/AssociationMap.java b/app/src/main/java/be/ugent/zeus/hydra/association/AssociationMap.java similarity index 55% rename from app/src/main/java/be/ugent/zeus/hydra/association/common/AssociationMap.java rename to app/src/main/java/be/ugent/zeus/hydra/association/AssociationMap.java index 4fbd1383c..acaa015bc 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/association/common/AssociationMap.java +++ b/app/src/main/java/be/ugent/zeus/hydra/association/AssociationMap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 The Hydra authors + * Copyright (c) 2023 Niko Strijbol * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,24 +20,41 @@ * SOFTWARE. */ -package be.ugent.zeus.hydra.association.common; +package be.ugent.zeus.hydra.association; import android.util.Pair; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import java.util.List; +import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; -import be.ugent.zeus.hydra.association.Association; - /** - * Represents a mapping of association abbreviation to their object. + * A class representing a map of associations. * - * @author Niko Strijbol + *

+ * The AssociationMap class provides methods to access associations based on their abbreviation, + * check if an association was requested to be shown, and combine the requested associations with + * the association list. + *

*/ -public interface AssociationMap { +public class AssociationMap { + + private final Map associationMap; + private final Set associationRequested; + + public AssociationMap() { + this(Collections.emptyList(), Collections.emptySet()); + } + + public AssociationMap(@NonNull List list, @NonNull Set requestedAssociations) { + this.associationMap = new HashMap<>(); + for (var association : list) { + associationMap.put(association.abbreviation(), association); + } + this.associationRequested = requestedAssociations; + } /** * Get the association linked to the specified mapping. @@ -49,29 +66,35 @@ public interface AssociationMap { * @return The association. */ @NonNull - Association get(@Nullable String abbreviation); + public Association get(@Nullable String abbreviation) { + return associationMap.computeIfAbsent(abbreviation, Association::unknown); + } /** * @return A stream of all known associations. */ - Stream associations(); + @NonNull + public Stream associations() { + return associationMap.values().stream(); + } /** - * Check if the associations was requested to be shown by the request that + * Check if the association was requested to be shown by the request that * produced this association map. - * + * * @param abbreviation The abbreviation. - * * @return True if requested to be shown, false otherwise. */ - boolean isRequested(@NonNull String abbreviation); + public boolean isRequested(@NonNull String abbreviation) { + return associationRequested.contains(abbreviation); + } /** * Combine the {@link #isRequested(String)} data with the association list. */ - default List> getSelectedAssociations() { + public List> requestedAssociations() { return this.associations() - .map(a -> Pair.create(a, this.isRequested(a.getAbbreviation()))) + .map(a -> Pair.create(a, this.isRequested(a.abbreviation()))) .collect(Collectors.toList()); } } diff --git a/app/src/main/java/be/ugent/zeus/hydra/association/AssociationRequest.java b/app/src/main/java/be/ugent/zeus/hydra/association/AssociationRequest.java new file mode 100644 index 000000000..96594a81c --- /dev/null +++ b/app/src/main/java/be/ugent/zeus/hydra/association/AssociationRequest.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2022 The Hydra authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package be.ugent.zeus.hydra.association; + +import android.content.Context; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import java.time.Duration; +import java.time.temporal.ChronoUnit; +import java.util.List; +import java.util.Objects; + +import androidx.annotation.VisibleForTesting; + +import be.ugent.zeus.hydra.common.network.Endpoints; +import be.ugent.zeus.hydra.common.network.JsonOkHttpRequest; +import be.ugent.zeus.hydra.common.request.Request; + +/** + * Builder to create various requests to get associations from the DSA. + * + * @author Niko Strijbol + */ +public class AssociationRequest extends JsonOkHttpRequest { + + private static final String FILENAME = "verenigingen"; + + @VisibleForTesting + AssociationRequest(@NonNull Context context) { + super(context, AssociationList.class); + } + + @NonNull + @Override + protected String apiUrl() { + return Endpoints.DSA_V4 + FILENAME; + } + + @Override + public Duration cacheDuration() { + return ChronoUnit.WEEKS.getDuration().multipliedBy(4); + } + + public record EventsAndAssociations( + AssociationMap associations, + List events + ) { + } + + public record EventItemsAndAssociations( + AssociationMap associations, + List events + ) { + } + + /** + * Returns a request object that retrieves a list of associations. + * + * @param context The context. + * @return A request object that retrieves a list of associations. + */ + public static Request> associationListRequest(@NonNull Context context) { + return new AssociationRequest(context) + .map(AssociationList::associations); + } + + /** + * Creates a filtered event item request. + *

+ * This contains all events that satisfy the filter, with an association map. + * + * @param context The context of the application. + * @param filter The event filter to apply. + * @return A request object containing a pair of an association map and a list of event items. + */ + public static Request filteredEventItemRequest(@NonNull Context context, @NonNull EventFilter filter) { + return filteredEventRequest(context, filter) + .map(results -> { + var eventItems = EventItem.fromEvents(results.events); + return new EventItemsAndAssociations(results.associations, eventItems); + }); + } + + /** + * Creates a filtered events request. + *

+ * This contains all events that satisfy the filter, with an association map. + * + * @param context The context of the application. + * @param optionalFilter The event filter to apply. + * @return A request object containing a pair of an association map and a list of events. + */ + public static Request filteredEventRequest(@NonNull Context context, @Nullable EventFilter optionalFilter) { + var filter = Objects.requireNonNullElse(optionalFilter, new EventFilter()); + return associationListRequest(context) + .andThen(associations -> { + var eventRequestFilter = filter.toRequestFilter(context, associations); + var requestedAssociations = eventRequestFilter.getRequestedAssociations(); + var associationMap = new AssociationMap(associations, requestedAssociations); + return EventRequest.eventRequest(context, eventRequestFilter) + .map(events -> new EventsAndAssociations(associationMap, events)); + }); + } +} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/association/common/AssociationVisibilityStorage.java b/app/src/main/java/be/ugent/zeus/hydra/association/AssociationVisibilityStorage.java similarity index 92% rename from app/src/main/java/be/ugent/zeus/hydra/association/common/AssociationVisibilityStorage.java rename to app/src/main/java/be/ugent/zeus/hydra/association/AssociationVisibilityStorage.java index e33a91f29..d7afc755b 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/association/common/AssociationVisibilityStorage.java +++ b/app/src/main/java/be/ugent/zeus/hydra/association/AssociationVisibilityStorage.java @@ -20,7 +20,7 @@ * SOFTWARE. */ -package be.ugent.zeus.hydra.association.common; +package be.ugent.zeus.hydra.association; import android.content.Context; import android.content.SharedPreferences; @@ -33,8 +33,6 @@ import java.util.*; import java.util.stream.Collectors; -import be.ugent.zeus.hydra.association.Association; - /** * Class that manages storing which associations the user wants to see * and which they don't. @@ -73,13 +71,13 @@ public static Set calculateWhitelist(Context context, List // Start with all associations. Set whitelist = new HashSet<>(); for (Association association : associations) { - whitelist.add(association.getAbbreviation()); + whitelist.add(association.abbreviation()); } // Get the existing blacklist, either from storage or from the selected one. Set blacklist; if (newWhitelist == null) { - blacklist = getBlacklist(context); + blacklist = blacklist(context); // Remove any obsolete associations. Set obsolete = new HashSet<>(); @@ -94,7 +92,7 @@ public static Set calculateWhitelist(Context context, List } else { blacklist = newWhitelist.stream() .filter(p -> !p.second) - .map(p -> p.first.getAbbreviation()) + .map(p -> p.first.abbreviation()) .collect(Collectors.toCollection(HashSet::new)); } @@ -110,7 +108,7 @@ public static Set calculateWhitelist(Context context, List * Get the saved blacklist. */ @NonNull - public static Set getBlacklist(@NonNull Context context) { + public static Set blacklist(@NonNull Context context) { SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context); return new HashSet<>(preferences.getStringSet(PREF_BLACKLIST, new HashSet<>())); } @@ -123,7 +121,7 @@ public static Set getBlacklist(@NonNull Context context) { * @param abbreviation The abbreviation of the association you want to whitelist. */ public static void blacklist(@NonNull Context context, @NonNull String abbreviation) { - Set existing = getBlacklist(context); + Set existing = blacklist(context); existing.add(abbreviation); saveBlacklist(context, existing); } @@ -136,7 +134,7 @@ public static void blacklist(@NonNull Context context, @NonNull String abbreviat * @param abbreviation The abbreviation of the association you want to whitelist. */ public static void whitelist(@NonNull Context context, @NonNull String abbreviation) { - Set existing = getBlacklist(context); + Set existing = blacklist(context); existing.remove(abbreviation); saveBlacklist(context, existing); } diff --git a/app/src/main/java/be/ugent/zeus/hydra/association/event/Event.java b/app/src/main/java/be/ugent/zeus/hydra/association/Event.java similarity index 59% rename from app/src/main/java/be/ugent/zeus/hydra/association/event/Event.java rename to app/src/main/java/be/ugent/zeus/hydra/association/Event.java index 113a228f7..d8f4709b0 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/association/event/Event.java +++ b/app/src/main/java/be/ugent/zeus/hydra/association/Event.java @@ -20,7 +20,7 @@ * SOFTWARE. */ -package be.ugent.zeus.hydra.association.event; +package be.ugent.zeus.hydra.association; import android.os.Parcel; import android.os.Parcelable; @@ -28,12 +28,11 @@ import java.time.LocalDateTime; import java.time.OffsetDateTime; -import java.util.Objects; -import be.ugent.zeus.hydra.association.Association; import be.ugent.zeus.hydra.common.converter.DateTypeConverters; import be.ugent.zeus.hydra.common.utils.DateUtils; import com.squareup.moshi.Json; +import io.soabase.recordbuilder.core.RecordBuilder; /** * Event from an {@link Association}. @@ -41,51 +40,47 @@ * @author Niko Strijbol * @author feliciaan */ -public final class Event implements Parcelable, Comparable { - - private long id; - private String title; - @Json(name = "start_time") - private OffsetDateTime start; - @Json(name = "end_time") - private OffsetDateTime end; - private String location; - private String address; - private String description; - @Json(name = "infolink") - private String url; - private String association; - private boolean advertise; - - public Event() { - // Moshi uses this! - } - - protected Event(Parcel in) { - id = in.readLong(); - title = in.readString(); - location = in.readString(); - address = in.readString(); - description = in.readString(); - url = in.readString(); - association = in.readString(); - advertise = in.readInt() == 1; - start = end = DateTypeConverters.toOffsetDateTime(in.readString()); - end = DateTypeConverters.toOffsetDateTime(in.readString()); +@RecordBuilder +public record Event( + long id, + String title, + @Json(name = "start_time") OffsetDateTime start, + @Nullable @Json(name = "end_time") OffsetDateTime end, + @Nullable String location, + @Nullable String address, + @Nullable String description, + @Nullable @Json(name = "infolink") String url, + String association, + boolean advertise +) implements Parcelable, Comparable, EventBuilder.With { + + private Event(Parcel in) { + this( + in.readLong(), + in.readString(), + DateTypeConverters.toOffsetDateTime(in.readString()), + DateTypeConverters.toOffsetDateTime(in.readString()), + in.readString(), + in.readString(), + in.readString(), + in.readString(), + in.readString(), + in.readInt() == 1 + ); } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeLong(id); dest.writeString(title); + dest.writeString(DateTypeConverters.fromOffsetDateTime(start)); + dest.writeString(DateTypeConverters.fromOffsetDateTime(end)); dest.writeString(location); dest.writeString(address); dest.writeString(description); dest.writeString(url); dest.writeString(association); dest.writeInt(advertise ? 1 : 0); - dest.writeString(DateTypeConverters.fromOffsetDateTime(start)); - dest.writeString(DateTypeConverters.fromOffsetDateTime(end)); } @Override @@ -93,7 +88,7 @@ public int describeContents() { return 0; } - public static final Creator CREATOR = new Creator() { + public static final Creator CREATOR = new Creator<>() { @Override public Event createFromParcel(Parcel in) { return new Event(in); @@ -113,8 +108,8 @@ public Event[] newArray(int size) { * * @return The converted start date. */ - public LocalDateTime getLocalStart() { - return DateUtils.toLocalDateTime(getStart()); + public LocalDateTime localStart() { + return DateUtils.toLocalDateTime(start()); } /** @@ -126,56 +121,23 @@ public LocalDateTime getLocalStart() { * @return The converted end date. */ @Nullable - public LocalDateTime getLocalEnd() { - if (getEnd() == null) { + public LocalDateTime localEnd() { + if (end == null) { return null; } - return DateUtils.toLocalDateTime(getEnd()); - } - - public String getTitle() { - return title; - } - - public OffsetDateTime getStart() { - return start; - } - - @Nullable - public OffsetDateTime getEnd() { - return end; - } - - public String getLocation() { - return location; - } - - public String getAddress() { - return address; + return DateUtils.toLocalDateTime(end); } public boolean hasPreciseLocation() { - return getAddress() != null; + return address != null; } public boolean hasLocation() { - return getLocation() != null && !getLocation().trim().isEmpty(); - } - - public String getDescription() { - return description; - } - - public String getUrl() { - return url; + return location != null && !location.trim().isEmpty(); } public boolean hasUrl() { - return getUrl() != null && !getUrl().trim().isEmpty(); - } - - public String getAssociation() { - return association; + return url != null && !url.trim().isEmpty(); } /** @@ -187,8 +149,12 @@ public String getAssociation() { * * @return The identifier. */ - public String getIdentifier() { - return title + start.toString() + end.toString() + location + url + association; + public String identifier() { + String end = ""; + if (this.end != null) { + end = this.end.toString(); + } + return title + start.toString() + end + location + url + association; } /** @@ -198,17 +164,4 @@ public String getIdentifier() { public int compareTo(Event o) { return start.compareTo(o.start); } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - Event event = (Event) o; - return id == event.id; - } - - @Override - public int hashCode() { - return Objects.hash(id); - } } diff --git a/app/src/main/java/be/ugent/zeus/hydra/association/event/EventDetailsActivity.java b/app/src/main/java/be/ugent/zeus/hydra/association/EventDetailsActivity.java similarity index 79% rename from app/src/main/java/be/ugent/zeus/hydra/association/event/EventDetailsActivity.java rename to app/src/main/java/be/ugent/zeus/hydra/association/EventDetailsActivity.java index 8e967b68b..d4de8be26 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/association/event/EventDetailsActivity.java +++ b/app/src/main/java/be/ugent/zeus/hydra/association/EventDetailsActivity.java @@ -20,7 +20,7 @@ * SOFTWARE. */ -package be.ugent.zeus.hydra.association.event; +package be.ugent.zeus.hydra.association; import android.content.Context; import android.content.Intent; @@ -43,7 +43,6 @@ import java.time.format.DateTimeFormatter; import be.ugent.zeus.hydra.R; -import be.ugent.zeus.hydra.association.Association; import be.ugent.zeus.hydra.common.reporting.BaseEvents; import be.ugent.zeus.hydra.common.reporting.Reporting; import be.ugent.zeus.hydra.common.ui.BaseActivity; @@ -86,39 +85,39 @@ protected void onCreate(Bundle savedInstanceState) { assert event != null; assert association != null; - if (event.getTitle() != null) { - requireToolbar().setTitle(event.getTitle()); + if (event.title() != null) { + requireToolbar().setTitle(event.title()); } - if (event.getAssociation() != null) { - binding.eventOrganisatorMain.setText(association.getName()); + if (event.association() != null) { + binding.eventOrganisatorMain.setText(association.name()); } - if (event.getDescription() != null && !event.getDescription().trim().isEmpty()) { - binding.description.setText(event.getDescription()); + if (event.description() != null && !event.description().trim().isEmpty()) { + binding.description.setText(event.description()); LinkifyCompat.addLinks(binding.description, Linkify.EMAIL_ADDRESSES | Linkify.WEB_URLS); } else { hasDescription = false; binding.eventDescriptionBlock.setVisibility(View.GONE); } - if (association.getDescription() != null && !association.getDescription().trim().isEmpty()) { - binding.eventOrganisatorSmall.setText(association.getDescription()); + if (association.description() != null && !association.description().trim().isEmpty()) { + binding.eventOrganisatorSmall.setText(association.description()); // If there is no event description, allow the association description to be longer. if (!hasDescription) { binding.eventOrganisatorSmall.setMaxLines(Integer.MAX_VALUE); } } - if (association.getWebsite() != null) { - binding.eventOrganizer.setOnClickListener(v -> NetworkUtils.maybeLaunchBrowser(v.getContext(), association.getWebsite())); + if (association.website() != null) { + binding.eventOrganizer.setOnClickListener(v -> NetworkUtils.maybeLaunchBrowser(v.getContext(), association.website())); } if (event.hasPreciseLocation() || event.hasLocation()) { if (event.hasLocation()) { - binding.location.setText(event.getLocation()); + binding.location.setText(event.location()); } else { - binding.location.setText(event.getAddress()); + binding.location.setText(event.address()); } // Make location clickable binding.locationRow.setOnClickListener(view -> NetworkUtils.maybeLaunchIntent(this, getLocationIntent())); @@ -126,16 +125,17 @@ protected void onCreate(Bundle savedInstanceState) { binding.location.setText(R.string.event_detail_no_location); } - binding.timeStart.setText(event.getLocalStart().format(format)); + binding.timeStart.setText(event.localStart().format(format)); - if (event.getLocalEnd() != null) { - binding.timeEnd.setText(event.getLocalEnd().format(format)); + var localEnd = event.localEnd(); + if (localEnd != null) { + binding.timeEnd.setText(localEnd.format(format)); } else { binding.timeEnd.setText(R.string.event_detail_date_unknown); } - if (event.getAssociation() != null) { - Picasso.get().load(association.getImageLink()).into(binding.eventOrganisatorImage, new EventCallback(binding.eventOrganisatorImage)); + if (event.association() != null) { + Picasso.get().load(association.logo()).into(binding.eventOrganisatorImage, new EventCallback(binding.eventOrganisatorImage)); } else { binding.eventOrganisatorImage.setLayoutParams(new LinearLayout.LayoutParams(0, 0)); } @@ -152,8 +152,8 @@ public boolean onOptionsItemSelected(@NonNull MenuItem item) { supportFinishAfterTransition(); return true; } else if (itemId == R.id.event_link) { - NetworkUtils.maybeLaunchBrowser(this, event.getUrl()); - return true; + NetworkUtils.maybeLaunchBrowser(this, event.url()); + return true; } else if (itemId == R.id.menu_event_add_to_calendar) { addToCalendar(); @@ -180,14 +180,14 @@ public boolean onCreateOptionsMenu(Menu menu) { private void addToCalendar() { Intent intent = new Intent(Intent.ACTION_INSERT) .setData(CalendarContract.Events.CONTENT_URI) - .putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, event.getStart().toInstant().toEpochMilli()) - .putExtra(CalendarContract.Events.TITLE, event.getTitle()) - .putExtra(CalendarContract.Events.EVENT_LOCATION, event.getLocation()) - .putExtra(CalendarContract.Events.DESCRIPTION, event.getDescription()) + .putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, event.start().toInstant().toEpochMilli()) + .putExtra(CalendarContract.Events.TITLE, event.title()) + .putExtra(CalendarContract.Events.EVENT_LOCATION, event.location()) + .putExtra(CalendarContract.Events.DESCRIPTION, event.description()) .putExtra(CalendarContract.Events.AVAILABILITY, CalendarContract.Events.AVAILABILITY_TENTATIVE); - if (event.getEnd() != null) { - intent.putExtra(CalendarContract.EXTRA_EVENT_END_TIME, event.getEnd().toInstant().toEpochMilli()); + if (event.end() != null) { + intent.putExtra(CalendarContract.EXTRA_EVENT_END_TIME, event.end().toInstant().toEpochMilli()); } NetworkUtils.maybeLaunchIntent(this, intent); @@ -218,9 +218,9 @@ private Intent getLocationIntent() { //If there is a precise location, use that. if (event.hasPreciseLocation()) { - uriLocation = Uri.parse("geo:" + GENT + "?q=" + event.getAddress()); + uriLocation = Uri.parse("geo:" + GENT + "?q=" + event.address()); } else { - uriLocation = Uri.parse("geo:" + GENT + "?q=" + event.getLocation()); + uriLocation = Uri.parse("geo:" + GENT + "?q=" + event.location()); } Intent intent = new Intent(Intent.ACTION_VIEW, uriLocation); @@ -244,27 +244,21 @@ public void onError(Exception e) { } } - private static final class EventViewedEvent implements be.ugent.zeus.hydra.common.reporting.Event { - - private final Event event; - - private EventViewedEvent(Event event) { - this.event = event; - } + private record EventViewedEvent(Event event) implements be.ugent.zeus.hydra.common.reporting.Event { @Override - public Bundle getParams() { + public Bundle params() { BaseEvents.Params names = Reporting.getEvents().params(); Bundle params = new Bundle(); params.putString(names.itemCategory(), Event.class.getSimpleName()); - params.putString(names.itemId(), event.getIdentifier()); - params.putString(names.itemName(), event.getTitle()); + params.putString(names.itemId(), event.identifier()); + params.putString(names.itemName(), event.title()); return params; } @Nullable @Override - public String getEventName() { + public String eventName() { return Reporting.getEvents().viewItem(); } } diff --git a/app/src/main/java/be/ugent/zeus/hydra/association/common/EventFilter.java b/app/src/main/java/be/ugent/zeus/hydra/association/EventFilter.java similarity index 85% rename from app/src/main/java/be/ugent/zeus/hydra/association/common/EventFilter.java rename to app/src/main/java/be/ugent/zeus/hydra/association/EventFilter.java index 9da4b129a..74a41c4a3 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/association/common/EventFilter.java +++ b/app/src/main/java/be/ugent/zeus/hydra/association/EventFilter.java @@ -20,7 +20,7 @@ * SOFTWARE. */ -package be.ugent.zeus.hydra.association.common; +package be.ugent.zeus.hydra.association; import android.content.Context; import android.util.Pair; @@ -33,8 +33,6 @@ import java.util.Set; import java.util.function.Function; -import be.ugent.zeus.hydra.association.Association; - /** * Search filter for event requests. * @@ -49,15 +47,15 @@ public class EventFilter { public EventFilter() { } - public OffsetDateTime getAfter() { + public OffsetDateTime after() { return after; } - public OffsetDateTime getBefore() { + public OffsetDateTime before() { return before; } - public String getTerm() { + public String term() { return term; } @@ -83,22 +81,22 @@ public Live() { this.filter = getValue(); } - public void setAfter(OffsetDateTime after) { + public void after(OffsetDateTime after) { this.filter.after = after; setValue(filter); } - public void setBefore(OffsetDateTime before) { + public void before(OffsetDateTime before) { this.filter.before = before; setValue(filter); } - public void setSelectedAssociations(List> selectedAssociations) { + public void selectedAssociations(List> selectedAssociations) { this.filter.selectedAssociations = selectedAssociations; setValue(filter); } - public void setTerm(String term) { + public void term(String term) { this.filter.term = term; setValue(filter); } @@ -107,6 +105,6 @@ public void setTerm(String term) { public static Comparator> selectionComparator() { return Comparator.comparing((Function, Boolean>) p -> p.second) .reversed() - .thenComparing(p -> p.first.getAbbreviation()); + .thenComparing(p -> p.first.abbreviation()); } } diff --git a/app/src/main/java/be/ugent/zeus/hydra/association/common/EventItem.java b/app/src/main/java/be/ugent/zeus/hydra/association/EventItem.java similarity index 50% rename from app/src/main/java/be/ugent/zeus/hydra/association/common/EventItem.java rename to app/src/main/java/be/ugent/zeus/hydra/association/EventItem.java index d77fec757..e73a5788f 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/association/common/EventItem.java +++ b/app/src/main/java/be/ugent/zeus/hydra/association/EventItem.java @@ -20,40 +20,42 @@ * SOFTWARE. */ -package be.ugent.zeus.hydra.association.common; +package be.ugent.zeus.hydra.association; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import java.time.LocalDate; import java.time.OffsetDateTime; import java.time.ZoneId; -import java.util.Objects; - -import be.ugent.zeus.hydra.association.event.Event; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; /** - * Data structure for a list of events. The contains an item, a header or a footer, but only one of the elements. + * Data structure for a list of events. + * The event contains an item, a header or a footer, but only one of the elements. * If it is an item, it contains some additional metadata. * * @author Niko Strijbol */ -public final class EventItem implements Comparable { - - private final Event event; - private final LocalDate header; - - private boolean isLastOfSection; - - private EventItem(Event event, LocalDate header) { - this.event = event; - this.header = header; +public record EventItem( + @Nullable Event event, + @Nullable LocalDate header, + boolean isLastOfSection +) implements Comparable { + + public static EventItem create(Event event) { + return new EventItem(event, null, false); } - public EventItem(Event event, boolean isLastOfSection) { - this(event, null); - this.isLastOfSection = isLastOfSection; + public static EventItem create(LocalDate header) { + return new EventItem(null, header, false); } - public EventItem(LocalDate header) { - this(null, header); + public static EventItem create(Event event, boolean isLastOfSection) { + return new EventItem(event, null, isLastOfSection); } public boolean isHeader() { @@ -64,6 +66,7 @@ public boolean isItem() { return event != null; } + @Override public boolean isLastOfSection() { if (!isItem()) { throw new IllegalStateException("Can only be used if the EventItem contains an item."); @@ -71,45 +74,57 @@ public boolean isLastOfSection() { return isLastOfSection; } - public Event getItem() { + @Override + public Event event() { if (!isItem()) { throw new IllegalStateException("Can only be used if the EventItem contains an item."); } return event; } - public LocalDate getHeader() { + @Override + public LocalDate header() { if (!isHeader()) { throw new IllegalStateException("Can only be used if the EventItem contains a header."); } return header; } - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - EventItem eventItem = (EventItem) o; - return isLastOfSection == eventItem.isLastOfSection && - Objects.equals(event, eventItem.event) && - Objects.equals(header, eventItem.header); - } - - @Override - public int hashCode() { - return Objects.hash(event, header, isLastOfSection); - } - - public OffsetDateTime getDate() { + public OffsetDateTime date() { if (isItem()) { - return getItem().getStart(); + return event().start(); } else { - return getHeader().atStartOfDay(ZoneId.systemDefault()).toOffsetDateTime(); + return header().atStartOfDay(ZoneId.systemDefault()).toOffsetDateTime(); } } @Override public int compareTo(EventItem o) { - return getDate().compareTo(o.getDate()); + return date().compareTo(o.date()); + } + + @NonNull + public static List fromEvents(@NonNull List events) { + if (events.isEmpty()) { + return Collections.emptyList(); + } + + return events.stream() + .collect(Collectors.groupingBy(event -> event.start().toLocalDate())) + .entrySet() + .stream() + .flatMap(entry -> { + List list = entry.getValue(); + EventItem header = EventItem.create(entry.getKey()); + Stream events1 = list.subList(0, list.size() - 1).stream().map(EventItem::create); + EventItem last = EventItem.create(list.get(list.size() - 1), true); + + return Stream.concat( + Stream.of(header), + Stream.concat(events1, Stream.of(last)) + ); + }) + .sorted() + .collect(Collectors.toList()); } } diff --git a/app/src/test/java/be/ugent/zeus/hydra/association/event/EventPageTest.java b/app/src/main/java/be/ugent/zeus/hydra/association/EventList.java similarity index 76% rename from app/src/test/java/be/ugent/zeus/hydra/association/event/EventPageTest.java rename to app/src/main/java/be/ugent/zeus/hydra/association/EventList.java index beb95e117..c3016dc85 100644 --- a/app/src/test/java/be/ugent/zeus/hydra/association/event/EventPageTest.java +++ b/app/src/main/java/be/ugent/zeus/hydra/association/EventList.java @@ -20,22 +20,10 @@ * SOFTWARE. */ -package be.ugent.zeus.hydra.association.event; - -import be.ugent.zeus.hydra.testing.Utils; -import nl.jqno.equalsverifier.Warning; -import org.junit.Test; +package be.ugent.zeus.hydra.association; /** * @author Niko Strijbol */ -public class EventPageTest { - - @Test - public void equalsAndHash() { - Utils.defaultVerifier(EventPage.class) - .suppress(Warning.NONFINAL_FIELDS) - .verify(); - } - -} \ No newline at end of file +public record EventList(EventPage page) { +} diff --git a/app/src/test/java/be/ugent/zeus/hydra/association/event/EventListTest.java b/app/src/main/java/be/ugent/zeus/hydra/association/EventPage.java similarity index 76% rename from app/src/test/java/be/ugent/zeus/hydra/association/event/EventListTest.java rename to app/src/main/java/be/ugent/zeus/hydra/association/EventPage.java index 3a26d502a..2d035fc01 100644 --- a/app/src/test/java/be/ugent/zeus/hydra/association/event/EventListTest.java +++ b/app/src/main/java/be/ugent/zeus/hydra/association/EventPage.java @@ -20,22 +20,12 @@ * SOFTWARE. */ -package be.ugent.zeus.hydra.association.event; +package be.ugent.zeus.hydra.association; -import be.ugent.zeus.hydra.testing.Utils; -import nl.jqno.equalsverifier.Warning; -import org.junit.Test; +import java.util.List; /** * @author Niko Strijbol */ -public class EventListTest { - - @Test - public void equalsAndHash() { - Utils.defaultVerifier(EventList.class) - .suppress(Warning.NONFINAL_FIELDS) - .verify(); - } - -} \ No newline at end of file +public record EventPage(List entries) { +} diff --git a/app/src/main/java/be/ugent/zeus/hydra/association/common/EventRequest.java b/app/src/main/java/be/ugent/zeus/hydra/association/EventRequest.java similarity index 84% rename from app/src/main/java/be/ugent/zeus/hydra/association/common/EventRequest.java rename to app/src/main/java/be/ugent/zeus/hydra/association/EventRequest.java index 3ecc7fb09..09b0db12c 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/association/common/EventRequest.java +++ b/app/src/main/java/be/ugent/zeus/hydra/association/EventRequest.java @@ -20,7 +20,7 @@ * SOFTWARE. */ -package be.ugent.zeus.hydra.association.common; +package be.ugent.zeus.hydra.association; import android.content.Context; import android.net.Uri; @@ -33,8 +33,6 @@ import java.util.List; import java.util.Set; -import be.ugent.zeus.hydra.association.event.Event; -import be.ugent.zeus.hydra.association.event.EventList; import be.ugent.zeus.hydra.common.network.Endpoints; import be.ugent.zeus.hydra.common.network.JsonOkHttpRequest; import be.ugent.zeus.hydra.common.request.Request; @@ -85,25 +83,19 @@ public Set getRequestedAssociations() { private final Filter filter; - public EventRequest(Context context, Filter filter) { + private EventRequest(Context context, Filter filter) { super(context, EventList.class); this.filter = filter; } - public static Request> createItemRequest(Context context, Filter filter) { + public static Request> eventRequest(Context context, Filter filter) { return new EventRequest(context, filter) - .map(e -> e.getPage().getEntries()) - .map(new EventListConverter()); - } - - public static Request> createRequest(Context context, Filter filter) { - return new EventRequest(context, filter) - .map(e -> e.getPage().getEntries()); + .map(e -> e.page().entries()); } @NonNull @Override - protected String getAPIUrl() { + protected String apiUrl() { Uri.Builder uri = Uri.parse(Endpoints.DSA_V4 + FILENAME).buildUpon(); for (String association : filter.requestedAssociations) { @@ -125,12 +117,12 @@ protected String getAPIUrl() { } String t = uri.appendQueryParameter("page_size", "50").build().toString(); - Log.d("TAG", "getAPIUrl: " + t); + Log.d("TAG", "apiUrl: " + t); return t; } @Override - public Duration getCacheDuration() { + public Duration cacheDuration() { return Duration.ofHours(1); } } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/association/common/AssociationRequestBuilder.java b/app/src/main/java/be/ugent/zeus/hydra/association/common/AssociationRequestBuilder.java deleted file mode 100644 index 387b84959..000000000 --- a/app/src/main/java/be/ugent/zeus/hydra/association/common/AssociationRequestBuilder.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (c) 2022 The Hydra authors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package be.ugent.zeus.hydra.association.common; - -import android.content.Context; -import android.util.Pair; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.VisibleForTesting; - -import java.time.Duration; -import java.time.temporal.ChronoUnit; -import java.util.*; -import java.util.function.Function; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import be.ugent.zeus.hydra.association.Association; -import be.ugent.zeus.hydra.association.event.Event; -import be.ugent.zeus.hydra.common.network.Endpoints; -import be.ugent.zeus.hydra.common.network.JsonOkHttpRequest; -import be.ugent.zeus.hydra.common.request.Request; -import com.squareup.moshi.Json; - -/** - * Builder to create various requests to get associations from the DSA. - * - * @author Niko Strijbol - */ -public class AssociationRequestBuilder { - - /** - * Raw representation of how the data comes to use from the API. - */ - @VisibleForTesting - static class AssociationList { - @Json(name = "associations") - private List associations; - - public AssociationList() { - } - - @NonNull - public List getAssociations() { - if (associations == null) { - return Collections.emptyList(); - } else { - return associations; - } - } - } - - private static class Mapper implements AssociationMap { - - private final Map associationMap; - private final Set associationRequested; - - private Mapper(@NonNull AssociationRequestBuilder.AssociationList list, @NonNull Set requestedAssociations) { - this.associationMap = list.getAssociations() - .stream() - .collect(Collectors.toMap(Association::getAbbreviation, Function.identity())); - this.associationRequested = requestedAssociations; - } - - @NonNull - @Override - public Association get(@Nullable String abbreviation) { - return associationMap.computeIfAbsent(abbreviation, Association::unknown); - } - - @Override - public Stream associations() { - return associationMap.values().stream(); - } - - @Override - public boolean isRequested(@NonNull String abbreviation) { - return associationRequested.contains(abbreviation); - } - } - - @VisibleForTesting - static class RawRequest extends JsonOkHttpRequest { - private static final String FILENAME = "verenigingen"; - - RawRequest(@NonNull Context context) { - super(context, AssociationList.class); - } - - @NonNull - @Override - protected String getAPIUrl() { - return Endpoints.DSA_V4 + FILENAME; - } - - @Override - public Duration getCacheDuration() { - return ChronoUnit.WEEKS.getDuration().multipliedBy(4); - } - } - - @NonNull - public static Request> createListRequest(@NonNull Context context) { - return new RawRequest(context) - .map(AssociationList::getAssociations); - } - - public static Request>> createItemFilteredEventRequest(@NonNull Context context, EventFilter filter) { - return new RawRequest(context) - .andThen((Function, Set>>>) data -> { - EventRequest.Filter newFilter = filter.toRequestFilter(context, data.getAssociations()); - Set requestedAssociations = newFilter.getRequestedAssociations(); - return EventRequest.createItemRequest(context, newFilter).map(e -> Pair.create(e, requestedAssociations)); - }) - .map(pair -> { - AssociationMap map = new Mapper(pair.first, pair.second.second); - return Pair.create(map, pair.second.first); - }); - } - - public static Request>> createFilteredEventRequest(@NonNull Context context) { - return new RawRequest(context) - .andThen((Function, Set>>>) data -> { - EventFilter eventFilter = new EventFilter(); - EventRequest.Filter newFilter = eventFilter.toRequestFilter(context, data.getAssociations()); - Set requestedAssociations = newFilter.getRequestedAssociations(); - return EventRequest.createRequest(context, newFilter).map(e -> Pair.create(e, requestedAssociations)); - }) - .map(pair -> { - AssociationMap map = new Mapper(pair.first, pair.second.second); - return Pair.create(map, pair.second.first); - }); - } -} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/association/common/EventListConverter.java b/app/src/main/java/be/ugent/zeus/hydra/association/common/EventListConverter.java deleted file mode 100644 index 162cd8aff..000000000 --- a/app/src/main/java/be/ugent/zeus/hydra/association/common/EventListConverter.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2021 The Hydra authors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package be.ugent.zeus.hydra.association.common; - -import java.time.LocalDate; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.function.Function; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import be.ugent.zeus.hydra.association.event.Event; - -/** - * Convert events to EventItems. The list of events MUST be sorted by start date. - */ -class EventListConverter implements Function, List> { - - @Override - public List apply(List events) { - - if (events.isEmpty()) { - return Collections.emptyList(); - } - - return events.stream() - .collect(Collectors.groupingBy(event -> event.getStart().toLocalDate())) - .entrySet() - .stream() - .flatMap(this::convert) - .sorted() - .collect(Collectors.toList()); - } - - private Stream convert(Map.Entry> entry) { - List list = entry.getValue(); - EventItem header = new EventItem(entry.getKey()); - Stream events = list.subList(0, list.size() - 1).stream().map(event -> new EventItem(event, false)); - EventItem last = new EventItem(list.get(list.size() - 1), true); - - return Stream.concat( - Stream.of(header), - Stream.concat(events, Stream.of(last)) - ); - } -} diff --git a/app/src/main/java/be/ugent/zeus/hydra/association/event/EventSorter.java b/app/src/main/java/be/ugent/zeus/hydra/association/event/EventSorter.java deleted file mode 100644 index df9c02361..000000000 --- a/app/src/main/java/be/ugent/zeus/hydra/association/event/EventSorter.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2021 The Hydra authors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package be.ugent.zeus.hydra.association.event; - -import java.util.List; -import java.util.function.Function; -import java.util.stream.Collectors; - -/** - * Sorts the events according to their natural ordening. - * - * @author Niko Strijbol - */ -class EventSorter implements Function, List> { - @Override - public List apply(List events) { - return events.stream() - .sorted() - .collect(Collectors.toList()); - } -} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/association/list/AssociationsAdapter.java b/app/src/main/java/be/ugent/zeus/hydra/association/list/AssociationAdapter.java similarity index 96% rename from app/src/main/java/be/ugent/zeus/hydra/association/list/AssociationsAdapter.java rename to app/src/main/java/be/ugent/zeus/hydra/association/list/AssociationAdapter.java index acc3a6b41..3da10d0c4 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/association/list/AssociationsAdapter.java +++ b/app/src/main/java/be/ugent/zeus/hydra/association/list/AssociationAdapter.java @@ -33,7 +33,7 @@ /** * @author Niko Strijbol */ -class AssociationsAdapter extends MultiSelectAdapter { +class AssociationAdapter extends MultiSelectAdapter { @NonNull @Override diff --git a/app/src/main/java/be/ugent/zeus/hydra/association/list/AssociationViewHolder.java b/app/src/main/java/be/ugent/zeus/hydra/association/list/AssociationViewHolder.java index 5e81b168a..350a30454 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/association/list/AssociationViewHolder.java +++ b/app/src/main/java/be/ugent/zeus/hydra/association/list/AssociationViewHolder.java @@ -58,7 +58,7 @@ class AssociationViewHolder extends DataViewHolder { @Override public void populate(Association data) { - title.setText(data.getName()); + title.setText(data.name()); checkBox.setChecked(adapter.isChecked(getBindingAdapterPosition())); parent.setOnClickListener(v -> { adapter.setChecked(getBindingAdapterPosition()); diff --git a/app/src/main/java/be/ugent/zeus/hydra/association/list/DateHeaderViewHolder.java b/app/src/main/java/be/ugent/zeus/hydra/association/list/DateHeaderViewHolder.java index 21d62fd7f..f7032ffee 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/association/list/DateHeaderViewHolder.java +++ b/app/src/main/java/be/ugent/zeus/hydra/association/list/DateHeaderViewHolder.java @@ -30,7 +30,7 @@ import java.time.LocalDate; import be.ugent.zeus.hydra.R; -import be.ugent.zeus.hydra.association.common.EventItem; +import be.ugent.zeus.hydra.association.EventItem; import be.ugent.zeus.hydra.common.ui.recyclerview.viewholders.DataViewHolder; @@ -55,6 +55,6 @@ static String formatDate(Context context, LocalDate localDate) { @Override public void populate(EventItem eventItem) { - headerText.setText(formatDate(headerText.getContext(), eventItem.getHeader())); + headerText.setText(formatDate(headerText.getContext(), eventItem.header())); } } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/association/list/EventAdapter.java b/app/src/main/java/be/ugent/zeus/hydra/association/list/EventAdapter.java index aebc2bafc..6c1871b1e 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/association/list/EventAdapter.java +++ b/app/src/main/java/be/ugent/zeus/hydra/association/list/EventAdapter.java @@ -28,8 +28,8 @@ import java.util.Objects; import be.ugent.zeus.hydra.R; -import be.ugent.zeus.hydra.association.common.AssociationMap; -import be.ugent.zeus.hydra.association.common.EventItem; +import be.ugent.zeus.hydra.association.AssociationMap; +import be.ugent.zeus.hydra.association.EventItem; import be.ugent.zeus.hydra.common.ui.recyclerview.adapters.DiffAdapter; import be.ugent.zeus.hydra.common.ui.recyclerview.viewholders.DataViewHolder; import be.ugent.zeus.hydra.common.utils.ViewUtils; @@ -63,7 +63,7 @@ public DataViewHolder onCreateViewHolder(@NonNull ViewGroup parent, i @Override public int getItemViewType(int position) { - if (getItem(position).isHeader()) { + if (item(position).isHeader()) { return HEADER_TYPE; } else { return super.getItemViewType(position); diff --git a/app/src/main/java/be/ugent/zeus/hydra/association/list/EventFragment.java b/app/src/main/java/be/ugent/zeus/hydra/association/list/EventFragment.java index 590beeb0f..2604a004f 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/association/list/EventFragment.java +++ b/app/src/main/java/be/ugent/zeus/hydra/association/list/EventFragment.java @@ -24,7 +24,6 @@ import android.os.Bundle; import android.util.Log; -import android.util.Pair; import android.view.*; import android.widget.Button; import android.widget.FrameLayout; @@ -43,14 +42,12 @@ import java.time.Instant; import java.time.OffsetDateTime; import java.time.ZoneOffset; -import java.util.List; import java.util.Objects; import be.ugent.zeus.hydra.MainActivity; import be.ugent.zeus.hydra.R; -import be.ugent.zeus.hydra.association.common.AssociationMap; -import be.ugent.zeus.hydra.association.common.EventFilter; -import be.ugent.zeus.hydra.association.common.EventItem; +import be.ugent.zeus.hydra.association.AssociationRequest; +import be.ugent.zeus.hydra.association.EventFilter; import be.ugent.zeus.hydra.common.arch.observers.PartialErrorObserver; import be.ugent.zeus.hydra.common.arch.observers.ProgressObserver; import be.ugent.zeus.hydra.common.arch.observers.SuccessObserver; @@ -77,7 +74,7 @@ public class EventFragment extends Fragment implements MainActivity.ScheduledRem private final EventAdapter adapter = new EventAdapter(); private final EventFilter.Live filter = new EventFilter.Live(); - private final AssociationsAdapter associationAdapter = new AssociationsAdapter(); + private final AssociationAdapter associationAdapter = new AssociationAdapter(); private EventViewModel viewModel; private FrameLayout bottomSheet; private BottomSheetBehavior behavior; @@ -140,7 +137,7 @@ public boolean onMenuItemSelected(@NonNull @NotNull MenuItem menuItem) { .build(); picker.addOnPositiveButtonClickListener(selection -> { OffsetDateTime offsetDateTime = Instant.ofEpochMilli(selection).atOffset(ZoneOffset.UTC); - filter.setAfter(offsetDateTime); + filter.after(offsetDateTime); }); picker.show(getChildFragmentManager(), picker.toString()); }); @@ -152,7 +149,7 @@ public boolean onMenuItemSelected(@NonNull @NotNull MenuItem menuItem) { .build(); picker.addOnPositiveButtonClickListener(selection -> { OffsetDateTime offsetDateTime = Instant.ofEpochMilli(selection).atOffset(ZoneOffset.UTC); - filter.setBefore(offsetDateTime); + filter.before(offsetDateTime); }); picker.show(getChildFragmentManager(), picker.toString()); }); @@ -179,18 +176,18 @@ public boolean onMenuItemSelected(@NonNull @NotNull MenuItem menuItem) { swipeRefreshLayout.setColorSchemeColors(secondaryColour); viewModel = new ViewModelProvider(this).get(EventViewModel.class); - viewModel.setParams(filter.getValue()); - viewModel.getData().observe(getViewLifecycleOwner(), PartialErrorObserver.with(this::onError)); - viewModel.getData().observe(getViewLifecycleOwner(), new ProgressObserver<>(view.findViewById(R.id.progress_bar))); - viewModel.getData().observe(getViewLifecycleOwner(), new SuccessObserver>>() { + viewModel.params(filter.getValue()); + viewModel.data().observe(getViewLifecycleOwner(), PartialErrorObserver.with(this::onError)); + viewModel.data().observe(getViewLifecycleOwner(), new ProgressObserver<>(view.findViewById(R.id.progress_bar))); + viewModel.data().observe(getViewLifecycleOwner(), new SuccessObserver<>() { @Override - protected void onSuccess(@NonNull Pair> data) { - adapter.setAssociationMap(data.first); - adapter.submitData(data.second); - associationAdapter.setItemsAndState(data.first.getSelectedAssociations()); + protected void onSuccess(@NonNull AssociationRequest.EventItemsAndAssociations data) { + adapter.setAssociationMap(data.associations()); + adapter.submitData(data.events()); + associationAdapter.itemsAndState(data.associations().requestedAssociations()); } }); - viewModel.getRefreshing().observe(getViewLifecycleOwner(), swipeRefreshLayout::setRefreshing); + viewModel.refreshing().observe(getViewLifecycleOwner(), swipeRefreshLayout::setRefreshing); swipeRefreshLayout.setOnRefreshListener(viewModel); view.