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 9ff5920c4..4e6d5dbf2 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 @@ -52,6 +52,7 @@ public Association() { // Moshi uses this! } + /** @noinspection ProtectedMemberInFinalClass*/ protected Association(Parcel in) { abbreviation = in.readString(); name = in.readString(); @@ -86,7 +87,7 @@ public int describeContents() { return 0; } - public static final Creator CREATOR = new Creator() { + public static final Creator CREATOR = new Creator<>() { @Override public Association createFromParcel(Parcel in) { return new Association(in); 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 index 6622e59fc..387b84959 100644 --- 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 @@ -119,11 +119,6 @@ public Duration getCacheDuration() { } } - @NonNull - public static Request createRawAssociationRequest(@NonNull Context context) { - return new RawRequest(context); - } - @NonNull public static Request> createListRequest(@NonNull Context context) { return new RawRequest(context) @@ -131,7 +126,7 @@ public static Request> createListRequest(@NonNull Context cont } public static Request>> createItemFilteredEventRequest(@NonNull Context context, EventFilter filter) { - return createRawAssociationRequest(context) + return new RawRequest(context) .andThen((Function, Set>>>) data -> { EventRequest.Filter newFilter = filter.toRequestFilter(context, data.getAssociations()); Set requestedAssociations = newFilter.getRequestedAssociations(); @@ -144,7 +139,7 @@ public static Request>> createItemFilteredE } public static Request>> createFilteredEventRequest(@NonNull Context context) { - return createRawAssociationRequest(context) + return new RawRequest(context) .andThen((Function, Set>>>) data -> { EventFilter eventFilter = new EventFilter(); EventRequest.Filter newFilter = eventFilter.toRequestFilter(context, data.getAssociations()); 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/common/EventItem.java index cdd1a9370..d77fec757 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/association/common/EventItem.java +++ b/app/src/main/java/be/ugent/zeus/hydra/association/common/EventItem.java @@ -99,10 +99,6 @@ public boolean equals(Object o) { public int hashCode() { return Objects.hash(event, header, isLastOfSection); } - - void markAsLastOfSection() { - this.isLastOfSection = true; - } public OffsetDateTime getDate() { if (isItem()) { 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/common/EventRequest.java index 922a28b8a..3ecc7fb09 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/association/common/EventRequest.java +++ b/app/src/main/java/be/ugent/zeus/hydra/association/common/EventRequest.java @@ -42,9 +42,9 @@ /** * Get the events for all associations. - * - * The general event flow it like this: - * + *

+ * The general event flow is like this: + *

* 1. We get the list of associations from the server. * 2. Use the filter to update the blacklist. * 3. Use the blacklist to get a whitelist. 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/event/EventDetailsActivity.java index 8d8628185..8e967b68b 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/association/event/EventDetailsActivity.java +++ b/app/src/main/java/be/ugent/zeus/hydra/association/event/EventDetailsActivity.java @@ -36,6 +36,7 @@ import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.core.content.IntentCompat; import androidx.core.text.util.LinkifyCompat; import androidx.core.view.WindowCompat; @@ -80,8 +81,8 @@ protected void onCreate(Bundle savedInstanceState) { boolean hasDescription = true; // Get data from saved instance, or from intent. - event = getIntent().getParcelableExtra(PARCEL_EVENT); - Association association = getIntent().getParcelableExtra(PARCEL_ASSOCIATION); + event = IntentCompat.getParcelableExtra(getIntent(), PARCEL_EVENT, Event.class); + Association association = IntentCompat.getParcelableExtra(getIntent(), PARCEL_ASSOCIATION, Association.class); assert event != null; assert association != null; @@ -95,7 +96,7 @@ protected void onCreate(Bundle savedInstanceState) { if (event.getDescription() != null && !event.getDescription().trim().isEmpty()) { binding.description.setText(event.getDescription()); - LinkifyCompat.addLinks(binding.description, Linkify.ALL); + LinkifyCompat.addLinks(binding.description, Linkify.EMAIL_ADDRESSES | Linkify.WEB_URLS); } else { hasDescription = false; binding.eventDescriptionBlock.setVisibility(View.GONE); diff --git a/app/src/main/java/be/ugent/zeus/hydra/association/event/EventList.java b/app/src/main/java/be/ugent/zeus/hydra/association/event/EventList.java index 6a7612dc1..ef853a823 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/association/event/EventList.java +++ b/app/src/main/java/be/ugent/zeus/hydra/association/event/EventList.java @@ -22,7 +22,6 @@ package be.ugent.zeus.hydra.association.event; -import java.util.Map; import java.util.Objects; /** @@ -30,6 +29,7 @@ */ public final class EventList { + /** @noinspection unused*/ private EventPage page; public EventList() { 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/event/EventPage.java index 87d249cc4..5d5619a4a 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/association/event/EventPage.java +++ b/app/src/main/java/be/ugent/zeus/hydra/association/event/EventPage.java @@ -30,6 +30,7 @@ */ public final class EventPage { + /** @noinspection unused*/ private List entries; public List getEntries() { 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 f0fd577a0..590beeb0f 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 @@ -32,8 +32,10 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.widget.Toolbar; +import androidx.core.view.MenuProvider; import androidx.core.view.ViewCompat; import androidx.fragment.app.Fragment; +import androidx.lifecycle.Lifecycle; import androidx.lifecycle.ViewModelProvider; import androidx.recyclerview.widget.RecyclerView; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; @@ -59,6 +61,7 @@ import com.google.android.material.datepicker.MaterialDatePicker; import com.google.android.material.snackbar.Snackbar; import com.google.android.material.textfield.TextInputLayout; +import org.jetbrains.annotations.NotNull; import static be.ugent.zeus.hydra.common.utils.FragmentUtils.requireBaseActivity; @@ -83,12 +86,6 @@ public class EventFragment extends Fragment implements MainActivity.ScheduledRem private TextInputLayout startTime; private TextInputLayout endTime; - @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) { @@ -99,6 +96,27 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); + requireActivity().addMenuProvider(new MenuProvider() { + @Override + public void onCreateMenu(@NonNull @NotNull Menu menu, @NonNull @NotNull MenuInflater menuInflater) { + menuInflater.inflate(R.menu.menu_main_events, menu); + requireBaseActivity(EventFragment.this).tintToolbarIcons(menu, R.id.action_refresh, R.id.action_search); + } + + @Override + public boolean onMenuItemSelected(@NonNull @NotNull MenuItem menuItem) { + int itemId = menuItem.getItemId(); + if (itemId == R.id.action_refresh) { + viewModel.onRefresh(); + return true; + } else if (itemId == R.id.action_search) { + showSheet(); + return true; + } + return false; + } + }, getViewLifecycleOwner(), Lifecycle.State.RESUMED); + bottomSheet = requireActivity().findViewById(R.id.bottom_sheet); // Load the options. getLayoutInflater().inflate(R.layout.item_search_filter, bottomSheet, true); @@ -221,26 +239,6 @@ private void onError(Throwable throwable) { .show(); } - @Override - public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { - super.onCreateOptionsMenu(menu, inflater); - inflater.inflate(R.menu.menu_main_events, menu); - requireBaseActivity(this).tintToolbarIcons(menu, R.id.action_refresh, R.id.action_search); - } - - @Override - public boolean onOptionsItemSelected(@NonNull MenuItem item) { - int itemId = item.getItemId(); - if (itemId == R.id.action_refresh) { - viewModel.onRefresh(); - return true; - } else if (itemId == R.id.action_search) { - showSheet(); - return true; - } - return super.onOptionsItemSelected(item); - } - @Override public void onRemovalScheduled() { hideExternalViews(); diff --git a/app/src/main/java/be/ugent/zeus/hydra/association/preference/AssociationSelectionPreferenceFragment.java b/app/src/main/java/be/ugent/zeus/hydra/association/preference/AssociationSelectionPreferenceFragment.java index 8532e823d..aa18434a7 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/association/preference/AssociationSelectionPreferenceFragment.java +++ b/app/src/main/java/be/ugent/zeus/hydra/association/preference/AssociationSelectionPreferenceFragment.java @@ -28,6 +28,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.widget.SearchView; +import androidx.core.view.MenuProvider; import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProvider; import androidx.recyclerview.widget.LinearLayoutManager; @@ -43,6 +44,7 @@ import be.ugent.zeus.hydra.common.arch.observers.ProgressObserver; import be.ugent.zeus.hydra.common.arch.observers.SuccessObserver; import com.google.android.material.snackbar.Snackbar; +import org.jetbrains.annotations.NotNull; import static be.ugent.zeus.hydra.common.utils.FragmentUtils.requireBaseActivity; @@ -57,12 +59,6 @@ public class AssociationSelectionPreferenceFragment extends Fragment { private final SearchableAssociationsAdapter adapter = new SearchableAssociationsAdapter(); - @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) { @@ -73,6 +69,27 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); + requireActivity().addMenuProvider(new MenuProvider() { + @Override + public void onCreateMenu(@NonNull @NotNull Menu menu, @NonNull @NotNull MenuInflater menuInflater) { + menuInflater.inflate(R.menu.menu_pref_selectors, menu); + requireBaseActivity(AssociationSelectionPreferenceFragment.this).tintToolbarIcons(menu, R.id.action_select_all, R.id.action_select_none); + } + + @Override + public boolean onMenuItemSelected(@NonNull @NotNull MenuItem menuItem) { + int itemId = menuItem.getItemId(); + if (itemId == R.id.action_select_all) { + adapter.setAllChecked(true); + return true; + } else if (itemId == R.id.action_select_none) { + adapter.setAllChecked(false); + return true; + } + return false; + } + }, getViewLifecycleOwner()); + RecyclerView recyclerView = view.findViewById(R.id.recycler_view); recyclerView.setHasFixedSize(true); SearchView searchView = view.findViewById(R.id.search_view); @@ -89,26 +106,6 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat model.getData().observe(getViewLifecycleOwner(), new ProgressObserver<>(view.findViewById(R.id.progress_bar))); } - @Override - public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { - inflater.inflate(R.menu.menu_pref_selectors, menu); - requireBaseActivity(this).tintToolbarIcons(menu, R.id.action_select_all, R.id.action_select_none); - super.onCreateOptionsMenu(menu, inflater); - } - - @Override - public boolean onOptionsItemSelected(@NonNull MenuItem item) { - int itemId = item.getItemId(); - if (itemId == R.id.action_select_all) { - adapter.setAllChecked(true); - return true; - } else if (itemId == R.id.action_select_none) { - adapter.setAllChecked(false); - return true; - } - return super.onOptionsItemSelected(item); - } - @Override public void onPause() { super.onPause(); diff --git a/app/src/main/java/be/ugent/zeus/hydra/common/ExtendedSparseArray.java b/app/src/main/java/be/ugent/zeus/hydra/common/ExtendedSparseArray.java index b54f1d5a4..61b4dd0f3 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/common/ExtendedSparseArray.java +++ b/app/src/main/java/be/ugent/zeus/hydra/common/ExtendedSparseArray.java @@ -47,7 +47,7 @@ public class ExtendedSparseArray extends SparseArray implements Iterable iterator() { - return new Iterator() { + return new Iterator<>() { private int current; @Override diff --git a/app/src/main/java/be/ugent/zeus/hydra/common/arch/data/BaseLiveData.java b/app/src/main/java/be/ugent/zeus/hydra/common/arch/data/BaseLiveData.java index c92e94ace..78b2b4e6f 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/common/arch/data/BaseLiveData.java +++ b/app/src/main/java/be/ugent/zeus/hydra/common/arch/data/BaseLiveData.java @@ -91,13 +91,4 @@ protected void onActive() { protected void loadData() { this.loadData(Bundle.EMPTY); } - - @FunctionalInterface - public interface OnRefreshStartListener { - - /** - * Starts when the refresh begins. - */ - void onRefreshStart(); - } } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/common/arch/observers/ErrorObserver.java b/app/src/main/java/be/ugent/zeus/hydra/common/arch/observers/ErrorObserver.java index 772b9e203..15fd4f5f9 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/common/arch/observers/ErrorObserver.java +++ b/app/src/main/java/be/ugent/zeus/hydra/common/arch/observers/ErrorObserver.java @@ -41,7 +41,7 @@ public abstract class ErrorObserver implements Observer> { public static ErrorObserver with(Consumer consumer) { - return new ErrorObserver() { + return new ErrorObserver<>() { @Override protected void onError(RequestException throwable) { consumer.accept(throwable); diff --git a/app/src/main/java/be/ugent/zeus/hydra/common/arch/observers/EventObserver.java b/app/src/main/java/be/ugent/zeus/hydra/common/arch/observers/EventObserver.java index 3a22906ae..da377acac 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/common/arch/observers/EventObserver.java +++ b/app/src/main/java/be/ugent/zeus/hydra/common/arch/observers/EventObserver.java @@ -36,7 +36,7 @@ public abstract class EventObserver implements Observer> { public static EventObserver with(Consumer consumer) { - return new EventObserver() { + return new EventObserver<>() { @Override protected void onUnhandled(D data) { consumer.accept(data); diff --git a/app/src/main/java/be/ugent/zeus/hydra/common/arch/observers/PartialErrorObserver.java b/app/src/main/java/be/ugent/zeus/hydra/common/arch/observers/PartialErrorObserver.java index 00eaa774d..4b0886cdb 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/common/arch/observers/PartialErrorObserver.java +++ b/app/src/main/java/be/ugent/zeus/hydra/common/arch/observers/PartialErrorObserver.java @@ -38,7 +38,7 @@ public abstract class PartialErrorObserver implements Observer> { public static PartialErrorObserver with(Consumer consumer) { - return new PartialErrorObserver() { + return new PartialErrorObserver<>() { @Override protected void onPartialError(RequestException throwable) { consumer.accept(throwable); diff --git a/app/src/main/java/be/ugent/zeus/hydra/common/arch/observers/SuccessObserver.java b/app/src/main/java/be/ugent/zeus/hydra/common/arch/observers/SuccessObserver.java index dbf1d66da..9bd1906bb 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/common/arch/observers/SuccessObserver.java +++ b/app/src/main/java/be/ugent/zeus/hydra/common/arch/observers/SuccessObserver.java @@ -38,7 +38,7 @@ public abstract class SuccessObserver implements Observer> { public static SuccessObserver with(Consumer onSuccess) { - return new SuccessObserver() { + return new SuccessObserver<>() { @Override protected void onSuccess(@NonNull D data) { onSuccess.accept(data); diff --git a/app/src/main/java/be/ugent/zeus/hydra/common/converter/PairJsonAdapter.java b/app/src/main/java/be/ugent/zeus/hydra/common/converter/PairJsonAdapter.java index c44b0c1fb..aa1aa5370 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/common/converter/PairJsonAdapter.java +++ b/app/src/main/java/be/ugent/zeus/hydra/common/converter/PairJsonAdapter.java @@ -23,20 +23,17 @@ package be.ugent.zeus.hydra.common.converter; import android.util.Pair; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import com.squareup.moshi.*; - import java.io.IOException; import java.lang.annotation.Annotation; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.List; import java.util.Set; +import com.squareup.moshi.*; + /** * @author Niko Strijbol */ diff --git a/app/src/main/java/be/ugent/zeus/hydra/common/database/migrations/Migration_10_11.java b/app/src/main/java/be/ugent/zeus/hydra/common/database/migrations/Migration_10_11.java index 5e244994f..00b891753 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/common/database/migrations/Migration_10_11.java +++ b/app/src/main/java/be/ugent/zeus/hydra/common/database/migrations/Migration_10_11.java @@ -23,7 +23,6 @@ package be.ugent.zeus.hydra.common.database.migrations; import android.content.ContentValues; -import android.database.Cursor; import android.database.DatabaseUtils; import android.database.sqlite.SQLiteDatabase; import android.util.Log; @@ -110,32 +109,28 @@ public void migrate(@NonNull SupportSQLiteDatabase database) { "CREATE TABLE `new_minerva_announcements` (`title` TEXT, `content` TEXT, `email_sent` INTEGER NOT NULL, `_id` INTEGER NOT NULL, `last_edit_user` TEXT, `date` TEXT, `read_at` TEXT, `course` TEXT, PRIMARY KEY(`_id`), FOREIGN KEY(`course`) REFERENCES `minerva_courses`(`_id`) ON UPDATE NO ACTION ON DELETE CASCADE)" ); // We cannot just copy the data, since we need to modify the format of the data. - Cursor cursor = database.query("SELECT * FROM minerva_announcements"); - if (cursor != null) { - while (cursor.moveToNext()) { - ContentValues contentValues = new ContentValues(); - DatabaseUtils.cursorRowToContentValues(cursor, contentValues); - // We need to adjust the 'date' and 'read_at' field. - ZonedDateTime originalDate = legacyUnserialize(contentValues.getAsLong("date")); - if (originalDate != null) { - OffsetDateTime newDate = originalDate.toOffsetDateTime(); - contentValues.put("date", fromOffsetDateTime(newDate)); - } else { - contentValues.put("date", (String) null); - } - ZonedDateTime originalReadDate = legacyUnserialize(contentValues.getAsLong("read_at")); - if (originalReadDate != null) { - Instant newReadDate = originalReadDate.toInstant(); - contentValues.put("read_at", fromInstant(newReadDate)); - } else { - contentValues.put("read_at", (String) null); - } - - // Insert the row into the new table. - database.insert("new_minerva_announcements", SQLiteDatabase.CONFLICT_NONE, contentValues); + var cursor = database.query("SELECT * FROM minerva_announcements"); + while (cursor.moveToNext()) { + ContentValues contentValues = new ContentValues(); + DatabaseUtils.cursorRowToContentValues(cursor, contentValues); + // We need to adjust the 'date' and 'read_at' field. + ZonedDateTime originalDate = legacyUnserialize(contentValues.getAsLong("date")); + if (originalDate != null) { + OffsetDateTime newDate = originalDate.toOffsetDateTime(); + contentValues.put("date", fromOffsetDateTime(newDate)); + } else { + contentValues.put("date", (String) null); } - } else { - Log.w(TAG, "Cursor for announcements is null, skipping data conversion."); + ZonedDateTime originalReadDate = legacyUnserialize(contentValues.getAsLong("read_at")); + if (originalReadDate != null) { + Instant newReadDate = originalReadDate.toInstant(); + contentValues.put("read_at", fromInstant(newReadDate)); + } else { + contentValues.put("read_at", (String) null); + } + + // Insert the row into the new table. + database.insert("new_minerva_announcements", SQLiteDatabase.CONFLICT_NONE, contentValues); } // Drop the old table. database.execSQL("DROP TABLE minerva_announcements"); @@ -150,39 +145,35 @@ public void migrate(@NonNull SupportSQLiteDatabase database) { "CREATE TABLE `new_minerva_calendar` (`_id` INTEGER NOT NULL, `title` TEXT, `content` TEXT, `start_date` TEXT, `end_date` TEXT, `location` TEXT, `type` TEXT, `last_edit_user` TEXT, `last_edit` TEXT, `last_edit_type` TEXT, `course` TEXT, `calendar_id` INTEGER NOT NULL, `is_merged` INTEGER NOT NULL DEFAULT 0, PRIMARY KEY(`_id`), FOREIGN KEY(`course`) REFERENCES `minerva_courses`(`_id`) ON UPDATE NO ACTION ON DELETE CASCADE)" ); // We cannot just copy the data, since we need to modify the format of the data. - Cursor calendarCursor = database.query("SELECT * FROM minerva_calendar"); - if (calendarCursor != null) { - while (calendarCursor.moveToNext()) { - ContentValues contentValues = new ContentValues(); - DatabaseUtils.cursorRowToContentValues(calendarCursor, contentValues); - // We must convert the start_date and end_date. - ZonedDateTime originalStartDate = legacyUnserialize(contentValues.getAsLong("start_date")); - if (originalStartDate != null) { - OffsetDateTime newStartDate = originalStartDate.toOffsetDateTime(); - contentValues.put("start_date", fromOffsetDateTime(newStartDate)); - } else { - contentValues.put("start_date", (String) null); - } - ZonedDateTime originalEndDate = legacyUnserialize(contentValues.getAsLong("end_date")); - if (originalEndDate != null) { - OffsetDateTime newEndDate = originalEndDate.toOffsetDateTime(); - contentValues.put("end_date", fromOffsetDateTime(newEndDate)); - } else { - contentValues.put("end_date", (String) null); - } - ZonedDateTime originalEditDate = legacyUnserialize(contentValues.getAsLong("last_edit")); - if (originalEditDate != null) { - OffsetDateTime newEditDate = originalEditDate.toOffsetDateTime(); - contentValues.put("last_edit", fromOffsetDateTime(newEditDate)); - } else { - contentValues.put("last_edit", (String) null); - } - - // Insert the row into the new table. - database.insert("new_minerva_calendar", SQLiteDatabase.CONFLICT_NONE, contentValues); + var calendarCursor = database.query("SELECT * FROM minerva_calendar"); + while (calendarCursor.moveToNext()) { + ContentValues contentValues = new ContentValues(); + DatabaseUtils.cursorRowToContentValues(calendarCursor, contentValues); + // We must convert the start_date and end_date. + ZonedDateTime originalStartDate = legacyUnserialize(contentValues.getAsLong("start_date")); + if (originalStartDate != null) { + OffsetDateTime newStartDate = originalStartDate.toOffsetDateTime(); + contentValues.put("start_date", fromOffsetDateTime(newStartDate)); + } else { + contentValues.put("start_date", (String) null); } - } else { - Log.w(TAG, "Cursor for calendar is null, skipping data conversion."); + ZonedDateTime originalEndDate = legacyUnserialize(contentValues.getAsLong("end_date")); + if (originalEndDate != null) { + OffsetDateTime newEndDate = originalEndDate.toOffsetDateTime(); + contentValues.put("end_date", fromOffsetDateTime(newEndDate)); + } else { + contentValues.put("end_date", (String) null); + } + ZonedDateTime originalEditDate = legacyUnserialize(contentValues.getAsLong("last_edit")); + if (originalEditDate != null) { + OffsetDateTime newEditDate = originalEditDate.toOffsetDateTime(); + contentValues.put("last_edit", fromOffsetDateTime(newEditDate)); + } else { + contentValues.put("last_edit", (String) null); + } + + // Insert the row into the new table. + database.insert("new_minerva_calendar", SQLiteDatabase.CONFLICT_NONE, contentValues); } // Drop the old table. database.execSQL("DROP TABLE minerva_calendar"); diff --git a/app/src/main/java/be/ugent/zeus/hydra/common/network/InstanceProvider.java b/app/src/main/java/be/ugent/zeus/hydra/common/network/InstanceProvider.java index 718a0fe44..a17c0f600 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/common/network/InstanceProvider.java +++ b/app/src/main/java/be/ugent/zeus/hydra/common/network/InstanceProvider.java @@ -60,6 +60,7 @@ public static void setClient(OkHttpClient client) { @VisibleForTesting public static OkHttpClient.Builder getBuilder(File cacheDir) { + //noinspection KotlinInternalInJava return new OkHttpClient.Builder().cache(new Cache(cacheDir, CACHE_SIZE)); } diff --git a/app/src/main/java/be/ugent/zeus/hydra/common/network/JsonOkHttpRequest.java b/app/src/main/java/be/ugent/zeus/hydra/common/network/JsonOkHttpRequest.java index 2def0be21..31ef87489 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/common/network/JsonOkHttpRequest.java +++ b/app/src/main/java/be/ugent/zeus/hydra/common/network/JsonOkHttpRequest.java @@ -46,7 +46,7 @@ /** * Common implementation base for requests that are network requests. This request provides built-in caching on the * networking level. - * + *

*

Caching

* The caching implementation uses OkHttp's cache implementation. How long a response is cached is determined by * {@link #getCacheDuration()}. By default, requests are not cached. @@ -54,13 +54,12 @@ * Additionally, stale data is always used by default if needed. *

* To disable the cache, pass {@link BaseLiveData#REFRESH_COLD} as an argument to the request. - * + *

*

Decode

* The request uses Moshi to decode the json response into Java objects. * * @author Niko Strijbol */ -@SuppressWarnings("WeakerAccess") public abstract class JsonOkHttpRequest extends OkHttpRequest { private static final String TAG = "JsonOkHttpRequest"; diff --git a/app/src/main/java/be/ugent/zeus/hydra/common/network/OkHttpRequest.java b/app/src/main/java/be/ugent/zeus/hydra/common/network/OkHttpRequest.java index 668403a09..836e62026 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/common/network/OkHttpRequest.java +++ b/app/src/main/java/be/ugent/zeus/hydra/common/network/OkHttpRequest.java @@ -23,42 +23,21 @@ package be.ugent.zeus.hydra.common.network; import android.content.Context; -import android.os.Bundle; -import android.util.Log; import androidx.annotation.NonNull; -import androidx.annotation.VisibleForTesting; -import androidx.annotation.WorkerThread; -import com.squareup.moshi.JsonAdapter; -import com.squareup.moshi.JsonDataException; -import com.squareup.moshi.Moshi; - -import java.io.IOException; -import java.lang.reflect.Type; -import java.net.UnknownServiceException; -import java.time.Duration; -import java.util.Objects; -import java.util.concurrent.TimeUnit; - -import be.ugent.zeus.hydra.common.arch.data.BaseLiveData; import be.ugent.zeus.hydra.common.reporting.Reporting; import be.ugent.zeus.hydra.common.reporting.Tracker; import be.ugent.zeus.hydra.common.request.Request; -import be.ugent.zeus.hydra.common.request.Result; -import okhttp3.CacheControl; +import com.squareup.moshi.Moshi; import okhttp3.OkHttpClient; -import okhttp3.Response; /** * Common implementation for requests using OkHttp. * * @author Niko Strijbol */ -@SuppressWarnings("WeakerAccess") public abstract class OkHttpRequest implements Request { - private static final String TAG = "OkHttpRequest"; - protected final Moshi moshi; protected final OkHttpClient client; protected final Tracker tracker; diff --git a/app/src/main/java/be/ugent/zeus/hydra/common/reporting/BaseEvents.java b/app/src/main/java/be/ugent/zeus/hydra/common/reporting/BaseEvents.java index 2fe04b506..b5c531feb 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/common/reporting/BaseEvents.java +++ b/app/src/main/java/be/ugent/zeus/hydra/common/reporting/BaseEvents.java @@ -44,16 +44,6 @@ public interface BaseEvents { */ String login(); - /** - * Search event. Apps that support search features can use this event to contextualize search operations by - * supplying the appropriate, corresponding parameters. This event can help you identify the most popular content in - * your app. Params: - *
    - *
  • {@link Params#searchTerm()}
  • - *
- */ - String search(); - /** * Select Content event. This general purpose event signifies that a user has selected some content of a certain * type in an app. The content can be any object in your app. This event can help you identify popular content and @@ -121,11 +111,6 @@ interface Params { */ String method(); - /** - * The search string/keywords used (String). - */ - String searchTerm(); - /** * Type of content selected (String). */ diff --git a/app/src/main/java/be/ugent/zeus/hydra/common/reporting/Tracker.java b/app/src/main/java/be/ugent/zeus/hydra/common/reporting/Tracker.java index b0507763b..0f8e3d899 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/common/reporting/Tracker.java +++ b/app/src/main/java/be/ugent/zeus/hydra/common/reporting/Tracker.java @@ -57,7 +57,6 @@ public interface Tracker { * @param classOverride The name of the screen class. By default, this is the current activity. */ @MainThread - @SuppressWarnings("EmptyMethod") void setCurrentScreen(@NonNull Activity activity, String screenName, String classOverride); /** diff --git a/app/src/main/java/be/ugent/zeus/hydra/common/request/Result.java b/app/src/main/java/be/ugent/zeus/hydra/common/request/Result.java index cccd743eb..967aa7b14 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/common/request/Result.java +++ b/app/src/main/java/be/ugent/zeus/hydra/common/request/Result.java @@ -32,7 +32,7 @@ /** * The result of a {@link Request}. - * + *

*

Either-or-both

* This class represents an "inclusive or" type, sometimes referred to as an "outer join" type. * This means the class holds either a value, an error or both. To prevent wrong usage, a builder is provided, while the @@ -42,7 +42,7 @@ * exception. Note that implementing monad laws is not the goal of this class. *

* The class supports various methods for working with this, similar to {@link java.util.Optional}. - * + *

*

Status

* In addition to data, this class has support for indicating the status of the request result. The * status is either done or continuing. @@ -243,9 +243,7 @@ public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Result result = (Result) o; - return done == result.done && - Objects.equals(data, result.data) && - Objects.equals(throwable, result.throwable); + return done == result.done && Objects.equals(data, result.data) && Objects.equals(throwable, result.throwable); } @Override diff --git a/app/src/main/java/be/ugent/zeus/hydra/common/scanner/BarcodeScanner.java b/app/src/main/java/be/ugent/zeus/hydra/common/scanner/BarcodeScanner.java index eb276f373..7f76c1db5 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/common/scanner/BarcodeScanner.java +++ b/app/src/main/java/be/ugent/zeus/hydra/common/scanner/BarcodeScanner.java @@ -31,7 +31,7 @@ /** * Ask some service to scan for barcodes. - * + *

* TODO: this is an ugly interface. * * @author Niko Strijbol @@ -66,7 +66,7 @@ public interface BarcodeScanner { /** * Get a barcode without activity. - * + *

* Implementations should optimize, if possible, for scanning product barcodes. * This includes EAN/UPC codes. */ diff --git a/app/src/main/java/be/ugent/zeus/hydra/common/ui/BaseActivity.java b/app/src/main/java/be/ugent/zeus/hydra/common/ui/BaseActivity.java index 51a2b2a3a..19cc125bc 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/common/ui/BaseActivity.java +++ b/app/src/main/java/be/ugent/zeus/hydra/common/ui/BaseActivity.java @@ -164,6 +164,7 @@ protected boolean hasParent() { * will return null. In that case, you shouldn't show the a new snackbar. * Otherwise, you will get a snackbar for the message and length. This is * a new snackbar, which you can do with want you want. + * @noinspection SameParameterValue */ @Nullable protected Snackbar createSnackbar(String text, @BaseTransientBottomBar.Duration int duration) { diff --git a/app/src/main/java/be/ugent/zeus/hydra/common/ui/RefreshViewModel.java b/app/src/main/java/be/ugent/zeus/hydra/common/ui/RefreshViewModel.java index 8ab87eda5..9a3e30657 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/common/ui/RefreshViewModel.java +++ b/app/src/main/java/be/ugent/zeus/hydra/common/ui/RefreshViewModel.java @@ -113,7 +113,7 @@ private LiveData buildRefreshLiveData() { } else { busyData.add(data.hashCode()); } - refreshing.setValue(busyData.size() != 0); + refreshing.setValue(!busyData.isEmpty()); }); } return refreshing; diff --git a/app/src/main/java/be/ugent/zeus/hydra/common/ui/customtabs/HasTabActivityHelper.java b/app/src/main/java/be/ugent/zeus/hydra/common/ui/customtabs/HasTabActivityHelper.java index a90ce0fbc..f64c3525b 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/common/ui/customtabs/HasTabActivityHelper.java +++ b/app/src/main/java/be/ugent/zeus/hydra/common/ui/customtabs/HasTabActivityHelper.java @@ -45,7 +45,7 @@ /** * Helper for activities that use custom tabs. *

- * Taken from https://github.com/hitherejoe/Tabby + * Taken from Tabby * * @author Niko Strijbol */ diff --git a/app/src/main/java/be/ugent/zeus/hydra/common/ui/html/HtmlTagHandler.java b/app/src/main/java/be/ugent/zeus/hydra/common/ui/html/HtmlTagHandler.java index 5fd15469c..0b202b5c5 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/common/ui/html/HtmlTagHandler.java +++ b/app/src/main/java/be/ugent/zeus/hydra/common/ui/html/HtmlTagHandler.java @@ -43,7 +43,7 @@ * More elements can be added. However, some elements, such as center, are no longer part of the HTML standard. Thus, * this is 'pseudo-HTML'. *

- * This class is based on work in https://github.com/skimarxall/RealTextView. + * This class is based on work in RealTextView. * * @author Niko Strijbol * @author Dominik Schürmann diff --git a/app/src/main/java/be/ugent/zeus/hydra/common/ui/html/PicassoImageGetter.java b/app/src/main/java/be/ugent/zeus/hydra/common/ui/html/PicassoImageGetter.java index caa21fa16..713951e20 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/common/ui/html/PicassoImageGetter.java +++ b/app/src/main/java/be/ugent/zeus/hydra/common/ui/html/PicassoImageGetter.java @@ -22,17 +22,15 @@ package be.ugent.zeus.hydra.common.ui.html; -import android.annotation.SuppressLint; import android.content.res.Resources; -import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; -import android.os.AsyncTask; import android.text.Html; import android.util.Log; import android.widget.TextView; +import be.ugent.zeus.hydra.common.utils.ThreadingUtils; import com.squareup.picasso.Picasso; /** @@ -55,36 +53,25 @@ public PicassoImageGetter(TextView textView, Resources resources) { @Override public Drawable getDrawable(final String source) { final DrawableWrapper result = new DrawableWrapper(new ColorDrawable()); - - // TODO: move out of async task? - @SuppressLint("StaticFieldLeak") // There is no leak - AsyncTask t = new AsyncTask() { - @Override - protected Bitmap doInBackground(final Void... meh) { - try { - return Picasso.get().load(source).get(); - } catch (Exception e) { - return null; - } + ThreadingUtils.executeWithResult(() -> { + try { + return Picasso.get().load(source).get(); + } catch (Exception e) { + return null; } + }, bitmap -> { + try { + final BitmapDrawable drawable = new BitmapDrawable(resources, bitmap); + drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); + result.setWrappedDrawable(drawable); + result.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); + result.invalidateSelf(); - @Override - protected void onPostExecute(final Bitmap bitmap) { - try { - final BitmapDrawable drawable = new BitmapDrawable(resources, bitmap); - drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); - result.setWrappedDrawable(drawable); - result.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); - result.invalidateSelf(); - - view.setText(view.getText()); - } catch (Exception e) { - Log.w(TAG, "Error while setting image", e); - } + view.setText(view.getText()); + } catch (Exception e) { + Log.w(TAG, "Error while setting image", e); } - - }; - t.execute(); + }); return result; } diff --git a/app/src/main/java/be/ugent/zeus/hydra/common/ui/recyclerview/ResultStarter.java b/app/src/main/java/be/ugent/zeus/hydra/common/ui/recyclerview/ResultStarter.java index 9d818a4fb..b5f81f8d2 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/common/ui/recyclerview/ResultStarter.java +++ b/app/src/main/java/be/ugent/zeus/hydra/common/ui/recyclerview/ResultStarter.java @@ -32,8 +32,8 @@ * {@link androidx.fragment.app.Fragment#startActivity(Intent, Bundle)}. * * @author Niko Strijbol + * @noinspection unused */ -@SuppressWarnings("unused") public interface ResultStarter { Context getContext(); diff --git a/app/src/main/java/be/ugent/zeus/hydra/common/ui/recyclerview/SpanItemSpacingDecoration.java b/app/src/main/java/be/ugent/zeus/hydra/common/ui/recyclerview/SpanItemSpacingDecoration.java index d948ac925..a1c60d912 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/common/ui/recyclerview/SpanItemSpacingDecoration.java +++ b/app/src/main/java/be/ugent/zeus/hydra/common/ui/recyclerview/SpanItemSpacingDecoration.java @@ -43,7 +43,6 @@ public class SpanItemSpacingDecoration extends RecyclerView.ItemDecoration { private final int spacing; - @SuppressWarnings("WeakerAccess") public SpanItemSpacingDecoration(int spacing) { this.spacing = spacing; } diff --git a/app/src/main/java/be/ugent/zeus/hydra/common/ui/recyclerview/adapters/DataContainer.java b/app/src/main/java/be/ugent/zeus/hydra/common/ui/recyclerview/adapters/DataContainer.java index f2e5dc099..5fe1cf441 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/common/ui/recyclerview/adapters/DataContainer.java +++ b/app/src/main/java/be/ugent/zeus/hydra/common/ui/recyclerview/adapters/DataContainer.java @@ -84,8 +84,7 @@ private static Executor getDefaultBackgroundExecutor() { * @param update The update to apply. */ @MainThread - public void submitUpdate(AdapterUpdate update) { - + void submitUpdate(AdapterUpdate update) { int generation = ++maxScheduledGeneration; // Construct a unit of work for the update. @@ -102,7 +101,7 @@ public void submitUpdate(AdapterUpdate update) { // Schedule the update. backgroundExecutor.execute(work); } else { - // Just run execute the work if threading is not allowed. + // Just execute the work if threading is not allowed. work.run(); } } diff --git a/app/src/main/java/be/ugent/zeus/hydra/common/ui/recyclerview/adapters/DiffAdapter.java b/app/src/main/java/be/ugent/zeus/hydra/common/ui/recyclerview/adapters/DiffAdapter.java index 5256a5669..fc8218822 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/common/ui/recyclerview/adapters/DiffAdapter.java +++ b/app/src/main/java/be/ugent/zeus/hydra/common/ui/recyclerview/adapters/DiffAdapter.java @@ -30,11 +30,11 @@ /** * Generic adapter with support for calculating diffs on a background thread for data updates. - * + *

*

View types

* By default, the adapter only supports one view type. Additional types must be implemented by the * subclasses. - * + *

*

Data updates

* When calling {@link #submitData(List)}, a diff with the current data will be calculated on a background thread, * after which the changes will be dispatched to this adapter. This uses {@link androidx.recyclerview.widget.DiffUtil} diff --git a/app/src/main/java/be/ugent/zeus/hydra/common/ui/recyclerview/adapters/MultiSelectAdapter.java b/app/src/main/java/be/ugent/zeus/hydra/common/ui/recyclerview/adapters/MultiSelectAdapter.java index 5925b8532..541d92921 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/common/ui/recyclerview/adapters/MultiSelectAdapter.java +++ b/app/src/main/java/be/ugent/zeus/hydra/common/ui/recyclerview/adapters/MultiSelectAdapter.java @@ -29,7 +29,6 @@ import androidx.annotation.NonNull; import java.util.*; -import java.util.stream.Stream; import be.ugent.zeus.hydra.common.ui.recyclerview.viewholders.DataViewHolder; @@ -37,8 +36,8 @@ * Adapter with items that are checkable. An item is considered checked if the state is {@code true}. * * @author Niko Strijbol + * @noinspection unused */ -@SuppressWarnings("WeakerAccess") public abstract class MultiSelectAdapter extends DiffAdapter> { private static final String TAG = "MultiSelectAdapter"; diff --git a/app/src/main/java/be/ugent/zeus/hydra/common/ui/recyclerview/adapters/MultiSelectSearchableAdapter.java b/app/src/main/java/be/ugent/zeus/hydra/common/ui/recyclerview/adapters/MultiSelectSearchableAdapter.java index d357a8e34..b1ce3a8d0 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/common/ui/recyclerview/adapters/MultiSelectSearchableAdapter.java +++ b/app/src/main/java/be/ugent/zeus/hydra/common/ui/recyclerview/adapters/MultiSelectSearchableAdapter.java @@ -80,7 +80,7 @@ public void clear() { * @param position The position. */ public void setChecked(int position) { - dataContainer.submitUpdate(new AdapterUpdate>() { + dataContainer.submitUpdate(new AdapterUpdate<>() { @Override public List> getNewData(List> existingData) { @@ -115,7 +115,7 @@ public boolean shouldUseMultiThreading() { * @param checked The value. */ public void setAllChecked(boolean checked) { - dataContainer.submitUpdate(new AdapterUpdate>() { + dataContainer.submitUpdate(new AdapterUpdate<>() { @Override @Nullable public List> getNewData(@Nullable List> existingData) { diff --git a/app/src/main/java/be/ugent/zeus/hydra/common/ui/recyclerview/adapters/SearchableAdapter.java b/app/src/main/java/be/ugent/zeus/hydra/common/ui/recyclerview/adapters/SearchableAdapter.java index 051dd56bc..18f4dc390 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/common/ui/recyclerview/adapters/SearchableAdapter.java +++ b/app/src/main/java/be/ugent/zeus/hydra/common/ui/recyclerview/adapters/SearchableAdapter.java @@ -95,7 +95,7 @@ public boolean onQueryTextSubmit(String query) { @Override public void submitData(List data) { - this.allData = Collections.unmodifiableList(new ArrayList<>(data)); + this.allData = List.copyOf(data); super.submitData(data); } diff --git a/app/src/main/java/be/ugent/zeus/hydra/common/ui/recyclerview/headers/HeaderAdapter.java b/app/src/main/java/be/ugent/zeus/hydra/common/ui/recyclerview/headers/HeaderAdapter.java index 1da31489c..03035433d 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/common/ui/recyclerview/headers/HeaderAdapter.java +++ b/app/src/main/java/be/ugent/zeus/hydra/common/ui/recyclerview/headers/HeaderAdapter.java @@ -55,15 +55,6 @@ public class HeaderAdapter extends RecyclerView.AdapterBased on this library * @see LocalTime#toString() The exact documentation on how the value is saved. - * @noinspection unused */ public class TimePreference extends DialogPreference { @@ -148,7 +149,7 @@ private static class SavedState extends BaseSavedState { public SavedState(Parcel source) { super(source); - time = (LocalTime) source.readSerializable(); + time = (LocalTime) ParcelCompat.readSerializable(source, LocalTime.class.getClassLoader(), LocalTime.class); } public SavedState(Parcelable superState) { @@ -162,7 +163,7 @@ public void writeToParcel(Parcel dest, int flags) { } public static final Parcelable.Creator CREATOR = - new Parcelable.Creator() { + new Parcelable.Creator<>() { @Override public SavedState createFromParcel(Parcel in) { return new SavedState(in); diff --git a/app/src/main/java/be/ugent/zeus/hydra/common/ui/widgets/TimePreferenceDialogFragmentCompat.java b/app/src/main/java/be/ugent/zeus/hydra/common/ui/widgets/TimePreferenceDialogFragmentCompat.java index beb0ef05b..7ae1bbced 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/common/ui/widgets/TimePreferenceDialogFragmentCompat.java +++ b/app/src/main/java/be/ugent/zeus/hydra/common/ui/widgets/TimePreferenceDialogFragmentCompat.java @@ -76,7 +76,7 @@ public Dialog onCreateDialog(Bundle savedInstanceState) { } @Override - public void onClick(DialogInterface dialog, int which) { + public void onClick(@NonNull DialogInterface dialog, int which) { super.onClick(dialog, which); if (which == DialogInterface.BUTTON_POSITIVE) { @@ -97,6 +97,6 @@ public void onDialogClosed(boolean positiveResult) { @Override public void onTimeSet(TimePicker view, int hourOfDay, int minute) { this.time = LocalTime.of(hourOfDay, minute); - super.onClick(getDialog(), DialogInterface.BUTTON_POSITIVE); + super.onClick(requireDialog(), DialogInterface.BUTTON_POSITIVE); } } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/common/utils/ColourUtils.java b/app/src/main/java/be/ugent/zeus/hydra/common/utils/ColourUtils.java index ec36edd0f..c1c8917a5 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/common/utils/ColourUtils.java +++ b/app/src/main/java/be/ugent/zeus/hydra/common/utils/ColourUtils.java @@ -47,6 +47,7 @@ public static boolean isDark(@ColorInt int colorInt) { @ColorInt public static int resolveColour(Context context, @AttrRes int attribute) { int[] attrs = {attribute}; + //noinspection resource @SuppressLint("ResourceType") // False positive I think. TypedArray ta = context.obtainStyledAttributes(attrs); try { diff --git a/app/src/main/java/be/ugent/zeus/hydra/common/utils/NetworkUtils.java b/app/src/main/java/be/ugent/zeus/hydra/common/utils/NetworkUtils.java index 039623616..c956dcecc 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/common/utils/NetworkUtils.java +++ b/app/src/main/java/be/ugent/zeus/hydra/common/utils/NetworkUtils.java @@ -55,11 +55,13 @@ public static boolean isConnected(Context context) { } if (Build.VERSION.SDK_INT < 29) { - NetworkInfo networkInfo = manager.getActiveNetworkInfo(); + //noinspection deprecation + var networkInfo = manager.getActiveNetworkInfo(); + //noinspection deprecation return (networkInfo != null && networkInfo.isConnected()); } else { - Network network = manager.getActiveNetwork(); - NetworkCapabilities capabilities = manager.getNetworkCapabilities(network); + var network = manager.getActiveNetwork(); + var capabilities = manager.getNetworkCapabilities(network); if (capabilities != null) { return capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); } else { diff --git a/app/src/main/java/be/ugent/zeus/hydra/common/utils/StringUtils.java b/app/src/main/java/be/ugent/zeus/hydra/common/utils/StringUtils.java index 56c248414..b7c801515 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/common/utils/StringUtils.java +++ b/app/src/main/java/be/ugent/zeus/hydra/common/utils/StringUtils.java @@ -26,7 +26,6 @@ import androidx.annotation.NonNull; import java.util.Collection; -import java.util.List; import java.util.Locale; /** @@ -46,7 +45,7 @@ public static String capitaliseFirst(@NonNull String s) { /** * Format a set of elements into a textual list (e.g. "one, two and three"). - * + *

* On supported Android versions, this will use the ICU library to get a * nicely formatted list. On older versions, the items will be joined using * a comma. diff --git a/app/src/main/java/be/ugent/zeus/hydra/feed/FeedException.java b/app/src/main/java/be/ugent/zeus/hydra/feed/FeedException.java index 09585f49d..2be6a9041 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/feed/FeedException.java +++ b/app/src/main/java/be/ugent/zeus/hydra/feed/FeedException.java @@ -39,6 +39,7 @@ public class FeedException extends RequestException { this.failedTypes = failedTypes; } + /** @noinspection unused*/ public Set getFailedTypes() { return failedTypes; } diff --git a/app/src/main/java/be/ugent/zeus/hydra/feed/FeedLiveData.java b/app/src/main/java/be/ugent/zeus/hydra/feed/FeedLiveData.java index 144024586..8f4f73e2b 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/feed/FeedLiveData.java +++ b/app/src/main/java/be/ugent/zeus/hydra/feed/FeedLiveData.java @@ -32,7 +32,6 @@ import androidx.preference.PreferenceManager; import java.util.*; -import java.util.function.Consumer; import java.util.function.IntPredicate; import java.util.stream.Collectors; @@ -84,13 +83,7 @@ public class FeedLiveData extends BaseLiveData>> { private static final String TAG = "HomeFeedLoader"; // For which settings the loader must refresh. - private static final String[] watchedPreferences = { - HomeFeedFragment.PREF_DISABLED_CARD_TYPES, - AssociationVisibilityStorage.PREF_BLACKLIST, - RestoPreferenceFragment.PREF_RESTO_KEY, - RestoPreferenceFragment.PREF_RESTO_NAME, - HomeFeedFragment.PREF_DISABLED_CARD_HACK - }; + private static final String[] watchedPreferences = {HomeFeedFragment.PREF_DISABLED_CARD_TYPES, AssociationVisibilityStorage.PREF_BLACKLIST, RestoPreferenceFragment.PREF_RESTO_KEY, RestoPreferenceFragment.PREF_RESTO_NAME, HomeFeedFragment.PREF_DISABLED_CARD_HACK}; private final SharedPreferences.OnSharedPreferenceChangeListener restoListener = new RestoListener(); private final Context applicationContext; private final Map oldPreferences = new HashMap<>(); @@ -100,10 +93,7 @@ public class FeedLiveData extends BaseLiveData>> { loadData(); } - private static List executeOperation(@Nullable Bundle args, - FeedOperation operation, - Collection errors, - List results) { + private static List executeOperation(@Nullable Bundle args, FeedOperation operation, Collection errors, List results) { Result> result = operation.transform(args, results); @@ -176,48 +166,44 @@ protected void onInactive() { @Override @SuppressLint("StaticFieldLeak") protected void loadData(@NonNull Bundle bundle) { - ThreadingUtils.executeWithProgress(new Consumer>>>() { - @Override - public void accept(Consumer>> publishProgress) { - // Get the operations. - Log.d(TAG, "doInBackground: received load request with " + bundle); - Iterable operations = findOperations(scheduleOperations(), bundle); - - // Get existing value if needed. - Result> loaderResult = getValue(); - //We initialize with a copy of the existing data; we do reset the errors. - List results; - - if (loaderResult == null) { - results = Collections.emptyList(); - } else { - results = loaderResult.orElse(new ArrayList<>()); - } + ThreadingUtils.executeWithProgress(publishProgress -> { + // Get the operations. + Log.d(TAG, "doInBackground: received load request with " + bundle); + Iterable operations = findOperations(scheduleOperations(), bundle); + + // Get existing value if needed. + Result> loaderResult = getValue(); + //We initialize with a copy of the existing data; we do reset the errors. + List results; + + if (loaderResult == null) { + results = Collections.emptyList(); + } else { + results = loaderResult.orElse(new ArrayList<>()); + } - Set errors = new HashSet<>(); - Result> result = null; + Set errors = new HashSet<>(); + Result> result = null; - for (FeedOperation operation : operations) { - results = executeOperation(bundle, operation, errors, results); + for (FeedOperation operation : operations) { + results = executeOperation(bundle, operation, errors, results); - List finalResults = new ArrayList<>(results); - // Deliver intermediary results. - Log.d(TAG, "loadInBackground: Operation " + operation + " completed."); - Result.Builder> builder = new Result.Builder>() - .withData(finalResults); + List finalResults = new ArrayList<>(results); + // Deliver intermediary results. + Log.d(TAG, "loadInBackground: Operation " + operation + " completed."); + Result.Builder> builder = new Result.Builder>().withData(finalResults); - if (!errors.isEmpty()) { - builder.withError(new FeedException(errors)); - } + if (!errors.isEmpty()) { + builder.withError(new FeedException(errors)); + } - result = builder.buildPartial(); + result = builder.buildPartial(); - publishProgress.accept(result); - } + publishProgress.accept(result); + } - if (result != null) { - publishProgress.accept(result.asCompleted()); - } + if (result != null) { + publishProgress.accept(result.asCompleted()); } }, this::setValue); } @@ -232,11 +218,7 @@ private ExtendedSparseArray scheduleOperations() { FeedCollection operations = new FeedCollection(); Context c = applicationContext; - Set disabled = PreferenceManager.getDefaultSharedPreferences(c) - .getStringSet(HomeFeedFragment.PREF_DISABLED_CARD_TYPES, Collections.emptySet()) - .stream() - .map(Integer::parseInt) - .collect(Collectors.toSet()); + Set disabled = PreferenceManager.getDefaultSharedPreferences(c).getStringSet(HomeFeedFragment.PREF_DISABLED_CARD_TYPES, Collections.emptySet()).stream().map(Integer::parseInt).collect(Collectors.toSet()); // Don't do Urgent.fm if there is no network. if (!NetworkUtils.isConnected(c)) { diff --git a/app/src/main/java/be/ugent/zeus/hydra/feed/FeedViewModel.java b/app/src/main/java/be/ugent/zeus/hydra/feed/FeedViewModel.java index b3c593db0..9a12b3e37 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/feed/FeedViewModel.java +++ b/app/src/main/java/be/ugent/zeus/hydra/feed/FeedViewModel.java @@ -23,7 +23,6 @@ package be.ugent.zeus.hydra.feed; import android.app.Application; -import android.os.AsyncTask; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; @@ -33,6 +32,7 @@ import be.ugent.zeus.hydra.common.arch.data.Event; import be.ugent.zeus.hydra.common.request.Result; import be.ugent.zeus.hydra.common.ui.SingleRefreshViewModel; +import be.ugent.zeus.hydra.common.utils.ThreadingUtils; import be.ugent.zeus.hydra.feed.cards.Card; import be.ugent.zeus.hydra.feed.commands.CommandResult; import be.ugent.zeus.hydra.feed.commands.FeedCommand; @@ -61,14 +61,14 @@ LiveData> getCommandLiveData() { } void execute(FeedCommand command) { - AsyncTask.execute(() -> { + ThreadingUtils.execute(() -> { int result = command.execute(getApplication()); commandLiveData.postValue(new Event<>(CommandResult.forExecute(command, result))); }); } void undo(FeedCommand command) { - AsyncTask.execute(() -> { + ThreadingUtils.execute(() -> { int result = command.undo(getApplication()); commandLiveData.postValue(new Event<>(CommandResult.forUndo(result))); }); diff --git a/app/src/main/java/be/ugent/zeus/hydra/feed/HomeFeedFragment.java b/app/src/main/java/be/ugent/zeus/hydra/feed/HomeFeedFragment.java index 6cd7a31cf..ef5c933bb 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/feed/HomeFeedFragment.java +++ b/app/src/main/java/be/ugent/zeus/hydra/feed/HomeFeedFragment.java @@ -27,6 +27,7 @@ import android.view.*; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.core.view.MenuProvider; import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProvider; import androidx.recyclerview.widget.ItemTouchHelper; @@ -44,6 +45,7 @@ import be.ugent.zeus.hydra.feed.commands.CommandResult; import be.ugent.zeus.hydra.feed.commands.FeedCommand; import com.google.android.material.snackbar.Snackbar; +import org.jetbrains.annotations.NotNull; import static be.ugent.zeus.hydra.common.utils.FragmentUtils.requireBaseActivity; import static be.ugent.zeus.hydra.feed.FeedLiveData.REFRESH_HOMECARD_TYPE; @@ -80,7 +82,6 @@ public class HomeFeedFragment extends Fragment implements SwipeRefreshLayout.OnR @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setHasOptionsMenu(true); helper = CustomTabsHelper.initHelper(getActivity(), null); helper.setShareMenu(); } @@ -99,6 +100,23 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); + requireActivity().addMenuProvider(new MenuProvider() { + @Override + public void onCreateMenu(@NonNull @NotNull Menu menu, @NonNull @NotNull MenuInflater menuInflater) { + menuInflater.inflate(R.menu.menu_refresh, menu); + requireBaseActivity(HomeFeedFragment.this).tintToolbarIcons(menu, R.id.action_refresh); + } + + @Override + public boolean onMenuItemSelected(@NonNull @NotNull MenuItem menuItem) { + if (menuItem.getItemId() == R.id.action_refresh) { + onRefresh(); + return true; + } + return false; + } + }, getViewLifecycleOwner()); + RecyclerView recyclerView = view.findViewById(R.id.home_cards_view); recyclerView.setHasFixedSize(true); SwipeRefreshLayout swipeRefreshLayout = view.findViewById(R.id.swipeRefreshLayout); @@ -162,23 +180,6 @@ public void onRemovalScheduled() { } } - @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(MenuItem item) { - - if (item.getItemId() == R.id.action_refresh) { - onRefresh(); - return true; - } - - return super.onOptionsItemSelected(item); - } - @Override public void onRefresh() { model.requestRefresh(); diff --git a/app/src/main/java/be/ugent/zeus/hydra/feed/cards/Card.java b/app/src/main/java/be/ugent/zeus/hydra/feed/cards/Card.java index e58bcafed..25499693e 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/feed/cards/Card.java +++ b/app/src/main/java/be/ugent/zeus/hydra/feed/cards/Card.java @@ -32,7 +32,7 @@ /** * Every subclass should have a {@link Card.Type} associated with it. This is to facilitate working with adapters. - * + *

*

Priority

* Every card must give itself a priority in [0,1000]. This defines the natural ordening of the cards; 0 is the * card with the highest priority, 1000 has the lowest priority. Cards should generally strive to produce unique @@ -45,7 +45,7 @@ * special occasions, such as giving the resto card a temporarily higher score because it is eating time. *

* The negative values ]-Inf,0[ are reserved for use with special cards. - * + *

*

Identifier

* Each card instance should have an unique identifier. The identifier must be unique within the card type. *

diff --git a/app/src/main/java/be/ugent/zeus/hydra/feed/cards/library/LibraryViewHolder.java b/app/src/main/java/be/ugent/zeus/hydra/feed/cards/library/LibraryViewHolder.java index 4c68a8e9d..3580c1481 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/feed/cards/library/LibraryViewHolder.java +++ b/app/src/main/java/be/ugent/zeus/hydra/feed/cards/library/LibraryViewHolder.java @@ -109,7 +109,7 @@ private void addOpeningHour(Context context, Result> resu } v.setLayoutParams(textParam); - if (!result.hasData() || !result.getData().isPresent()) { + if (!result.hasData() || result.getData().isEmpty()) { v.setText(R.string.library_list_no_opening_hours); } else { v.setText(context.getString(R.string.library_list_opening_hours_today, result.getData().get().getHours())); diff --git a/app/src/main/java/be/ugent/zeus/hydra/feed/operations/RemoveOperation.java b/app/src/main/java/be/ugent/zeus/hydra/feed/operations/RemoveOperation.java index 5ab0370dd..a91ee3a70 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/feed/operations/RemoveOperation.java +++ b/app/src/main/java/be/ugent/zeus/hydra/feed/operations/RemoveOperation.java @@ -63,6 +63,7 @@ public int getCardType() { return cardType; } + @NonNull @Override public String toString() { return "REMOVE -> Card Type " + cardType; diff --git a/app/src/main/java/be/ugent/zeus/hydra/feed/operations/RequestOperation.java b/app/src/main/java/be/ugent/zeus/hydra/feed/operations/RequestOperation.java index b4ca5984b..f34559038 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/feed/operations/RequestOperation.java +++ b/app/src/main/java/be/ugent/zeus/hydra/feed/operations/RequestOperation.java @@ -73,6 +73,7 @@ public int getCardType() { return request.getCardType(); } + @NonNull @Override public String toString() { return "REQUEST -> Card Type " + request.getCardType(); diff --git a/app/src/main/java/be/ugent/zeus/hydra/feed/preferences/HomeFragment.java b/app/src/main/java/be/ugent/zeus/hydra/feed/preferences/HomeFragment.java index 303fce2a6..c5c9257ad 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/feed/preferences/HomeFragment.java +++ b/app/src/main/java/be/ugent/zeus/hydra/feed/preferences/HomeFragment.java @@ -86,7 +86,7 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View v = super.onCreateView(inflater, container, savedInstanceState); viewModel = new ViewModelProvider(this).get(DeleteViewModel.class); - viewModel.getLiveData().observe(getViewLifecycleOwner(), new EventObserver() { + viewModel.getLiveData().observe(getViewLifecycleOwner(), new EventObserver<>() { @Override protected void onUnhandled(Context data) { Toast.makeText(data, R.string.feed_pref_hidden_cleared, Toast.LENGTH_SHORT).show(); diff --git a/app/src/main/java/be/ugent/zeus/hydra/info/InfoFragment.java b/app/src/main/java/be/ugent/zeus/hydra/info/InfoFragment.java index d10d862d0..1233d77da 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/info/InfoFragment.java +++ b/app/src/main/java/be/ugent/zeus/hydra/info/InfoFragment.java @@ -28,6 +28,8 @@ import android.widget.ProgressBar; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.core.os.BundleCompat; +import androidx.core.view.MenuProvider; import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProvider; import androidx.recyclerview.widget.DividerItemDecoration; @@ -40,6 +42,7 @@ import be.ugent.zeus.hydra.common.ui.customtabs.ActivityHelper; import be.ugent.zeus.hydra.common.ui.customtabs.CustomTabsHelper; import com.google.android.material.snackbar.Snackbar; +import org.jetbrains.annotations.NotNull; import static be.ugent.zeus.hydra.common.utils.FragmentUtils.requireBaseActivity; @@ -53,8 +56,6 @@ public class InfoFragment extends Fragment { private static final String TAG = "InfoFragment"; private ActivityHelper helper; - @Nullable - private InfoViewModel model; @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -66,7 +67,6 @@ public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); helper = CustomTabsHelper.initHelper(getActivity(), null); helper.setShareMenu(); - setHasOptionsMenu(true); } @Override @@ -84,7 +84,7 @@ public void onStop() { @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); - + InfoListAdapter adapter = new InfoListAdapter(helper); RecyclerView recyclerView = view.findViewById(R.id.recycler_view); recyclerView.setHasFixedSize(true); @@ -93,39 +93,43 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat ProgressBar progressBar = view.findViewById(R.id.progress_bar); + InfoViewModel model; Bundle bundle = getArguments(); // If we receive a list as argument, just show that list. No need to load anything. - if (bundle != null && bundle.getParcelableArrayList(InfoSubItemActivity.INFO_ITEMS) != null) { - adapter.submitData(bundle.getParcelableArrayList(InfoSubItemActivity.INFO_ITEMS)); + if (bundle != null && BundleCompat.getParcelableArrayList(bundle, InfoSubItemActivity.INFO_ITEMS, InfoItem.class) != null) { + adapter.submitData(BundleCompat.getParcelableArrayList(bundle, InfoSubItemActivity.INFO_ITEMS, InfoItem.class)); progressBar.setVisibility(View.GONE); + model = null; } else { model = new ViewModelProvider(this).get(InfoViewModel.class); model.getData().observe(getViewLifecycleOwner(), PartialErrorObserver.with(this::onError)); model.getData().observe(getViewLifecycleOwner(), new ProgressObserver<>(progressBar)); model.getData().observe(getViewLifecycleOwner(), new AdapterObserver<>(adapter)); } + + requireActivity().addMenuProvider(new MenuProvider() { + @Override + public void onCreateMenu(@NonNull @NotNull Menu menu, @NonNull @NotNull MenuInflater menuInflater) { + menuInflater.inflate(R.menu.menu_refresh, menu); + requireBaseActivity(InfoFragment.this).tintToolbarIcons(menu, R.id.action_refresh); + if (model == null) { + menu.findItem(R.id.action_refresh).setVisible(false); + } + } + + @Override + public boolean onMenuItemSelected(@NonNull @NotNull MenuItem menuItem) { + if (menuItem.getItemId() == R.id.action_refresh && model != null) { + model.requestRefresh(); + return true; + } + return false; + } + }, getViewLifecycleOwner()); } private void onError(Throwable throwable) { Log.e(TAG, "Error while getting data.", throwable); Snackbar.make(requireView(), getString(R.string.error_network), Snackbar.LENGTH_LONG).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); - if (model == null) { - menu.findItem(R.id.action_refresh).setVisible(false); - } - } - - @Override - public boolean onOptionsItemSelected(@NonNull MenuItem item) { - if (item.getItemId() == R.id.action_refresh && model != null) { - model.requestRefresh(); - return true; - } - return super.onOptionsItemSelected(item); - } } diff --git a/app/src/main/java/be/ugent/zeus/hydra/info/InfoItem.java b/app/src/main/java/be/ugent/zeus/hydra/info/InfoItem.java index 70df4d009..cf0f0e9ea 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/info/InfoItem.java +++ b/app/src/main/java/be/ugent/zeus/hydra/info/InfoItem.java @@ -35,8 +35,8 @@ * * @author Juta * @author Niko Strijbol + * @noinspection unused */ -@SuppressWarnings("unused") public final class InfoItem implements Parcelable { private String title; @@ -52,6 +52,7 @@ public InfoItem() { // Used by Moshi. } + /** @noinspection ProtectedMemberInFinalClass*/ protected InfoItem(Parcel in) { title = in.readString(); image = in.readString(); @@ -61,7 +62,7 @@ protected InfoItem(Parcel in) { subContent = in.createTypedArrayList(CREATOR); } - public static final Creator CREATOR = new Creator() { + public static final Creator CREATOR = new Creator<>() { @Override public InfoItem createFromParcel(Parcel in) { return new InfoItem(in); diff --git a/app/src/main/java/be/ugent/zeus/hydra/info/InfoSubItemActivity.java b/app/src/main/java/be/ugent/zeus/hydra/info/InfoSubItemActivity.java index 768a01f16..9e4a9d6f5 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/info/InfoSubItemActivity.java +++ b/app/src/main/java/be/ugent/zeus/hydra/info/InfoSubItemActivity.java @@ -27,6 +27,8 @@ import java.util.ArrayList; +import androidx.core.content.IntentCompat; + import be.ugent.zeus.hydra.R; import be.ugent.zeus.hydra.common.ui.BaseActivity; import be.ugent.zeus.hydra.databinding.ActivityInfoSubItemBinding; @@ -50,7 +52,7 @@ protected void onCreate(Bundle savedInstanceState) { requireToolbar().setTitle(title); // Create bundle for fragment - ArrayList infoList = intent.getParcelableArrayListExtra(INFO_ITEMS); + ArrayList infoList = IntentCompat.getParcelableArrayListExtra(intent, INFO_ITEMS, InfoItem.class); Bundle bundle = new Bundle(); bundle.putParcelableArrayList(INFO_ITEMS, infoList); fragment.setArguments(bundle); diff --git a/app/src/main/java/be/ugent/zeus/hydra/library/details/LibraryDetailActivity.java b/app/src/main/java/be/ugent/zeus/hydra/library/details/LibraryDetailActivity.java index c86530e3f..4510304dc 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/library/details/LibraryDetailActivity.java +++ b/app/src/main/java/be/ugent/zeus/hydra/library/details/LibraryDetailActivity.java @@ -26,7 +26,6 @@ import android.content.Intent; import android.graphics.drawable.Drawable; import android.net.Uri; -import android.os.AsyncTask; import android.os.Bundle; import android.text.TextUtils; import android.text.util.Linkify; @@ -39,7 +38,7 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.core.content.ContextCompat; +import androidx.core.content.IntentCompat; import androidx.core.text.util.LinkifyCompat; import androidx.core.view.WindowCompat; import androidx.lifecycle.ViewModelProvider; @@ -58,9 +57,7 @@ import be.ugent.zeus.hydra.common.reporting.Reporting; import be.ugent.zeus.hydra.common.ui.BaseActivity; import be.ugent.zeus.hydra.common.ui.html.Utils; -import be.ugent.zeus.hydra.common.utils.DateUtils; -import be.ugent.zeus.hydra.common.utils.NetworkUtils; -import be.ugent.zeus.hydra.common.utils.ViewUtils; +import be.ugent.zeus.hydra.common.utils.*; import be.ugent.zeus.hydra.databinding.ActivityLibraryDetailsBinding; import be.ugent.zeus.hydra.library.Library; import be.ugent.zeus.hydra.library.favourites.FavouritesRepository; @@ -94,7 +91,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { setContentView(ActivityLibraryDetailsBinding::inflate); WindowCompat.setDecorFitsSystemWindows(getWindow(), false); - library = getIntent().getParcelableExtra(ARG_LIBRARY); + library = IntentCompat.getParcelableExtra(getIntent(), ARG_LIBRARY, Library.class); Picasso.get().load(library.getHeaderImage(this)).into(binding.headerImage); @@ -167,7 +164,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { private void updateStatus(Library library, boolean isSelected) { FavouritesRepository repository = Database.get(this).getFavouritesRepository(); - AsyncTask.execute(() -> { + ThreadingUtils.execute(() -> { if (isSelected) { repository.delete(LibraryFavourite.from(library)); } else { @@ -187,7 +184,7 @@ protected void onSaveInstanceState(@NonNull Bundle outState) { protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); // Restore the toggle button state. - if (savedInstanceState.get("button") != null) { + if (savedInstanceState.getString("button") != null) { binding.expandButton.setText(savedInstanceState.getString("button")); } } diff --git a/app/src/main/java/be/ugent/zeus/hydra/library/list/LibraryList.java b/app/src/main/java/be/ugent/zeus/hydra/library/list/LibraryList.java index 3ff0a297e..eac0d8fe4 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/library/list/LibraryList.java +++ b/app/src/main/java/be/ugent/zeus/hydra/library/list/LibraryList.java @@ -38,7 +38,7 @@ */ public final class LibraryList implements Parcelable { - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public static final Parcelable.Creator CREATOR = new Parcelable.Creator<>() { @Override public LibraryList createFromParcel(Parcel source) { return new LibraryList(source); diff --git a/app/src/main/java/be/ugent/zeus/hydra/library/list/LibraryListAdapter.java b/app/src/main/java/be/ugent/zeus/hydra/library/list/LibraryListAdapter.java index 7b2fd6934..951df6e9e 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/library/list/LibraryListAdapter.java +++ b/app/src/main/java/be/ugent/zeus/hydra/library/list/LibraryListAdapter.java @@ -51,10 +51,7 @@ class LibraryListAdapter extends SearchableAdapter, Libra LibraryListAdapter(LibraryViewModel viewModel) { super((pair, s) -> { Library library = pair.first; - boolean contained = false; - if (library.getName() != null && library.getName().toLowerCase(Locale.getDefault()).contains(s)) { - contained = true; - } + boolean contained = library.getName() != null && library.getName().toLowerCase(Locale.getDefault()).contains(s); if (library.getCampus() != null && library.getCampus().toLowerCase(Locale.getDefault()).contains(s)) { contained = true; } diff --git a/app/src/main/java/be/ugent/zeus/hydra/library/list/LibraryListFragment.java b/app/src/main/java/be/ugent/zeus/hydra/library/list/LibraryListFragment.java index 4baf404ca..734aa38af 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/library/list/LibraryListFragment.java +++ b/app/src/main/java/be/ugent/zeus/hydra/library/list/LibraryListFragment.java @@ -28,6 +28,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.widget.SearchView; +import androidx.core.view.MenuProvider; import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProvider; import androidx.recyclerview.widget.DividerItemDecoration; @@ -41,6 +42,7 @@ import be.ugent.zeus.hydra.common.utils.ColourUtils; import be.ugent.zeus.hydra.common.utils.NetworkUtils; import com.google.android.material.snackbar.Snackbar; +import org.jetbrains.annotations.NotNull; import static be.ugent.zeus.hydra.common.utils.FragmentUtils.requireBaseActivity; @@ -55,12 +57,6 @@ public class LibraryListFragment extends Fragment { private LibraryListAdapter adapter; private LibraryViewModel 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) { @@ -70,6 +66,32 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); + + requireActivity().addMenuProvider(new MenuProvider() { + @Override + public void onCreateMenu(@NonNull @NotNull Menu menu, @NonNull @NotNull MenuInflater menuInflater) { + menuInflater.inflate(R.menu.menu_library_list, menu); + requireBaseActivity(LibraryListFragment.this).tintToolbarIcons(menu, R.id.library_visit_catalogue, R.id.action_refresh); + SearchView view = (SearchView) menu.findItem(R.id.action_search).getActionView(); + view.setOnQueryTextListener(adapter); + view.setOnCloseListener(adapter); + view.setOnSearchClickListener(v -> adapter.onOpen()); + } + + @Override + public boolean onMenuItemSelected(@NonNull @NotNull MenuItem menuItem) { + int itemId = menuItem.getItemId(); + if (itemId == R.id.library_visit_catalogue) { + NetworkUtils.maybeLaunchBrowser(getContext(), LIB_URL); + return true; + } else if (itemId == R.id.action_refresh) { + viewModel.onRefresh(); + return true; + } + return false; + } + }, getViewLifecycleOwner()); + RecyclerView recyclerView = view.findViewById(R.id.recycler_view); recyclerView.setHasFixedSize(true); recyclerView.addItemDecoration(new DividerItemDecoration(requireContext(), DividerItemDecoration.VERTICAL)); @@ -88,30 +110,6 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat swipeRefreshLayout.setOnRefreshListener(viewModel); } - @Override - public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { - inflater.inflate(R.menu.menu_library_list, menu); - requireBaseActivity(this).tintToolbarIcons(menu, R.id.library_visit_catalogue, R.id.action_refresh); - SearchView view = (SearchView) menu.findItem(R.id.action_search).getActionView(); - view.setOnQueryTextListener(adapter); - view.setOnCloseListener(adapter); - view.setOnSearchClickListener(v -> adapter.onOpen()); - super.onCreateOptionsMenu(menu, inflater); - } - - @Override - public boolean onOptionsItemSelected(@NonNull MenuItem item) { - int itemId = item.getItemId(); - if (itemId == R.id.library_visit_catalogue) { - NetworkUtils.maybeLaunchBrowser(getContext(), LIB_URL); - return true; - } else if (itemId == R.id.action_refresh) { - viewModel.onRefresh(); - return true; - } - return super.onOptionsItemSelected(item); - } - private void onError(Throwable throwable) { Log.e(TAG, "Error while getting data.", throwable); Snackbar.make(requireView(), getString(R.string.error_network), Snackbar.LENGTH_LONG) diff --git a/app/src/main/java/be/ugent/zeus/hydra/library/list/LibraryViewHolder.java b/app/src/main/java/be/ugent/zeus/hydra/library/list/LibraryViewHolder.java index 2e8a1022a..80f5ef88c 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/library/list/LibraryViewHolder.java +++ b/app/src/main/java/be/ugent/zeus/hydra/library/list/LibraryViewHolder.java @@ -82,7 +82,7 @@ public void onViewRecycled() { @Override public void onChanged(@Nullable Result> result) { - if (result == null || !result.hasData() || !result.getData().isPresent()) { + if (result == null || !result.hasData() || result.getData().isEmpty()) { openingHours.setText(R.string.library_list_no_opening_hours); } else { OpeningHours hours = result.getData().get(); diff --git a/app/src/main/java/be/ugent/zeus/hydra/news/NewsFragment.java b/app/src/main/java/be/ugent/zeus/hydra/news/NewsFragment.java index c3a78eaf5..98f2b1758 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/news/NewsFragment.java +++ b/app/src/main/java/be/ugent/zeus/hydra/news/NewsFragment.java @@ -27,6 +27,7 @@ import android.view.*; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.core.view.MenuProvider; import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProvider; import androidx.recyclerview.widget.RecyclerView; @@ -41,6 +42,7 @@ import be.ugent.zeus.hydra.common.ui.recyclerview.SpanItemSpacingDecoration; import be.ugent.zeus.hydra.common.utils.ColourUtils; import com.google.android.material.snackbar.Snackbar; +import org.jetbrains.annotations.NotNull; import static be.ugent.zeus.hydra.common.utils.FragmentUtils.requireBaseActivity; @@ -61,7 +63,6 @@ public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); helper = CustomTabsHelper.initHelper(getActivity(), null); helper.setShareMenu(); - setHasOptionsMenu(true); } @Override @@ -73,6 +74,23 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); + requireActivity().addMenuProvider(new MenuProvider() { + @Override + public void onCreateMenu(@NonNull @NotNull Menu menu, @NonNull @NotNull MenuInflater menuInflater) { + menuInflater.inflate(R.menu.menu_refresh, menu); + requireBaseActivity(NewsFragment.this).tintToolbarIcons(menu, R.id.action_refresh); + } + + @Override + public boolean onMenuItemSelected(@NonNull @NotNull MenuItem menuItem) { + if (menuItem.getItemId() == R.id.action_refresh) { + viewModel.onRefresh(); + return true; + } + return false; + } + }, getViewLifecycleOwner()); + RecyclerView recyclerView = view.findViewById(R.id.recycler_view); recyclerView.setHasFixedSize(true); recyclerView.addItemDecoration(new SpanItemSpacingDecoration(requireContext())); @@ -90,24 +108,6 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat swipeRefreshLayout.setOnRefreshListener(viewModel); } - @Override - public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { - super.onCreateOptionsMenu(menu, inflater); - inflater.inflate(R.menu.menu_refresh, menu); - requireBaseActivity(this).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); - } - private void onError(Throwable throwable) { Log.e(TAG, "Error while getting data.", throwable); Snackbar.make(requireView(), getString(R.string.error_network), Snackbar.LENGTH_LONG) diff --git a/app/src/main/java/be/ugent/zeus/hydra/news/NewsStream.java b/app/src/main/java/be/ugent/zeus/hydra/news/NewsStream.java index 9aef3ec9a..a694000d9 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/news/NewsStream.java +++ b/app/src/main/java/be/ugent/zeus/hydra/news/NewsStream.java @@ -28,6 +28,7 @@ /** * @author Niko Strijbol + * @noinspection unused */ public final class NewsStream { diff --git a/app/src/main/java/be/ugent/zeus/hydra/preferences/PreferenceActivity.java b/app/src/main/java/be/ugent/zeus/hydra/preferences/PreferenceActivity.java index bbe36a673..53eebf214 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/preferences/PreferenceActivity.java +++ b/app/src/main/java/be/ugent/zeus/hydra/preferences/PreferenceActivity.java @@ -28,6 +28,8 @@ import android.os.Parcelable; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.core.content.IntentCompat; +import androidx.core.os.BundleCompat; import androidx.fragment.app.Fragment; import be.ugent.zeus.hydra.R; @@ -71,13 +73,13 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { if (savedInstanceState != null) { // If a specific screen is requested, use that one. - entry = savedInstanceState.getParcelable(ARG_FRAGMENT); + entry = BundleCompat.getParcelable(savedInstanceState, ARG_FRAGMENT, PreferenceEntry.class); } else if (Intent.ACTION_MANAGE_NETWORK_USAGE.equals(getIntent().getAction())) { // We come from the device data usage settings screen, show network options. entry = PreferenceEntry.HOME; } else { // Nothing was requested, show the overview. - entry = getIntent().getParcelableExtra(ARG_FRAGMENT); + entry = IntentCompat.getParcelableExtra(getIntent(), ARG_FRAGMENT, PreferenceEntry.class); } setFragment(); @@ -86,7 +88,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); - entry = intent.getParcelableExtra(ARG_FRAGMENT); + entry = IntentCompat.getParcelableExtra(intent, ARG_FRAGMENT, PreferenceEntry.class); setFragment(); } diff --git a/app/src/main/java/be/ugent/zeus/hydra/preferences/PreferenceEntry.java b/app/src/main/java/be/ugent/zeus/hydra/preferences/PreferenceEntry.java index b69b9eb7b..3c139d888 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/preferences/PreferenceEntry.java +++ b/app/src/main/java/be/ugent/zeus/hydra/preferences/PreferenceEntry.java @@ -116,7 +116,7 @@ public int describeContents() { return 0; } - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public static final Parcelable.Creator CREATOR = new Parcelable.Creator<>() { @Override public PreferenceEntry createFromParcel(Parcel in) { return PreferenceEntry.values()[in.readInt()]; diff --git a/app/src/main/java/be/ugent/zeus/hydra/preferences/ThemeFragment.java b/app/src/main/java/be/ugent/zeus/hydra/preferences/ThemeFragment.java index 9d79be11e..ea94e8b4e 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/preferences/ThemeFragment.java +++ b/app/src/main/java/be/ugent/zeus/hydra/preferences/ThemeFragment.java @@ -37,6 +37,8 @@ import be.ugent.zeus.hydra.common.reporting.Reporting; import be.ugent.zeus.hydra.common.ui.PreferenceFragment; +import java.util.Objects; + /** * Show preferences related to the theme of the app. * @@ -78,7 +80,7 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { setPreferencesFromResource(R.xml.pref_theme, rootKey); SharedPreferences preferences = getPreferenceManager().getSharedPreferences(); - existing = preferences.getString(PREF_THEME_NIGHT_MODE, defaultValue()); + existing = Objects.requireNonNull(preferences).getString(PREF_THEME_NIGHT_MODE, defaultValue()); ListPreference listPreference = requirePreference(PREF_THEME_NIGHT_MODE); if (Build.VERSION.SDK_INT < 29) { diff --git a/app/src/main/java/be/ugent/zeus/hydra/resto/extrafood/FoodAdapter.java b/app/src/main/java/be/ugent/zeus/hydra/resto/extrafood/FoodAdapter.java index 804ccf54f..ef5cf988f 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/resto/extrafood/FoodAdapter.java +++ b/app/src/main/java/be/ugent/zeus/hydra/resto/extrafood/FoodAdapter.java @@ -34,7 +34,7 @@ * * @author Niko Strijbol */ -public class FoodAdapter extends DiffAdapter { +class FoodAdapter extends DiffAdapter { @NonNull @Override diff --git a/app/src/main/java/be/ugent/zeus/hydra/resto/extrafood/FoodFragment.java b/app/src/main/java/be/ugent/zeus/hydra/resto/extrafood/FoodFragment.java index 929bdcce6..c444b23e7 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/resto/extrafood/FoodFragment.java +++ b/app/src/main/java/be/ugent/zeus/hydra/resto/extrafood/FoodFragment.java @@ -79,7 +79,7 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat viewModel = new ViewModelProvider(this).get(ExtraFoodViewModel.class); 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.getData().observe(getViewLifecycleOwner(), new SuccessObserver<>() { @Override protected void onSuccess(@NonNull ExtraFood data) { adapter.submitData(ExtraFoodViewModel.getFor(position, data)); diff --git a/app/src/main/java/be/ugent/zeus/hydra/resto/history/HistoryActivity.java b/app/src/main/java/be/ugent/zeus/hydra/resto/history/HistoryActivity.java index 1d504c361..95f07dccf 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/resto/history/HistoryActivity.java +++ b/app/src/main/java/be/ugent/zeus/hydra/resto/history/HistoryActivity.java @@ -85,7 +85,7 @@ protected void onCreate(Bundle savedInstanceState) { viewModel = provider.get(SingleDayViewModel.class); viewModel.changeDate(localDate); // Set the initial date - viewModel.getData().observe(this, new SuccessObserver() { + viewModel.getData().observe(this, new SuccessObserver<>() { @Override protected void onSuccess(@NonNull RestoMenu data) { // Add the fragment diff --git a/app/src/store/java/be/ugent/zeus/hydra/common/reporting/FirebaseEvents.java b/app/src/store/java/be/ugent/zeus/hydra/common/reporting/FirebaseEvents.java index 65059d22a..f333fe490 100644 --- a/app/src/store/java/be/ugent/zeus/hydra/common/reporting/FirebaseEvents.java +++ b/app/src/store/java/be/ugent/zeus/hydra/common/reporting/FirebaseEvents.java @@ -44,11 +44,6 @@ public String login() { return FirebaseAnalytics.Event.LOGIN; } - @Override - public String search() { - return FirebaseAnalytics.Event.SEARCH; - } - @Override public String selectContent() { return FirebaseAnalytics.Event.SELECT_CONTENT; @@ -91,11 +86,6 @@ public String method() { return FirebaseAnalytics.Param.METHOD; } - @Override - public String searchTerm() { - return FirebaseAnalytics.Param.SEARCH_TERM; - } - @Override public String contentType() { return FirebaseAnalytics.Param.CONTENT_TYPE;