From 9cfa057b85e33680206c0a443076ee25bd40bc4d Mon Sep 17 00:00:00 2001 From: Youssef Habri Date: Tue, 26 Feb 2019 11:21:37 +0000 Subject: [PATCH 01/17] Bug fixes for v1.3.1 (#103) - Disable Toolbar buttons when empty image - Fixed opening the ImagePreview when invalid/non existing image - Fixed Series Types filter and made it independent based on MediaType - Make media spoiler tags hidden by default --- .../graphql/Media/Query/MediaOverview.graphql | 1 + .../custom/view/text/SpoilerTagTextView.java | 28 +++++++++++++++ .../anitrend/model/entity/anilist/Media.java | 8 ++++- .../mxt/anitrend/util/ApplicationPref.java | 22 ++++++++++++ .../com/mxt/anitrend/util/CompatUtil.java | 13 +++++++ .../com/mxt/anitrend/util/DialogUtil.java | 14 ++++++++ .../java/com/mxt/anitrend/util/KeyUtil.java | 8 +++++ .../activity/base/ImagePreviewActivity.java | 3 +- .../view/activity/detail/MediaActivity.java | 4 +-- .../view/activity/detail/ProfileActivity.java | 4 +-- .../detail/CharacterOverviewFragment.java | 12 +++---- .../detail/MediaOverviewFragment.java | 16 +++++---- .../detail/StaffOverviewFragment.java | 12 +++---- .../fragment/detail/UserOverviewFragment.java | 10 +++--- .../fragment/list/MediaBrowseFragment.java | 35 ++++++++++++------- app/src/main/res/drawable/ic_spoiler_tag.xml | 15 ++++++++ app/src/main/res/layout/adapter_tag.xml | 3 +- .../res/layout/fragment_series_overview.xml | 9 +++++ app/src/main/res/values-ar/strings.xml | 6 +++- app/src/main/res/values-de/strings.xml | 6 +++- app/src/main/res/values-es/strings.xml | 6 +++- app/src/main/res/values-fr/strings.xml | 6 +++- app/src/main/res/values-it/strings.xml | 6 +++- app/src/main/res/values-nl/strings.xml | 6 +++- app/src/main/res/values-pl/strings.xml | 6 +++- app/src/main/res/values-pt/strings.xml | 6 +++- app/src/main/res/values-sv/strings.xml | 6 +++- app/src/main/res/values/attr.xml | 4 +++ app/src/main/res/values/strings.xml | 18 +++++++++- 29 files changed, 235 insertions(+), 58 deletions(-) create mode 100644 app/src/main/java/com/mxt/anitrend/base/custom/view/text/SpoilerTagTextView.java create mode 100644 app/src/main/res/drawable/ic_spoiler_tag.xml diff --git a/app/src/main/assets/graphql/Media/Query/MediaOverview.graphql b/app/src/main/assets/graphql/Media/Query/MediaOverview.graphql index d4e423dc7..6d2d584e2 100644 --- a/app/src/main/assets/graphql/Media/Query/MediaOverview.graphql +++ b/app/src/main/assets/graphql/Media/Query/MediaOverview.graphql @@ -42,6 +42,7 @@ query MediaOverview($id: Int!, $type: MediaType, $isAdult: Boolean = false, $isM category rank isGeneralSpoiler + isMediaSpoiler isAdult } } diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/text/SpoilerTagTextView.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/text/SpoilerTagTextView.java new file mode 100644 index 000000000..5ab0f1688 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/text/SpoilerTagTextView.java @@ -0,0 +1,28 @@ +package com.mxt.anitrend.base.custom.view.text; + +import android.content.Context; +import android.databinding.BindingAdapter; +import android.text.TextUtils; +import android.util.AttributeSet; +import com.mxt.anitrend.util.CompatUtil; +import com.mxt.anitrend.R; + +public class SpoilerTagTextView extends SingleLineTextView { + + public SpoilerTagTextView(Context context) { + super(context); + } + + public SpoilerTagTextView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public SpoilerTagTextView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + @BindingAdapter("app:isSpoiler") + public static void setIsSpoiler(SingleLineTextView view, Boolean isSpoiler) { + if (isSpoiler) view.setTextColor(CompatUtil.getColor(view.getContext(), R.color.colorStateOrange)); + } +} diff --git a/app/src/main/java/com/mxt/anitrend/model/entity/anilist/Media.java b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/Media.java index 8224dea90..c874eb8f8 100644 --- a/app/src/main/java/com/mxt/anitrend/model/entity/anilist/Media.java +++ b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/Media.java @@ -1,7 +1,7 @@ package com.mxt.anitrend.model.entity.anilist; import android.os.Parcel; - +import com.annimon.stream.Stream; import com.mxt.anitrend.model.entity.anilist.meta.MediaStats; import com.mxt.anitrend.model.entity.anilist.meta.MediaTrailer; import com.mxt.anitrend.model.entity.base.MediaBase; @@ -92,6 +92,12 @@ public List getTags() { return tags; } + public List getTagsNoSpoilers() { + return Stream.of(tags) + .filterNot(MediaTag::isMediaSpoiler) + .toList(); + } + public MediaTrailer getTrailer() { return trailer; } diff --git a/app/src/main/java/com/mxt/anitrend/util/ApplicationPref.java b/app/src/main/java/com/mxt/anitrend/util/ApplicationPref.java index 2c01744b9..6eca7f5f2 100644 --- a/app/src/main/java/com/mxt/anitrend/util/ApplicationPref.java +++ b/app/src/main/java/com/mxt/anitrend/util/ApplicationPref.java @@ -38,6 +38,8 @@ public class ApplicationPref { private static final String _sortOrder = "_sortOrder"; private static final String _mediaStatus = "_mediaStatus"; private static final String _mediaFormat = "_mediaFormat"; + private static final String _animeFormat = "_animeFormat"; + private static final String _mangaFormat = "_mangaFormat"; private static final String _mediaSource = "_mediaSource"; private static final String _airingSort = "_airingSort"; private static final String _characterSort = "_characterSort"; @@ -192,12 +194,32 @@ public void setMediaStatus(@KeyUtil.MediaStatus String mediaStatus) { return sharedPreferences.getString(_mediaFormat, null); } + public @Nullable @KeyUtil.AnimeFormat String getAnimeFormat() { + return sharedPreferences.getString(_animeFormat, null); + } + + public @Nullable @KeyUtil.MangaFormat String getMangaFormat() { + return sharedPreferences.getString(_mangaFormat, null); + } + public void setMediaFormat(@KeyUtil.MediaFormat String mediaFormat) { SharedPreferences.Editor editor = sharedPreferences.edit(); editor.putString(_mediaFormat, mediaFormat); editor.apply(); } + public void setAnimeFormat(@KeyUtil.AnimeFormat String animeFormat) { + SharedPreferences.Editor editor = sharedPreferences.edit(); + editor.putString(_animeFormat, animeFormat); + editor.apply(); + } + + public void setMangaFormat(@KeyUtil.MangaFormat String mangaFormat) { + SharedPreferences.Editor editor = sharedPreferences.edit(); + editor.putString(_mangaFormat, mangaFormat); + editor.apply(); + } + public @Nullable @KeyUtil.MediaSource String getMediaSource() { return sharedPreferences.getString(_mediaSource, null); diff --git a/app/src/main/java/com/mxt/anitrend/util/CompatUtil.java b/app/src/main/java/com/mxt/anitrend/util/CompatUtil.java index 9711cdd90..0892cd6ee 100644 --- a/app/src/main/java/com/mxt/anitrend/util/CompatUtil.java +++ b/app/src/main/java/com/mxt/anitrend/util/CompatUtil.java @@ -33,12 +33,15 @@ import android.view.View; import android.view.WindowManager; import android.view.inputmethod.InputMethodManager; +import android.widget.Toast; import com.annimon.stream.IntPair; import com.annimon.stream.Optional; import com.annimon.stream.Stream; import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.view.container.CustomSwipeRefreshLayout; +import com.mxt.anitrend.model.entity.anilist.meta.ImageBase; +import com.mxt.anitrend.view.activity.base.ImagePreviewActivity; import java.io.File; import java.util.Arrays; @@ -84,6 +87,16 @@ public static Cache cacheProvider(Context context) { return cache; } + public static void imagePreview(FragmentActivity activity, View view, String imageUri, int errorMessage) { + if (imageUri != null && !imageUri.isEmpty()) { + Intent intent = new Intent(activity, ImagePreviewActivity.class); + intent.putExtra(KeyUtil.arg_model, imageUri); + CompatUtil.startSharedImageTransition(activity, view, intent, R.string.transition_image_preview); + } else { + NotifyUtil.makeText(activity, errorMessage, Toast.LENGTH_SHORT).show(); + } + } + /** * Avoids resource not found when using vector drawables in API levels < Lollipop * diff --git a/app/src/main/java/com/mxt/anitrend/util/DialogUtil.java b/app/src/main/java/com/mxt/anitrend/util/DialogUtil.java index 61d757cb3..86900869b 100644 --- a/app/src/main/java/com/mxt/anitrend/util/DialogUtil.java +++ b/app/src/main/java/com/mxt/anitrend/util/DialogUtil.java @@ -188,6 +188,20 @@ public static void createMessage(Context context, String title, String content, .autoDismiss(true).onAny(singleButtonCallback).show(); } + public static void createTagMessage(Context context, String title, String content, Boolean isSpoiler, @StringRes int positive, @StringRes int negative, MaterialDialog.SingleButtonCallback singleButtonCallback) { + MaterialDialog.Builder builder = createDefaultDialog(context).title(title) + .positiveText(positive) + .negativeText(negative) + .icon(CompatUtil.getTintedDrawable(context, R.drawable.ic_new_releases_white_24dp)) + .content(MarkDownUtil.convert(content)) + .autoDismiss(true).onAny(singleButtonCallback); + + if (isSpoiler) builder.icon(CompatUtil.getDrawable(context, R.drawable.ic_spoiler_tag)); + else builder.icon(CompatUtil.getDrawable(context, R.drawable.ic_loyalty_white_24dp)); + + builder.show(); + } + public static void createCheckList(Context context, @StringRes int title, Collection selectableItems, Integer[] selectedIndices, MaterialDialog.ListCallbackMultiChoice listCallbackMultiChoice, MaterialDialog.SingleButtonCallback singleButtonCallback) { createDefaultDialog(context).title(title) .items(selectableItems) diff --git a/app/src/main/java/com/mxt/anitrend/util/KeyUtil.java b/app/src/main/java/com/mxt/anitrend/util/KeyUtil.java index dc546b55f..a40e31ec6 100644 --- a/app/src/main/java/com/mxt/anitrend/util/KeyUtil.java +++ b/app/src/main/java/com/mxt/anitrend/util/KeyUtil.java @@ -359,6 +359,12 @@ public interface KeyUtil { @StringDef({TV, TV_SHORT, MOVIE, SPECIAL, OVA, ONA, MUSIC, MANGA, NOVEL, ONE_SHOT}) @interface MediaFormat {} + @StringDef({TV, TV_SHORT, MOVIE, SPECIAL, OVA, ONA, MUSIC}) + @interface AnimeFormat {} + + @StringDef({MANGA, NOVEL, ONE_SHOT}) + @interface MangaFormat {} + String RATED = "RATED", POPULAR = "POPULAR"; @StringDef({RATED, POPULAR}) @@ -369,6 +375,8 @@ public interface KeyUtil { String[] MediaStatus = {null, FINISHED, RELEASING, NOT_YET_RELEASED, CANCELLED}; String[] MediaSource = {null, ORIGINAL, MANGA, LIGHT_NOVEL, VISUAL_NOVEL, VIDEO_GAME, OTHER}; String[] MediaFormat = {null, TV, TV_SHORT, MOVIE, SPECIAL, OVA, ONA, MUSIC, MANGA, NOVEL, ONE_SHOT}; + String[] AnimeFormat = {null, TV, TV_SHORT, MOVIE, SPECIAL, OVA, ONA, MUSIC}; + String[] MangaFormat = {null, MANGA, NOVEL, ONE_SHOT}; String[] MediaRankType = {RATED, POPULAR}; // ------------------------------------------------------------------------------------ diff --git a/app/src/main/java/com/mxt/anitrend/view/activity/base/ImagePreviewActivity.java b/app/src/main/java/com/mxt/anitrend/view/activity/base/ImagePreviewActivity.java index 199d28b61..ab7c3e30b 100644 --- a/app/src/main/java/com/mxt/anitrend/view/activity/base/ImagePreviewActivity.java +++ b/app/src/main/java/com/mxt/anitrend/view/activity/base/ImagePreviewActivity.java @@ -73,7 +73,8 @@ protected void onPostCreate(@Nullable Bundle savedInstanceState) { @Override public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.image_preview_menu, menu); + if (mImageUri != null && !mImageUri.isEmpty()) + getMenuInflater().inflate(R.menu.image_preview_menu, menu); return true; } diff --git a/app/src/main/java/com/mxt/anitrend/view/activity/detail/MediaActivity.java b/app/src/main/java/com/mxt/anitrend/view/activity/detail/MediaActivity.java index cfed51047..e532ff4a0 100644 --- a/app/src/main/java/com/mxt/anitrend/view/activity/detail/MediaActivity.java +++ b/app/src/main/java/com/mxt/anitrend/view/activity/detail/MediaActivity.java @@ -192,9 +192,7 @@ public void onChanged(@Nullable MediaBase model) { public void onClick(View view) { switch (view.getId()) { case R.id.series_banner: - Intent intent = new Intent(this, ImagePreviewActivity.class); - intent.putExtra(KeyUtil.arg_model, model.getBannerImage()); - CompatUtil.startSharedImageTransition(this, view, intent, R.string.transition_image_preview); + CompatUtil.imagePreview(this, view, model.getBannerImage(), R.string.image_preview_error_series_banner); break; } } diff --git a/app/src/main/java/com/mxt/anitrend/view/activity/detail/ProfileActivity.java b/app/src/main/java/com/mxt/anitrend/view/activity/detail/ProfileActivity.java index 3c9abf388..283c7621c 100644 --- a/app/src/main/java/com/mxt/anitrend/view/activity/detail/ProfileActivity.java +++ b/app/src/main/java/com/mxt/anitrend/view/activity/detail/ProfileActivity.java @@ -179,9 +179,7 @@ public void onChanged(@Nullable UserBase model) { public void onClick(View view) { switch (view.getId()) { case R.id.profile_banner: - Intent intent = new Intent(this, ImagePreviewActivity.class); - intent.putExtra(KeyUtil.arg_model, model.getBannerImage()); - CompatUtil.startSharedImageTransition(this, view, intent, R.string.transition_image_preview); + CompatUtil.imagePreview(this, view, model.getBannerImage(), R.string.image_preview_error_profile_banner); break; } } diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/CharacterOverviewFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/CharacterOverviewFragment.java index 3665ae68c..684142b5d 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/CharacterOverviewFragment.java +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/CharacterOverviewFragment.java @@ -87,18 +87,16 @@ public void makeRequest() { /** * Called when a view has been clicked. * - * @param v The view that was clicked. + * @param view The view that was clicked. */ @Override @OnClick(R.id.character_img) - public void onClick(View v) { - switch (v.getId()) { + public void onClick(View view) { + switch (view.getId()) { case R.id.character_img: - Intent intent = new Intent(getActivity(), ImagePreviewActivity.class); - intent.putExtra(KeyUtil.arg_model, model.getImage().getLarge()); - CompatUtil.startSharedImageTransition(getActivity(), v, intent, R.string.transition_image_preview); + CompatUtil.imagePreview(getActivity(), view, model.getImage().getLarge(), R.string.image_preview_error_character_image); break; default: - super.onClick(v); + super.onClick(view); break; } } diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/MediaOverviewFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/MediaOverviewFragment.java index b4160ccc1..ced40124f 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/MediaOverviewFragment.java +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/MediaOverviewFragment.java @@ -28,7 +28,6 @@ import com.mxt.anitrend.util.GraphUtil; import com.mxt.anitrend.util.KeyUtil; import com.mxt.anitrend.util.MediaBrowseUtil; -import com.mxt.anitrend.view.activity.base.ImagePreviewActivity; import com.mxt.anitrend.view.activity.detail.MediaBrowseActivity; import com.mxt.anitrend.view.activity.detail.StudioActivity; import com.mxt.anitrend.view.fragment.youtube.YouTubeEmbedFragment; @@ -150,13 +149,13 @@ public void onItemLongClick(View target, IntPair data) { if(tagAdapter == null) { tagAdapter = new TagAdapter(getContext()); - tagAdapter.onItemsInserted(model.getTags()); + tagAdapter.onItemsInserted(model.getTagsNoSpoilers()); tagAdapter.setClickListener(new ItemClickListener() { @Override public void onItemClick(View target, IntPair data) { switch (target.getId()) { case R.id.container: - DialogUtil.createMessage(getActivity(), data.getSecond().getName(), data.getSecond().getDescription(), + DialogUtil.createTagMessage(getActivity(), data.getSecond().getName(), data.getSecond().getDescription(), data.getSecond().isMediaSpoiler(), R.string.More, R.string.Close, (dialog, which) -> { switch (which) { case POSITIVE: @@ -222,14 +221,12 @@ public void onChanged(@Nullable Media model) { * * @param v The view that was clicked. */ - @Override @OnClick({R.id.series_image, R.id.anime_main_studio_container}) + @Override @OnClick({R.id.series_image, R.id.anime_main_studio_container, R.id.show_spoiler_tags}) public void onClick(View v) { Intent intent; switch (v.getId()) { case R.id.series_image: - intent = new Intent(getActivity(), ImagePreviewActivity.class); - intent.putExtra(KeyUtil.arg_model, model.getCoverImage().getLarge()); - CompatUtil.startSharedImageTransition(getActivity(), v, intent, R.string.transition_image_preview); + CompatUtil.imagePreview(getActivity(), v, model.getCoverImage().getLarge(), R.string.image_preview_error_series_cover); break; case R.id.anime_main_studio_container: StudioBase studioBase = getPresenter().getMainStudioObject(model); @@ -239,6 +236,11 @@ public void onClick(View v) { startActivity(intent); } break; + case R.id.show_spoiler_tags: + tagAdapter.onItemRangeChanged(model.getTags()); + tagAdapter.notifyDataSetChanged(); + v.setVisibility(View.INVISIBLE); + break; default: super.onClick(v); break; diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/StaffOverviewFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/StaffOverviewFragment.java index 774c4049e..5c23be3b5 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/StaffOverviewFragment.java +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/StaffOverviewFragment.java @@ -88,18 +88,16 @@ public void makeRequest() { /** * Called when a view has been clicked. * - * @param v The view that was clicked. + * @param view The view that was clicked. */ @Override @OnClick(R.id.staff_img) - public void onClick(View v) { - switch (v.getId()) { + public void onClick(View view) { + switch (view.getId()) { case R.id.staff_img: - Intent intent = new Intent(getActivity(), ImagePreviewActivity.class); - intent.putExtra(KeyUtil.arg_model, model.getImage().getLarge()); - CompatUtil.startSharedImageTransition(getActivity(), v, intent, R.string.transition_image_preview); + CompatUtil.imagePreview(getActivity(), view, model.getImage().getLarge(), R.string.image_preview_error_staff_image); break; default: - super.onClick(v); + super.onClick(view); break; } } diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/UserOverviewFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/UserOverviewFragment.java index 46bbc6020..8f908bef7 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/UserOverviewFragment.java +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/UserOverviewFragment.java @@ -181,15 +181,13 @@ private void showRingStats() { /** * Called when a view has been clicked. * - * @param v The view that was clicked. + * @param view The view that was clicked. */ @Override @OnClick({R.id.user_avatar, R.id.user_stats_container}) - public void onClick(View v) { - switch (v.getId()) { + public void onClick(View view) { + switch (view.getId()) { case R.id.user_avatar: - Intent intent = new Intent(getActivity(), ImagePreviewActivity.class); - intent.putExtra(KeyUtil.arg_model, model.getAvatar().getLarge()); - CompatUtil.startSharedImageTransition(getActivity(), v, intent, R.string.transition_image_preview); + CompatUtil.imagePreview(getActivity(), view, model.getAvatar().getLarge(), R.string.image_preview_error_user_avatar); break; case R.id.user_stats_container: List ringList = generateStatsData(); diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/list/MediaBrowseFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/list/MediaBrowseFragment.java index 45370ce91..33c94ce52 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/list/MediaBrowseFragment.java +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/list/MediaBrowseFragment.java @@ -180,12 +180,21 @@ public boolean onOptionsItemSelected(MenuItem item) { } return true; case R.id.action_type: - DialogUtil.createSelection(getContext(), R.string.app_filter_show_type, CompatUtil.getIndexOf(KeyUtil.MediaFormat, - getPresenter().getApplicationPref().getMediaFormat()), CompatUtil.getStringList(getContext(), R.array.media_formats), - (dialog, which) -> { - if(which == DialogAction.POSITIVE) - getPresenter().getApplicationPref().setMediaFormat(KeyUtil.MediaFormat[dialog.getSelectedIndex()]); - }); + if (CompatUtil.equals(queryContainer.getVariable(KeyUtil.arg_mediaType), KeyUtil.ANIME)) { + DialogUtil.createSelection(getContext(), R.string.app_filter_show_type, CompatUtil.getIndexOf(KeyUtil.AnimeFormat, + getPresenter().getApplicationPref().getAnimeFormat()), CompatUtil.getStringList(getContext(), R.array.anime_formats), + (dialog, which) -> { + if(which == DialogAction.POSITIVE) + getPresenter().getApplicationPref().setAnimeFormat(KeyUtil.AnimeFormat[dialog.getSelectedIndex()]); + }); + } else { + DialogUtil.createSelection(getContext(), R.string.app_filter_show_type, CompatUtil.getIndexOf(KeyUtil.MangaFormat, + getPresenter().getApplicationPref().getMangaFormat()), CompatUtil.getStringList(getContext(), R.array.manga_formats), + (dialog, which) -> { + if(which == DialogAction.POSITIVE) + getPresenter().getApplicationPref().setMangaFormat(KeyUtil.MangaFormat[dialog.getSelectedIndex()]); + }); + } return true; case R.id.action_year: final List yearRanges = DateUtil.getYearRanges(1950, 1); @@ -220,16 +229,18 @@ public void makeRequest() { if(isFilterable) { if(!mediaBrowseUtil.isBasicFilter()) { - if (CompatUtil.equals(queryContainer.getVariable(KeyUtil.arg_mediaType), KeyUtil.MANGA)) + if (CompatUtil.equals(queryContainer.getVariable(KeyUtil.arg_mediaType), KeyUtil.MANGA)) { queryContainer.putVariable(KeyUtil.arg_startDateLike, String.format(Locale.getDefault(), - "%d%%", getPresenter().getApplicationPref().getSeasonYear())); - else - queryContainer.putVariable(KeyUtil.arg_seasonYear, getPresenter().getApplicationPref().getSeasonYear()); + "%d%%", getPresenter().getApplicationPref().getSeasonYear())) + .putVariable(KeyUtil.arg_format, pref.getMangaFormat()); + } else { + queryContainer.putVariable(KeyUtil.arg_seasonYear, getPresenter().getApplicationPref().getSeasonYear()) + .putVariable(KeyUtil.arg_format, pref.getAnimeFormat()); + } queryContainer.putVariable(KeyUtil.arg_status, pref.getMediaStatus()) .putVariable(KeyUtil.arg_genres, GenreTagUtil.getMappedValues(pref.getSelectedGenres())) - .putVariable(KeyUtil.arg_tags, GenreTagUtil.getMappedValues(pref.getSelectedTags())) - .putVariable(KeyUtil.arg_format, pref.getMediaFormat()); + .putVariable(KeyUtil.arg_tags, GenreTagUtil.getMappedValues(pref.getSelectedTags())); } queryContainer.putVariable(KeyUtil.arg_sort, pref.getMediaSort() + pref.getSortOrder()); } diff --git a/app/src/main/res/drawable/ic_spoiler_tag.xml b/app/src/main/res/drawable/ic_spoiler_tag.xml new file mode 100644 index 000000000..de1b043a9 --- /dev/null +++ b/app/src/main/res/drawable/ic_spoiler_tag.xml @@ -0,0 +1,15 @@ + + + + + + + diff --git a/app/src/main/res/layout/adapter_tag.xml b/app/src/main/res/layout/adapter_tag.xml index 3e2c04a3f..470478d6a 100644 --- a/app/src/main/res/layout/adapter_tag.xml +++ b/app/src/main/res/layout/adapter_tag.xml @@ -38,12 +38,13 @@ android:layout_width="match_parent" android:layout_height="wrap_content"> - + + diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 42c34ce93..23ed4beaa 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -804,7 +804,7 @@ ملغاة - + الكل تلفزيوني تلفزيوني قصير @@ -813,6 +813,10 @@ اوفا اونا موسيقى + + + + الكل مانغا رواية ون شوت diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 247f6da5b..c1e63e1ec 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -804,7 +804,7 @@ Canceled - + All TV TV Short @@ -813,6 +813,10 @@ OVA ONA Music + + + + All Manga Novel One Shot diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index af8f5f0d5..f5300e85e 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -804,7 +804,7 @@ elementos de tus favoritos al presionar en el icono del corazón . Cancelados - + Todos TV TV Cortos @@ -813,6 +813,10 @@ elementos de tus favoritos al presionar en el icono del corazón . OVA ONA Musical + + + + Todos Manga Novela One Shot diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 256816f7d..c8faab615 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -808,7 +808,7 @@ Canceled - + All TV TV Short @@ -817,6 +817,10 @@ OVA ONA Music + + + + All Manga Novel One Shot diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index d85396b17..5d0700848 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -803,7 +803,7 @@ Cancellati - + Tutti TV Corti TV @@ -812,6 +812,10 @@ OVA ONA Musica + + + + Tutti Manga Novel One Shot diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index b1dd56c6b..2696210c0 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -805,7 +805,7 @@ geannuleerd - + Alles TV TV Mini @@ -814,6 +814,10 @@ OVA ONA Muziek + + + + Alles Manga Roman Één Opname diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 2463a0b0d..110b7e004 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -806,7 +806,7 @@ Anulowane - + Wszystko TV TV Short @@ -815,6 +815,10 @@ OVA ONA Muzyka + + + + Wszystko Manga Novelka One Shot diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 83e643085..241afb11e 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -806,7 +806,7 @@ Cancelado - + Todos TV Curta @@ -815,6 +815,10 @@ OVA ONA Música + + + + Todos Mangá Novel One Shot diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index b2b056b6e..d8a530ca0 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -805,7 +805,7 @@ Avbruten - + Alla TV TV Kort @@ -814,6 +814,10 @@ OVA ONA Musik + + + + Alla Manga Novel One Shot diff --git a/app/src/main/res/values/attr.xml b/app/src/main/res/values/attr.xml index ace8e1296..4efdac984 100644 --- a/app/src/main/res/values/attr.xml +++ b/app/src/main/res/values/attr.xml @@ -31,4 +31,8 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6c1fcd673..e6b4cce2a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -831,7 +831,7 @@ Canceled - + All TV TV Short @@ -840,6 +840,10 @@ OVA ONA Music + + + + All Manga Novel One Shot @@ -1013,7 +1017,19 @@ Download Share Original Link + + + The character image doesn\'t exist! + The user has not set a banner image! + The series cover image doesn\'t exist! + The series banner image doesn\'t exist! + The staff image doesn\'t exist! + The user\'s avatar image doesn\'t exist + + App Logs Save Bug Report Bug Report saved to Downloads Folder (AniTrend Logcat.txt) + + Show Spoiler Tags From dc1dae9c254232bb22232db1a3ad86bc2faa03e6 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Sat, 2 Mar 2019 14:49:50 +0200 Subject: [PATCH 02/17] Rich Markdown, Emoji & Kotlin Experimental --- app/build.gradle | 24 +- app/src/main/java/com/mxt/anitrend/App.java | 127 -------- app/src/main/java/com/mxt/anitrend/App.kt | 112 +++++++ .../recycler/detail/ImagePreviewAdapter.java | 2 +- .../adapter/recycler/index/FeedAdapter.java | 6 +- .../base/custom/async/WebTokenRequest.java | 2 +- .../custom/view/editor/ComposerWidget.java | 24 +- .../view/editor/MarkdownInputEditor.java | 287 ------------------ .../custom/view/editor/MarkdownInputEditor.kt | 287 ++++++++++++++++++ .../view/text/RichMarkdownTextView.java | 103 ------- .../custom/view/text/RichMarkdownTextView.kt | 99 ++++++ .../custom/view/text/SpoilerTagTextView.java | 2 +- .../view/widget/StatusContentWidget.java | 4 +- .../binding/RichMarkdownExtensions.kt | 42 +++ .../com/mxt/anitrend/data/DatabaseHelper.java | 193 ------------ .../com/mxt/anitrend/data/DatabaseHelper.kt | 171 +++++++++++ .../anitrend/receiver/SchedulerDelegate.java | 21 -- .../anitrend/receiver/SchedulerDelegate.kt | 20 ++ .../service/JobDispatcherService.java | 80 ----- .../anitrend/service/JobDispatcherService.kt | 77 +++++ .../com/mxt/anitrend/util/DialogUtil.java | 19 +- .../mxt/anitrend/util/IntentBundleUtil.java | 2 +- .../mxt/anitrend/util/JobSchedulerUtil.java | 44 --- .../com/mxt/anitrend/util/JobSchedulerUtil.kt | 48 +++ .../com/mxt/anitrend/util/MarkDownUtil.java | 103 ------- .../com/mxt/anitrend/util/MarkDownUtil.kt | 81 +++++ .../mxt/anitrend/util/MediaDialogUtil.java | 2 +- .../java/com/mxt/anitrend/util/RegexUtil.java | 156 ---------- .../java/com/mxt/anitrend/util/RegexUtil.kt | 170 +++++++++++ .../view/activity/base/SettingsActivity.java | 8 +- .../activity/base/SharedContentActivity.java | 8 +- .../activity/detail/MediaBrowseActivity.java | 2 +- .../view/activity/index/LoginActivity.java | 2 +- .../view/activity/index/MainActivity.java | 2 +- .../fragment/detail/UserOverviewFragment.java | 4 +- .../youtube/YouTubeEmbedFragment.java | 6 +- .../view/sheet/BottomSheetMessage.java | 3 +- .../anitrend/worker/AuthenticatorWorker.java | 77 ----- .../anitrend/worker/AuthenticatorWorker.kt | 77 +++++ .../main/res/layout/adapter_feed_status.xml | 9 +- .../main/res/layout/fragment_user_about.xml | 15 +- app/src/main/res/layout/widget_composer.xml | 8 +- .../com/mxt/anitrend/util/RegexUtilTests.java | 32 +- build.gradle | 21 +- gradle.properties | 9 + gradle/wrapper/gradle-wrapper.properties | 4 +- 46 files changed, 1318 insertions(+), 1277 deletions(-) delete mode 100644 app/src/main/java/com/mxt/anitrend/App.java create mode 100644 app/src/main/java/com/mxt/anitrend/App.kt delete mode 100644 app/src/main/java/com/mxt/anitrend/base/custom/view/editor/MarkdownInputEditor.java create mode 100644 app/src/main/java/com/mxt/anitrend/base/custom/view/editor/MarkdownInputEditor.kt delete mode 100644 app/src/main/java/com/mxt/anitrend/base/custom/view/text/RichMarkdownTextView.java create mode 100644 app/src/main/java/com/mxt/anitrend/base/custom/view/text/RichMarkdownTextView.kt create mode 100644 app/src/main/java/com/mxt/anitrend/binding/RichMarkdownExtensions.kt delete mode 100644 app/src/main/java/com/mxt/anitrend/data/DatabaseHelper.java create mode 100644 app/src/main/java/com/mxt/anitrend/data/DatabaseHelper.kt delete mode 100644 app/src/main/java/com/mxt/anitrend/receiver/SchedulerDelegate.java create mode 100644 app/src/main/java/com/mxt/anitrend/receiver/SchedulerDelegate.kt delete mode 100644 app/src/main/java/com/mxt/anitrend/service/JobDispatcherService.java create mode 100644 app/src/main/java/com/mxt/anitrend/service/JobDispatcherService.kt delete mode 100644 app/src/main/java/com/mxt/anitrend/util/JobSchedulerUtil.java create mode 100644 app/src/main/java/com/mxt/anitrend/util/JobSchedulerUtil.kt delete mode 100644 app/src/main/java/com/mxt/anitrend/util/MarkDownUtil.java create mode 100644 app/src/main/java/com/mxt/anitrend/util/MarkDownUtil.kt delete mode 100644 app/src/main/java/com/mxt/anitrend/util/RegexUtil.java create mode 100644 app/src/main/java/com/mxt/anitrend/util/RegexUtil.kt delete mode 100644 app/src/main/java/com/mxt/anitrend/worker/AuthenticatorWorker.java create mode 100644 app/src/main/java/com/mxt/anitrend/worker/AuthenticatorWorker.kt diff --git a/app/build.gradle b/app/build.gradle index 8a3884d09..2235c13dd 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,6 +1,7 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'io.objectbox' +apply plugin: 'kotlin-kapt' apply plugin: 'io.fabric' android { @@ -112,15 +113,15 @@ dependencies { exclude group: 'stax', module: 'stax-api' exclude group: 'stax', module: 'stax' } - implementation "com.squareup.okhttp3:logging-interceptor:3.11.0" + implementation "com.squareup.okhttp3:logging-interceptor:3.12.1" /** Glide Libraries */ implementation "com.github.bumptech.glide:glide:${rootProject.glide}" - annotationProcessor "com.github.bumptech.glide:compiler:${rootProject.glide}" + kapt "com.github.bumptech.glide:compiler:${rootProject.glide}" /** Butter Knife Libraries */ implementation "com.jakewharton:butterknife:${rootProject.butterKnife}" - annotationProcessor "com.jakewharton:butterknife-compiler:${rootProject.butterKnife}" + kapt "com.jakewharton:butterknife-compiler:${rootProject.butterKnife}" /** State Layout Library */ implementation 'com.github.nguyenhoanglam:ProgressLayout:1.0.1' @@ -133,7 +134,7 @@ dependencies { /** Object Box */ implementation "io.objectbox:objectbox-android:${rootProject.objectBox}" - annotationProcessor "io.objectbox:objectbox-processor:${rootProject.objectBox}" + kapt "io.objectbox:objectbox-processor:${rootProject.objectBox}" /** Pretty Time */ implementation 'org.ocpsoft.prettytime:prettytime:4.0.1.Final' @@ -154,8 +155,15 @@ dependencies { implementation 'com.tapadoo.android:alerter:2.0.4' /** Rich Text Markdown Parser */ - implementation "ru.noties:markwon:2.0.1" - implementation "ru.noties:markwon-image-loader:2.0.1" + implementation "ru.noties.markwon:core:$rootProject.markwon" + implementation "ru.noties.markwon:ext-strikethrough:$rootProject.markwon" + implementation "ru.noties.markwon:ext-tables:$rootProject.markwon" + implementation "ru.noties.markwon:ext-tasklist:$rootProject.markwon" + implementation "ru.noties.markwon:html:$rootProject.markwon" + implementation "ru.noties.markwon:image-gif:$rootProject.markwon" + implementation "ru.noties.markwon:image-okhttp:$rootProject.markwon" + implementation "ru.noties.markwon:image-svg:$rootProject.markwon" + implementation "ru.noties.markwon:recycler:$rootProject.markwon" /** Tap Target Prompt */ implementation 'uk.co.samuelwall:material-tap-target-prompt:2.12.1' @@ -170,13 +178,15 @@ dependencies { implementation'com.github.PhilJay:MPAndroidChart:v3.0.3' /** About Library */ - implementation 'com.github.medyo:android-about-page:1.2.4' + implementation 'com.github.medyo:android-about-page:1.2.5' /** Multi Dex */ implementation 'com.android.support:multidex:1.0.3' /** Material Search View */ implementation 'com.miguelcatalan:materialsearchview:1.4.0' + + implementation "com.github.wax911:android-emojify:$rootProject.emojify" } apply plugin: 'com.google.gms.google-services' diff --git a/app/src/main/java/com/mxt/anitrend/App.java b/app/src/main/java/com/mxt/anitrend/App.java deleted file mode 100644 index 7bea2cef3..000000000 --- a/app/src/main/java/com/mxt/anitrend/App.java +++ /dev/null @@ -1,127 +0,0 @@ -package com.mxt.anitrend; - -import android.content.Context; -import android.content.Intent; -import android.os.Build; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.multidex.MultiDex; -import android.support.multidex.MultiDexApplication; - -import com.crashlytics.android.core.CrashlyticsCore; -import com.google.android.gms.security.ProviderInstaller; -import com.google.firebase.analytics.FirebaseAnalytics; -import com.mxt.anitrend.model.entity.MyObjectBox; -import com.mxt.anitrend.util.ApplicationPref; -import com.mxt.anitrend.util.JobSchedulerUtil; -import com.mxt.anitrend.util.LocaleUtil; - -import org.greenrobot.eventbus.EventBus; - -import io.fabric.sdk.android.Fabric; -import io.objectbox.BoxStore; -import io.objectbox.android.AndroidObjectBrowser; - -/** - * Created by max on 2017/10/22. - * Application class - */ - -public class App extends MultiDexApplication { - - private @Nullable FirebaseAnalytics analytics; - private BoxStore boxStore; - private @Nullable Fabric fabric; - - private void setupBoxStore() { - boxStore = MyObjectBox.builder() - .androidContext(App.this) - .build(); - if(BuildConfig.DEBUG) - new AndroidObjectBrowser(boxStore).start(this); - } - - private void setCrashAnalytics(ApplicationPref pref) { - if (!BuildConfig.DEBUG) - if (pref.isCrashReportsEnabled()) { - CrashlyticsCore crashlyticsCore = new CrashlyticsCore.Builder() - .build(); - - fabric = Fabric.with(new Fabric.Builder(this) - .kits(crashlyticsCore) - .appIdentifier(BuildConfig.BUILD_TYPE) - .build()); - } - } - - private void initApp(ApplicationPref pref) { - EventBus.builder().logNoSubscriberMessages(BuildConfig.DEBUG) - .sendNoSubscriberEvent(BuildConfig.DEBUG) - .sendSubscriberExceptionEvent(BuildConfig.DEBUG) - .throwSubscriberException(BuildConfig.DEBUG) - .installDefaultEventBus(); - if (pref.isUsageAnalyticsEnabled()) { - analytics = FirebaseAnalytics.getInstance(this); - analytics.setAnalyticsCollectionEnabled(pref.isUsageAnalyticsEnabled()); - analytics.setMinimumSessionDuration(5000L); - } - JobSchedulerUtil.scheduleJob(getApplicationContext()); - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) - ProviderInstaller.installIfNeededAsync(getApplicationContext(), - new ProviderInstaller.ProviderInstallListener() { - @Override - public void onProviderInstalled() { - - } - - @Override - public void onProviderInstallFailed(int i, Intent intent) { - - } - }); - } - - @Override - public void onCreate() { - super.onCreate(); - ApplicationPref pref = new ApplicationPref(this); - setCrashAnalytics(pref); - setupBoxStore(); - initApp(pref); - } - - @Override - protected void attachBaseContext(Context base) { - super.attachBaseContext(LocaleUtil.onAttach(base)); - MultiDex.install(this); - } - - /** - * @return Default application object box database instance - * - * @see com.mxt.anitrend.data.DatabaseHelper - */ - public @NonNull BoxStore getBoxStore() { - return boxStore; - } - - /** - * Get application global registered fabric instance, depending on - * the current application preferences the application may have - * disabled the current instance from sending any data - * - * @see com.mxt.anitrend.util.AnalyticsUtil - */ - public @Nullable Fabric getFabric() { - return fabric; - } - - /** - * @return Application global registered firebase analytics - * - * @see com.mxt.anitrend.util.AnalyticsUtil - */ - public @Nullable FirebaseAnalytics getAnalytics() { - return analytics; - } -} diff --git a/app/src/main/java/com/mxt/anitrend/App.kt b/app/src/main/java/com/mxt/anitrend/App.kt new file mode 100644 index 000000000..eb37afdf4 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/App.kt @@ -0,0 +1,112 @@ +package com.mxt.anitrend + +import android.content.Context +import android.content.Intent +import android.os.Build +import android.support.multidex.MultiDex +import android.support.multidex.MultiDexApplication +import com.crashlytics.android.core.CrashlyticsCore +import com.google.android.gms.security.ProviderInstaller +import com.google.firebase.analytics.FirebaseAnalytics +import com.mxt.anitrend.model.entity.MyObjectBox +import com.mxt.anitrend.util.ApplicationPref +import com.mxt.anitrend.util.JobSchedulerUtil +import com.mxt.anitrend.util.LocaleUtil +import io.fabric.sdk.android.Fabric +import io.objectbox.BoxStore +import io.wax911.emojify.EmojiManager +import org.greenrobot.eventbus.EventBus + +/** + * Created by max on 2017/10/22. + * Application class + */ + +class App : MultiDexApplication() { + + /** + * @return Application global registered firebase analytics + * + * @see com.mxt.anitrend.util.AnalyticsUtil + */ + var analytics: FirebaseAnalytics? = null + private set + /** + * @return Default application object box database instance + * + * @see com.mxt.anitrend.data.DatabaseHelper + */ + var boxStore: BoxStore? = null + private set + /** + * Get application global registered fabric instance, depending on + * the current application preferences the application may have + * disabled the current instance from sending any data + * + * @see com.mxt.anitrend.util.AnalyticsUtil + */ + var fabric: Fabric? = null + private set + + private fun setupBoxStore() { + boxStore = MyObjectBox.builder() + .androidContext(this@App) + .build() + } + + private fun setCrashAnalytics(pref: ApplicationPref) { + if (!BuildConfig.DEBUG) + if (pref.isCrashReportsEnabled!!) { + val crashlyticsCore = CrashlyticsCore.Builder() + .build() + + fabric = Fabric.with(Fabric.Builder(this) + .kits(crashlyticsCore) + .appIdentifier(BuildConfig.BUILD_TYPE) + .build()) + } + } + + private fun initApp(pref: ApplicationPref) { + EventBus.builder().logNoSubscriberMessages(BuildConfig.DEBUG) + .sendNoSubscriberEvent(BuildConfig.DEBUG) + .sendSubscriberExceptionEvent(BuildConfig.DEBUG) + .throwSubscriberException(BuildConfig.DEBUG) + .installDefaultEventBus() + if (pref.isUsageAnalyticsEnabled!!) { + analytics = FirebaseAnalytics.getInstance(this).apply { + setAnalyticsCollectionEnabled(pref.isUsageAnalyticsEnabled!!) + } + } + JobSchedulerUtil.scheduleJob(applicationContext) + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) + ProviderInstaller.installIfNeededAsync(applicationContext, + object : ProviderInstaller.ProviderInstallListener { + override fun onProviderInstalled() { + + } + + override fun onProviderInstallFailed(i: Int, intent: Intent) { + + } + }) + try { + EmojiManager.initEmojiData(this) + } catch (e: Exception) { + e.printStackTrace() + } + } + + override fun onCreate() { + super.onCreate() + val pref = ApplicationPref(this) + setCrashAnalytics(pref) + setupBoxStore() + initApp(pref) + } + + override fun attachBaseContext(base: Context) { + super.attachBaseContext(LocaleUtil.onAttach(base)) + MultiDex.install(this) + } +} diff --git a/app/src/main/java/com/mxt/anitrend/adapter/recycler/detail/ImagePreviewAdapter.java b/app/src/main/java/com/mxt/anitrend/adapter/recycler/detail/ImagePreviewAdapter.java index 951491a97..45f724712 100644 --- a/app/src/main/java/com/mxt/anitrend/adapter/recycler/detail/ImagePreviewAdapter.java +++ b/app/src/main/java/com/mxt/anitrend/adapter/recycler/detail/ImagePreviewAdapter.java @@ -75,7 +75,7 @@ public void onBindViewHolder(String model) { binding.feedPlayBack.setVisibility(View.GONE); break; case RegexUtil.KEY_YOU: - targetModel = RegexUtil.getYoutubeThumb(model); + targetModel = RegexUtil.INSTANCE.getYoutubeThumb(model); binding.feedPlayBack.setVisibility(View.VISIBLE); requestOptions = RequestOptions.centerCropTransform(); break; diff --git a/app/src/main/java/com/mxt/anitrend/adapter/recycler/index/FeedAdapter.java b/app/src/main/java/com/mxt/anitrend/adapter/recycler/index/FeedAdapter.java index 83bfa9073..07dce491a 100644 --- a/app/src/main/java/com/mxt/anitrend/adapter/recycler/index/FeedAdapter.java +++ b/app/src/main/java/com/mxt/anitrend/adapter/recycler/index/FeedAdapter.java @@ -180,7 +180,8 @@ public StatusFeedViewHolder(AdapterFeedStatusBinding binding) { @Override public void onBindViewHolder(FeedList model) { binding.setModel(model); - binding.widgetStatus.setModel(model); + // TODO: Temporarily disabled widget status to try out rich markdown rendering + //binding.widgetStatus.setModel(model); binding.widgetFavourite.setRequestParams(KeyUtil.ACTIVITY, model.getId()); binding.widgetFavourite.setModel(model.getLikes()); @@ -211,7 +212,8 @@ public void onBindViewHolder(FeedList model) { public void onViewRecycled() { Glide.with(getContext()).clear(binding.userAvatar); binding.widgetFavourite.onViewRecycled(); - binding.widgetStatus.onViewRecycled(); + // TODO: Temporarily disabled widget status to try out rich markdown rendering + // binding.widgetStatus.onViewRecycled(); binding.widgetDelete.onViewRecycled(); binding.unbind(); } diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/async/WebTokenRequest.java b/app/src/main/java/com/mxt/anitrend/base/custom/async/WebTokenRequest.java index 5cba8f8b0..2bf277dd7 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/async/WebTokenRequest.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/async/WebTokenRequest.java @@ -43,7 +43,7 @@ public static void invalidateInstance(Context context) { CommonPresenter presenter = new BasePresenter(context); presenter.getApplicationPref().setAuthenticated(false); presenter.getDatabase().invalidateBoxStores(); - JobSchedulerUtil.cancelJob(); + JobSchedulerUtil.INSTANCE.cancelJob(); WebFactory.invalidate(); token = null; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/editor/ComposerWidget.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/editor/ComposerWidget.java index 622cfb745..bee516b4f 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/editor/ComposerWidget.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/editor/ComposerWidget.java @@ -42,6 +42,8 @@ import java.util.Locale; +import io.wax911.emojify.EmojiManager; +import io.wax911.emojify.parser.EmojiParser; import okhttp3.ResponseBody; import retrofit2.Call; import retrofit2.Response; @@ -293,7 +295,7 @@ public void onGiphyClicked(IntPair pair) { EditText editor = binding.comment; int start = editor.getSelectionStart(); Gif gif = pair.getSecond().getImages().get(index); - editor.getEditableText().insert(start, MarkDownUtil.convertImage(gif.getUrl())); + editor.getEditableText().insert(start, MarkDownUtil.INSTANCE.convertImage(gif.getUrl())); } public void appendText(String textValue) { @@ -303,10 +305,22 @@ public void appendText(String textValue) { } public void setText(String textValue) { - if(TextUtils.isEmpty(binding.comment.getText())) - binding.comment.setText(textValue); - else - appendText(textValue); + // TODO: Added emojify on text edit + String emojified; + if(TextUtils.isEmpty(binding.comment.getText())) { + emojified = EmojiParser.INSTANCE.parseToUnicode(textValue); + if (!TextUtils.isEmpty(emojified)) + binding.comment.setText(emojified); + else + binding.comment.setText(textValue); + } + else { + emojified = EmojiParser.INSTANCE.parseToUnicode(textValue); + if (!TextUtils.isEmpty(emojified)) + appendText(emojified); + else + appendText(textValue); + } } public void mentionUserFrom(FeedReply feedReply) { diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/editor/MarkdownInputEditor.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/editor/MarkdownInputEditor.java deleted file mode 100644 index d2bddf9e6..000000000 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/editor/MarkdownInputEditor.java +++ /dev/null @@ -1,287 +0,0 @@ -package com.mxt.anitrend.base.custom.view.editor; - -import android.content.Context; -import android.graphics.Typeface; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.support.annotation.IdRes; -import android.support.annotation.Nullable; -import android.support.design.widget.TextInputEditText; -import android.support.v13.view.inputmethod.EditorInfoCompat; -import android.support.v13.view.inputmethod.InputConnectionCompat; -import android.support.v13.view.inputmethod.InputContentInfoCompat; -import android.support.v4.content.ContextCompat; -import android.text.InputFilter; -import android.text.TextUtils; -import android.util.AttributeSet; -import android.view.ActionMode; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.inputmethod.EditorInfo; -import android.view.inputmethod.InputConnection; - -import com.mxt.anitrend.R; -import com.mxt.anitrend.base.interfaces.view.CustomView; -import com.mxt.anitrend.util.CompatUtil; -import com.mxt.anitrend.util.KeyUtil; -import com.mxt.anitrend.util.MarkDownUtil; - -import static com.mxt.anitrend.util.KeyUtil.MD_BOLD; -import static com.mxt.anitrend.util.KeyUtil.MD_BULLET; -import static com.mxt.anitrend.util.KeyUtil.MD_CENTER_ALIGN; -import static com.mxt.anitrend.util.KeyUtil.MD_CODE; -import static com.mxt.anitrend.util.KeyUtil.MD_HEADING; -import static com.mxt.anitrend.util.KeyUtil.MD_ITALIC; -import static com.mxt.anitrend.util.KeyUtil.MD_NUMBER; -import static com.mxt.anitrend.util.KeyUtil.MD_QUOTE; -import static com.mxt.anitrend.util.KeyUtil.MD_STRIKE; - -/** - * Created by max on 2017/08/14. - * Markdown input editor - */ - -public class MarkdownInputEditor extends TextInputEditText implements CustomView, ActionMode.Callback, - InputConnectionCompat.OnCommitContentListener{ - - public MarkdownInputEditor(Context context) { - super(context); - onInit(); - } - - public MarkdownInputEditor(Context context, AttributeSet attrs) { - super(context, attrs); - onInit(); - } - - public MarkdownInputEditor(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - onInit(); - } - - private InputFilter EMOJI_FILTER = (source, start, end, dest, dstart, dend) -> { - for (int index = start; index < end; index++) { - int type = Character.getType(source.charAt(index)); - if (type == Character.SURROGATE) - return ""; - } - return null; - }; - - /** - * Optionally included when constructing custom views - */ - @Override - public void onInit() { - setFilters(new InputFilter[] {EMOJI_FILTER}); - setVerticalScrollBarEnabled(true); - setCustomSelectionActionModeCallback(this); - setMaxHeight(CompatUtil.dipToPx(KeyUtil.PEEK_HEIGHT)); - setBackgroundColor(ContextCompat.getColor(getContext(), android.R.color.transparent)); - setTypeface(Typeface.create("sans-serif-condensed", Typeface.NORMAL)); - } - - @Override - public InputConnection onCreateInputConnection(EditorInfo outAttrs) { - InputConnection ic = super.onCreateInputConnection(outAttrs); - EditorInfoCompat.setContentMimeTypes(outAttrs, new String [] {"image/png", "image/gif"}); - return InputConnectionCompat.createWrapper(ic, outAttrs, this); - } - - - - /** - * Called when action mode is first created. The menu supplied will be used to - * generate action buttons for the action mode. - * - * @param mode ActionMode being created - * @param menu Menu used to populate action buttons - * @return true if the action mode should be created, false if entering this - * mode should be aborted. - */ - @Override - public boolean onCreateActionMode(ActionMode mode, Menu menu) { - MenuInflater inflater = mode.getMenuInflater(); - inflater.inflate(R.menu.editor_menu, menu); - return true; - } - - /** - * Called to refresh an action mode's action menu whenever it is invalidated. - * - * @param mode ActionMode being prepared - * @param menu Menu used to populate action buttons - * @return true if the menu or action mode was updated, false otherwise. - */ - @Override - public boolean onPrepareActionMode(ActionMode mode, Menu menu) { - return false; - } - - /** - * Used to get the correct selection end range depending on the text size - * of the preferred mark_down styling. - * - * @param selection The menu item from the selection mode - * @return end selection size with applied offset - */ - private int getSelectionEnd(@IdRes int selection) { - int end = getSelectionEnd(); - final int init_end = getSelectionEnd(); - switch (selection) { - case R.id.menu_bold: - end += MD_BOLD.length(); - break; - case R.id.menu_italic: - end += MD_ITALIC.length(); - break; - case R.id.menu_strike: - end += MD_STRIKE.length(); - break; - case R.id.menu_list: - end += MD_NUMBER.length(); - break; - case R.id.menu_bullet: - end += MD_BULLET.length(); - break; - case R.id.menu_heading: - end += MD_HEADING.length(); - break; - case R.id.menu_center: - end += MD_CENTER_ALIGN.length(); - break; - case R.id.menu_quote: - end += MD_QUOTE.length(); - break; - case R.id.menu_code: - end += MD_CODE.length(); - break; - } - // Rare case but if it ever happens reduce end by 1 - final int text_length = getText().length(); - if(end > text_length + (end - init_end)) - end -= (end - init_end) - 1; - return end; - } - - /** - * Called to report a user click on an action button. - * - * @param mode The current ActionMode - * @param item The item that was clicked - * @return true if this callback handled the event, false if the standard MenuItem - * invocation should continue. - */ - @Override - public boolean onActionItemClicked(ActionMode mode, MenuItem item) { - int start = getSelectionStart(); - int end = getSelectionEnd(item.getItemId()); - switch (item.getItemId()) { - case R.id.menu_bold: - getText().insert(start, MD_BOLD); - getText().insert(end, MD_BOLD, 0, MD_BOLD.length()); - mode.finish(); - return true; - case R.id.menu_italic: - getText().insert(start, MD_ITALIC); - getText().insert(end, MD_ITALIC, 0, MD_ITALIC.length()); - mode.finish(); - return true; - case R.id.menu_strike: - getText().insert(start, MD_STRIKE); - getText().insert(end, MD_STRIKE, 0, MD_STRIKE.length()); - mode.finish(); - return true; - case R.id.menu_list: - getText().insert(start, MD_NUMBER); - mode.finish(); - return true; - case R.id.menu_bullet: - getText().insert(start, MD_BULLET); - mode.finish(); - return true; - case R.id.menu_heading: - getText().insert(start, MD_HEADING); - mode.finish(); - return true; - case R.id.menu_center: - getText().insert(start, MD_CENTER_ALIGN); - getText().insert(end, MD_CENTER_ALIGN, 0, MD_CENTER_ALIGN.length()); - mode.finish(); - return true; - case R.id.menu_quote: - getText().insert(start, MD_QUOTE); - mode.finish(); - return true; - case R.id.menu_code: - getText().insert(start, MD_CODE); - getText().insert(end, MD_CODE, 0, MD_CODE.length()); - mode.finish(); - return true; - } - return false; - } - - /** - * @return composed text as hex html entities - */ - public String getFormattedText() { - String content = getText().toString(); - // disabled until anilist introduces emojis - //return EmojiUtils.hexHtmlify(content); - return content; - } - - /** - * Called when an action mode is about to be exited and destroyed. - * - * @param mode The current ActionMode being destroyed - */ - @Override - public void onDestroyActionMode(ActionMode mode) { - - } - - /** - * Clean up any resources that won't be needed - */ - @Override - public void onViewRecycled() { - - } - - public boolean isEmpty() { - return TextUtils.isEmpty(getText()); - } - - /** - * Intercepts InputConnection#commitContent API calls. - * - * @param inputContentInfo content to be committed - * @param flags {@code 0} or {@link InputConnection#INPUT_CONTENT_GRANT_READ_URI_PERMISSION} - * @param opts optional bundle data. This can be {@code null} - * @return {@code true} if this request is accepted by the application, no matter if the - * request is already handled or still being handled in background. {@code false} to use the - * default implementation - */ - @Override - public boolean onCommitContent(InputContentInfoCompat inputContentInfo, int flags, @Nullable Bundle opts) { - try { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1 && (flags & InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION) != 0) - inputContentInfo.requestPermission(); - Uri linkUri = inputContentInfo.getLinkUri(); - if(linkUri != null) { - String link = MarkDownUtil.convertImage(linkUri.toString()); - getText().insert(getSelectionStart(), link); - inputContentInfo.releasePermission(); - return true; - } - inputContentInfo.releasePermission(); - } catch (Exception e) { - e.printStackTrace(); - } - return false; // return true if succeeded - } -} diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/editor/MarkdownInputEditor.kt b/app/src/main/java/com/mxt/anitrend/base/custom/view/editor/MarkdownInputEditor.kt new file mode 100644 index 000000000..bb9cbe499 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/editor/MarkdownInputEditor.kt @@ -0,0 +1,287 @@ +package com.mxt.anitrend.base.custom.view.editor + +import android.content.Context +import android.graphics.Typeface +import android.os.Build +import android.os.Bundle +import android.support.annotation.IdRes +import android.support.design.widget.TextInputEditText +import android.support.v13.view.inputmethod.EditorInfoCompat +import android.support.v13.view.inputmethod.InputConnectionCompat +import android.support.v13.view.inputmethod.InputContentInfoCompat +import android.support.v4.content.ContextCompat +import android.text.InputFilter +import android.text.Spanned +import android.text.TextUtils +import android.util.AttributeSet +import android.view.ActionMode +import android.view.Menu +import android.view.MenuItem +import android.view.inputmethod.EditorInfo +import android.view.inputmethod.InputConnection + +import com.mxt.anitrend.R +import com.mxt.anitrend.base.interfaces.view.CustomView +import com.mxt.anitrend.util.CompatUtil +import com.mxt.anitrend.util.KeyUtil +import com.mxt.anitrend.util.MarkDownUtil + +import io.wax911.emojify.parser.EmojiParser + +import com.mxt.anitrend.util.KeyUtil.MD_BOLD +import com.mxt.anitrend.util.KeyUtil.MD_BULLET +import com.mxt.anitrend.util.KeyUtil.MD_CENTER_ALIGN +import com.mxt.anitrend.util.KeyUtil.MD_CODE +import com.mxt.anitrend.util.KeyUtil.MD_HEADING +import com.mxt.anitrend.util.KeyUtil.MD_ITALIC +import com.mxt.anitrend.util.KeyUtil.MD_NUMBER +import com.mxt.anitrend.util.KeyUtil.MD_QUOTE +import com.mxt.anitrend.util.KeyUtil.MD_STRIKE + +/** + * Created by max on 2017/08/14. + * Markdown input editor + */ + +class MarkdownInputEditor : TextInputEditText, CustomView, ActionMode.Callback, InputConnectionCompat.OnCommitContentListener { + + private val emojiInputFilter = object: InputFilter { + /** + * This method is called when the buffer is going to replace the + * range `dstart dend` of `dest` + * with the new text from the range `start end` + * of `source`. Return the CharSequence that you would + * like to have placed there instead, including an empty string + * if appropriate, or `null` to accept the original + * replacement. Be careful to not to reject 0-length replacements, + * as this is what happens when you delete text. Also beware that + * you should not attempt to make any changes to `dest` + * from this method; you may only examine it for context. + * + * Note: If source is an instance of [Spanned] or + * [Spannable], the span objects in the source should be + * copied into the filtered result (i.e. the non-null return value). + * [TextUtils.copySpansFrom] can be used for convenience if the + * span boundary indices would be remaining identical relative to the source. + */ + override fun filter(source: CharSequence?, start: Int, end: Int, dest: Spanned?, dstart: Int, dend: Int): CharSequence { + source?.also { + for (index in start until end) { + val type = Character.getType(it[index]) + if (type == Character.SURROGATE.toInt()) + return "" + } + } + return "" + } + + } + + /** + * @return composed text as hex html entities + */ + val formattedText: String? + get() { + val content = text.toString() + return EmojiParser.parseToHtmlHexadecimal(content) + } + + val isEmpty: Boolean + get() = text.isNullOrBlank() + + constructor(context: Context) : super(context) { + onInit() + } + + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { + onInit() + } + + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { + onInit() + } + + /** + * Optionally included when constructing custom views + */ + override fun onInit() { + // filters = arrayOf(emojiInputFilter) + isVerticalScrollBarEnabled = true + customSelectionActionModeCallback = this + maxHeight = CompatUtil.dipToPx(KeyUtil.PEEK_HEIGHT) + setBackgroundColor(ContextCompat.getColor(context, android.R.color.transparent)) + typeface = Typeface.create("sans-serif-condensed", Typeface.NORMAL) + } + + override fun onCreateInputConnection(outAttrs: EditorInfo): InputConnection { + val ic = super.onCreateInputConnection(outAttrs) + EditorInfoCompat.setContentMimeTypes(outAttrs, arrayOf("image/png", "image/gif")) + return InputConnectionCompat.createWrapper(ic, outAttrs, this) + } + + + /** + * Called when action mode is first created. The menu supplied will be used to + * generate action buttons for the action mode. + * + * @param mode ActionMode being created + * @param menu Menu used to populate action buttons + * @return true if the action mode should be created, false if entering this + * mode should be aborted. + */ + override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean { + val inflater = mode.menuInflater + inflater.inflate(R.menu.editor_menu, menu) + return true + } + + /** + * Called to refresh an action mode's action menu whenever it is invalidated. + * + * @param mode ActionMode being prepared + * @param menu Menu used to populate action buttons + * @return true if the menu or action mode was updated, false otherwise. + */ + override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean { + return false + } + + /** + * Used to get the correct selection end range depending on the text size + * of the preferred mark_down styling. + * + * @param selection The menu item from the selection mode + * @return end selection size with applied offset + */ + private fun getSelectionEnd(@IdRes selection: Int): Int { + var end = selectionEnd + val init_end = selectionEnd + when (selection) { + R.id.menu_bold -> end += MD_BOLD.length + R.id.menu_italic -> end += MD_ITALIC.length + R.id.menu_strike -> end += MD_STRIKE.length + R.id.menu_list -> end += MD_NUMBER.length + R.id.menu_bullet -> end += MD_BULLET.length + R.id.menu_heading -> end += MD_HEADING.length + R.id.menu_center -> end += MD_CENTER_ALIGN.length + R.id.menu_quote -> end += MD_QUOTE.length + R.id.menu_code -> end += MD_CODE.length + } + // Rare case but if it ever happens reduce end by 1 + val text_length = text.length + if (end > text_length + (end - init_end)) + end -= end - init_end - 1 + return end + } + + /** + * Called to report a user click on an action button. + * + * @param mode The current ActionMode + * @param item The item that was clicked + * @return true if this callback handled the event, false if the standard MenuItem + * invocation should continue. + */ + override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean { + val start = selectionStart + val end = getSelectionEnd(item.itemId) + when (item.itemId) { + R.id.menu_bold -> { + text.insert(start, MD_BOLD) + text.insert(end, MD_BOLD, 0, MD_BOLD.length) + mode.finish() + return true + } + R.id.menu_italic -> { + text.insert(start, MD_ITALIC) + text.insert(end, MD_ITALIC, 0, MD_ITALIC.length) + mode.finish() + return true + } + R.id.menu_strike -> { + text.insert(start, MD_STRIKE) + text.insert(end, MD_STRIKE, 0, MD_STRIKE.length) + mode.finish() + return true + } + R.id.menu_list -> { + text.insert(start, MD_NUMBER) + mode.finish() + return true + } + R.id.menu_bullet -> { + text.insert(start, MD_BULLET) + mode.finish() + return true + } + R.id.menu_heading -> { + text.insert(start, MD_HEADING) + mode.finish() + return true + } + R.id.menu_center -> { + text.insert(start, MD_CENTER_ALIGN) + text.insert(end, MD_CENTER_ALIGN, 0, MD_CENTER_ALIGN.length) + mode.finish() + return true + } + R.id.menu_quote -> { + text.insert(start, MD_QUOTE) + mode.finish() + return true + } + R.id.menu_code -> { + text.insert(start, MD_CODE) + text.insert(end, MD_CODE, 0, MD_CODE.length) + mode.finish() + return true + } + } + return false + } + + /** + * Called when an action mode is about to be exited and destroyed. + * + * @param mode The current ActionMode being destroyed + */ + override fun onDestroyActionMode(mode: ActionMode) { + + } + + /** + * Clean up any resources that won't be needed + */ + override fun onViewRecycled() { + + } + + /** + * Intercepts InputConnection#commitContent API calls. + * + * @param inputContentInfo content to be committed + * @param flags `0` or [InputConnection.INPUT_CONTENT_GRANT_READ_URI_PERMISSION] + * @param opts optional bundle data. This can be `null` + * @return `true` if this request is accepted by the application, no matter if the + * request is already handled or still being handled in background. `false` to use the + * default implementation + */ + override fun onCommitContent(inputContentInfo: InputContentInfoCompat, flags: Int, opts: Bundle?): Boolean { + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1 && flags and InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION != 0) + inputContentInfo.requestPermission() + val linkUri = inputContentInfo.linkUri + if (linkUri != null) { + val link = MarkDownUtil.convertImage(linkUri.toString()) + text.insert(selectionStart, link) + inputContentInfo.releasePermission() + return true + } + inputContentInfo.releasePermission() + } catch (e: Exception) { + e.printStackTrace() + } + + return false // return true if succeeded + } +} diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/text/RichMarkdownTextView.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/text/RichMarkdownTextView.java deleted file mode 100644 index 7280d9a3f..000000000 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/text/RichMarkdownTextView.java +++ /dev/null @@ -1,103 +0,0 @@ -package com.mxt.anitrend.base.custom.view.text; - -import android.content.Context; -import android.databinding.BindingAdapter; -import android.support.annotation.StringRes; -import android.support.v4.text.util.LinkifyCompat; -import android.support.v7.widget.AppCompatTextView; -import android.text.Html; -import android.text.Spanned; -import android.text.method.LinkMovementMethod; -import android.text.util.Linkify; -import android.util.AttributeSet; -import android.widget.TextView; -import android.widget.Toast; - -import com.mxt.anitrend.base.interfaces.view.CustomView; -import com.mxt.anitrend.util.MarkDownUtil; -import com.mxt.anitrend.util.RegexUtil; - -import ru.noties.markwon.Markwon; -import ru.noties.markwon.SpannableConfiguration; -import ru.noties.markwon.il.AsyncDrawableLoader; - -public class RichMarkdownTextView extends AppCompatTextView implements CustomView { - - public RichMarkdownTextView(Context context) { - super(context); - onInit(); - } - - public RichMarkdownTextView(Context context, AttributeSet attrs) { - super(context, attrs); - onInit(); - } - - public RichMarkdownTextView(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - onInit(); - } - - /** - * Optionally included when constructing custom views - */ - @Override - public void onInit() { - setFocusable(false); - LinkifyCompat.addLinks(this, Linkify.WEB_URLS); - setMovementMethod(LinkMovementMethod.getInstance()); - } - - /** - * Clean up any resources that won't be needed - */ - @Override - public void onViewRecycled() { - - } - - @BindingAdapter("markDown") - public static void markDown(RichMarkdownTextView richMarkdownTextView, String markdown) { - String strippedText = RegexUtil.removeTags(markdown); - Spanned markdownSpan = MarkDownUtil.convert(strippedText, richMarkdownTextView.getContext(), richMarkdownTextView); - richMarkdownTextView.setText(markdownSpan, TextView.BufferType.SPANNABLE); - } - - @BindingAdapter("textHtml") - public static void htmlText(RichMarkdownTextView richMarkdownTextView, String html) { - Spanned markdownSpan = MarkDownUtil.convert(html, richMarkdownTextView.getContext(), richMarkdownTextView); - richMarkdownTextView.setText(markdownSpan, TextView.BufferType.SPANNABLE); - } - - @BindingAdapter("basicHtml") - public static void basicText(RichMarkdownTextView richMarkdownTextView, String html) { - Spanned htmlSpan = Html.fromHtml(html); - richMarkdownTextView.setText(htmlSpan); - } - - @BindingAdapter("textHtml") - public static void htmlText(RichMarkdownTextView richMarkdownTextView, @StringRes int resId) { - String text = richMarkdownTextView.getContext().getString(resId); - Spanned markdownSpan = MarkDownUtil.convert(text, richMarkdownTextView.getContext(), richMarkdownTextView); - richMarkdownTextView.setText(markdownSpan, TextView.BufferType.SPANNABLE); - } - - @BindingAdapter("richMarkDown") - public static void richMarkDown(RichMarkdownTextView richMarkdownTextView, String markdown) { - final Context context = richMarkdownTextView.getContext(); - - final SpannableConfiguration configuration = SpannableConfiguration.builder(context) - .asyncDrawableLoader(AsyncDrawableLoader.create()) - .htmlAllowNonClosedTags(false) - .softBreakAddsNewLine(false) - .build(); - - Markwon.setMarkdown(richMarkdownTextView, configuration, RegexUtil.convertToStandardMarkdown(markdown)); - } - - public void setMarkDownText(String markDownText) { - String strippedText = RegexUtil.removeTags(markDownText); - Spanned markdownSpan = MarkDownUtil.convert(strippedText, getContext(), this); - setText(markdownSpan, TextView.BufferType.SPANNABLE); - } -} diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/text/RichMarkdownTextView.kt b/app/src/main/java/com/mxt/anitrend/base/custom/view/text/RichMarkdownTextView.kt new file mode 100644 index 000000000..53843a302 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/text/RichMarkdownTextView.kt @@ -0,0 +1,99 @@ +package com.mxt.anitrend.base.custom.view.text + +import android.content.Context +import android.databinding.BindingAdapter +import android.support.annotation.StringRes +import android.support.v4.text.util.LinkifyCompat +import android.support.v7.widget.AppCompatTextView +import android.text.Html +import android.text.Spanned +import android.text.method.LinkMovementMethod +import android.text.util.Linkify +import android.util.AttributeSet +import android.widget.TextView +import com.mxt.anitrend.base.interfaces.view.CustomView +import com.mxt.anitrend.model.api.retro.WebFactory +import com.mxt.anitrend.util.MarkDownUtil +import com.mxt.anitrend.util.RegexUtil +import org.commonmark.ext.gfm.strikethrough.StrikethroughExtension +import org.commonmark.ext.gfm.tables.TablesExtension +import org.commonmark.parser.Parser +import ru.noties.markwon.AbstractMarkwonPlugin +import ru.noties.markwon.Markwon +import ru.noties.markwon.MarkwonConfiguration +import ru.noties.markwon.core.CorePlugin +import ru.noties.markwon.ext.tasklist.TaskListPlugin +import ru.noties.markwon.html.MarkwonHtmlParserImpl +import ru.noties.markwon.image.AsyncDrawableScheduler +import ru.noties.markwon.image.ImagesPlugin +import ru.noties.markwon.image.gif.GifPlugin +import ru.noties.markwon.image.okhttp.OkHttpImagesPlugin +import ru.noties.markwon.syntax.SyntaxHighlight +import java.util.Arrays.asList + +class RichMarkdownTextView : AppCompatTextView, CustomView { + + constructor(context: Context) : + super(context) { onInit() } + + constructor(context: Context, attrs: AttributeSet) : + super(context, attrs) { onInit() } + + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : + super(context, attrs, defStyleAttr) { onInit() } + + val markwon by lazy { + Markwon.builder(context) + .usePlugins(asList( + CorePlugin.create(), + ImagesPlugin.create(context), + GifPlugin.create(), + OkHttpImagesPlugin.create(), + TaskListPlugin.create(context), + object: AbstractMarkwonPlugin() { + @Override + override fun configureParser(builder: Parser.Builder) { + builder.extensions(asList( + StrikethroughExtension.create(), + TablesExtension.create() + )) + } + + override fun configureConfiguration(builder: MarkwonConfiguration.Builder) { + builder.htmlParser(MarkwonHtmlParserImpl.create()) + } + + override fun beforeSetText(textView: TextView, markdown: Spanned) { + AsyncDrawableScheduler.unschedule(textView) + } + + override fun afterSetText(textView: TextView) { + AsyncDrawableScheduler.schedule(textView) + } + } + )) + .build() + } + + /** + * Optionally included when constructing custom views + */ + override fun onInit() { + isFocusable = false + LinkifyCompat.addLinks(this, Linkify.WEB_URLS) + movementMethod = LinkMovementMethod.getInstance() + } + + /** + * Clean up any resources that won't be needed + */ + override fun onViewRecycled() { + + } + + fun setMarkDownText(markDownText: String) { + val strippedText = RegexUtil.removeTags(markDownText) + val markdownSpan = MarkDownUtil.convert(strippedText, context, this) + setText(markdownSpan, TextView.BufferType.SPANNABLE) + } +} diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/text/SpoilerTagTextView.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/text/SpoilerTagTextView.java index 5ab0f1688..9f54fc531 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/text/SpoilerTagTextView.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/text/SpoilerTagTextView.java @@ -21,7 +21,7 @@ public SpoilerTagTextView(Context context, AttributeSet attrs, int defStyleAttr) super(context, attrs, defStyleAttr); } - @BindingAdapter("app:isSpoiler") + @BindingAdapter({"isSpoiler"}) public static void setIsSpoiler(SingleLineTextView view, Boolean isSpoiler) { if (isSpoiler) view.setTextColor(CompatUtil.getColor(view.getContext(), R.color.colorStateOrange)); } diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/StatusContentWidget.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/StatusContentWidget.java index 15eeeb537..36020bf3c 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/StatusContentWidget.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/StatusContentWidget.java @@ -105,7 +105,7 @@ public void onViewRecycled() { private void findMediaAttachments(@Nullable String value) { if(!TextUtils.isEmpty(value)) { - Matcher matcher = RegexUtil.findMedia(value); + Matcher matcher = RegexUtil.INSTANCE.findMedia(value); contentLinks = new ArrayList<>(); contentTypes = new ArrayList<>(); while (matcher.find()) { @@ -114,7 +114,7 @@ private void findMediaAttachments(@Nullable String value) { String media = matcher.group(gc); contentTypes.add(tag); if (tag.equals(RegexUtil.KEY_YOU)) - contentLinks.add(RegexUtil.buildYoutube(media.replace("(", "").replace(")", ""))); + contentLinks.add(RegexUtil.INSTANCE.buildYoutube(media.replace("(", "").replace(")", ""))); else contentLinks.add(media.replace("(", "").replace(")", "")); } diff --git a/app/src/main/java/com/mxt/anitrend/binding/RichMarkdownExtensions.kt b/app/src/main/java/com/mxt/anitrend/binding/RichMarkdownExtensions.kt new file mode 100644 index 000000000..4fefef85b --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/binding/RichMarkdownExtensions.kt @@ -0,0 +1,42 @@ +package com.mxt.anitrend.binding + +import android.databinding.BindingAdapter +import android.support.annotation.StringRes +import android.text.Html +import android.widget.TextView +import com.mxt.anitrend.base.custom.view.text.RichMarkdownTextView +import com.mxt.anitrend.util.MarkDownUtil +import com.mxt.anitrend.util.RegexUtil + +@BindingAdapter("markDown") +fun markDown(richMarkdownTextView: RichMarkdownTextView, markdown: String?) { + val strippedText = RegexUtil.removeTags(markdown) + val markdownSpan = MarkDownUtil.convert(strippedText, richMarkdownTextView.context, richMarkdownTextView) + richMarkdownTextView.setText(markdownSpan, TextView.BufferType.SPANNABLE) +} + +@BindingAdapter("textHtml") +fun htmlText(richMarkdownTextView: RichMarkdownTextView, html: String) { + val markdownSpan = MarkDownUtil.convert(html, richMarkdownTextView.context, richMarkdownTextView) + richMarkdownTextView.setText(markdownSpan, TextView.BufferType.SPANNABLE) +} + +@BindingAdapter("basicHtml") +fun basicText(richMarkdownTextView: RichMarkdownTextView, html: String) { + val htmlSpan = Html.fromHtml(html) + richMarkdownTextView.text = htmlSpan +} + +@BindingAdapter("textHtml") +fun htmlText(richMarkdownTextView: RichMarkdownTextView, @StringRes resId: Int) { + val text = richMarkdownTextView.context.getString(resId) + val markdownSpan = MarkDownUtil.convert(text, richMarkdownTextView.context, richMarkdownTextView) + richMarkdownTextView.setText(markdownSpan, TextView.BufferType.SPANNABLE) +} + +@BindingAdapter("richMarkDown") +fun richMarkDown(richMarkdownTextView: RichMarkdownTextView, markdown: String?) { + richMarkdownTextView.also { + it.markwon.setMarkdown(it, RegexUtil.convertToStandardMarkdown(markdown)) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/mxt/anitrend/data/DatabaseHelper.java b/app/src/main/java/com/mxt/anitrend/data/DatabaseHelper.java deleted file mode 100644 index e2d829971..000000000 --- a/app/src/main/java/com/mxt/anitrend/data/DatabaseHelper.java +++ /dev/null @@ -1,193 +0,0 @@ -package com.mxt.anitrend.data; - -import android.content.Context; -import android.support.annotation.Nullable; - -import com.mxt.anitrend.App; -import com.mxt.anitrend.base.interfaces.dao.BoxQuery; -import com.mxt.anitrend.model.entity.anilist.Genre; -import com.mxt.anitrend.model.entity.anilist.MediaTag; -import com.mxt.anitrend.model.entity.anilist.User; -import com.mxt.anitrend.model.entity.anilist.WebToken; -import com.mxt.anitrend.model.entity.base.AuthBase; -import com.mxt.anitrend.model.entity.base.NotificationHistory; -import com.mxt.anitrend.model.entity.base.UserBase; -import com.mxt.anitrend.model.entity.base.VersionBase; - -import java.util.List; - -import io.objectbox.Box; -import io.objectbox.BoxStore; - -/** - * Created by max on 2017/11/02. - * Database helper class - */ - -public class DatabaseHelper implements BoxQuery { - - private BoxStore boxStore; - private Context context; - - // Frequently used instance variables - private User user; - - public DatabaseHelper(Context context) { - this.context = context; - } - - /** - * Gets the object box from a requested class type. - * - *
- * @param classType Type of class which must not be a list instance - * @return Box of type class requested - */ - @Override - public Box getBoxStore(Class classType) { - if(boxStore == null) - boxStore = ((App)context.getApplicationContext()).getBoxStore(); - return boxStore.boxFor(classType); - } - - /** - * Used when the application is logging out a user preferably - */ - @Override - public void invalidateBoxStores() { - getBoxStore(WebToken.class).removeAll(); - getBoxStore(AuthBase.class).removeAll(); - getBoxStore(User.class).removeAll(); - getBoxStore(UserBase.class).removeAll(); - getBoxStore(VersionBase.class).removeAll(); - getBoxStore(NotificationHistory.class).removeAll(); - } - - /** - * Gets current authenticated user - */ - @Override - public User getCurrentUser() { - if(user == null) - user = getBoxStore(User.class).query() - .build().findFirst(); - return user; - } - - /** - * Get default authentication code - */ - @Override - public AuthBase getAuthCode() { - return getBoxStore(AuthBase.class).query() - .build().findFirst(); - } - - /** - * Get web token - */ - @Override - public @Nullable WebToken getWebToken() { - return getBoxStore(WebToken.class).query() - .build().findFirst(); - } - - /** - * Get the application version on github - */ - @Override - public VersionBase getRemoteVersion() { - return getBoxStore(VersionBase.class).query() - .build().findFirst(); - } - - /** - * Gets all saved tags - */ - @Override - public List getMediaTags() { - return getBoxStore(MediaTag.class).query() - .build().findLazy(); - } - - /** - * Gets all saved genres - */ - @Override - public List getGenreCollection() { - return getBoxStore(Genre.class).query() - .build().findLazy(); - } - - /** - * Saves current authenticated user - * - * @param user - */ - @Override - public void saveCurrentUser(User user) { - this.user = user; - getBoxStore(User.class).put(user); - } - - /** - * Get default authentication code - * - * @param authBase - */ - @Override - public void saveAuthCode(AuthBase authBase) { - getBoxStore(AuthBase.class).removeAll(); - getBoxStore(AuthBase.class).put(authBase); - } - - /** - * Get web token - * - * @param webToken - */ - @Override - public void saveWebToken(WebToken webToken) { - getBoxStore(WebToken.class).removeAll(); - Box tokenBox = getBoxStore(WebToken.class); - tokenBox.put(webToken); - } - - /** - * Save the application version on github - * - * @param versionBase - */ - @Override - public void saveRemoteVersion(VersionBase versionBase) { - Box versionBox = getBoxStore(VersionBase.class); - if(versionBox.count() > 0) - versionBox.removeAll(); - versionBase.setLastChecked(System.currentTimeMillis()); - versionBox.put(versionBase); - } - - /** - * Saves all saved mediaTags - * - * @param mediaTags - */ - @Override - public void saveMediaTags(List mediaTags) { - Box tagBox = getBoxStore(MediaTag.class); - if(tagBox.count() < mediaTags.size()) - tagBox.put(mediaTags); - } - - /** - * Saves all saved genres - * - * @param genres - */ - @Override - public void saveGenreCollection(List genres) { - Box genreBox = getBoxStore(Genre.class); - if(genreBox.count() < genres.size()) - genreBox.put(genres); - } -} \ No newline at end of file diff --git a/app/src/main/java/com/mxt/anitrend/data/DatabaseHelper.kt b/app/src/main/java/com/mxt/anitrend/data/DatabaseHelper.kt new file mode 100644 index 000000000..086d3077d --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/data/DatabaseHelper.kt @@ -0,0 +1,171 @@ +package com.mxt.anitrend.data + +import android.content.Context + +import com.mxt.anitrend.App +import com.mxt.anitrend.base.interfaces.dao.BoxQuery +import com.mxt.anitrend.model.entity.anilist.Genre +import com.mxt.anitrend.model.entity.anilist.MediaTag +import com.mxt.anitrend.model.entity.anilist.User +import com.mxt.anitrend.model.entity.anilist.WebToken +import com.mxt.anitrend.model.entity.base.AuthBase +import com.mxt.anitrend.model.entity.base.NotificationHistory +import com.mxt.anitrend.model.entity.base.UserBase +import com.mxt.anitrend.model.entity.base.VersionBase + +import io.objectbox.Box +import io.objectbox.BoxStore + +/** + * Created by max on 2017/11/02. + * Database helper class + */ + +class DatabaseHelper(private val context: Context) : BoxQuery { + + private var boxStore: BoxStore? = null + + // Frequently used instance variables + private var user: User? = null + + /** + * Gets the object box from a requested class type. + * + *

+ * @param classType Type of class which must not be a list instance + * @return Box of type class requested + */ + override fun getBoxStore(classType: Class): Box { + if (boxStore == null) + boxStore = (context.applicationContext as App).boxStore + return boxStore!!.boxFor(classType) + } + + /** + * Used when the application is logging out a user preferably + */ + override fun invalidateBoxStores() { + getBoxStore(WebToken::class.java).removeAll() + getBoxStore(AuthBase::class.java).removeAll() + getBoxStore(User::class.java).removeAll() + getBoxStore(UserBase::class.java).removeAll() + getBoxStore(VersionBase::class.java).removeAll() + getBoxStore(NotificationHistory::class.java).removeAll() + } + + /** + * Gets current authenticated user + */ + override fun getCurrentUser(): User? { + if (user == null) + user = getBoxStore(User::class.java).query() + .build().findFirst() + return user + } + + /** + * Get default authentication code + */ + override fun getAuthCode(): AuthBase? { + return getBoxStore(AuthBase::class.java).query() + .build().findFirst() + } + + /** + * Get web token + */ + override fun getWebToken(): WebToken? { + return getBoxStore(WebToken::class.java).query() + .build().findFirst() + } + + /** + * Get the application version on github + */ + override fun getRemoteVersion(): VersionBase? { + return getBoxStore(VersionBase::class.java).query() + .build().findFirst() + } + + /** + * Gets all saved tags + */ + override fun getMediaTags(): List { + return getBoxStore(MediaTag::class.java).query() + .build().findLazy() + } + + /** + * Gets all saved genres + */ + override fun getGenreCollection(): List { + return getBoxStore(Genre::class.java).query() + .build().findLazy() + } + + /** + * Saves current authenticated user + * + * @param user + */ + override fun saveCurrentUser(user: User) { + this.user = user + getBoxStore(User::class.java).put(user) + } + + /** + * Get default authentication code + * + * @param authBase + */ + override fun saveAuthCode(authBase: AuthBase) { + getBoxStore(AuthBase::class.java).removeAll() + getBoxStore(AuthBase::class.java).put(authBase) + } + + /** + * Get web token + * + * @param webToken + */ + override fun saveWebToken(webToken: WebToken) { + getBoxStore(WebToken::class.java).removeAll() + val tokenBox = getBoxStore(WebToken::class.java) + tokenBox.put(webToken) + } + + /** + * Save the application version on github + * + * @param versionBase + */ + override fun saveRemoteVersion(versionBase: VersionBase) { + val versionBox = getBoxStore(VersionBase::class.java) + if (versionBox.count() > 0) + versionBox.removeAll() + versionBase.lastChecked = System.currentTimeMillis() + versionBox.put(versionBase) + } + + /** + * Saves all saved mediaTags + * + * @param mediaTags + */ + override fun saveMediaTags(mediaTags: List) { + val tagBox = getBoxStore(MediaTag::class.java) + if (tagBox.count() < mediaTags.size) + tagBox.put(mediaTags) + } + + /** + * Saves all saved genres + * + * @param genres + */ + override fun saveGenreCollection(genres: List) { + val genreBox = getBoxStore(Genre::class.java) + if (genreBox.count() < genres.size) + genreBox.put(genres) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/mxt/anitrend/receiver/SchedulerDelegate.java b/app/src/main/java/com/mxt/anitrend/receiver/SchedulerDelegate.java deleted file mode 100644 index 0b668f04a..000000000 --- a/app/src/main/java/com/mxt/anitrend/receiver/SchedulerDelegate.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.mxt.anitrend.receiver; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; - -import com.mxt.anitrend.util.JobSchedulerUtil; - -/** - * Created by max on 2017/03/03. - * broadcast receiver for scheduling or cancelling jobs - */ - -public class SchedulerDelegate extends BroadcastReceiver { - - @Override - public void onReceive(Context context, Intent intent) { - if(intent.getAction() != null && intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) - JobSchedulerUtil.scheduleJob(context); - } -} \ No newline at end of file diff --git a/app/src/main/java/com/mxt/anitrend/receiver/SchedulerDelegate.kt b/app/src/main/java/com/mxt/anitrend/receiver/SchedulerDelegate.kt new file mode 100644 index 000000000..69eb9e406 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/receiver/SchedulerDelegate.kt @@ -0,0 +1,20 @@ +package com.mxt.anitrend.receiver + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent + +import com.mxt.anitrend.util.JobSchedulerUtil + +/** + * Created by max on 2017/03/03. + * broadcast receiver for scheduling or cancelling jobs + */ + +class SchedulerDelegate : BroadcastReceiver() { + + override fun onReceive(context: Context, intent: Intent) { + if (intent.action != null && intent.action == Intent.ACTION_BOOT_COMPLETED) + JobSchedulerUtil.scheduleJob(context) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/mxt/anitrend/service/JobDispatcherService.java b/app/src/main/java/com/mxt/anitrend/service/JobDispatcherService.java deleted file mode 100644 index 0e68c32b7..000000000 --- a/app/src/main/java/com/mxt/anitrend/service/JobDispatcherService.java +++ /dev/null @@ -1,80 +0,0 @@ -package com.mxt.anitrend.service; - -import android.content.Context; -import android.support.annotation.NonNull; -import android.util.Log; - -import com.mxt.anitrend.base.custom.consumer.BaseConsumer; -import com.mxt.anitrend.model.api.retro.WebFactory; -import com.mxt.anitrend.model.api.retro.anilist.UserModel; -import com.mxt.anitrend.model.entity.anilist.User; -import com.mxt.anitrend.model.entity.container.body.GraphContainer; -import com.mxt.anitrend.presenter.base.BasePresenter; -import com.mxt.anitrend.util.GraphUtil; -import com.mxt.anitrend.util.KeyUtil; -import com.mxt.anitrend.util.NotificationUtil; - -import androidx.work.ListenableWorker; -import androidx.work.Worker; -import androidx.work.WorkerParameters; -import retrofit2.Call; -import retrofit2.Response; - -/** - * Created by Maxwell on 1/22/2017. - */ -public class JobDispatcherService extends Worker { - - private final BasePresenter presenter; - - public JobDispatcherService(@NonNull Context context, @NonNull WorkerParameters workerParams) { - super(context, workerParams); - presenter = new BasePresenter(context); - } - - /** - * Override this method to do your actual background processing. This method is called on a - * background thread - you are required to synchronously do your work and return the - * {@link Result} from this method. Once you return from this - * method, the Worker is considered to have finished what its doing and will be destroyed. If - * you need to do your work asynchronously on a thread of your own choice, see - * {@link ListenableWorker}. - *

- * A Worker is given a maximum of ten minutes to finish its execution and return a - * {@link Result}. After this time has expired, the Worker will - * be signalled to stop. - * - * @return The {@link Result} of the computation; note that - * dependent work will not execute if you use - * {@link Result#failure()} - */ - @NonNull - @Override - public Result doWork() { - if (presenter.getApplicationPref().isAuthenticated()) { - UserModel userModel = WebFactory.createService(UserModel.class, getApplicationContext()); - Call> request = userModel.getCurrentUser(GraphUtil.getDefaultQuery(false)); - try { - Response> response = request.execute(); - Object userGraphContainer = response.body(); - if (response.isSuccessful() && userGraphContainer != null) { - @SuppressWarnings("ConstantConditions") - User currentUser = (User)userGraphContainer; - User previousUserData = presenter.getDatabase().getCurrentUser(); - presenter.getDatabase().saveCurrentUser(currentUser); - if (previousUserData.getUnreadNotificationCount() != currentUser.getUnreadNotificationCount()) { - if (currentUser.getUnreadNotificationCount() > 0) { - presenter.notifyAllListeners(new BaseConsumer<>(KeyUtil.USER_CURRENT_REQ, currentUser), false); - NotificationUtil.createNotification(getApplicationContext(), currentUser); - } - } - return Result.success(); - } - } catch (Exception e) { - Log.e(toString(), e.getMessage()); - e.printStackTrace(); - } - } - return Result.retry(); - } -} diff --git a/app/src/main/java/com/mxt/anitrend/service/JobDispatcherService.kt b/app/src/main/java/com/mxt/anitrend/service/JobDispatcherService.kt new file mode 100644 index 000000000..12e547575 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/service/JobDispatcherService.kt @@ -0,0 +1,77 @@ +package com.mxt.anitrend.service + +import android.content.Context +import android.util.Log + +import com.mxt.anitrend.base.custom.consumer.BaseConsumer +import com.mxt.anitrend.model.api.retro.WebFactory +import com.mxt.anitrend.model.api.retro.anilist.UserModel +import com.mxt.anitrend.model.entity.anilist.User +import com.mxt.anitrend.model.entity.container.body.GraphContainer +import com.mxt.anitrend.presenter.base.BasePresenter +import com.mxt.anitrend.util.GraphUtil +import com.mxt.anitrend.util.KeyUtil +import com.mxt.anitrend.util.NotificationUtil + +import androidx.work.ListenableWorker +import androidx.work.Worker +import androidx.work.WorkerParameters +import retrofit2.Call +import retrofit2.Response + +/** + * Created by Maxwell on 1/22/2017. + */ +class JobDispatcherService(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) { + + private val presenter by lazy { + BasePresenter(context) + } + + /** + * Override this method to do your actual background processing. This method is called on a + * background thread - you are required to **synchronously** do your work and return the + * [Result] from this method. Once you return from this + * method, the Worker is considered to have finished what its doing and will be destroyed. If + * you need to do your work asynchronously on a thread of your own choice, see + * [ListenableWorker]. + * + * + * A Worker is given a maximum of ten minutes to finish its execution and return a + * [Result]. After this time has expired, the Worker will + * be signalled to stop. + * + * @return The [Result] of the computation; note that + * dependent work will not execute if you use + * [Result.failure] + */ + override fun doWork(): ListenableWorker.Result { + if (presenter.applicationPref.isAuthenticated) { + val userModel = WebFactory.createService(UserModel::class.java, applicationContext) + val request = userModel.getCurrentUser(GraphUtil.getDefaultQuery(false)) + try { + val response = request.execute() + val userGraphContainer: Any? = response.body() + if (response.isSuccessful && userGraphContainer != null) { + val currentUser = userGraphContainer as User? + val previousUserData = presenter.database.currentUser + presenter.database.saveCurrentUser(currentUser) + if (previousUserData.unreadNotificationCount != currentUser!!.unreadNotificationCount) { + if (currentUser.unreadNotificationCount > 0) { + presenter.notifyAllListeners(BaseConsumer(KeyUtil.USER_CURRENT_REQ, currentUser), false) + NotificationUtil.createNotification(applicationContext, currentUser) + } + } + return ListenableWorker.Result.success() + } + } catch (e: Exception) { + e.message?.apply { + Log.e(toString(), this) + } + e.printStackTrace() + } + + } + return ListenableWorker.Result.retry() + } +} diff --git a/app/src/main/java/com/mxt/anitrend/util/DialogUtil.java b/app/src/main/java/com/mxt/anitrend/util/DialogUtil.java index 86900869b..11372fe7d 100644 --- a/app/src/main/java/com/mxt/anitrend/util/DialogUtil.java +++ b/app/src/main/java/com/mxt/anitrend/util/DialogUtil.java @@ -17,6 +17,7 @@ import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.view.text.RichMarkdownTextView; import com.mxt.anitrend.base.custom.view.text.SingleLineTextView; +import com.mxt.anitrend.binding.RichMarkdownExtensionsKt; import java.io.IOException; import java.io.InputStream; @@ -49,7 +50,7 @@ public static void createDialogAttachMedia(@IdRes int action, final EditText edi if(editText != null) { if(!TextUtils.isEmpty(editText.getText())) { int start = editor.getSelectionStart(); - editor.getEditableText().insert(start, MarkDownUtil.convertLink(editText.getText())); + editor.getEditableText().insert(start, MarkDownUtil.INSTANCE.convertLink(editText.getText().toString())); dialog.dismiss(); } else { NotifyUtil.makeText(context, R.string.input_empty_warning, Toast.LENGTH_SHORT).show(); @@ -74,7 +75,7 @@ public static void createDialogAttachMedia(@IdRes int action, final EditText edi if(editText != null) { if(!TextUtils.isEmpty(editText.getText())) { int start = editor.getSelectionStart(); - editor.getEditableText().insert(start, MarkDownUtil.convertImage(editText.getText())); + editor.getEditableText().insert(start, MarkDownUtil.INSTANCE.convertImage(editText.getText().toString())); dialog.dismiss(); } else { NotifyUtil.makeText(context, R.string.input_empty_warning, Toast.LENGTH_SHORT).show(); @@ -99,7 +100,7 @@ public static void createDialogAttachMedia(@IdRes int action, final EditText edi if(editText != null) { if(!TextUtils.isEmpty(editText.getText())) { int start = editor.getSelectionStart(); - editor.getEditableText().insert(start, MarkDownUtil.convertYoutube(editText.getText())); + editor.getEditableText().insert(start, MarkDownUtil.INSTANCE.convertYoutube(editText.getText().toString())); dialog.dismiss(); } else { NotifyUtil.makeText(context, R.string.input_empty_warning, Toast.LENGTH_SHORT).show(); @@ -124,7 +125,7 @@ public static void createDialogAttachMedia(@IdRes int action, final EditText edi if(editText != null) { if(!TextUtils.isEmpty(editText.getText())) { int start = editor.getSelectionStart(); - editor.getEditableText().insert(start, MarkDownUtil.convertVideo(editText.getText())); + editor.getEditableText().insert(start, MarkDownUtil.INSTANCE.convertVideo(editText.getText().toString())); dialog.dismiss(); } else { NotifyUtil.makeText(context, R.string.input_empty_warning, Toast.LENGTH_SHORT).show(); @@ -165,7 +166,7 @@ public static void createMessage(Context context, String title, String content) createDefaultDialog(context).title(title) .positiveText(R.string.Close) .icon(CompatUtil.getTintedDrawable(context, R.drawable.ic_new_releases_white_24dp)) - .content(MarkDownUtil.convert(content)) + .content(MarkDownUtil.INSTANCE.convert(content)) .autoDismiss(true).show(); } @@ -175,7 +176,7 @@ public static void createMessage(Context context, String title, String content, .negativeText(negative) .neutralText(neutral) .icon(CompatUtil.getTintedDrawable(context, R.drawable.ic_new_releases_white_24dp)) - .content(MarkDownUtil.convert(content)) + .content(MarkDownUtil.INSTANCE.convert(content)) .autoDismiss(true).onAny(singleButtonCallback).show(); } @@ -184,7 +185,7 @@ public static void createMessage(Context context, String title, String content, .positiveText(positive) .negativeText(negative) .icon(CompatUtil.getTintedDrawable(context, R.drawable.ic_new_releases_white_24dp)) - .content(MarkDownUtil.convert(content)) + .content(MarkDownUtil.INSTANCE.convert(content)) .autoDismiss(true).onAny(singleButtonCallback).show(); } @@ -193,7 +194,7 @@ public static void createTagMessage(Context context, String title, String conten .positiveText(positive) .negativeText(negative) .icon(CompatUtil.getTintedDrawable(context, R.drawable.ic_new_releases_white_24dp)) - .content(MarkDownUtil.convert(content)) + .content(MarkDownUtil.INSTANCE.convert(content)) .autoDismiss(true).onAny(singleButtonCallback); if (isSpoiler) builder.icon(CompatUtil.getDrawable(context, R.drawable.ic_spoiler_tag)); @@ -229,7 +230,7 @@ public static void createChangeLog(Context context) { while ((buffer = inputStream.read()) != -1) stringBuilder.append((char)buffer); RichMarkdownTextView richMarkdownTextView = (RichMarkdownTextView) materialDialog.findViewById(R.id.changelog_information); - RichMarkdownTextView.richMarkDown(richMarkdownTextView, stringBuilder.toString()); + RichMarkdownExtensionsKt.richMarkDown(richMarkdownTextView, stringBuilder.toString()); materialDialog.show(); } catch (IOException e) { diff --git a/app/src/main/java/com/mxt/anitrend/util/IntentBundleUtil.java b/app/src/main/java/com/mxt/anitrend/util/IntentBundleUtil.java index 413d6778e..f233f7e10 100644 --- a/app/src/main/java/com/mxt/anitrend/util/IntentBundleUtil.java +++ b/app/src/main/java/com/mxt/anitrend/util/IntentBundleUtil.java @@ -105,7 +105,7 @@ private void checkIntentData(Intent intent, FragmentActivity context) { sharedIntent = ShareCompat.IntentReader.from(context); else if ((INTENT_DATA = hasData(intent)) != null) - if((deepLinkMatcher = RegexUtil.findIntentKeys(INTENT_DATA.getPath())) != null) + if((deepLinkMatcher = RegexUtil.INSTANCE.findIntentKeys(INTENT_DATA.getPath())) != null) injectIntentParams(intent); } diff --git a/app/src/main/java/com/mxt/anitrend/util/JobSchedulerUtil.java b/app/src/main/java/com/mxt/anitrend/util/JobSchedulerUtil.java deleted file mode 100644 index 6af97f492..000000000 --- a/app/src/main/java/com/mxt/anitrend/util/JobSchedulerUtil.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.mxt.anitrend.util; - -import android.content.Context; - -import com.mxt.anitrend.service.JobDispatcherService; - -import java.util.concurrent.TimeUnit; - -import androidx.work.ExistingPeriodicWorkPolicy; -import androidx.work.PeriodicWorkRequest; -import androidx.work.WorkManager; - -/** - * Created by Maxwell on 12/4/2016. - * Schedules future services via job dispatcher - */ -public final class JobSchedulerUtil { - - /** - * Schedules a new job service or replaces the existing job if one exists. - * @param context any valid application context - */ - public static void scheduleJob(Context context) { - ApplicationPref applicationPref = new ApplicationPref(context); - if (applicationPref.isAuthenticated() && applicationPref.isNotificationEnabled()) { - PeriodicWorkRequest periodicWorkRequest = - new PeriodicWorkRequest.Builder(JobDispatcherService.class, - applicationPref.getSyncTime(), TimeUnit.MINUTES) - .addTag(KeyUtil.WorkNotificationTag) - .build(); - - WorkManager.getInstance() - .enqueueUniquePeriodicWork(KeyUtil.WorkNotificationId, - ExistingPeriodicWorkPolicy.REPLACE, periodicWorkRequest); - } - } - - /** - * Cancels any scheduled jobs. - */ - public static void cancelJob() { - WorkManager.getInstance().cancelUniqueWork(KeyUtil.WorkNotificationId); - } -} diff --git a/app/src/main/java/com/mxt/anitrend/util/JobSchedulerUtil.kt b/app/src/main/java/com/mxt/anitrend/util/JobSchedulerUtil.kt new file mode 100644 index 000000000..73f731981 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/util/JobSchedulerUtil.kt @@ -0,0 +1,48 @@ +package com.mxt.anitrend.util + +import android.content.Context +import androidx.work.* + +import com.mxt.anitrend.service.JobDispatcherService + +import java.util.concurrent.TimeUnit + +/** + * Created by Maxwell on 12/4/2016. + * Schedules future services via job dispatcher + */ +object JobSchedulerUtil { + + private val constraints by lazy { + Constraints.Builder() + .setRequiresCharging(false) + .setRequiredNetworkType(NetworkType.CONNECTED) + .build() + } + + /** + * Schedules a new job service or replaces the existing job if one exists. + * @param context any valid application context + */ + fun scheduleJob(context: Context) { + val applicationPref = ApplicationPref(context) + if (applicationPref.isAuthenticated && applicationPref.isNotificationEnabled) { + val periodicWorkRequest = PeriodicWorkRequest.Builder(JobDispatcherService::class.java, + applicationPref.syncTime.toLong(), TimeUnit.MINUTES) + .addTag(KeyUtil.WorkNotificationTag) + .setConstraints(constraints) + .build() + + WorkManager.getInstance() + .enqueueUniquePeriodicWork(KeyUtil.WorkNotificationId, + ExistingPeriodicWorkPolicy.REPLACE, periodicWorkRequest) + } + } + + /** + * Cancels any scheduled jobs. + */ + fun cancelJob() { + WorkManager.getInstance().cancelUniqueWork(KeyUtil.WorkNotificationId) + } +} diff --git a/app/src/main/java/com/mxt/anitrend/util/MarkDownUtil.java b/app/src/main/java/com/mxt/anitrend/util/MarkDownUtil.java deleted file mode 100644 index 1ba9165b5..000000000 --- a/app/src/main/java/com/mxt/anitrend/util/MarkDownUtil.java +++ /dev/null @@ -1,103 +0,0 @@ -package com.mxt.anitrend.util; - -import android.content.Context; -import android.os.Build; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.v7.widget.AppCompatTextView; -import android.text.Editable; -import android.text.Html; -import android.text.SpannableStringBuilder; -import android.text.Spanned; -import android.text.TextUtils; -import android.util.Log; - -import com.github.rjeschke.txtmark.Processor; - -/** - * Created by max on 2017/03/26. - * Moved markdown processor to global location - */ -public final class MarkDownUtil { - - private static SpannableStringBuilder fromMD(@NonNull String content) { - Spanned htmlConverted; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) - htmlConverted = Html.fromHtml(Processor.process(content), - Html.FROM_HTML_MODE_LEGACY); - else - htmlConverted = Html.fromHtml(Processor.process(content)); - return (SpannableStringBuilder) htmlConverted; - } - - public static Spanned convert(@Nullable String input) { - SpannableStringBuilder result; - if(TextUtils.isEmpty(input)) - result = fromMD("No content available"); - else - result = fromMD(RegexUtil.findUserTags(input)); - - try { - if(result.length() > 0) - while (result.charAt(result.length() - 1) == '\n') - result = result.delete(result.length() - 1, result.length()); - } catch (Exception e) { - e.printStackTrace(); - Log.e("convert(input)", e.getMessage()); - } - - return result; - } - - public static Spanned convert(@Nullable String input, Context context, AppCompatTextView source) { - SpannableStringBuilder result; - if(TextUtils.isEmpty(input)) - result = fromMD("No content available"); - else - result = fromMD(RegexUtil.findUserTags(input)); - // result = fromMD(RegexUtil.findUserTags(input), context, source); - - try { - if(result.length() > 0) - while (result.charAt(result.length() - 1) == '\n') - result = result.delete(result.length() - 1, result.length()); - } catch (Exception e) { - e.printStackTrace(); - Log.e("convert(input...)", e.getMessage()); - } - - return result; - } - - static String convertLink(Editable text) { - return convertLink(text.toString()); - } - - static String convertImage(Editable text) { - return convertImage(text.toString()); - } - - static String convertYoutube(Editable text) { - return convertYoutube(text.toString()); - } - - static String convertVideo(Editable text) { - return convertVideo(text.toString()); - } - - public static String convertLink(String text) { - return RegexUtil.createLinkStandard(text); - } - - public static String convertImage(String text) { - return RegexUtil.createImageStandard(text); - } - - public static String convertYoutube(String text) { - return RegexUtil.createYoutubeStandard(text); - } - - public static String convertVideo(String text) { - return RegexUtil.createWebMStandard(text); - } -} diff --git a/app/src/main/java/com/mxt/anitrend/util/MarkDownUtil.kt b/app/src/main/java/com/mxt/anitrend/util/MarkDownUtil.kt new file mode 100644 index 000000000..3d0d6680b --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/util/MarkDownUtil.kt @@ -0,0 +1,81 @@ +package com.mxt.anitrend.util + +import android.content.Context +import android.os.Build +import android.support.v7.widget.AppCompatTextView +import android.text.Editable +import android.text.Html +import android.text.SpannableStringBuilder +import android.text.Spanned +import android.text.TextUtils +import android.util.Log + +import com.github.rjeschke.txtmark.Processor + +/** + * Created by max on 2017/03/26. + * Moved markdown processor to global location + */ +object MarkDownUtil { + + private fun fromMD(content: String): SpannableStringBuilder { + return try { + val processedText = Processor.process(content) + when { + Build.VERSION.SDK_INT >= Build.VERSION_CODES.N -> Html.fromHtml(processedText, + Html.FROM_HTML_MODE_LEGACY) + else -> Html.fromHtml(processedText) + } as SpannableStringBuilder + } catch (e: Exception) { + e.printStackTrace() + SpannableStringBuilder("Unable to process content") + } + } + + fun convert(input: String?): Spanned { + var result: SpannableStringBuilder + result = if (input.isNullOrBlank()) + fromMD("No content available") + else + fromMD(RegexUtil.findUserTags(input)) + + try { + if (result.isNotEmpty()) + while (result[result.length - 1] == '\n') + result = result.delete(result.length - 1, result.length) + } catch (e: Exception) { + e.printStackTrace() + Log.e("convert(input)", e.message) + } + + return result + } + + fun convert(input: String?, context: Context, source: AppCompatTextView): Spanned { + var result: SpannableStringBuilder + result = when { + input.isNullOrBlank() -> fromMD("No content available") + else -> fromMD(RegexUtil.findUserTags(input)) + } + // result = fromMD(RegexUtil.findUserTags(input), context, source); + + try { + if (result.isNotEmpty()) + while (result[result.length - 1] == '\n') + result = result.delete(result.length - 1, result.length) + } catch (e: Exception) { + e.printStackTrace() + Log.e("convert(input...)", e.message) + } + + return result + } + + fun convertLink(text: String) = RegexUtil.createLinkStandard(text) + + fun convertImage(text: String) = RegexUtil.createImageStandard(text) + + fun convertYoutube(text: String) = RegexUtil.createYoutubeStandard(text) + + fun convertVideo(text: String) = RegexUtil.createWebMStandard(text) +} diff --git a/app/src/main/java/com/mxt/anitrend/util/MediaDialogUtil.java b/app/src/main/java/com/mxt/anitrend/util/MediaDialogUtil.java index d11194bed..627c6ac9f 100644 --- a/app/src/main/java/com/mxt/anitrend/util/MediaDialogUtil.java +++ b/app/src/main/java/com/mxt/anitrend/util/MediaDialogUtil.java @@ -185,7 +185,7 @@ private static CustomSeriesManageBase buildManagerType(Context context, @KeyUtil private static MaterialDialog.Builder createSeriesManageDialog(Context context, boolean isNewEntry, String title) { MaterialDialog.Builder materialBuilder = createDefaultDialog(context) .icon(CompatUtil.getDrawableTintAttr(context, isNewEntry ? R.drawable.ic_fiber_new_white_24dp : R.drawable.ic_border_color_white_24dp, R.attr.colorAccent)) - .title(MarkDownUtil.convert(context.getString(isNewEntry? R.string.dialog_add_title : R.string.dialog_edit_title, title))) + .title(MarkDownUtil.INSTANCE.convert(context.getString(isNewEntry? R.string.dialog_add_title : R.string.dialog_edit_title, title))) .positiveText(isNewEntry? R.string.Add: R.string.Update) .neutralText(R.string.Cancel) .autoDismiss(false); diff --git a/app/src/main/java/com/mxt/anitrend/util/RegexUtil.java b/app/src/main/java/com/mxt/anitrend/util/RegexUtil.java deleted file mode 100644 index 8ecc14ac4..000000000 --- a/app/src/main/java/com/mxt/anitrend/util/RegexUtil.java +++ /dev/null @@ -1,156 +0,0 @@ -package com.mxt.anitrend.util; - -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.text.TextUtils; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Created by max on 2017/04/08. - * Pattern matcher uses regex to return possible matches for media types - */ -public class RegexUtil { - - public static final String KEY_IMG = "img"; - public static final String KEY_WEB = "webm"; - public static final String KEY_YOU = "youtube"; - public static final String NO_THUMBNAIL = "http://placehold.it/1280x720?text=No+Preview+Available"; - - private static final String VID_THUMB = "https://img.youtube.com/vi/%s/hqdefault.jpg"; - private static final String Youtube = "https://www.youtube.com/watch?v="; - private static final String YoutubeShort = "https://youtu.be/"; - private static final String PATTERN_YOUTUBE_EXTRACT = "(\\?v=)(.*)"; - - private static final Pattern pattern; - private static final String PATTERN_MEDIA = "(img|webm|youtube).*?(\\([^)]+\\))"; - private static final String PATTERN_DEEP_LINKS = "(user|manga|anime|character|staff|studio)\\/(.*)"; - - private static final String USER_URL_LINK = "__[%s](https://anilist.co/user/%s)__"; - private static final String PATTERN_USER_TAGS = "(@[A-Za-z]\\w+)"; - - private static final String PATTERN_TRAILING_SPACES = "(^[\\r\\n]+|[\\r\\n]+$)"; - - - static { - pattern = Pattern.compile(PATTERN_MEDIA, Pattern.CASE_INSENSITIVE); - } - - /** - * finds images and youtube videos - */ - public static Matcher findMedia(@NonNull String param) { - return pattern.matcher(param); - } - - private static @NonNull Matcher findImages(@NonNull String param) { - return Pattern.compile("(img|Img|IMG).*?(\\([^)]+\\))", Pattern.CASE_INSENSITIVE).matcher(param); - } - - /** - * Removes trailing white spaces from a given string and returns the - * mutated string object. - * - * Deprecated please use the String.trim() method to - * achieve the same result: - * @see String#trim() - * */ - @Deprecated - public static String removeTrailingWhiteSpaces(@NonNull String param) { - if(TextUtils.isEmpty(param)) - return null; - return Pattern.compile(PATTERN_TRAILING_SPACES).matcher(param).replaceAll(""); - } - - static @NonNull String findUserTags(String text) { - if(TextUtils.isEmpty(text)) - return "No content available"; - Matcher matcher = Pattern.compile(PATTERN_USER_TAGS).matcher(text); - while (matcher.find()) { - String match = matcher.group(); - text = text.replace(match, String.format(USER_URL_LINK, match, match.replace("@",""))); - } - return text; - } - - /** - * Returns either an Id of anime listing or user name - */ - public static @Nullable Matcher findIntentKeys(String path) { - Matcher deepLinkMatcher = Pattern.compile(PATTERN_DEEP_LINKS).matcher(path); - if(deepLinkMatcher.find()) - return deepLinkMatcher; - return null; - } - - /** - * Builds a full youtube link from either an id or a valid youtube link - */ - public static String buildYoutube(String id) { - if(!id.contains("youtube")) { - if (id.contains(YoutubeShort)) - return Youtube + id.replace(YoutubeShort, ""); - return Youtube + id; - } - return id; - } - - public static String createYoutubeStandard(String link) { - if(!link.contains("youtube")) - if (link.contains(YoutubeShort)) - return String.format("%s(%s)", KEY_YOU, link.replace(YoutubeShort, "")); - return String.format("%s(%s)", KEY_YOU, link); - } - - public static String createLinkStandard(String link) { - return String.format("[%s](%s)", link, link) ; - } - - public static String createWebMStandard(String link) { - return String.format("%s(%s)", KEY_WEB, link) ; - } - - public static String createImageStandard(String link) { - return String.format("%s250(%s)", KEY_IMG, link) ; - } - - /** - * Get the thumbnail image of a youtube video - *
- * - * @param link full youtube link - */ - public static String getYoutubeThumb(String link) { - Matcher matcher = Pattern.compile(PATTERN_YOUTUBE_EXTRACT).matcher(link); - String temp; - - if(matcher.find()) - temp = matcher.group(matcher.groupCount()); - else - return NO_THUMBNAIL; - return String.format(VID_THUMB, temp); - } - - public static String removeTags(@Nullable String value) { - if(TextUtils.isEmpty(value)) - return null; - return findImages(findMedia(value).replaceAll("")).replaceAll("") - .replaceAll("!~", "").replaceAll("~!", "") - .replaceAll("~", ""); - } - - public static String convertToStandardMarkdown(@Nullable String value) { - if(!TextUtils.isEmpty(value)) { - Matcher matcher = findImages(value); - String TAG = "![image]"; - while (matcher.find()) { - String match = matcher.group(); - int group = matcher.groupCount(); - value = value.replace(match, TAG + matcher.group(group)); - } - return value.replaceAll("!~", "").replaceAll("~!", "").replaceAll("~", ""); - } else - return "No content available"; - } -} diff --git a/app/src/main/java/com/mxt/anitrend/util/RegexUtil.kt b/app/src/main/java/com/mxt/anitrend/util/RegexUtil.kt new file mode 100644 index 000000000..fb91e016a --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/util/RegexUtil.kt @@ -0,0 +1,170 @@ +package com.mxt.anitrend.util + +import android.text.TextUtils + +import java.util.regex.Matcher +import java.util.regex.Pattern + +/** + * Created by max on 2017/04/08. + * Pattern matcher uses regex to return possible matches for media types + */ +object RegexUtil { + + const val KEY_IMG = "img" + const val KEY_WEB = "webm" + const val KEY_YOU = "youtube" + const val NO_THUMBNAIL = "http://placehold.it/1280x720?text=No+Preview+Available" + + private const val VID_THUMB = "https://img.youtube.com/vi/%s/hqdefault.jpg" + private const val Youtube = "https://www.youtube.com/watch?v=" + private const val YoutubeShort = "https://youtu.be/" + private const val PATTERN_YOUTUBE_EXTRACT = "(\\?v=)(.*)" + + private val pattern: Pattern + private const val PATTERN_MEDIA = "(img|webm|youtube).*?(\\([^)]+\\))" + private const val PATTERN_DEEP_LINKS = "(user|manga|anime|character|staff|studio)\\/(.*)" + + private const val USER_URL_LINK = "__[%s](https://anilist.co/user/%s)__" + private const val PATTERN_USER_TAGS = "(@[A-Za-z]\\w+)" + + private const val PATTERN_TRAILING_SPACES = "(^[\\r\\n]+|[\\r\\n]+$)" + + + init { + pattern = Pattern.compile(PATTERN_MEDIA, Pattern.CASE_INSENSITIVE) + } + + /** + * finds images and youtube videos + */ + fun findMedia(param: String): Matcher { + return pattern.matcher(param) + } + + private fun findImages(param: String): Matcher { + return Pattern.compile("(img|Img|IMG).*?(\\([^)]+\\))", Pattern.CASE_INSENSITIVE).matcher(param) + } + + /** + * Removes trailing white spaces from a given string and returns the + * mutated string object. + * + * Deprecated please use the String.trim() method to + * achieve the same result: + * @see String.trim + */ + @Deprecated("") + fun removeTrailingWhiteSpaces(param: String): String? { + return if (param.isBlank()) null else Pattern.compile(PATTERN_TRAILING_SPACES).matcher(param).replaceAll("") + } + + internal fun findUserTags(text: String): String { + var newText = text + if (text.isBlank()) + return "No content available" + val matcher = Pattern.compile(PATTERN_USER_TAGS).matcher(text) + while (matcher.find()) { + val match = matcher.group() + newText = text.replace(match, String.format(USER_URL_LINK, match, match.replace("@", ""))) + } + return newText + } + + /** + * Returns either an Id of anime listing or user name + */ + fun findIntentKeys(path: String): Matcher? { + val deepLinkMatcher = Pattern.compile(PATTERN_DEEP_LINKS).matcher(path) + return if (deepLinkMatcher.find()) deepLinkMatcher else null + } + + /** + * Builds a full youtube link from either an id or a valid youtube link + */ + fun buildYoutube(id: String): String { + return if (!id.contains("youtube")) { + if (id.contains(YoutubeShort)) Youtube + id.replace(YoutubeShort, "") else Youtube + id + } else id + } + + fun createYoutubeStandard(link: String): String { + if (!link.contains("youtube")) + if (link.contains(YoutubeShort)) + return String.format("%s(%s)", KEY_YOU, link.replace(YoutubeShort, "")) + return String.format("%s(%s)", KEY_YOU, link) + } + + fun createLinkStandard(link: String): String { + return String.format("[%s](%s)", link, link) + } + + fun createWebMStandard(link: String): String { + return String.format("%s(%s)", KEY_WEB, link) + } + + fun createImageStandard(link: String): String { + return String.format("%s250(%s)", KEY_IMG, link) + } + + /** + * Get the thumbnail image of a youtube video + * + * + * @param link full youtube link + */ + fun getYoutubeThumb(link: String): String { + val matcher = Pattern.compile(PATTERN_YOUTUBE_EXTRACT).matcher(link) + val temp: String + + if (matcher.find()) + temp = matcher.group(matcher.groupCount()) + else + return NO_THUMBNAIL + return String.format(VID_THUMB, temp) + } + + fun removeTags(value: String?): String? { + return when (value.isNullOrBlank()) { + true -> null + else -> findImages(findMedia(value) + .replaceAll("")) + .replaceAll("") + .replace("!~", "") + .replace("~!", "") + .replace("~", "") + } + } + + fun convertToStandardMarkdown(value: String?): String { + var substitute = "No content available" + return value?.let { + if (!it.isBlank()) { + substitute = value.replace("!~", "") + .replace("~!", "") + .replace("~", "") + + val matcher = findMedia(it) + + while (matcher.find()) { + val gc = matcher.groupCount() + val match = matcher.group() // the full match e.g. img%(http://git.raw.sample.jpg) + val tag = matcher.group(gc - 1) // returns the first match group tag of the regex match img|IMG|Img + val media = matcher.group(gc) // contains the second match group e.g. (http://git.raw.sample.jpg) brackets included + val mediaWithoutBrackets = media.removeSurrounding("(", ")") + substitute = when (tag.toLowerCase()) { + KEY_IMG -> + substitute.replace(match, "![image]$media") + KEY_WEB -> + substitute.replace(match, "") + KEY_YOU -> + substitute.replace(match, "") + else -> substitute + } + + } + } + substitute + } ?: substitute + } +} diff --git a/app/src/main/java/com/mxt/anitrend/view/activity/base/SettingsActivity.java b/app/src/main/java/com/mxt/anitrend/view/activity/base/SettingsActivity.java index 1d2e12452..2650e9334 100644 --- a/app/src/main/java/com/mxt/anitrend/view/activity/base/SettingsActivity.java +++ b/app/src/main/java/com/mxt/anitrend/view/activity/base/SettingsActivity.java @@ -51,13 +51,13 @@ public class SettingsActivity extends AppCompatPreferenceActivity { applicationPref.toggleTheme(); Toast.makeText(getApplicationContext(), R.string.text_application_restart_required, Toast.LENGTH_LONG).show(); } else if (CompatUtil.equals(key, getString(R.string.pref_key_sync_frequency))) { - JobSchedulerUtil.cancelJob(); - JobSchedulerUtil.scheduleJob(getApplicationContext()); + JobSchedulerUtil.INSTANCE.cancelJob(); + JobSchedulerUtil.INSTANCE.scheduleJob(getApplicationContext()); } else if (CompatUtil.equals(key, getString(R.string.pref_key_new_message_notifications))) { if (applicationPref.isNotificationEnabled()) - JobSchedulerUtil.scheduleJob(getApplicationContext()); + JobSchedulerUtil.INSTANCE.scheduleJob(getApplicationContext()); else - JobSchedulerUtil.cancelJob(); + JobSchedulerUtil.INSTANCE.cancelJob(); } }; diff --git a/app/src/main/java/com/mxt/anitrend/view/activity/base/SharedContentActivity.java b/app/src/main/java/com/mxt/anitrend/view/activity/base/SharedContentActivity.java index da9712510..9ae01d8dc 100644 --- a/app/src/main/java/com/mxt/anitrend/view/activity/base/SharedContentActivity.java +++ b/app/src/main/java/com/mxt/anitrend/view/activity/base/SharedContentActivity.java @@ -203,16 +203,16 @@ public void getItemSelected() { @KeyUtil.ShareType int position = sharedResourceType.getSelectedItemPosition(); switch (position) { case KeyUtil.IMAGE_TYPE: - binding.composerWidget.setText(MarkDownUtil.convertImage(text)); + binding.composerWidget.setText(MarkDownUtil.INSTANCE.convertImage(text)); break; case KeyUtil.LINK_TYPE: - binding.composerWidget.setText(MarkDownUtil.convertLink(text)); + binding.composerWidget.setText(MarkDownUtil.INSTANCE.convertLink(text)); break; case KeyUtil.WEBM_TYPE: - binding.composerWidget.setText(MarkDownUtil.convertVideo(text)); + binding.composerWidget.setText(MarkDownUtil.INSTANCE.convertVideo(text)); break; case KeyUtil.YOUTUBE_TYPE: - binding.composerWidget.setText(MarkDownUtil.convertYoutube(text)); + binding.composerWidget.setText(MarkDownUtil.INSTANCE.convertYoutube(text)); break; case KeyUtil.PLAIN_TYPE: binding.composerWidget.setText(text); diff --git a/app/src/main/java/com/mxt/anitrend/view/activity/detail/MediaBrowseActivity.java b/app/src/main/java/com/mxt/anitrend/view/activity/detail/MediaBrowseActivity.java index c181b6bcd..6bb78a9d0 100644 --- a/app/src/main/java/com/mxt/anitrend/view/activity/detail/MediaBrowseActivity.java +++ b/app/src/main/java/com/mxt/anitrend/view/activity/detail/MediaBrowseActivity.java @@ -42,7 +42,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { protected void onPostCreate(@Nullable Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); if(getIntent().hasExtra(KeyUtil.arg_activity_tag)) { - Spanned activityTitle = MarkDownUtil.convert(getIntent().getStringExtra(KeyUtil.arg_activity_tag)); + Spanned activityTitle = MarkDownUtil.INSTANCE.convert(getIntent().getStringExtra(KeyUtil.arg_activity_tag)); mActionBar.setTitle(activityTitle); } onActivityReady(); diff --git a/app/src/main/java/com/mxt/anitrend/view/activity/index/LoginActivity.java b/app/src/main/java/com/mxt/anitrend/view/activity/index/LoginActivity.java index d6db2bb52..e50a36fde 100644 --- a/app/src/main/java/com/mxt/anitrend/view/activity/index/LoginActivity.java +++ b/app/src/main/java/com/mxt/anitrend/view/activity/index/LoginActivity.java @@ -93,7 +93,7 @@ protected void onActivityReady() { @Override protected void updateUI() { if(getPresenter().getApplicationPref().isNotificationEnabled()) - JobSchedulerUtil.scheduleJob(getApplicationContext()); + JobSchedulerUtil.INSTANCE.scheduleJob(getApplicationContext()); createApplicationShortcuts(); finish(); } diff --git a/app/src/main/java/com/mxt/anitrend/view/activity/index/MainActivity.java b/app/src/main/java/com/mxt/anitrend/view/activity/index/MainActivity.java index b9e6d1e45..de19d6f54 100644 --- a/app/src/main/java/com/mxt/anitrend/view/activity/index/MainActivity.java +++ b/app/src/main/java/com/mxt/anitrend/view/activity/index/MainActivity.java @@ -431,7 +431,7 @@ protected void updateUI() { if(versionBase != null && versionBase.isNewerVersion()) { // If a new version of the application is available on GitHub TextView mAppUpdateWidget = menuItems.findItem(R.id.nav_check_update).getActionView().findViewById(R.id.app_update_info); - mAppUpdateWidget.setText(MarkDownUtil.convert(getString(R.string.app_update, versionBase.getVersion()))); + mAppUpdateWidget.setText(MarkDownUtil.INSTANCE.convert(getString(R.string.app_update, versionBase.getVersion()))); mAppUpdateWidget.setVisibility(View.VISIBLE); } checkNewInstallation(); diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/UserOverviewFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/UserOverviewFragment.java index 8f908bef7..444eca216 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/UserOverviewFragment.java +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/UserOverviewFragment.java @@ -1,6 +1,5 @@ package com.mxt.anitrend.view.fragment.detail; -import android.content.Intent; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -21,7 +20,6 @@ import com.mxt.anitrend.util.GraphUtil; import com.mxt.anitrend.util.KeyUtil; import com.mxt.anitrend.util.NotifyUtil; -import com.mxt.anitrend.view.activity.base.ImagePreviewActivity; import java.util.ArrayList; import java.util.List; @@ -101,7 +99,7 @@ public void onStart() { protected void updateUI() { binding.setModel(model); binding.stateLayout.showContent(); - binding.widgetStatus.setTextData(model.getAbout()); + //binding.widgetStatus.setTextData(model.getAbout()); binding.userFollowStateWidget.setUserModel(model); binding.userAboutPanelWidget.setFragmentActivity(getActivity()); diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/youtube/YouTubeEmbedFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/youtube/YouTubeEmbedFragment.java index 5d48bb4ec..58a7d1943 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/youtube/YouTubeEmbedFragment.java +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/youtube/YouTubeEmbedFragment.java @@ -84,8 +84,8 @@ public void onResume() { */ @Override protected void updateUI() { - String youtubeLink = RegexUtil.buildYoutube(mediaTrailer.getId()); - String thumbnailUrl =RegexUtil.getYoutubeThumb(youtubeLink); + String youtubeLink = RegexUtil.INSTANCE.buildYoutube(mediaTrailer.getId()); + String thumbnailUrl = RegexUtil.INSTANCE.getYoutubeThumb(youtubeLink); if (getActivity() != null) Glide.with(getActivity()).load(thumbnailUrl) .transition(DrawableTransitionOptions.withCrossFade(250)) @@ -100,7 +100,7 @@ protected void updateUI() { public void makeRequest() { binding.setOnClickListener((v) -> { try { - String youtubeLink = RegexUtil.buildYoutube(mediaTrailer.getId()); + String youtubeLink = RegexUtil.INSTANCE.buildYoutube(mediaTrailer.getId()); Intent intent = new Intent(Intent.ACTION_VIEW); intent.setData(Uri.parse(youtubeLink)); startActivity(intent); diff --git a/app/src/main/java/com/mxt/anitrend/view/sheet/BottomSheetMessage.java b/app/src/main/java/com/mxt/anitrend/view/sheet/BottomSheetMessage.java index 1a665ced8..cbeaceb2b 100644 --- a/app/src/main/java/com/mxt/anitrend/view/sheet/BottomSheetMessage.java +++ b/app/src/main/java/com/mxt/anitrend/view/sheet/BottomSheetMessage.java @@ -10,6 +10,7 @@ import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.sheet.BottomSheetBase; import com.mxt.anitrend.base.custom.view.text.RichMarkdownTextView; +import com.mxt.anitrend.binding.RichMarkdownExtensionsKt; import com.mxt.anitrend.util.KeyUtil; import butterknife.BindView; @@ -53,7 +54,7 @@ public Dialog onCreateDialog(Bundle savedInstanceState) { @Override public void onStart() { super.onStart(); - RichMarkdownTextView.basicText(bottom_text, getString(mText)); + RichMarkdownExtensionsKt.basicText(bottom_text, getString(mText)); if(mPositive != 0) bottom_positive.setText(mPositive); else diff --git a/app/src/main/java/com/mxt/anitrend/worker/AuthenticatorWorker.java b/app/src/main/java/com/mxt/anitrend/worker/AuthenticatorWorker.java deleted file mode 100644 index 70acf3df4..000000000 --- a/app/src/main/java/com/mxt/anitrend/worker/AuthenticatorWorker.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.mxt.anitrend.worker; - -import android.content.Context; -import android.net.Uri; -import android.support.annotation.NonNull; -import android.text.TextUtils; -import android.util.Log; - -import com.mxt.anitrend.BuildConfig; -import com.mxt.anitrend.base.custom.async.WebTokenRequest; -import com.mxt.anitrend.presenter.base.BasePresenter; -import com.mxt.anitrend.util.KeyUtil; - -import java.util.concurrent.ExecutionException; - -import androidx.work.Data; -import androidx.work.ListenableWorker; -import androidx.work.Worker; -import androidx.work.WorkerParameters; - -public class AuthenticatorWorker extends Worker { - - private final BasePresenter presenter; - private final Uri authenticatorUri; - - public AuthenticatorWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { - super(context, workerParams); - authenticatorUri = Uri.parse(workerParams.getInputData() - .getString(KeyUtil.arg_model)); - presenter = new BasePresenter(context); - } - - /** - * Override this method to do your actual background processing. This method is called on a - * background thread - you are required to synchronously do your work and return the - * {@link Result} from this method. Once you return from this - * method, the Worker is considered to have finished what its doing and will be destroyed. If - * you need to do your work asynchronously on a thread of your own choice, see - * {@link ListenableWorker}. - *

- * A Worker is given a maximum of ten minutes to finish its execution and return a - * {@link Result}. After this time has expired, the Worker will - * be signalled to stop. - * - * @return The {@link Result} of the computation; note that - * dependent work will not execute if you use - * {@link Result#failure()} or - * {@link Result#failure(Data)} - */ - @NonNull - @Override - public Result doWork() { - Data.Builder errorDataBuilder = new Data.Builder(); - try { - String authorizationCode = authenticatorUri.getQueryParameter(BuildConfig.RESPONSE_TYPE); - if (!TextUtils.isEmpty(authorizationCode)) { - boolean isSuccess = WebTokenRequest.getToken(getApplicationContext(), authorizationCode); - presenter.getApplicationPref().setAuthenticated(isSuccess); - Data outputData = new Data.Builder() - .putBoolean(KeyUtil.arg_model, isSuccess) - .build(); - return Result.success(outputData); - } else - Log.e(toString(), "Authorization authenticatorUri was empty or null, cannot authenticate with the current state"); - } catch (ExecutionException | InterruptedException e) { - e.printStackTrace(); - errorDataBuilder.putString(KeyUtil.arg_exception_error, e.getMessage()); - } - Data workerErrorOutputData = errorDataBuilder - .putString(KeyUtil.arg_uri_error, authenticatorUri - .getQueryParameter(KeyUtil.arg_uri_error)) - .putString(KeyUtil.arg_uri_error_description, authenticatorUri - .getQueryParameter(KeyUtil.arg_uri_error_description)) - .build(); - return Result.failure(workerErrorOutputData); - } -} diff --git a/app/src/main/java/com/mxt/anitrend/worker/AuthenticatorWorker.kt b/app/src/main/java/com/mxt/anitrend/worker/AuthenticatorWorker.kt new file mode 100644 index 000000000..9c226ace9 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/worker/AuthenticatorWorker.kt @@ -0,0 +1,77 @@ +package com.mxt.anitrend.worker + +import android.content.Context +import android.net.Uri +import android.text.TextUtils +import android.util.Log + +import com.mxt.anitrend.BuildConfig +import com.mxt.anitrend.base.custom.async.WebTokenRequest +import com.mxt.anitrend.presenter.base.BasePresenter +import com.mxt.anitrend.util.KeyUtil + +import java.util.concurrent.ExecutionException + +import androidx.work.Data +import androidx.work.ListenableWorker +import androidx.work.Worker +import androidx.work.WorkerParameters + +class AuthenticatorWorker(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) { + + private val presenter by lazy { + BasePresenter(context) + } + private val authenticatorUri: Uri by lazy { + Uri.parse(workerParams.inputData + .getString(KeyUtil.arg_model)) + } + + /** + * Override this method to do your actual background processing. This method is called on a + * background thread - you are required to **synchronously** do your work and return the + * [Result] from this method. Once you return from this + * method, the Worker is considered to have finished what its doing and will be destroyed. If + * you need to do your work asynchronously on a thread of your own choice, see + * [ListenableWorker]. + * + * + * A Worker is given a maximum of ten minutes to finish its execution and return a + * [Result]. After this time has expired, the Worker will + * be signalled to stop. + * + * @return The [Result] of the computation; note that + * dependent work will not execute if you use + * [Result.failure] or + * [Result.failure] + */ + override fun doWork(): ListenableWorker.Result { + val errorDataBuilder = Data.Builder() + try { + val authorizationCode = authenticatorUri.getQueryParameter(BuildConfig.RESPONSE_TYPE) + if (!TextUtils.isEmpty(authorizationCode)) { + val isSuccess = WebTokenRequest.getToken(applicationContext, authorizationCode) + presenter.applicationPref.isAuthenticated = isSuccess + val outputData = Data.Builder() + .putBoolean(KeyUtil.arg_model, isSuccess) + .build() + return ListenableWorker.Result.success(outputData) + } else + Log.e(toString(), "Authorization authenticatorUri was empty or null, cannot authenticate with the current state") + } catch (e: ExecutionException) { + e.printStackTrace() + errorDataBuilder.putString(KeyUtil.arg_exception_error, e.message) + } catch (e: InterruptedException) { + e.printStackTrace() + errorDataBuilder.putString(KeyUtil.arg_exception_error, e.message) + } + + val workerErrorOutputData = errorDataBuilder + .putString(KeyUtil.arg_uri_error, authenticatorUri + .getQueryParameter(KeyUtil.arg_uri_error)) + .putString(KeyUtil.arg_uri_error_description, authenticatorUri + .getQueryParameter(KeyUtil.arg_uri_error_description)) + .build() + return ListenableWorker.Result.failure(workerErrorOutputData) + } +} diff --git a/app/src/main/res/layout/adapter_feed_status.xml b/app/src/main/res/layout/adapter_feed_status.xml index 56f03b44d..ec7dab251 100644 --- a/app/src/main/res/layout/adapter_feed_status.xml +++ b/app/src/main/res/layout/adapter_feed_status.xml @@ -60,10 +60,15 @@ android:layout_width="wrap_content" android:layout_height="@dimen/lg_margin" /> - + android:layout_height="wrap_content"/>--> + + - - - --> + + + android:layout_height="wrap_content" + app:richMarkDown="@{model.about}"/> + android:focusable="true" + android:isScrollContainer="false"> + android:textSize="@dimen/subtitle_text_size" + android:overScrollMode="always" + android:scrollbarStyle="insideInset" + android:scrollbars="vertical"/> diff --git a/app/src/test/java/com/mxt/anitrend/util/RegexUtilTests.java b/app/src/test/java/com/mxt/anitrend/util/RegexUtilTests.java index 3e58d0520..b80fd644c 100644 --- a/app/src/test/java/com/mxt/anitrend/util/RegexUtilTests.java +++ b/app/src/test/java/com/mxt/anitrend/util/RegexUtilTests.java @@ -12,7 +12,7 @@ public class RegexUtilTests { @Test public void findMedia() { String testStatus = "MAL is back\\n\\nand i no longer give a shit\\n\\nimg220(https:\\/\\/static1.fjcdn.com\\/thumbnails\\/comments\\/Go+talk+to+our+friendly+fellows+on+the+anime+board+_496f62c2f231bc1c8a9b77a449bf628f.gif)\\nThis place is nice, i like it."; - Matcher matcher = RegexUtil.findMedia(testStatus); + Matcher matcher = RegexUtil.INSTANCE.findMedia(testStatus); assertNotNull(matcher); int expectedCount = 1, current = 0; while (matcher.find()) { @@ -28,39 +28,39 @@ public void findMedia() { @Test public void findIntentKeys() { - Matcher matcher = RegexUtil.findIntentKeys("https://anitrend.gitbook.io/project/architecture"); + Matcher matcher = RegexUtil.INSTANCE.findIntentKeys("https://anitrend.gitbook.io/project/architecture"); assertNull(matcher); - matcher = RegexUtil.findIntentKeys("https://anilist.co/anime/100483/Yuragisou-no-Yuunasan/"); + matcher = RegexUtil.INSTANCE.findIntentKeys("https://anilist.co/anime/100483/Yuragisou-no-Yuunasan/"); assertNotNull(matcher); String type = matcher.group(1); assertEquals(KeyUtil.DEEP_LINK_ANIME, type); - matcher = RegexUtil.findIntentKeys("https://anilist.co/manga/87213/Yuragisou-no-Yuunasan/"); + matcher = RegexUtil.INSTANCE.findIntentKeys("https://anilist.co/manga/87213/Yuragisou-no-Yuunasan/"); assertNotNull(matcher); type = matcher.group(1); assertEquals(KeyUtil.DEEP_LINK_MANGA, type); /* This is deprecated in the new front end */ - matcher = RegexUtil.findIntentKeys("https://anilist.co/actor/102263/Youko-Hikasa"); + matcher = RegexUtil.INSTANCE.findIntentKeys("https://anilist.co/actor/102263/Youko-Hikasa"); assertNull(matcher); - matcher = RegexUtil.findIntentKeys("https://anilist.co/character/88573/Subaru-Natsuki"); + matcher = RegexUtil.INSTANCE.findIntentKeys("https://anilist.co/character/88573/Subaru-Natsuki"); assertNotNull(matcher); type = matcher.group(1); assertEquals(KeyUtil.DEEP_LINK_CHARACTER, type); - matcher = RegexUtil.findIntentKeys("https://anilist.co/staff/102263/Youko-Hikasa"); + matcher = RegexUtil.INSTANCE.findIntentKeys("https://anilist.co/staff/102263/Youko-Hikasa"); assertNotNull(matcher); type = matcher.group(1); assertEquals(KeyUtil.DEEP_LINK_STAFF, type); - matcher = RegexUtil.findIntentKeys("https://anilist.co/studio/18/Toei-Animation"); + matcher = RegexUtil.INSTANCE.findIntentKeys("https://anilist.co/studio/18/Toei-Animation"); assertNotNull(matcher); type = matcher.group(1); assertEquals(KeyUtil.DEEP_LINK_STUDIO, type); - matcher = RegexUtil.findIntentKeys("https://anilist.co/user/wax911/"); + matcher = RegexUtil.INSTANCE.findIntentKeys("https://anilist.co/user/wax911/"); assertNotNull(matcher); type = matcher.group(1); assertEquals(KeyUtil.DEEP_LINK_USER, type); @@ -69,28 +69,28 @@ public void findIntentKeys() { @Test public void buildYoutube() { String expected = "https://www.youtube.com/watch?v=8a0gn8mmnaY"; - String result = RegexUtil.buildYoutube("https://www.youtube.com/watch?v=8a0gn8mmnaY"); + String result = RegexUtil.INSTANCE.buildYoutube("https://www.youtube.com/watch?v=8a0gn8mmnaY"); assertEquals(expected, result); - result = RegexUtil.buildYoutube("https://youtu.be/8a0gn8mmnaY"); + result = RegexUtil.INSTANCE.buildYoutube("https://youtu.be/8a0gn8mmnaY"); assertEquals(expected, result); - result = RegexUtil.buildYoutube("8a0gn8mmnaY"); + result = RegexUtil.INSTANCE.buildYoutube("8a0gn8mmnaY"); assertEquals(expected, result); } @Test public void createYoutubeStandard() { String expected = "youtube(8a0gn8mmnaY)"; - String result = RegexUtil.createYoutubeStandard("https://youtu.be/8a0gn8mmnaY"); + String result = RegexUtil.INSTANCE.createYoutubeStandard("https://youtu.be/8a0gn8mmnaY"); assertEquals(expected, result); } @Test public void getYoutubeThumb() { String expected = "https://img.youtube.com/vi/8a0gn8mmnaY/hqdefault.jpg"; - String result = RegexUtil.getYoutubeThumb("https://www.youtube.com/watch?v=8a0gn8mmnaY"); + String result = RegexUtil.INSTANCE.getYoutubeThumb("https://www.youtube.com/watch?v=8a0gn8mmnaY"); assertEquals(expected, result); - result = RegexUtil.getYoutubeThumb("https://data.whicdn.com/images/107659661/original.gif"); - assertEquals(RegexUtil.NO_THUMBNAIL, result); + result = RegexUtil.INSTANCE.getYoutubeThumb("https://data.whicdn.com/images/107659661/original.gif"); + assertEquals(RegexUtil.INSTANCE.getNO_THUMBNAIL(), result); } } \ No newline at end of file diff --git a/build.gradle b/build.gradle index dd46cc5df..ec8706a2d 100644 --- a/build.gradle +++ b/build.gradle @@ -5,36 +5,38 @@ buildscript { compileSdk = 28 targetSdk = 28 minSdk = 17 - versionCode = 101 - versionName = '1.3.1' + versionCode = 103 + versionName = '1.4.0' butterKnife = '8.8.1' glide = '4.8.0' retrofit = '2.4.0' supportLibrary = '27.1.1' - firebase = '16.0.6' - objectBox = '2.2.0' + firebase = '16.0.7' + objectBox = '2.3.3' architecture = '1.1.1' - workManager = '1.0.0-beta01' - emojify = '0.1.7' - kotlin = '1.3.11' + workManager = '1.0.0-rc02' + emojify = '1.4' + kotlin = '1.3.21' // testing libraries mockito = '2.18.3' hemcrest = '1.3' + markwon = '3.0.0-SNAPSHOT' } repositories { google() jcenter() maven { url 'https://maven.fabric.io/public' } maven { url "http://objectbox.net/beta-repo/" } + maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' } } dependencies { - classpath 'com.android.tools.build:gradle:3.2.1' + classpath 'com.android.tools.build:gradle:3.3.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${rootProject.kotlin}" // Google Play Services classpath 'com.google.gms:google-services:4.2.0' // Crash Analytics - classpath 'io.fabric.tools:gradle:1.27.0' + classpath 'io.fabric.tools:gradle:1.27.1' // Object Box classpath "io.objectbox:objectbox-gradle-plugin:${rootProject.objectBox}" } @@ -47,6 +49,7 @@ allprojects { mavenCentral() maven { url 'https://jitpack.io' } maven { url "http://objectbox.net/beta-repo/" } + maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' } } } diff --git a/gradle.properties b/gradle.properties index 9d7ef56c5..d08ab663f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -15,6 +15,15 @@ org.gradle.jvmargs=-Xmx1536m # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true +# android.useAndroidX=true +# android.enableJetifier=true +android.databinding.enableV2=true + +# Kotlin code style for this project: "official" or "obsolete": +# kotlin.code.style=official + +# Faster Gradle builds by parallelizing tasks +kotlin.parallel.tasks.in.project=true REDIRECT_URI = "intent://com.mxt.anitrend" HEADER_KEY = "Authorization" diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 0333748e7..4598db787 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Tue Oct 02 09:27:28 SAST 2018 +#Fri Feb 01 17:49:01 SAST 2019 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip From 629ba208d4c0f06c51974ba6cffc4b9b7ee600c9 Mon Sep 17 00:00:00 2001 From: Soitora Date: Sun, 7 Apr 2019 10:16:17 +0200 Subject: [PATCH 03/17] Swedish Translation Hotfix (#105) Fixed so that Swedish language can be selected, also removed a Spanish string from the settings menu. --- app/src/main/res/values-sv/strings.xml | 2 +- app/src/main/res/values/strings.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index d8a530ca0..85d602def 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -322,7 +322,7 @@ - Página de inicio + Startsida Hem diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e6b4cce2a..d68b5fe4f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1000,7 +1000,7 @@ it pl pt - se + sv nl From a792dd350e93c1a00176826d9d02f99b4a1ef43f Mon Sep 17 00:00:00 2001 From: Mehul Mittal Date: Sun, 7 Apr 2019 08:17:53 +0000 Subject: [PATCH 04/17] Partial Translation Fixes (#106) * Removed redundant values of some strings * Remove duplicate key * Remove extra newline --- app/src/main/res/values-ar/strings.xml | 1 - app/src/main/res/values-de/strings.xml | 22 ---------------------- app/src/main/res/values-es/strings.xml | 4 ---- app/src/main/res/values-fr/strings.xml | 24 +----------------------- app/src/main/res/values-it/strings.xml | 12 ------------ app/src/main/res/values-nl/strings.xml | 24 ------------------------ app/src/main/res/values-pl/strings.xml | 2 -- app/src/main/res/values-pt/strings.xml | 4 ---- app/src/main/res/values-sv/strings.xml | 5 ----- 9 files changed, 1 insertion(+), 97 deletions(-) diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 23ed4beaa..5930f84d5 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -932,7 +932,6 @@ Black Theme - Use black theme for devices that LED displays to save power Application Language diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index c1e63e1ec..638ca1671 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -1,26 +1,12 @@ - Discover - Manage - Customization - - Support - Contact - About - - Search @string/drawer_title_filter Help Selected: %d - Navigation drawer opened - Navigation drawer closed - - Home - History - Tutorial Bedeutung der Farben Farben zeigen den Anime/Manga Status! Inhalt Mehrere Anime & Manga Listen! Suche Anime, Manga & Weitere Suchfunktionen! - Videos Verwendet eingebauten Youtube Video Player! Wilkommen bei AniTrend! @@ -231,10 +215,8 @@ Meine Anime Liste Meine Manga Liste Serien Reviews - AniTrend Hub Einstellungen - Filter Helles Design Neue Listenansicht @@ -243,7 +225,6 @@ Profil Ausloggen - Extras Teilen Aktualisieren Nichts zum Anzeigen gefunden @@ -285,7 +266,6 @@ Benachrichtigungen Nachrichten Liste des Benutzers - Studio Einstellungen Antwort verfassen @@ -294,7 +274,6 @@ Neuer Follower Like im Forum Like eines Status - Reply Like Kommentar im Forum Antwort im Forum Kommentar zum Status @@ -932,7 +911,6 @@ Black Theme - Use black theme for devices that LED displays to save power Application Language diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index f5300e85e..b636f6480 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -149,7 +149,6 @@ ¡Cuenta con un extenso inventario de anime y mangas categorizados! Encuentra ¡Anime y Manga gracias a su motor de búsqueda eficiente y lleno de características! - Vídeos ¡Facilita la visualización de vídeos de Youtube a través del reproductor integrado! ¡Bienvenido/a a AniTrend! @@ -243,7 +242,6 @@ elementos de tus favoritos al presionar en el icono del corazón . Perfil Cerrar sesión - Extras Compartir Actualización Nada para mostrar @@ -309,7 +307,6 @@ elementos de tus favoritos al presionar en el icono del corazón . - General Ajusta el comportamiento de la aplicación Progreso Inteligente @@ -932,7 +929,6 @@ elementos de tus favoritos al presionar en el icono del corazón . Black Theme - Use black theme for devices that LED displays to save power Application Language diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index c8faab615..a3fa070b1 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -1,25 +1,10 @@ - + - Discover - Manage - Customization - Support - Contact - About - - Search @string/drawer_title_filter - Help Selected: %d - Navigation drawer opened - Navigation drawer closed - - - Home - History Black Theme - Use black theme for devices that LED displays to save power Application Language diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 5d0700848..ac8f8eb95 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -6,7 +6,6 @@ Supporto Contatti - Info Cerca @string/drawer_title_filter @@ -14,11 +13,7 @@ Selezioni: %d - Navigation drawer opened - Navigation drawer closed - - Home Cronologia - Home Scopri anime Scopri manga Di tendenza @@ -232,14 +224,12 @@ Lista anime Lista manga Recensioni - AniTrend Hub Configurazione Filtri Modalità notturna Stile della lista - Account Accedi Profilo Esci @@ -286,7 +276,6 @@ Centro notifiche Centro messaggi Lista utenti - Studio Impostazioni Rispondi @@ -931,7 +920,6 @@ Black Theme - Use black theme for devices that LED displays to save power Application Language diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 2696210c0..5d33daeb1 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -3,13 +3,10 @@ Beheren Personalisatie - Support - Contact Over ons Zoeken @string/drawer_title_filter - Help Selected: %d @@ -76,11 +73,9 @@ Afsluiten Toepassen - Reset Toevoegen Verwijderen - Update Teruggaan @@ -141,21 +136,16 @@ - Begin Kleurenstaten Kleuren die Anime / Manga-status vertegenwoordigen! Inhoud Multiple Anime & Manga Vermeldingen! - Searching Anime, Manga & Meer zoekfunctionaliteiten! - Videos Gebruikt een ingebouwde Youtube Video Player! - Welcome to AniTrend! Sorteer op? Volgorde op? - Series Genres? Type Serie? Serie jaar? Alleen weergeven? @@ -221,7 +211,6 @@ Het inloggen is gelukt! - Status Feeds Anime Ontdekken Manga Ontdekken Wat is populair @@ -229,23 +218,15 @@ Mijn Animne Lijst Mijn Manga Lijst - Series Reviews - - AniTrend Hub Configuratie - Filter Wissel Thema - Toggle Style - Account Inloggen Profiel Uitloggen - Extras Delen - Update Geen data @@ -253,21 +234,17 @@ Optie Menu Zoekbalk Zoek naar verschillende Anime & manga lijsten, vindbaar op naam sleutelwoorden. \n\nklik hier om te annuleren - Navigation Open de navigatielade om verschillende inhoud te bekijken binnen de applicatie. \n\nKlik hier om te annuleren Maak favoriet, voeg toe aan je lijst en deel dit de huidige lijst met vrienden. \n\nKlik hier om te annuleren Opties Beschikbaar Maar favoriet Maak dit Karakter je favoriet. \n\nKlik hier om te annuleren - Messages Bekijk al je binnenkomende en uitgaande berichten. \n\nKlik hier om te annuleren Maak een status post Post je status bericht zodat iedereen het kan zien. \n\nKlik hier om te annuleren - Notifications Beheer al je berichten op één plek. \n\nKlik hier om te annuleren Meer Acties Klik hier voor meer opties, zoals het bekijken van je likes. \n\nKlik hier om te annuleren - Compose Message Verzend een bericht naar de huidige gebruiker. \n\nKlik hier om te annuleren @@ -292,7 +269,6 @@ Onbepaade Activiteit Nieuwe aflevering uitgezonden Nieuwe volger - Forum Like Activiteiten Like Antwoord Like Commentaar op Forum diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 110b7e004..111ba364d 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -286,7 +286,6 @@ Centrum Powiadomień Centrum wiadomości Lista użytkowników - Studio Ustawienia Odpowiedz @@ -934,7 +933,6 @@ Black Theme - Use black theme for devices that LED displays to save power Application Language diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 241afb11e..dbcd1723e 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -18,7 +18,6 @@ Gaveta de navegação fechada - Home Histórico Anmälningsnav - Message Hub Användarlistor - Studio Inställningar Svara Kompositör @@ -933,7 +929,6 @@ Black Theme - Use black theme for devices that LED displays to save power Application Language From da7b73eb7a76be855a07d184f3b009caf2f2a09b Mon Sep 17 00:00:00 2001 From: Maxwell Date: Fri, 19 Apr 2019 16:34:32 +0200 Subject: [PATCH 05/17] Minor Improvements & Bug Fixes --- app/.meta/version.json | 4 +- app/build.gradle | 4 +- app/release/output.json | 2 +- app/src/main/assets/changelog.md | 14 +++--- .../adapter/pager/index/FeedPageAdapter.java | 6 ++- .../adapter/recycler/index/FeedAdapter.java | 4 +- .../custom/fragment/FragmentChannelBase.java | 17 +++++--- .../custom/view/editor/MarkdownInputEditor.kt | 40 +++++++++-------- .../custom/view/text/RichMarkdownTextView.kt | 6 ++- .../binding/RichMarkdownExtensions.kt | 9 ++-- .../com/mxt/anitrend/util/JobSchedulerUtil.kt | 3 ++ .../com/mxt/anitrend/util/MarkDownUtil.kt | 23 +++++----- .../mxt/anitrend/util/MediaDialogUtil.java | 3 +- .../java/com/mxt/anitrend/util/RegexUtil.kt | 20 +++++---- .../fragment/detail/UserOverviewFragment.java | 2 +- .../main/res/layout/adapter_feed_status.xml | 8 ++-- .../main/res/layout/fragment_user_about.xml | 8 ++-- build.gradle | 43 ++++++++++--------- 18 files changed, 116 insertions(+), 100 deletions(-) diff --git a/app/.meta/version.json b/app/.meta/version.json index c6981fed7..dfb15c12e 100644 --- a/app/.meta/version.json +++ b/app/.meta/version.json @@ -1,7 +1,7 @@ { - "code": 101, + "code": 103, "migration": false, "releaseNotes": "", - "version": "1.3.1", + "version": "1.4.0", "appId": "com.mxt.anitrend" } diff --git a/app/build.gradle b/app/build.gradle index 2235c13dd..415691ac9 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -92,7 +92,6 @@ dependencies { /** Android Support Libraries */ implementation 'com.android.support.constraint:constraint-layout:1.1.3' implementation "com.android.support:appcompat-v7:${rootProject.supportLibrary}" - implementation "com.android.support:support-v4:${rootProject.supportLibrary}" implementation "com.android.support:design:${rootProject.supportLibrary}" implementation "com.android.support:cardview-v7:${rootProject.supportLibrary}" implementation "com.android.support:support-vector-drawable:${rootProject.supportLibrary}" @@ -140,7 +139,7 @@ dependencies { implementation 'org.ocpsoft.prettytime:prettytime:4.0.1.Final' /** Smart Tab Layout */ - implementation 'com.ogaclejapan.smarttablayout:library:1.6.1@aar' + implementation 'com.ogaclejapan.smarttablayout:library:1.7.0' /** Java Streams Port */ implementation 'com.annimon:stream:1.2.1' @@ -163,7 +162,6 @@ dependencies { implementation "ru.noties.markwon:image-gif:$rootProject.markwon" implementation "ru.noties.markwon:image-okhttp:$rootProject.markwon" implementation "ru.noties.markwon:image-svg:$rootProject.markwon" - implementation "ru.noties.markwon:recycler:$rootProject.markwon" /** Tap Target Prompt */ implementation 'uk.co.samuelwall:material-tap-target-prompt:2.12.1' diff --git a/app/release/output.json b/app/release/output.json index 24095e8d1..e068d817c 100644 --- a/app/release/output.json +++ b/app/release/output.json @@ -1 +1 @@ -[{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":101,"versionName":"1.3.1","enabled":true,"outputFile":"anitrend_v1.3.1_rc_101.apk","fullName":"release","baseName":"release"},"path":"anitrend_v1.3.1_rc_101.apk","properties":{}}] \ No newline at end of file +[{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":103,"versionName":"1.4.0","enabled":true,"outputFile":"anitrend_v1.4.0_rc_103.apk","fullName":"release","baseName":"release"},"path":"anitrend_v1.4.0_rc_103.apk","properties":{}}] \ No newline at end of file diff --git a/app/src/main/assets/changelog.md b/app/src/main/assets/changelog.md index 1bbc8beb7..51b0e950b 100644 --- a/app/src/main/assets/changelog.md +++ b/app/src/main/assets/changelog.md @@ -1,18 +1,14 @@ -__Anitrend v2.0 Coming Soon [W.I.P] This is the last update for v1.X all efforts are being moved to v2.0__ +__Anitrend v2.0 Coming Soon [W.I.P]__ All v1.X updates will focus on major bug fixes as all resources are being moved to v2.0 __N.B__ v2.0 will be dropping support for Jellybean - Kitkat, due to missing or disabled _(TLS v1.2)_ which can result in authentication errors [read more](https://github.com/square/okhttp/issues/2372) #### Enhancements -- Bug reporter (Silver) -- Updated german translation, added nl region -- Image preview download & share feature (Mittens) +- Reintroduced emoji support #### Bug Fixes -- Improved authentication flow -- Crunchyroll link detection issues -- Notifications & Improved Job Scheduler -- Temporary fix for pre-lollipop login issues +- Multiple translations fixed +- Crashes on some device related to crunchyroll feeds #### Current Issues - Clicking on @username shows mixed feed @@ -25,5 +21,5 @@ __Admins, Devs & Cutie Pies:__ _Mittens, Senpai, Kuji, Moka, Flare, Silver, Mrspits4ever_ __Awesome Donators:__ -_Bas, Golumpa, artemisthemp, Trivernis_ +_Bas, Golumpa, artemisthemp, Trivernis, PeakZer0, KorenTeam_ diff --git a/app/src/main/java/com/mxt/anitrend/adapter/pager/index/FeedPageAdapter.java b/app/src/main/java/com/mxt/anitrend/adapter/pager/index/FeedPageAdapter.java index 61d2e815e..7c12569e5 100644 --- a/app/src/main/java/com/mxt/anitrend/adapter/pager/index/FeedPageAdapter.java +++ b/app/src/main/java/com/mxt/anitrend/adapter/pager/index/FeedPageAdapter.java @@ -37,11 +37,13 @@ public Fragment getItem(int position) { case 1: return FeedListFragment.newInstance(getParams(), GraphUtil.getDefaultQuery(true) .putVariable(KeyUtil.arg_isFollowing, true) - .putVariable(KeyUtil.arg_type, KeyUtil.TEXT)); + .putVariable(KeyUtil.arg_type, KeyUtil.TEXT) + .putVariable(KeyUtil.arg_asHtml, false)); case 2: return FeedListFragment.newInstance(getParams(), GraphUtil.getDefaultQuery(true) .putVariable(KeyUtil.arg_isFollowing, false) - .putVariable(KeyUtil.arg_isMixed, true)); + .putVariable(KeyUtil.arg_isMixed, true) + .putVariable(KeyUtil.arg_asHtml, false)); } return null; } diff --git a/app/src/main/java/com/mxt/anitrend/adapter/recycler/index/FeedAdapter.java b/app/src/main/java/com/mxt/anitrend/adapter/recycler/index/FeedAdapter.java index 07dce491a..28c1aac49 100644 --- a/app/src/main/java/com/mxt/anitrend/adapter/recycler/index/FeedAdapter.java +++ b/app/src/main/java/com/mxt/anitrend/adapter/recycler/index/FeedAdapter.java @@ -181,7 +181,7 @@ public StatusFeedViewHolder(AdapterFeedStatusBinding binding) { public void onBindViewHolder(FeedList model) { binding.setModel(model); // TODO: Temporarily disabled widget status to try out rich markdown rendering - //binding.widgetStatus.setModel(model); + binding.widgetStatus.setModel(model); binding.widgetFavourite.setRequestParams(KeyUtil.ACTIVITY, model.getId()); binding.widgetFavourite.setModel(model.getLikes()); @@ -213,7 +213,7 @@ public void onViewRecycled() { Glide.with(getContext()).clear(binding.userAvatar); binding.widgetFavourite.onViewRecycled(); // TODO: Temporarily disabled widget status to try out rich markdown rendering - // binding.widgetStatus.onViewRecycled(); + binding.widgetStatus.onViewRecycled(); binding.widgetDelete.onViewRecycled(); binding.unbind(); } diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/fragment/FragmentChannelBase.java b/app/src/main/java/com/mxt/anitrend/base/custom/fragment/FragmentChannelBase.java index 282dc80f6..8ed559768 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/fragment/FragmentChannelBase.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/fragment/FragmentChannelBase.java @@ -10,6 +10,7 @@ import android.support.design.widget.Snackbar; import android.support.v7.widget.StaggeredGridLayoutManager; import android.text.TextUtils; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -324,12 +325,18 @@ else if(swipeRefreshLayout.isLoading()) */ @Override public void onChanged(@Nullable Rss content) { - if(content != null) { - copyright = content.getChannel().getCopyright(); - mAdapter.onItemsInserted(content.getChannel().getEpisode()); - updateUI(); - } else + try { + if(content != null && content.getChannel().getEpisode() != null) { + copyright = content.getChannel().getCopyright(); + mAdapter.onItemsInserted(content.getChannel().getEpisode()); + updateUI(); + } else + showEmpty(getString(R.string.layout_empty_response)); + } catch (Exception e) { + e.printStackTrace(); + Log.e("onChanged(Rss content)", e.getLocalizedMessage()); showEmpty(getString(R.string.layout_empty_response)); + } } protected ItemClickListener clickListener = new ItemClickListener() { diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/editor/MarkdownInputEditor.kt b/app/src/main/java/com/mxt/anitrend/base/custom/view/editor/MarkdownInputEditor.kt index bb9cbe499..1cb067736 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/editor/MarkdownInputEditor.kt +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/editor/MarkdownInputEditor.kt @@ -155,7 +155,7 @@ class MarkdownInputEditor : TextInputEditText, CustomView, ActionMode.Callback, */ private fun getSelectionEnd(@IdRes selection: Int): Int { var end = selectionEnd - val init_end = selectionEnd + val initialEnd = selectionEnd when (selection) { R.id.menu_bold -> end += MD_BOLD.length R.id.menu_italic -> end += MD_ITALIC.length @@ -168,9 +168,11 @@ class MarkdownInputEditor : TextInputEditText, CustomView, ActionMode.Callback, R.id.menu_code -> end += MD_CODE.length } // Rare case but if it ever happens reduce end by 1 - val text_length = text.length - if (end > text_length + (end - init_end)) - end -= end - init_end - 1 + val textLength = text?.length + if (textLength != null) { + if (end > textLength + (end - initialEnd)) + end -= end - initialEnd - 1 + } return end } @@ -187,52 +189,52 @@ class MarkdownInputEditor : TextInputEditText, CustomView, ActionMode.Callback, val end = getSelectionEnd(item.itemId) when (item.itemId) { R.id.menu_bold -> { - text.insert(start, MD_BOLD) - text.insert(end, MD_BOLD, 0, MD_BOLD.length) + text?.insert(start, MD_BOLD) + text?.insert(end, MD_BOLD, 0, MD_BOLD.length) mode.finish() return true } R.id.menu_italic -> { - text.insert(start, MD_ITALIC) - text.insert(end, MD_ITALIC, 0, MD_ITALIC.length) + text?.insert(start, MD_ITALIC) + text?.insert(end, MD_ITALIC, 0, MD_ITALIC.length) mode.finish() return true } R.id.menu_strike -> { - text.insert(start, MD_STRIKE) - text.insert(end, MD_STRIKE, 0, MD_STRIKE.length) + text?.insert(start, MD_STRIKE) + text?.insert(end, MD_STRIKE, 0, MD_STRIKE.length) mode.finish() return true } R.id.menu_list -> { - text.insert(start, MD_NUMBER) + text?.insert(start, MD_NUMBER) mode.finish() return true } R.id.menu_bullet -> { - text.insert(start, MD_BULLET) + text?.insert(start, MD_BULLET) mode.finish() return true } R.id.menu_heading -> { - text.insert(start, MD_HEADING) + text?.insert(start, MD_HEADING) mode.finish() return true } R.id.menu_center -> { - text.insert(start, MD_CENTER_ALIGN) - text.insert(end, MD_CENTER_ALIGN, 0, MD_CENTER_ALIGN.length) + text?.insert(start, MD_CENTER_ALIGN) + text?.insert(end, MD_CENTER_ALIGN, 0, MD_CENTER_ALIGN.length) mode.finish() return true } R.id.menu_quote -> { - text.insert(start, MD_QUOTE) + text?.insert(start, MD_QUOTE) mode.finish() return true } R.id.menu_code -> { - text.insert(start, MD_CODE) - text.insert(end, MD_CODE, 0, MD_CODE.length) + text?.insert(start, MD_CODE) + text?.insert(end, MD_CODE, 0, MD_CODE.length) mode.finish() return true } @@ -273,7 +275,7 @@ class MarkdownInputEditor : TextInputEditText, CustomView, ActionMode.Callback, val linkUri = inputContentInfo.linkUri if (linkUri != null) { val link = MarkDownUtil.convertImage(linkUri.toString()) - text.insert(selectionStart, link) + text?.insert(selectionStart, link) inputContentInfo.releasePermission() return true } diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/text/RichMarkdownTextView.kt b/app/src/main/java/com/mxt/anitrend/base/custom/view/text/RichMarkdownTextView.kt index 53843a302..8f295cf8b 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/text/RichMarkdownTextView.kt +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/text/RichMarkdownTextView.kt @@ -12,6 +12,7 @@ import android.text.util.Linkify import android.util.AttributeSet import android.widget.TextView import com.mxt.anitrend.base.interfaces.view.CustomView +import com.mxt.anitrend.binding.richMarkDown import com.mxt.anitrend.model.api.retro.WebFactory import com.mxt.anitrend.util.MarkDownUtil import com.mxt.anitrend.util.RegexUtil @@ -23,6 +24,7 @@ import ru.noties.markwon.Markwon import ru.noties.markwon.MarkwonConfiguration import ru.noties.markwon.core.CorePlugin import ru.noties.markwon.ext.tasklist.TaskListPlugin +import ru.noties.markwon.html.HtmlPlugin import ru.noties.markwon.html.MarkwonHtmlParserImpl import ru.noties.markwon.image.AsyncDrawableScheduler import ru.noties.markwon.image.ImagesPlugin @@ -50,6 +52,7 @@ class RichMarkdownTextView : AppCompatTextView, CustomView { GifPlugin.create(), OkHttpImagesPlugin.create(), TaskListPlugin.create(context), + HtmlPlugin.create(), object: AbstractMarkwonPlugin() { @Override override fun configureParser(builder: Parser.Builder) { @@ -94,6 +97,7 @@ class RichMarkdownTextView : AppCompatTextView, CustomView { fun setMarkDownText(markDownText: String) { val strippedText = RegexUtil.removeTags(markDownText) val markdownSpan = MarkDownUtil.convert(strippedText, context, this) - setText(markdownSpan, TextView.BufferType.SPANNABLE) + setText(markdownSpan, BufferType.SPANNABLE) + //richMarkDown(this, markDownText) } } diff --git a/app/src/main/java/com/mxt/anitrend/binding/RichMarkdownExtensions.kt b/app/src/main/java/com/mxt/anitrend/binding/RichMarkdownExtensions.kt index 4fefef85b..fcefeec39 100644 --- a/app/src/main/java/com/mxt/anitrend/binding/RichMarkdownExtensions.kt +++ b/app/src/main/java/com/mxt/anitrend/binding/RichMarkdownExtensions.kt @@ -16,13 +16,13 @@ fun markDown(richMarkdownTextView: RichMarkdownTextView, markdown: String?) { } @BindingAdapter("textHtml") -fun htmlText(richMarkdownTextView: RichMarkdownTextView, html: String) { +fun htmlText(richMarkdownTextView: RichMarkdownTextView, html: String?) { val markdownSpan = MarkDownUtil.convert(html, richMarkdownTextView.context, richMarkdownTextView) richMarkdownTextView.setText(markdownSpan, TextView.BufferType.SPANNABLE) } @BindingAdapter("basicHtml") -fun basicText(richMarkdownTextView: RichMarkdownTextView, html: String) { +fun basicText(richMarkdownTextView: RichMarkdownTextView, html: String?) { val htmlSpan = Html.fromHtml(html) richMarkdownTextView.text = htmlSpan } @@ -37,6 +37,9 @@ fun htmlText(richMarkdownTextView: RichMarkdownTextView, @StringRes resId: Int) @BindingAdapter("richMarkDown") fun richMarkDown(richMarkdownTextView: RichMarkdownTextView, markdown: String?) { richMarkdownTextView.also { - it.markwon.setMarkdown(it, RegexUtil.convertToStandardMarkdown(markdown)) + val tagsStripped = RegexUtil.removeTags(markdown) + val userTagsConverted = RegexUtil.findUserTags(tagsStripped) + val standardMarkdown = RegexUtil.convertToStandardMarkdown(userTagsConverted) + it.markwon.setMarkdown(it, standardMarkdown) } } \ No newline at end of file diff --git a/app/src/main/java/com/mxt/anitrend/util/JobSchedulerUtil.kt b/app/src/main/java/com/mxt/anitrend/util/JobSchedulerUtil.kt index 73f731981..5554e2aed 100644 --- a/app/src/main/java/com/mxt/anitrend/util/JobSchedulerUtil.kt +++ b/app/src/main/java/com/mxt/anitrend/util/JobSchedulerUtil.kt @@ -29,6 +29,9 @@ object JobSchedulerUtil { if (applicationPref.isAuthenticated && applicationPref.isNotificationEnabled) { val periodicWorkRequest = PeriodicWorkRequest.Builder(JobDispatcherService::class.java, applicationPref.syncTime.toLong(), TimeUnit.MINUTES) + .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, + 5, TimeUnit.MINUTES + ) .addTag(KeyUtil.WorkNotificationTag) .setConstraints(constraints) .build() diff --git a/app/src/main/java/com/mxt/anitrend/util/MarkDownUtil.kt b/app/src/main/java/com/mxt/anitrend/util/MarkDownUtil.kt index 3d0d6680b..5fcf27e96 100644 --- a/app/src/main/java/com/mxt/anitrend/util/MarkDownUtil.kt +++ b/app/src/main/java/com/mxt/anitrend/util/MarkDownUtil.kt @@ -3,13 +3,10 @@ package com.mxt.anitrend.util import android.content.Context import android.os.Build import android.support.v7.widget.AppCompatTextView -import android.text.Editable import android.text.Html import android.text.SpannableStringBuilder import android.text.Spanned -import android.text.TextUtils import android.util.Log - import com.github.rjeschke.txtmark.Processor /** @@ -22,9 +19,10 @@ object MarkDownUtil { return try { val processedText = Processor.process(content) when { - Build.VERSION.SDK_INT >= Build.VERSION_CODES.N -> Html.fromHtml(processedText, - Html.FROM_HTML_MODE_LEGACY) - else -> Html.fromHtml(processedText) + Build.VERSION.SDK_INT >= Build.VERSION_CODES.N -> + Html.fromHtml(processedText, Html.FROM_HTML_MODE_LEGACY) + else -> + Html.fromHtml(processedText) } as SpannableStringBuilder } catch (e: Exception) { e.printStackTrace() @@ -33,16 +31,15 @@ object MarkDownUtil { } fun convert(input: String?): Spanned { - var result: SpannableStringBuilder - result = if (input.isNullOrBlank()) - fromMD("No content available") - else - fromMD(RegexUtil.findUserTags(input)) + var result = when(input.isNullOrBlank()) { + true -> fromMD("No content available") + else -> fromMD(RegexUtil.findUserTags(input)) + } try { if (result.isNotEmpty()) - while (result[result.length - 1] == '\n') - result = result.delete(result.length - 1, result.length) + while (result.last() == '\n') + result = result.delete(result.lastIndex - 1, result.length) } catch (e: Exception) { e.printStackTrace() Log.e("convert(input)", e.message) diff --git a/app/src/main/java/com/mxt/anitrend/util/MediaDialogUtil.java b/app/src/main/java/com/mxt/anitrend/util/MediaDialogUtil.java index 627c6ac9f..99565f144 100644 --- a/app/src/main/java/com/mxt/anitrend/util/MediaDialogUtil.java +++ b/app/src/main/java/com/mxt/anitrend/util/MediaDialogUtil.java @@ -4,6 +4,7 @@ import android.content.Context; import android.os.Bundle; import android.support.annotation.NonNull; +import android.text.Html; import android.util.Log; import android.widget.Toast; @@ -185,7 +186,7 @@ private static CustomSeriesManageBase buildManagerType(Context context, @KeyUtil private static MaterialDialog.Builder createSeriesManageDialog(Context context, boolean isNewEntry, String title) { MaterialDialog.Builder materialBuilder = createDefaultDialog(context) .icon(CompatUtil.getDrawableTintAttr(context, isNewEntry ? R.drawable.ic_fiber_new_white_24dp : R.drawable.ic_border_color_white_24dp, R.attr.colorAccent)) - .title(MarkDownUtil.INSTANCE.convert(context.getString(isNewEntry? R.string.dialog_add_title : R.string.dialog_edit_title, title))) + .title(Html.fromHtml(context.getString(isNewEntry ? R.string.dialog_add_title : R.string.dialog_edit_title, title))) .positiveText(isNewEntry? R.string.Add: R.string.Update) .neutralText(R.string.Cancel) .autoDismiss(false); diff --git a/app/src/main/java/com/mxt/anitrend/util/RegexUtil.kt b/app/src/main/java/com/mxt/anitrend/util/RegexUtil.kt index fb91e016a..ec7a8ebd7 100644 --- a/app/src/main/java/com/mxt/anitrend/util/RegexUtil.kt +++ b/app/src/main/java/com/mxt/anitrend/util/RegexUtil.kt @@ -1,6 +1,7 @@ package com.mxt.anitrend.util import android.text.TextUtils +import com.github.rjeschke.txtmark.Processor import java.util.regex.Matcher import java.util.regex.Pattern @@ -59,16 +60,16 @@ object RegexUtil { return if (param.isBlank()) null else Pattern.compile(PATTERN_TRAILING_SPACES).matcher(param).replaceAll("") } - internal fun findUserTags(text: String): String { + internal fun findUserTags(text: String?): String { var newText = text - if (text.isBlank()) + if (text.isNullOrBlank()) return "No content available" val matcher = Pattern.compile(PATTERN_USER_TAGS).matcher(text) while (matcher.find()) { val match = matcher.group() newText = text.replace(match, String.format(USER_URL_LINK, match, match.replace("@", ""))) } - return newText + return newText ?: "No content available" } /** @@ -130,9 +131,9 @@ object RegexUtil { else -> findImages(findMedia(value) .replaceAll("")) .replaceAll("") - .replace("!~", "") - .replace("~!", "") - .replace("~", "") + .replace("!~","") + .replace("~!","") + .replace("~","") } } @@ -140,9 +141,10 @@ object RegexUtil { var substitute = "No content available" return value?.let { if (!it.isBlank()) { - substitute = value.replace("!~", "") - .replace("~!", "") - .replace("~", "") + substitute = value/* + .replace("!~","") + .replace("~!","") + .replace("~","")*/ val matcher = findMedia(it) diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/UserOverviewFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/UserOverviewFragment.java index 444eca216..ed140eef5 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/UserOverviewFragment.java +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/UserOverviewFragment.java @@ -99,7 +99,7 @@ public void onStart() { protected void updateUI() { binding.setModel(model); binding.stateLayout.showContent(); - //binding.widgetStatus.setTextData(model.getAbout()); + binding.widgetStatus.setTextData(model.getAbout()); binding.userFollowStateWidget.setUserModel(model); binding.userAboutPanelWidget.setFragmentActivity(getActivity()); diff --git a/app/src/main/res/layout/adapter_feed_status.xml b/app/src/main/res/layout/adapter_feed_status.xml index ec7dab251..06b078986 100644 --- a/app/src/main/res/layout/adapter_feed_status.xml +++ b/app/src/main/res/layout/adapter_feed_status.xml @@ -60,15 +60,15 @@ android:layout_width="wrap_content" android:layout_height="@dimen/lg_margin" /> - + android:layout_height="wrap_content"/> - + app:richMarkDown="@{model.text}"/>--> - + android:layout_height="wrap_content" /> - + app:richMarkDown="@{model.about}"/>--> Date: Sun, 12 May 2019 20:45:04 +0200 Subject: [PATCH 06/17] Fixed Refactored Tests --- .../mxt/anitrend/util/GroupingUtilTests.java | 38 +++++++++---------- .../mxt/anitrend/util/EpisodeUtilTests.java | 8 ++-- .../util/EpisodeUtil_GetActualTitleTest.java | 2 +- .../com/mxt/anitrend/util/RegexUtilTests.java | 27 ++++++++++++- 4 files changed, 50 insertions(+), 25 deletions(-) diff --git a/app/src/androidTest/java/com/mxt/anitrend/util/GroupingUtilTests.java b/app/src/androidTest/java/com/mxt/anitrend/util/GroupingUtilTests.java index 6e2aadb4d..a8a08b5d2 100644 --- a/app/src/androidTest/java/com/mxt/anitrend/util/GroupingUtilTests.java +++ b/app/src/androidTest/java/com/mxt/anitrend/util/GroupingUtilTests.java @@ -189,7 +189,7 @@ public class GroupingUtilTests { @Test public void groupMediaByFormat_ifTheMediaListIsEmpty_shouldReturnAnEmptyList() { - assertThat(GroupingUtil.groupMediaByFormat(Collections.emptyList(), null), empty()); + assertThat(GroupingUtil.INSTANCE.groupMediaByFormat(Collections.emptyList(), null), empty()); } @Test @@ -208,7 +208,7 @@ public void groupMediaByFormat_ifTheExistingListIsNull_shouldReturnAllItems() { List results = - GroupingUtil.groupMediaByFormat(mediaOfAllFormats, null); + GroupingUtil.INSTANCE.groupMediaByFormat(mediaOfAllFormats, null); assertThat(results, hasSize(required.size())); assertThat(results, containsItemsOf(required)); @@ -243,7 +243,7 @@ public void groupMediaByFormat_ifTheExistingListIsNotEmpty_shouldNotReturnExisti .collect(Collectors.toList()); List results = - GroupingUtil.groupMediaByFormat(mediaOfAllFormats, existingItems); + GroupingUtil.INSTANCE.groupMediaByFormat(mediaOfAllFormats, existingItems); assertThat(results, hasSize(required.size())); assertThat(results, containsItemsOf(required)); @@ -253,7 +253,7 @@ public void groupMediaByFormat_ifTheExistingListIsNotEmpty_shouldNotReturnExisti //region groupStaffByLanguage @Test public void groupStaffByLanguage_ifTheMediaListIsEmpty_shouldReturnAnEmptyList() { - assertThat(GroupingUtil.groupStaffByLanguage(Collections.emptyList(), null), empty()); + assertThat(GroupingUtil.INSTANCE.groupStaffByLanguage(Collections.emptyList(), null), empty()); } @Test @@ -272,7 +272,7 @@ public void groupStaffByLanguage_ifTheExistingListIsNull_shouldReturnAllItems() List results = - GroupingUtil.groupStaffByLanguage(staffOfAllLanguages, null); + GroupingUtil.INSTANCE.groupStaffByLanguage(staffOfAllLanguages, null); assertThat(results, hasSize(required.size())); assertThat(results, containsItemsOf(required)); @@ -307,7 +307,7 @@ public void groupStaffByLanguage_ifTheExistingListIsNotEmpty_shouldNotReturnExis .collect(Collectors.toList()); List results = - GroupingUtil.groupStaffByLanguage(staffOfAllLanguages, existingItems); + GroupingUtil.INSTANCE.groupStaffByLanguage(staffOfAllLanguages, existingItems); assertThat(results, hasSize(required.size())); assertThat(results, containsItemsOf(required)); @@ -317,7 +317,7 @@ public void groupStaffByLanguage_ifTheExistingListIsNotEmpty_shouldNotReturnExis //region groupActorMediaEdge @Test public void groupActorMediaEdge_ifEdgeListIsEmpty_shouldReturnAnEmptyList() { - assertThat(GroupingUtil.groupActorMediaEdge(Collections.emptyList()), empty()); + assertThat(GroupingUtil.INSTANCE.groupActorMediaEdge(Collections.emptyList()), empty()); } @Test @@ -347,7 +347,7 @@ public void groupActorMediaEdge_shouldReturnTheMediaAsAHeaderFollowedByVoiceActo return items.stream(); }).collect(Collectors.toList()); - List result = GroupingUtil.groupActorMediaEdge(mediaEdges); + List result = GroupingUtil.INSTANCE.groupActorMediaEdge(mediaEdges); assertThat(result, hasSize(required.size())); assertThat(result, containsItemsOf(required)); @@ -370,7 +370,7 @@ public void groupActorMediaEdge_shouldReturnTheMediaAsAHeaderFollowedByVoiceActo //region groupMediaByRelationType @Test public void groupMediaByRelationType_ifEdgeListIsEmpty_shouldReturnAnEmptyList() { - assertThat(GroupingUtil.groupMediaByRelationType(Collections.emptyList()), empty()); + assertThat(GroupingUtil.INSTANCE.groupMediaByRelationType(Collections.emptyList()), empty()); } @Test @@ -382,7 +382,7 @@ public void groupMediaByRelationType_shouldReturnAHeaderForEachRelationFollowedB .collect(Collectors.toList()); List results = - GroupingUtil.groupMediaByRelationType(mediaOfAllRelations); + GroupingUtil.INSTANCE.groupMediaByRelationType(mediaOfAllRelations); assertThat(results, hasSize(required.size())); assertThat(results, containsItemsOf(required)); @@ -393,7 +393,7 @@ public void groupMediaByRelationType_shouldReturnAHeaderForEachRelationFollowedB @Test public void groupCharactersByRole_ifTheCharacterEdgeListIsEmpty_shouldReturnAnEmptyList() { - assertThat(GroupingUtil.groupCharactersByRole(Collections.emptyList(), null), empty()); + assertThat(GroupingUtil.INSTANCE.groupCharactersByRole(Collections.emptyList(), null), empty()); } @Test @@ -412,7 +412,7 @@ public void groupCharactersByRole_ifTheExistingListIsNull_shouldReturnAllItems() List results = - GroupingUtil.groupCharactersByRole(charactersOfAllRoles, null); + GroupingUtil.INSTANCE.groupCharactersByRole(charactersOfAllRoles, null); assertThat(results, hasSize(required.size())); assertThat(results, containsItemsOf(required)); @@ -445,7 +445,7 @@ public void groupCharactersByRole_ifTheExistingListIsNotEmpty_shouldNotReturnExi .collect(Collectors.toList()); List results = - GroupingUtil.groupCharactersByRole(charactersOfAllRoles, existingItems); + GroupingUtil.INSTANCE.groupCharactersByRole(charactersOfAllRoles, existingItems); assertThat(results, hasSize(required.size())); assertThat(results, containsItemsOf(required)); @@ -455,7 +455,7 @@ public void groupCharactersByRole_ifTheExistingListIsNotEmpty_shouldNotReturnExi //region groupStaffByRole @Test public void groupStaffByRole_ifTheStaffEdgeListIsEmpty_shouldReturnAnEmptyList() { - assertThat(GroupingUtil.groupStaffByRole(Collections.emptyList(), null), empty()); + assertThat(GroupingUtil.INSTANCE.groupStaffByRole(Collections.emptyList(), null), empty()); } @Test @@ -474,7 +474,7 @@ public void groupStaffByRole_ifTheExistingListIsNull_shouldReturnAllItems() { List results = - GroupingUtil.groupStaffByRole(staffOfAllRoles, null); + GroupingUtil.INSTANCE.groupStaffByRole(staffOfAllRoles, null); assertThat(results, hasSize(required.size())); assertThat(results, containsItemsOf(required)); @@ -507,7 +507,7 @@ public void groupStaffByRole_ifTheExistingListIsNotEmpty_shouldNotReturnExisting .collect(Collectors.toList()); List results = - GroupingUtil.groupStaffByRole(staffOfAllRoles, existingItems); + GroupingUtil.INSTANCE.groupStaffByRole(staffOfAllRoles, existingItems); assertThat(results, hasSize(required.size())); assertThat(results, containsItemsOf(required)); @@ -517,7 +517,7 @@ public void groupStaffByRole_ifTheExistingListIsNotEmpty_shouldNotReturnExisting //region groupMediaByStaffRole @Test public void groupMediaByStaffRole_ifTheMediaEdgeListIsEmpty_shouldReturnAnEmptyList() { - assertThat(GroupingUtil.groupMediaByStaffRole(Collections.emptyList(), null), empty()); + assertThat(GroupingUtil.INSTANCE.groupMediaByStaffRole(Collections.emptyList(), null), empty()); } @Test @@ -536,7 +536,7 @@ public void groupMediaByStaffRole_ifTheExistingListIsNull_shouldReturnAllItems() List results = - GroupingUtil.groupMediaByStaffRole(mediaOfAllStaffRoles, null); + GroupingUtil.INSTANCE.groupMediaByStaffRole(mediaOfAllStaffRoles, null); assertThat(results, hasSize(required.size())); assertThat(results, containsItemsOf(required)); @@ -569,7 +569,7 @@ public void groupMediaByStaffRole_ifTheExistingListIsNotEmpty_shouldNotReturnExi .collect(Collectors.toList()); List results = - GroupingUtil.groupMediaByStaffRole(mediaOfAllStaffRoles, existingItems); + GroupingUtil.INSTANCE.groupMediaByStaffRole(mediaOfAllStaffRoles, existingItems); assertThat(results, hasSize(required.size())); assertThat(results, containsItemsOf(required)); diff --git a/app/src/test/java/com/mxt/anitrend/util/EpisodeUtilTests.java b/app/src/test/java/com/mxt/anitrend/util/EpisodeUtilTests.java index ad5c45e12..f38f4a79c 100644 --- a/app/src/test/java/com/mxt/anitrend/util/EpisodeUtilTests.java +++ b/app/src/test/java/com/mxt/anitrend/util/EpisodeUtilTests.java @@ -28,7 +28,7 @@ public void episodeSupport_givenCrunchyrollUrl_shouldReturnTheFeedUrl() { List links = Collections.singletonList(link); - assertThat(EpisodeUtil.episodeSupport(links), equalTo(show + ".rss")); + assertThat(EpisodeUtil.INSTANCE.episodeSupport(links), equalTo(show + ".rss")); } @@ -40,7 +40,7 @@ public void episodeSupport_givenFeedUrl_shouldReturnTheSameLink() { when(link.getUrl()).thenReturn(url); List links = Collections.singletonList(link); - assertThat(EpisodeUtil.episodeSupport(links), equalTo(url)); + assertThat(EpisodeUtil.INSTANCE.episodeSupport(links), equalTo(url)); } @Test @@ -56,7 +56,7 @@ public void episodeSupport_givenCrunchyrollAndFeedUrl_shouldReturnEither() { when(link2.getUrl()).thenReturn(feedUrl); List links = Arrays.asList(link1, link2); - assertThat(EpisodeUtil.episodeSupport(links), + assertThat(EpisodeUtil.INSTANCE.episodeSupport(links), is(anyOf( equalTo(show + ".rss"), equalTo(feedUrl) @@ -75,6 +75,6 @@ public void episodeSupport_notGivenASupportedLink_shouldReturnNull() { when(link2.getUrl()).thenReturn(twitter); List links = Arrays.asList(link1, link2); - assertThat(EpisodeUtil.episodeSupport(links), nullValue()); + assertThat(EpisodeUtil.INSTANCE.episodeSupport(links), nullValue()); } } \ No newline at end of file diff --git a/app/src/test/java/com/mxt/anitrend/util/EpisodeUtil_GetActualTitleTest.java b/app/src/test/java/com/mxt/anitrend/util/EpisodeUtil_GetActualTitleTest.java index f173fd150..09fbe7dec 100644 --- a/app/src/test/java/com/mxt/anitrend/util/EpisodeUtil_GetActualTitleTest.java +++ b/app/src/test/java/com/mxt/anitrend/util/EpisodeUtil_GetActualTitleTest.java @@ -30,7 +30,7 @@ public static Iterable data() { @Test public void getActualTile() { - assertThat(EpisodeUtil.getActualTile(inputTitle), equalTo(actualTitle)); + assertThat(EpisodeUtil.INSTANCE.getActualTile(inputTitle), equalTo(actualTitle)); } } diff --git a/app/src/test/java/com/mxt/anitrend/util/RegexUtilTests.java b/app/src/test/java/com/mxt/anitrend/util/RegexUtilTests.java index b80fd644c..db237b272 100644 --- a/app/src/test/java/com/mxt/anitrend/util/RegexUtilTests.java +++ b/app/src/test/java/com/mxt/anitrend/util/RegexUtilTests.java @@ -91,6 +91,31 @@ public void getYoutubeThumb() { assertEquals(expected, result); result = RegexUtil.INSTANCE.getYoutubeThumb("https://data.whicdn.com/images/107659661/original.gif"); - assertEquals(RegexUtil.INSTANCE.getNO_THUMBNAIL(), result); + assertEquals(RegexUtil.NO_THUMBNAIL, result); + } + + @Test + public void findUserTags() { + String input = "img(https://cdn.discordapp.com/attachments/317768562620235776/525201025393754112/Anitrend.png)\n" + + "\n" + + "__The AniTrend Family__ by @Signi58\n" + + "\n" + + "Top Left -> @YouseffHabri | Top Right -> @Lionirdeadman \n" + + "Middle Left -> @Swap | Middle _who else??_ | Middle Right -> @Mokacchi\n" + + "Bottom Left -> @Signi58 | Bottom Right @Taichikuji\n" + + "\n" + + "Feel jealous yet <3"; + String actual = RegexUtil.INSTANCE.findUserTags(input); + + String expected = "img(https://cdn.discordapp.com/attachments/317768562620235776/525201025393754112/Anitrend.png)\n" + + "\n" + + "__The AniTrend Family__ by __[@Signi58](https://anilist.co/user/Signi58)__\n" + + "\n" + + "Top Left -> __[@YouseffHabri](https://anilist.co/user/YouseffHabri)__ | Top Right -> __[@Lionirdeadman](https://anilist.co/user/Lionirdeadman)__ \n" + + "Middle Left -> __[@Swap](https://anilist.co/user/Swap)__ | Middle _who else??_ | Middle Right -> __[@Mokacchi](https://anilist.co/user/Mokacchi)__\n" + + "Bottom Left -> __[@Signi58](https://anilist.co/user/Signi58)__ | Bottom Right __[@Taichikuji](https://anilist.co/user/Taichikuji)__\n" + + "\n" + + "Feel jealous yet <3"; + assertEquals(expected, actual); } } \ No newline at end of file From f52563ee59ce2468470a8053246468741fedd00e Mon Sep 17 00:00:00 2001 From: Maxwell Date: Sun, 12 May 2019 20:45:31 +0200 Subject: [PATCH 07/17] Added GraphQL Configuration Files --- app/.graphqlconfig | 15 + app/schema.graphql | 3897 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 3912 insertions(+) create mode 100644 app/.graphqlconfig create mode 100644 app/schema.graphql diff --git a/app/.graphqlconfig b/app/.graphqlconfig new file mode 100644 index 000000000..630839748 --- /dev/null +++ b/app/.graphqlconfig @@ -0,0 +1,15 @@ +{ + "name": "AniList GraphQL Schema", + "schemaPath": "schema.graphql", + "extensions": { + "endpoints": { + "Default GraphQL Endpoint": { + "url": "https://graphql.anilist.co", + "headers": { + "user-agent": "JS GraphQL" + }, + "introspect": true + } + } + } +} \ No newline at end of file diff --git a/app/schema.graphql b/app/schema.graphql new file mode 100644 index 000000000..a93faaefd --- /dev/null +++ b/app/schema.graphql @@ -0,0 +1,3897 @@ +# This file was generated based on ".graphqlconfig". Do not edit manually. + +schema { + query: Query + mutation: Mutation +} + +"Activity union type" +union ActivityUnion = ListActivity | MessageActivity | TextActivity + +"Notification union type" +union NotificationUnion = ActivityLikeNotification | ActivityMentionNotification | ActivityMessageNotification | ActivityReplyLikeNotification | ActivityReplyNotification | ActivityReplySubscribedNotification | AiringNotification | FollowingNotification | RelatedMediaAdditionNotification | ThreadCommentLikeNotification | ThreadCommentMentionNotification | ThreadCommentReplyNotification | ThreadCommentSubscribedNotification | ThreadLikeNotification + +"Notification for when a activity is liked" +type ActivityLikeNotification { + "The liked activity" + activity: ActivityUnion + "The id of the activity which was liked" + activityId: Int! + "The notification context text" + context: String + "The time the notification was created at" + createdAt: Int + "The id of the Notification" + id: Int! + "The type of notification" + type: NotificationType + "The user who liked the activity" + user: User + "The id of the user who liked to the activity" + userId: Int! +} + +"Notification for when authenticated user is @ mentioned in activity or reply" +type ActivityMentionNotification { + "The liked activity" + activity: ActivityUnion + "The id of the activity where mentioned" + activityId: Int! + "The notification context text" + context: String + "The time the notification was created at" + createdAt: Int + "The id of the Notification" + id: Int! + "The type of notification" + type: NotificationType + "The user who mentioned the authenticated user" + user: User + "The id of the user who mentioned the authenticated user" + userId: Int! +} + +"Notification for when a user is send an activity message" +type ActivityMessageNotification { + "The id of the activity message" + activityId: Int! + "The notification context text" + context: String + "The time the notification was created at" + createdAt: Int + "The id of the Notification" + id: Int! + "The message activity" + message: MessageActivity + "The type of notification" + type: NotificationType + "The user who sent the message" + user: User + "The if of the user who send the message" + userId: Int! +} + +"Replay to an activity item" +type ActivityReply { + "The id of the parent activity" + activityId: Int + "The time the reply was created at" + createdAt: Int! + "The id of the reply" + id: Int! + "The users who liked the reply" + likes: [User] + "The reply text" + text( + #Return the string in pre-parsed html instead of markdown + asHtml: Boolean + ): String + "The user who created reply" + user: User + "The id of the replies creator" + userId: Int +} + +"Notification for when a activity reply is liked" +type ActivityReplyLikeNotification { + "The liked activity" + activity: ActivityUnion + "The id of the activity where the reply which was liked" + activityId: Int! + "The notification context text" + context: String + "The time the notification was created at" + createdAt: Int + "The id of the Notification" + id: Int! + "The type of notification" + type: NotificationType + "The user who liked the activity reply" + user: User + "The id of the user who liked to the activity reply" + userId: Int! +} + +"Notification for when a user replies to the authenticated users activity" +type ActivityReplyNotification { + "The liked activity" + activity: ActivityUnion + "The id of the activity which was replied too" + activityId: Int! + "The notification context text" + context: String + "The time the notification was created at" + createdAt: Int + "The id of the Notification" + id: Int! + "The type of notification" + type: NotificationType + "The user who replied to the activity" + user: User + "The id of the user who replied to the activity" + userId: Int! +} + +"Notification for when a user replies to activity the authenticated user has replied to" +type ActivityReplySubscribedNotification { + "The liked activity" + activity: ActivityUnion + "The id of the activity which was replied too" + activityId: Int! + "The notification context text" + context: String + "The time the notification was created at" + createdAt: Int + "The id of the Notification" + id: Int! + "The type of notification" + type: NotificationType + "The user who replied to the activity" + user: User + "The id of the user who replied to the activity" + userId: Int! +} + +"Notification for when an episode of anime airs" +type AiringNotification { + "The id of the aired anime" + animeId: Int! + "The notification context text" + contexts: [String] + "The time the notification was created at" + createdAt: Int + "The episode number that just aired" + episode: Int! + "The id of the Notification" + id: Int! + "The associated media of the airing schedule" + media: Media + "The type of notification" + type: NotificationType +} + +"Score & Watcher stats for airing anime by episode and mid-week" +type AiringProgression { + "The episode the stats were recorded at. .5 is the mid point between 2 episodes airing dates." + episode: Float + "The average score for the media" + score: Float + "The amount of users watching the anime" + watching: Int +} + +"Media Airing Schedule" +type AiringSchedule { + "The time the episode airs at" + airingAt: Int! + "The airing episode number" + episode: Int! + "The id of the airing schedule item" + id: Int! + "The associate media of the airing episode" + media: Media + "The associate media id of the airing episode" + mediaId: Int! + "Seconds until episode starts airing" + timeUntilAiring: Int! +} + +type AiringScheduleConnection { + edges: [AiringScheduleEdge] + nodes: [AiringSchedule] + "The pagination information" + pageInfo: PageInfo +} + +"AiringSchedule connection edge" +type AiringScheduleEdge { + "The id of the connection" + id: Int + node: AiringSchedule +} + +type AniChartUser { + highlights: Json + settings: Json + user: User +} + +"A character that features in an anime or manga" +type Character { + "A general description of the character" + description( + #Return the string in pre-parsed html instead of markdown + asHtml: Boolean + ): String + "The amount of user's who have favourited the character" + favourites: Int + "The id of the character" + id: Int! + "Character images" + image: CharacterImage + "If the character is marked as favourite by the currently authenticated user" + isFavourite: Boolean! + "Media that includes the character" + media( + #The page + page: Int, + #The amount of entries per page, max 25 + perPage: Int, + sort: [MediaSort], + type: MediaType + ): MediaConnection + "The names of the character" + name: CharacterName + "The url for the character page on the AniList website" + siteUrl: String + "When the character's data was last updated" + updatedAt: Int +} + +type CharacterConnection { + edges: [CharacterEdge] + nodes: [Character] + "The pagination information" + pageInfo: PageInfo +} + +"Character connection edge" +type CharacterEdge { + "The order the character should be displayed from the users favourites" + favouriteOrder: Int + "The id of the connection" + id: Int + "The media the character is in" + media: [Media] + node: Character + "The characters role in the media" + role: CharacterRole + "The voice actors of the character" + voiceActors(language: StaffLanguage, sort: [StaffSort]): [Staff] +} + +type CharacterImage { + "The character's image of media at its largest size" + large: String + "The character's image of media at medium size" + medium: String +} + +"The names of the character" +type CharacterName { + "Other names the character might be referred to as" + alternative: [String] + "The character's given name" + first: String + "The character's surname" + last: String + "The character's full name in their native language" + native: String +} + +"A submission for a character that features in an anime or manga" +type CharacterSubmission { + "Character that the submission is referencing" + character: Character + createdAt: Int + "The id of the submission" + id: Int! + "Inner details of submission status" + notes: String + "Status of the submission" + status: SubmissionStatus + "The character submission changes" + submission: Character + "Submitter for the submission" + submitter: User +} + +type CharacterSubmissionConnection { + edges: [CharacterSubmissionEdge] + nodes: [CharacterSubmission] + "The pagination information" + pageInfo: PageInfo +} + +"CharacterSubmission connection edge" +type CharacterSubmissionEdge { + node: CharacterSubmission + "The characters role in the media" + role: CharacterRole + "The submitted voice actors of the character" + submittedVoiceActors: [StaffSubmission] + "The voice actors of the character" + voiceActors: [Staff] +} + +"Deleted data type" +type Deleted { + "If an item has been successfully deleted" + deleted: Boolean +} + +"User's favourite anime, manga, characters, staff & studios" +type Favourites { + "Favourite anime" + anime( + #The page number + page: Int, + #The amount of entries per page, max 25 + perPage: Int + ): MediaConnection + "Favourite characters" + characters( + #The page number + page: Int, + #The amount of entries per page, max 25 + perPage: Int + ): CharacterConnection + "Favourite manga" + manga( + #The page number + page: Int, + #The amount of entries per page, max 25 + perPage: Int + ): MediaConnection + "Favourite staff" + staff( + #The page number + page: Int, + #The amount of entries per page, max 25 + perPage: Int + ): StaffConnection + "Favourite studios" + studios( + #The page number + page: Int, + #The amount of entries per page, max 25 + perPage: Int + ): StudioConnection +} + +"Notification for when the authenticated user is followed by another user" +type FollowingNotification { + "The notification context text" + context: String + "The time the notification was created at" + createdAt: Int + "The id of the Notification" + id: Int! + "The type of notification" + type: NotificationType + "The liked activity" + user: User + "The id of the user who followed the authenticated user" + userId: Int! +} + +"User's format statistics" +type FormatStats { + amount: Int + format: MediaFormat +} + +"Date object that allows for incomplete date values (fuzzy)" +type FuzzyDate { + "Numeric Day (24)" + day: Int + "Numeric Month (3)" + month: Int + "Numeric Year (2017)" + year: Int +} + +"User's genre statistics" +type GenreStats { + amount: Int + genre: String + meanScore: Int + "The amount of time in minutes the genre has been watched by the user" + timeWatched: Int +} + +"Page of data (Used for internal use only)" +type InternalPage { + activities( + #Filter by the time the activity was created + createdAt: Int, + #Filter by the time the activity was created + createdAt_greater: Int, + #Filter by the time the activity was created + createdAt_lesser: Int, + #Filter activity to only activity with replies + hasReplies: Boolean, + #Filter activity to only activity with replies or is of type text + hasRepliesOrTypeText: Boolean, + #Filter by the activity id + id: Int, + #Filter by the activity id + id_in: [Int], + #Filter by the activity id + id_not: Int, + #Filter by the activity id + id_not_in: [Int], + #Filter activity to users who are being followed by the authenticated user + isFollowing: Boolean, + #Filter by the associated media id of the activity + mediaId: Int, + #Filter by the associated media id of the activity + mediaId_in: [Int], + #Filter by the associated media id of the activity + mediaId_not: Int, + #Filter by the associated media id of the activity + mediaId_not_in: [Int], + #Filter by the id of the user who sent a message + messengerId: Int, + #Filter by the id of the user who sent a message + messengerId_in: [Int], + #Filter by the id of the user who sent a message + messengerId_not: Int, + #Filter by the id of the user who sent a message + messengerId_not_in: [Int], + #The order the results will be returned in + sort: [ActivitySort], + #Filter by the type of activity + type: ActivityType, + #Filter by the type of activity + type_in: [ActivityType], + #Filter by the type of activity + type_not: ActivityType, + #Filter by the type of activity + type_not_in: [ActivityType], + #Filter by the owner user id + userId: Int, + #Filter by the owner user id + userId_in: [Int], + #Filter by the owner user id + userId_not: Int, + #Filter by the owner user id + userId_not_in: [Int] + ): [ActivityUnion] + activityReplies( + #Filter by the parent id + activityId: Int, + #Filter by the reply id + id: Int + ): [ActivityReply] + airingSchedules( + #Filter by the time of airing + airingAt: Int, + #Filter by the time of airing + airingAt_greater: Int, + #Filter by the time of airing + airingAt_lesser: Int, + #Filter by the airing episode number + episode: Int, + #Filter by the airing episode number + episode_greater: Int, + #Filter by the airing episode number + episode_in: [Int], + #Filter by the airing episode number + episode_lesser: Int, + #Filter by the airing episode number + episode_not: Int, + #Filter by the airing episode number + episode_not_in: [Int], + #Filter by the id of the airing schedule item + id: Int, + #Filter by the id of the airing schedule item + id_in: [Int], + #Filter by the id of the airing schedule item + id_not: Int, + #Filter by the id of the airing schedule item + id_not_in: [Int], + #Filter by the id of associated media + mediaId: Int, + #Filter by the id of associated media + mediaId_in: [Int], + #Filter by the id of associated media + mediaId_not: Int, + #Filter by the id of associated media + mediaId_not_in: [Int], + #Filter to episodes that haven't yet aired + notYetAired: Boolean, + #The order the results will be returned in + sort: [AiringSort] + ): [AiringSchedule] + characterSubmissions( + characterId: Int, + #Filter by the status of the submission + status: SubmissionStatus, + #Filter by the submitter of the submission + userId: Int + ): [CharacterSubmission] + characters( + #Filter by character id + id: Int, + #Filter by character id + id_in: [Int], + #Filter by character id + id_not: Int, + #Filter by character id + id_not_in: [Int], + #Filter by search query + search: String, + #The order the results will be returned in + sort: [CharacterSort] + ): [Character] + followers( + #The order the results will be returned in + sort: [UserSort], + #User id of the follower/followed + userId: Int! + ): [User] + following( + #The order the results will be returned in + sort: [UserSort], + #User id of the follower/followed + userId: Int! + ): [User] + media( + #Filter by the media's average score + averageScore: Int, + #Filter by the media's average score + averageScore_greater: Int, + #Filter by the media's average score + averageScore_lesser: Int, + #Filter by the media's average score + averageScore_not: Int, + #Filter by the media's chapter count + chapters: Int, + #Filter by the media's chapter count + chapters_greater: Int, + #Filter by the media's chapter count + chapters_lesser: Int, + #Filter by the media's country of origin + countryOfOrigin: CountryCode, + #Filter by the media's episode length + duration: Int, + #Filter by the media's episode length + duration_greater: Int, + #Filter by the media's episode length + duration_lesser: Int, + #Filter by the end date of the media + endDate: FuzzyDateInt, + #Filter by the end date of the media + endDate_greater: FuzzyDateInt, + #Filter by the end date of the media + endDate_lesser: FuzzyDateInt, + #Filter by the end date of the media + endDate_like: String, + #Filter by amount of episodes the media has + episodes: Int, + #Filter by amount of episodes the media has + episodes_greater: Int, + #Filter by amount of episodes the media has + episodes_lesser: Int, + #Filter by the media's format + format: MediaFormat, + #Filter by the media's format + format_in: [MediaFormat], + #Filter by the media's format + format_not: MediaFormat, + #Filter by the media's format + format_not_in: [MediaFormat], + #Filter by the media's genres + genre: String, + #Filter by the media's genres + genre_in: [String], + #Filter by the media's genres + genre_not_in: [String], + #Filter by the media id + id: Int, + #Filter by the media's MyAnimeList id + idMal: Int, + #Filter by the media's MyAnimeList id + idMal_in: [Int], + #Filter by the media's MyAnimeList id + idMal_not: Int, + #Filter by the media's MyAnimeList id + idMal_not_in: [Int], + #Filter by the media id + id_in: [Int], + #Filter by the media id + id_not: Int, + #Filter by the media id + id_not_in: [Int], + #Filter by if the media's intended for 18+ adult audiences + isAdult: Boolean, + #Filter media by sites with a online streaming or reading license + licensedBy: String, + #Filter media by sites with a online streaming or reading license + licensedBy_in: [String], + #Filter by the media on the authenticated user's lists + onList: Boolean, + #Filter by the number of users with this media on their list + popularity: Int, + #Filter by the number of users with this media on their list + popularity_greater: Int, + #Filter by the number of users with this media on their list + popularity_lesser: Int, + #Filter by the number of users with this media on their list + popularity_not: Int, + #Filter by search query + search: String, + #Filter by the season the media was released in + season: MediaSeason, + #The year of the season (Winter 2017 would also include December 2016 releases). Requires season argument + seasonYear: Int, + #The order the results will be returned in + sort: [MediaSort], + #Filter by the source type of the media + source: MediaSource, + #Filter by the source type of the media + source_in: [MediaSource], + #Filter by the start date of the media + startDate: FuzzyDateInt, + #Filter by the start date of the media + startDate_greater: FuzzyDateInt, + #Filter by the start date of the media + startDate_lesser: FuzzyDateInt, + #Filter by the start date of the media + startDate_like: String, + #Filter by the media's current release status + status: MediaStatus, + #Filter by the media's current release status + status_in: [MediaStatus], + #Filter by the media's current release status + status_not: MediaStatus, + #Filter by the media's current release status + status_not_in: [MediaStatus], + #Filter by the media's tags + tag: String, + #Filter by the media's tags with in a tag category + tagCategory: String, + #Filter by the media's tags with in a tag category + tagCategory_in: [String], + #Filter by the media's tags with in a tag category + tagCategory_not_in: [String], + #Filter by the media's tags + tag_in: [String], + #Filter by the media's tags + tag_not_in: [String], + #Filter by the media's type + type: MediaType, + #Filter by the media's volume count + volumes: Int, + #Filter by the media's volume count + volumes_greater: Int, + #Filter by the media's volume count + volumes_lesser: Int + ): [Media] + mediaList( + #Limit to only entries also on the auth user's list. Requires user id or name arguments. + compareWithAuthList: Boolean, + #Filter by the date the user completed the media + completedAt: FuzzyDateInt, + #Filter by the date the user completed the media + completedAt_greater: FuzzyDateInt, + #Filter by the date the user completed the media + completedAt_lesser: FuzzyDateInt, + #Filter by the date the user completed the media + completedAt_like: String, + #Filter by a list entry's id + id: Int, + #Filter list entries to users who are being followed by the authenticated user + isFollowing: Boolean, + #Filter by the media id of the list entry + mediaId: Int, + #Filter by note words and #tags + notes: String, + #Filter by note words and #tags + notes_like: String, + #The order the results will be returned in + sort: [MediaListSort], + #Filter by the date the user started the media + startedAt: FuzzyDateInt, + #Filter by the date the user started the media + startedAt_greater: FuzzyDateInt, + #Filter by the date the user started the media + startedAt_lesser: FuzzyDateInt, + #Filter by the date the user started the media + startedAt_like: String, + #Filter by the watching/reading status + status: MediaListStatus, + #Filter by the watching/reading status + status_in: [MediaListStatus], + #Filter by the watching/reading status + status_not: MediaListStatus, + #Filter by the watching/reading status + status_not_in: [MediaListStatus], + #Filter by the list entries media type + type: MediaType, + #Filter by a user's id + userId: Int, + #Filter by a user's id + userId_in: [Int], + #Filter by a user's name + userName: String + ): [MediaList] + mediaSubmissions( + mediaId: Int, + status: SubmissionStatus, + submissionId: Int, + #Filter by the media's type + type: MediaType, + userId: Int + ): [MediaSubmission] + mediaTrends( + #Filter by score + averageScore: Int, + #Filter by score + averageScore_greater: Int, + #Filter by score + averageScore_lesser: Int, + #Filter by score + averageScore_not: Int, + #Filter by date + date: Int, + #Filter by date + date_greater: Int, + #Filter by date + date_lesser: Int, + #Filter by episode number + episode: Int, + #Filter by episode number + episode_greater: Int, + #Filter by episode number + episode_lesser: Int, + #Filter by episode number + episode_not: Int, + #Filter by the media id + mediaId: Int, + #Filter by the media id + mediaId_in: [Int], + #Filter by the media id + mediaId_not: Int, + #Filter by the media id + mediaId_not_in: [Int], + #Filter by popularity + popularity: Int, + #Filter by popularity + popularity_greater: Int, + #Filter by popularity + popularity_lesser: Int, + #Filter by popularity + popularity_not: Int, + #Filter to stats recorded while the media was releasing + releasing: Boolean, + #The order the results will be returned in + sort: [MediaTrendSort], + #Filter by trending amount + trending: Int, + #Filter by trending amount + trending_greater: Int, + #Filter by trending amount + trending_lesser: Int, + #Filter by trending amount + trending_not: Int + ): [MediaTrend] + notifications( + #Reset the unread notification count to 0 on load + resetNotificationCount: Boolean, + #Filter by the type of notifications + type: NotificationType, + #Filter by the type of notifications + type_in: [NotificationType] + ): [NotificationUnion] + "The pagination information" + pageInfo: PageInfo + reports: [Report] + reviews( + #Filter by Review id + id: Int, + #Filter by media id + mediaId: Int, + #Filter by media type + mediaType: MediaType, + #The order the results will be returned in + sort: [ReviewSort], + #Filter by media id + userId: Int + ): [Review] + revisionHistory( + #Filter by the character id + characterId: Int, + #Filter by the media id + mediaId: Int, + #Filter by the staff id + staffId: Int, + #Filter by the studio id + studioId: Int, + #Filter by the user id + userId: Int + ): [RevisionHistory] + staff( + #Filter by the staff id + id: Int, + #Filter by the staff id + id_in: [Int], + #Filter by the staff id + id_not: Int, + #Filter by the staff id + id_not_in: [Int], + #Filter by search query + search: String, + #The order the results will be returned in + sort: [StaffSort] + ): [Staff] + staffSubmissions( + staffId: Int, + #Filter by the status of the submission + status: SubmissionStatus, + #Filter by the submitter of the submission + userId: Int + ): [StaffSubmission] + studios( + #Filter by the studio id + id: Int, + #Filter by the studio id + id_in: [Int], + #Filter by the studio id + id_not: Int, + #Filter by the studio id + id_not_in: [Int], + #Filter by search query + search: String, + #The order the results will be returned in + sort: [StudioSort] + ): [Studio] + threadComments( + #Filter by the comment id + id: Int, + #The order the results will be returned in + sort: [ThreadCommentSort], + #Filter by the thread id + threadId: Int, + #Filter by the user id of the comment's creator + userId: Int + ): [ThreadComment] + threads( + #Filter by thread category id + categoryId: Int, + #Filter by the thread id + id: Int, + #Filter by the thread id + id_in: [Int], + #Filter by thread media id category + mediaCategoryId: Int, + #Filter by the user id of the last user to comment on the thread + replyUserId: Int, + #Filter by search query + search: String, + #The order the results will be returned in + sort: [ThreadSort], + #Filter by if the currently authenticated user's subscribed threads + subscribed: Boolean, + #Filter by the user id of the thread's creator + userId: Int + ): [Thread] + users( + #Filter by the user id + id: Int, + #Filter by the name of the user + name: String, + #Filter by search query + search: String, + #The order the results will be returned in + sort: [UserSort] + ): [User] +} + +"User list activity (anime & manga updates)" +type ListActivity { + "The time the activity was created at" + createdAt: Int! + "The id of the activity" + id: Int! + "The users who liked the activity" + likes: [User] + "The associated media to the activity update" + media: Media + "The list progress made" + progress: String + "The written replies to the activity" + replies: [ActivityReply] + "The number of activity replies" + replyCount: Int! + "The url for the activity page on the AniList website" + siteUrl: String + "The list item's textual status" + status: String + "The type of activity" + type: ActivityType + "The owner of the activity" + user: User + "The user id of the activity's creator" + userId: Int +} + +"User's list score statistics" +type ListScoreStats { + meanScore: Int + standardDeviation: Int +} + +"Anime or Manga" +type Media { + "The media's entire airing schedule" + airingSchedule( + #Filter to episodes that have not yet aired + notYetAired: Boolean, + #The page + page: Int, + #The amount of entries per page, max 25 + perPage: Int + ): AiringScheduleConnection + "If the media should have forum thread automatically created for it on airing episode release" + autoCreateForumThread: Boolean + "A weighted average score of all the user's scores of the media" + averageScore: Int + "The banner image of the media" + bannerImage: String + "The amount of chapters the manga has when complete" + chapters: Int + "The characters in the media" + characters( + #The page + page: Int, + #The amount of entries per page, max 25 + perPage: Int, + role: CharacterRole, + sort: [CharacterSort] + ): CharacterConnection + "Where the media was created. (ISO 3166-1 alpha-2)" + countryOfOrigin: CountryCode + "The cover images of the media" + coverImage: MediaCoverImage + "Short description of the media's story and characters" + description( + #Return the string in pre-parsed html instead of markdown + asHtml: Boolean + ): String + "The general length of each anime episode in minutes" + duration: Int + "The last official release date of the media" + endDate: FuzzyDate + "The amount of episodes the anime has when complete" + episodes: Int + "External links to another site related to the media" + externalLinks: [MediaExternalLink] + "The amount of user's who have favourited the media" + favourites: Int + "The format the media was released in" + format: MediaFormat + "The genres of the media" + genres: [String] + "Official Twitter hashtags for the media" + hashtag: String + "The id of the media" + id: Int! + "The mal id of the media" + idMal: Int + "If the media is intended only for 18+ adult audiences" + isAdult: Boolean + "If the media is marked as favourite by the current authenticated user" + isFavourite: Boolean! + "If the media is officially licensed or a self-published doujin release" + isLicensed: Boolean + "Locked media may not be added to lists our favorited. This may be due to the entry pending for deletion or other reasons." + isLocked: Boolean + "Mean score of all the user's scores of the media" + meanScore: Int + "The authenticated user's media list entry for the media" + mediaListEntry: MediaList + "Notes for site moderators" + modNotes: String + "The media's next episode airing schedule" + nextAiringEpisode: AiringSchedule + "The number of users with the media on their list" + popularity: Int + "The ranking of the media in a particular time span and format compared to other media" + rankings: [MediaRank] + "Other media in the same or connecting franchise" + relations: MediaConnection + "User reviews of the media" + reviews( + limit: Int, + #The page + page: Int, + #The amount of entries per page, max 25 + perPage: Int, + sort: [ReviewSort] + ): ReviewConnection + "The year & season the media was initially released in" + season: MediaSeason + "The year & season the media was initially released in" + seasonInt: Int + "The url for the media page on the AniList website" + siteUrl: String + "Source type the media was adapted from." + source( + #Provide 2 to use new version 2 of sources enum + version: Int + ): MediaSource + "The staff who produced the media" + staff( + #The page + page: Int, + #The amount of entries per page, max 25 + perPage: Int, + sort: [StaffSort] + ): StaffConnection + "The first official release date of the media" + startDate: FuzzyDate + stats: MediaStats + "The current releasing status of the media" + status: MediaStatus + "Data and links to legal streaming episodes on external sites" + streamingEpisodes: [MediaStreamingEpisode] + "The companies who produced the media" + studios(isMain: Boolean, sort: [StudioSort]): StudioConnection + "Alternative titles of the media" + synonyms: [String] + "List of tags that describes elements and themes of the media" + tags: [MediaTag] + "The official titles of the media in various languages" + title: MediaTitle + "Media trailer or advertisement" + trailer: MediaTrailer + "The amount of related activity in the past hour" + trending: Int + "The media's daily trend stats" + trends( + #The page + page: Int, + #The amount of entries per page, max 25 + perPage: Int, + #Filter to stats recorded while the media was releasing + releasing: Boolean, + sort: [MediaTrendSort] + ): MediaTrendConnection + "The type of the media; anime or manga" + type: MediaType + "When the media's data was last updated" + updatedAt: Int + "The amount of volumes the manga has when complete" + volumes: Int +} + +"Internal - Media characters separated" +type MediaCharacter { + "The characters in the media voiced by the parent actor" + character: Character + "The id of the connection" + id: Int + "The characters role in the media" + role: CharacterRole + "The voice actor of the character" + voiceActor: Staff +} + +type MediaConnection { + edges: [MediaEdge] + nodes: [Media] + "The pagination information" + pageInfo: PageInfo +} + +type MediaCoverImage { + "Average #hex color of cover image" + color: String + "The cover image url of the media at its largest size. If this size isn't available, large will be provided instead." + extraLarge: String + "The cover image url of the media at a large size" + large: String + "The cover image url of the media at medium size" + medium: String +} + +"Media connection edge" +type MediaEdge { + "The characters role in the media" + characterRole: CharacterRole + "The characters in the media voiced by the parent actor" + characters: [Character] + "The order the media should be displayed from the users favourites" + favouriteOrder: Int + "The id of the connection" + id: Int + "If the studio is the main animation studio of the media (For Studio->MediaConnection field only)" + isMainStudio: Boolean! + node: Media + "The type of relation to the parent model" + relationType( + #Provide 2 to use new version 2 of relation enum + version: Int + ): MediaRelation + "The role of the staff member in the production of the media" + staffRole: String + "The voice actors of the character" + voiceActors(language: StaffLanguage, sort: [StaffSort]): [Staff] +} + +"An external link to another site related to the media" +type MediaExternalLink { + "The id of the external link" + id: Int! + "The site location of the external link" + site: String! + "The url of the external link" + url: String! +} + +"List of anime or manga" +type MediaList { + "Map of advanced scores with name keys" + advancedScores: Json + "When the entry was completed by the user" + completedAt: FuzzyDate + "When the entry data was created" + createdAt: Int + "Map of booleans for which custom lists the entry are in" + customLists( + #Change return structure to an array of objects + asArray: Boolean + ): Json + "If the entry shown be hidden from non-custom lists" + hiddenFromStatusLists: Boolean + "The id of the list entry" + id: Int! + media: Media + "The id of the media" + mediaId: Int! + "Text notes" + notes: String + "Priority of planning" + priority: Int + "If the entry should only be visible to authenticated user" + private: Boolean + "The amount of episodes/chapters consumed by the user" + progress: Int + "The amount of volumes read by the user" + progressVolumes: Int + "The amount of times the user has rewatched/read the media" + repeat: Int + "The score of the entry" + score( + #Force the score to be returned in the provided format type. + format: ScoreFormat + ): Float + "When the entry was started by the user" + startedAt: FuzzyDate + "The watching/reading status" + status: MediaListStatus + "When the entry data was last updated" + updatedAt: Int + user: User + "The id of the user owner of the list entry" + userId: Int! +} + +"List of anime or manga" +type MediaListCollection { + "A map of media list entry arrays grouped by custom lists" + customLists(asArray: Boolean): [[MediaList]] @deprecated(reason : "Not GraphQL spec compliant, use lists field instead.") + "If there is another chunk" + hasNextChunk: Boolean + "Grouped media list entries" + lists: [MediaListGroup] + "A map of media list entry arrays grouped by status" + statusLists(asArray: Boolean): [[MediaList]] @deprecated(reason : "Not GraphQL spec compliant, use lists field instead.") + "The owner of the list" + user: User +} + +"List group of anime or manga entries" +type MediaListGroup { + "Media list entries" + entries: [MediaList] + isCustomList: Boolean + isSplitCompletedList: Boolean + name: String + status: MediaListStatus +} + +"A user's list options" +type MediaListOptions { + "The user's anime list options" + animeList: MediaListTypeOptions + "The user's manga list options" + mangaList: MediaListTypeOptions + "The default order list rows should be displayed in" + rowOrder: String + "The score format the user is using for media lists" + scoreFormat: ScoreFormat + "The list theme options for both lists" + sharedTheme: Json @deprecated(reason : "This field has not yet been fully implemented and may change without warning") + "If the shared theme should be used instead of the individual list themes" + sharedThemeEnabled: Boolean @deprecated(reason : "This field has not yet been fully implemented and may change without warning") + "(Site only) If the user should be using legacy css-supporting list versions" + useLegacyLists: Boolean +} + +"A user's list options for anime or manga lists" +type MediaListTypeOptions { + "The names of the user's advanced scoring sections" + advancedScoring: [String] + "If advanced scoring is enabled" + advancedScoringEnabled: Boolean + "The names of the user's custom lists" + customLists: [String] + "The order each list should be displayed in" + sectionOrder: [String] + "If the completed sections of the list should be separated by format" + splitCompletedSectionByFormat: Boolean + "The list theme options" + theme: Json @deprecated(reason : "This field has not yet been fully implemented and may change without warning") +} + +"The ranking of a media in a particular time span and format compared to other media" +type MediaRank { + "If the ranking is based on all time instead of a season/year" + allTime: Boolean + "String that gives context to the ranking type and time span" + context: String! + "The format the media is ranked within" + format: MediaFormat! + "The id of the rank" + id: Int! + "The numerical rank of the media" + rank: Int! + "The season the media is ranked within" + season: MediaSeason + "The type of ranking" + type: MediaRankType! + "The year the media is ranked within" + year: Int +} + +"A media's statistics" +type MediaStats { + airingProgression: [AiringProgression] @deprecated(reason : "Replaced by MediaTrends") + scoreDistribution: [ScoreDistribution] + statusDistribution: [StatusDistribution] +} + +"Data and links to legal streaming episodes on external sites" +type MediaStreamingEpisode { + "The site location of the streaming episodes" + site: String + "Url of episode image thumbnail" + thumbnail: String + "Title of the episode" + title: String + "The url of the episode" + url: String +} + +"Media submission" +type MediaSubmission { + changes: [String] + characters: [MediaSubmissionComparison] + createdAt: Int + externalLinks: [MediaExternalLink] + "The id of the submission" + id: Int! + media: Media + notes: String + relations: [MediaEdge] + source: String + staff: [MediaSubmissionComparison] + "Status of the submission" + status: SubmissionStatus + studios: [MediaSubmissionComparison] + submission: Media + "User submitter of the submission" + submitter: User + submitterStats: Json +} + +"Media submission with comparison to current data" +type MediaSubmissionComparison { + character: MediaCharacter + staff: StaffEdge + studio: StudioEdge + submission: MediaSubmissionEdge +} + +type MediaSubmissionEdge { + character: Character + characterRole: CharacterRole + characterSubmission: Character + "The id of the direct submission" + id: Int + isMain: Boolean + media: Media + staff: Staff + staffRole: String + staffSubmission: Staff + studio: Studio + voiceActor: Staff + voiceActorSubmission: Staff +} + +"A tag that describes a theme or element of the media" +type MediaTag { + "The categories of tags this tag belongs to" + category: String + "A general description of the tag" + description: String + "The id of the tag" + id: Int! + "If the tag is only for adult 18+ media" + isAdult: Boolean + "If the tag could be a spoiler for any media" + isGeneralSpoiler: Boolean + "If the tag is a spoiler for this media" + isMediaSpoiler: Boolean + "The name of the tag" + name: String! + "The relevance ranking of the tag out of the 100 for this media" + rank: Int +} + +"The official titles of the media in various languages" +type MediaTitle { + "The official english title" + english(stylised: Boolean): String + "Official title in it's native language" + native(stylised: Boolean): String + "The romanization of the native language title" + romaji(stylised: Boolean): String + "The currently authenticated users preferred title language. Default romaji for non-authenticated" + userPreferred: String +} + +"Media trailer or advertisement" +type MediaTrailer { + "The trailer video id" + id: String + "The site the video is hosted by (Currently either youtube or dailymotion)" + site: String + "The url for the thumbnail image of the video" + thumbnail: String +} + +"Daily media statistics" +type MediaTrend { + "A weighted average score of all the user's scores of the media" + averageScore: Int + "The day the data was recorded (timestamp)" + date: Int! + "The episode number of the anime released on this day" + episode: Int + "The number of users with watching/reading the media" + inProgress: Int + "The related media" + media: Media + "The id of the tag" + mediaId: Int! + "The number of users with the media on their list" + popularity: Int + "If the media was being released at this time" + releasing: Boolean! + "The amount of media activity on the day" + trending: Int! +} + +type MediaTrendConnection { + edges: [MediaTrendEdge] + nodes: [MediaTrend] + "The pagination information" + pageInfo: PageInfo +} + +"Media trend connection edge" +type MediaTrendEdge { + node: MediaTrend +} + +"User message activity" +type MessageActivity { + "The time the activity was created at" + createdAt: Int! + "The id of the activity" + id: Int! + "The users who liked the activity" + likes: [User] + "The message text (Markdown)" + message( + #Return the string in pre-parsed html instead of markdown + asHtml: Boolean + ): String + "The user who sent the activity message" + messenger: User + "The user id of the activity's sender" + messengerId: Int + "The user who the activity message was sent to" + recipient: User + "The user id of the activity's recipient" + recipientId: Int + "The written replies to the activity" + replies: [ActivityReply] + "The number of activity replies" + replyCount: Int! + "The url for the activity page on the AniList website" + siteUrl: String + "The type of the activity" + type: ActivityType +} + +type Mutation { + "Delete an activity item of the authenticated users" + DeleteActivity( + #The id of the activity to delete + id: Int + ): Deleted + "Delete an activity reply of the authenticated users" + DeleteActivityReply( + #The id of the reply to delete + id: Int + ): Deleted + "Delete a custom list and remove the list entries from it" + DeleteCustomList( + #The name of the custom list to delete + customList: String, + #The media list type of the custom list + type: MediaType + ): Deleted + "Delete a media list entry" + DeleteMediaListEntry( + #The id of the media list entry to delete + id: Int + ): Deleted + "Delete a review" + DeleteReview( + #The id of the review to delete + id: Int + ): Deleted + "Delete a thread" + DeleteThread( + #The id of the thread to delete + id: Int + ): Deleted + "Delete a thread comment" + DeleteThreadComment( + #The id of the thread comment to delete + id: Int + ): Deleted + "Rate a review" + RateReview( + #The rating to apply to the review + rating: ReviewRating, + #The id of the review to rate + reviewId: Int + ): Review + "Create or update an activity reply" + SaveActivityReply( + #The id of the parent activity being replied to + activityId: Int, + #The activity reply id, required for updating + id: Int, + #The reply text + text: String + ): ActivityReply + "Create or update a media list entry" + SaveMediaListEntry( + #Array of advanced scores + advancedScores: [Float], + #When the entry was completed by the user + completedAt: FuzzyDateInput, + #Array of custom list names which should be enabled for this entry + customLists: [String], + #If the entry shown be hidden from non-custom lists + hiddenFromStatusLists: Boolean, + #The list entry id, required for updating + id: Int, + #The id of the media the entry is of + mediaId: Int, + #Text notes + notes: String, + #Priority of planning + priority: Int, + #If the entry should only be visible to authenticated user + private: Boolean, + #The amount of episodes/chapters consumed by the user + progress: Int, + #The amount of volumes read by the user + progressVolumes: Int, + #The amount of times the user has rewatched/read the media + repeat: Int, + #The score of the media in the user's chosen scoring method + score: Float, + #The score of the media in 100 point + scoreRaw: Int, + #When the entry was started by the user + startedAt: FuzzyDateInput, + #The watching/reading status + status: MediaListStatus + ): MediaList + "Create or update message activity for the currently authenticated user" + SaveMessageActivity( + #The activity id, required for updating + id: Int, + #The activity message text + message: String, + #The id of the user the message is being sent to + recipientId: Int + ): MessageActivity + "Create or update a review" + SaveReview( + #The main review text. Min:2200 characters + body: String, + #The review id, required for updating + id: Int, + #The id of the media the review is of + mediaId: Int, + #If the review should only be visible to its creator + private: Boolean, + #A short summary/preview of the review. Min:20, Max:120 characters + score: Int, + #A short summary/preview of the review. Min:20, Max:120 characters + summary: String + ): Review + "Create or update text activity for the currently authenticated user" + SaveTextActivity( + #The activity's id, required for updating + id: Int, + #The activity text + text: String + ): TextActivity + "Create or update a forum thread" + SaveThread( + #The main text body of the thread + body: String, + #Forum categories the thread should be within + categories: [Int], + #The thread id, required for updating + id: Int, + #If the thread should be locked. (Mod Only) + locked: Boolean, + #Media related to the contents of the thread + mediaCategories: [Int], + #If the thread should be stickied. (Mod Only) + sticky: Boolean, + #The title of the thread + title: String + ): Thread + "Create or update a thread comment" + SaveThreadComment( + #The comment markdown text + comment: String, + #The comment id, required for updating + id: Int, + #The id of thread comment to reply to + parentCommentId: Int, + #The id of thread the comment belongs to + threadId: Int + ): ThreadComment + "Favourite or unfavourite an anime, manga, character, staff member, or studio" + ToggleFavourite( + #The id of the anime to un/favourite + animeId: Int, + #The id of the character to un/favourite + characterId: Int, + #The id of the manga to un/favourite + mangaId: Int, + #The id of the staff to un/favourite + staffId: Int, + #The id of the studio to un/favourite + studioId: Int + ): Favourites + "Toggle the un/following of a user" + ToggleFollow( + #The id of the user to un/follow + userId: Int + ): User + """ + Add or remove a like from a likeable type. + Returns all the users who liked the same model + """ + ToggleLike( + #The id of the likeable type + id: Int, + #The type of model to be un/liked + type: LikeableType + ): [User] + "Toggle the subscription of a forum thread" + ToggleThreadSubscription( + #Whether to subscribe or unsubscribe from the forum thread + subscribe: Boolean, + #The id of the forum thread to un/subscribe + threadId: Int + ): Thread + UpdateAniChartHighlights(highlights: [AniChartHighlightInput]): Json + UpdateAniChartSettings(outgoingLinkProvider: String, sort: String, theme: String, titleLanguage: String): Json + "Update the order favourites are displayed in" + UpdateFavouriteOrder( + #The id of the anime to un/favourite + animeIds: [Int], + #List of integers which the anime should be ordered by (Asc) + animeOrder: [Int], + #The id of the character to un/favourite + characterIds: [Int], + #List of integers which the character should be ordered by (Asc) + characterOrder: [Int], + #The id of the manga to un/favourite + mangaIds: [Int], + #List of integers which the manga should be ordered by (Asc) + mangaOrder: [Int], + #The id of the staff to un/favourite + staffIds: [Int], + #List of integers which the staff should be ordered by (Asc) + staffOrder: [Int], + #The id of the studio to un/favourite + studioIds: [Int], + #List of integers which the studio should be ordered by (Asc) + studioOrder: [Int] + ): Favourites + "Update multiple media list entries to the same values" + UpdateMediaListEntries( + #Array of advanced scores + advancedScores: [Float], + #When the entry was completed by the user + completedAt: FuzzyDateInput, + #If the entry shown be hidden from non-custom lists + hiddenFromStatusLists: Boolean, + #The list entries ids to update + ids: [Int], + #Text notes + notes: String, + #Priority of planning + priority: Int, + #If the entry should only be visible to authenticated user + private: Boolean, + #The amount of episodes/chapters consumed by the user + progress: Int, + #The amount of volumes read by the user + progressVolumes: Int, + #The amount of times the user has rewatched/read the media + repeat: Int, + #The score of the media in the user's chosen scoring method + score: Float, + #The score of the media in 100 point + scoreRaw: Int, + #When the entry was started by the user + startedAt: FuzzyDateInput, + #The watching/reading status + status: MediaListStatus + ): [MediaList] + UpdateUser( + #User's about/bio text + about: String, + #If the user should get notifications when a show they are watching aires + airingNotifications: Boolean, + #The user's anime list options + animeListOptions: MediaListOptionsInput, + #If the user should see media marked as adult-only + displayAdultContent: Boolean, + #Profile highlight color + donatorBadge: String, + #The user's anime list options + mangaListOptions: MediaListOptionsInput, + #Notification options + notificationOptions: [NotificationOptionInput], + #Profile highlight color + profileColor: String, + #The user's default list order + rowOrder: String, + #The user's list scoring system + scoreFormat: ScoreFormat, + #User's title language + titleLanguage: UserTitleLanguage + ): User +} + +"Notification option" +type NotificationOption { + "Whether this type of notification is enabled" + enabled: Boolean + "The type of notification" + type: NotificationType +} + +"Page of data" +type Page { + activities( + #Filter by the time the activity was created + createdAt: Int, + #Filter by the time the activity was created + createdAt_greater: Int, + #Filter by the time the activity was created + createdAt_lesser: Int, + #Filter activity to only activity with replies + hasReplies: Boolean, + #Filter activity to only activity with replies or is of type text + hasRepliesOrTypeText: Boolean, + #Filter by the activity id + id: Int, + #Filter by the activity id + id_in: [Int], + #Filter by the activity id + id_not: Int, + #Filter by the activity id + id_not_in: [Int], + #Filter activity to users who are being followed by the authenticated user + isFollowing: Boolean, + #Filter by the associated media id of the activity + mediaId: Int, + #Filter by the associated media id of the activity + mediaId_in: [Int], + #Filter by the associated media id of the activity + mediaId_not: Int, + #Filter by the associated media id of the activity + mediaId_not_in: [Int], + #Filter by the id of the user who sent a message + messengerId: Int, + #Filter by the id of the user who sent a message + messengerId_in: [Int], + #Filter by the id of the user who sent a message + messengerId_not: Int, + #Filter by the id of the user who sent a message + messengerId_not_in: [Int], + #The order the results will be returned in + sort: [ActivitySort], + #Filter by the type of activity + type: ActivityType, + #Filter by the type of activity + type_in: [ActivityType], + #Filter by the type of activity + type_not: ActivityType, + #Filter by the type of activity + type_not_in: [ActivityType], + #Filter by the owner user id + userId: Int, + #Filter by the owner user id + userId_in: [Int], + #Filter by the owner user id + userId_not: Int, + #Filter by the owner user id + userId_not_in: [Int] + ): [ActivityUnion] + activityReplies( + #Filter by the parent id + activityId: Int, + #Filter by the reply id + id: Int + ): [ActivityReply] + airingSchedules( + #Filter by the time of airing + airingAt: Int, + #Filter by the time of airing + airingAt_greater: Int, + #Filter by the time of airing + airingAt_lesser: Int, + #Filter by the airing episode number + episode: Int, + #Filter by the airing episode number + episode_greater: Int, + #Filter by the airing episode number + episode_in: [Int], + #Filter by the airing episode number + episode_lesser: Int, + #Filter by the airing episode number + episode_not: Int, + #Filter by the airing episode number + episode_not_in: [Int], + #Filter by the id of the airing schedule item + id: Int, + #Filter by the id of the airing schedule item + id_in: [Int], + #Filter by the id of the airing schedule item + id_not: Int, + #Filter by the id of the airing schedule item + id_not_in: [Int], + #Filter by the id of associated media + mediaId: Int, + #Filter by the id of associated media + mediaId_in: [Int], + #Filter by the id of associated media + mediaId_not: Int, + #Filter by the id of associated media + mediaId_not_in: [Int], + #Filter to episodes that haven't yet aired + notYetAired: Boolean, + #The order the results will be returned in + sort: [AiringSort] + ): [AiringSchedule] + characters( + #Filter by character id + id: Int, + #Filter by character id + id_in: [Int], + #Filter by character id + id_not: Int, + #Filter by character id + id_not_in: [Int], + #Filter by search query + search: String, + #The order the results will be returned in + sort: [CharacterSort] + ): [Character] + followers( + #The order the results will be returned in + sort: [UserSort], + #User id of the follower/followed + userId: Int! + ): [User] + following( + #The order the results will be returned in + sort: [UserSort], + #User id of the follower/followed + userId: Int! + ): [User] + media( + #Filter by the media's average score + averageScore: Int, + #Filter by the media's average score + averageScore_greater: Int, + #Filter by the media's average score + averageScore_lesser: Int, + #Filter by the media's average score + averageScore_not: Int, + #Filter by the media's chapter count + chapters: Int, + #Filter by the media's chapter count + chapters_greater: Int, + #Filter by the media's chapter count + chapters_lesser: Int, + #Filter by the media's country of origin + countryOfOrigin: CountryCode, + #Filter by the media's episode length + duration: Int, + #Filter by the media's episode length + duration_greater: Int, + #Filter by the media's episode length + duration_lesser: Int, + #Filter by the end date of the media + endDate: FuzzyDateInt, + #Filter by the end date of the media + endDate_greater: FuzzyDateInt, + #Filter by the end date of the media + endDate_lesser: FuzzyDateInt, + #Filter by the end date of the media + endDate_like: String, + #Filter by amount of episodes the media has + episodes: Int, + #Filter by amount of episodes the media has + episodes_greater: Int, + #Filter by amount of episodes the media has + episodes_lesser: Int, + #Filter by the media's format + format: MediaFormat, + #Filter by the media's format + format_in: [MediaFormat], + #Filter by the media's format + format_not: MediaFormat, + #Filter by the media's format + format_not_in: [MediaFormat], + #Filter by the media's genres + genre: String, + #Filter by the media's genres + genre_in: [String], + #Filter by the media's genres + genre_not_in: [String], + #Filter by the media id + id: Int, + #Filter by the media's MyAnimeList id + idMal: Int, + #Filter by the media's MyAnimeList id + idMal_in: [Int], + #Filter by the media's MyAnimeList id + idMal_not: Int, + #Filter by the media's MyAnimeList id + idMal_not_in: [Int], + #Filter by the media id + id_in: [Int], + #Filter by the media id + id_not: Int, + #Filter by the media id + id_not_in: [Int], + #Filter by if the media's intended for 18+ adult audiences + isAdult: Boolean, + #Filter media by sites with a online streaming or reading license + licensedBy: String, + #Filter media by sites with a online streaming or reading license + licensedBy_in: [String], + #Filter by the media on the authenticated user's lists + onList: Boolean, + #Filter by the number of users with this media on their list + popularity: Int, + #Filter by the number of users with this media on their list + popularity_greater: Int, + #Filter by the number of users with this media on their list + popularity_lesser: Int, + #Filter by the number of users with this media on their list + popularity_not: Int, + #Filter by search query + search: String, + #Filter by the season the media was released in + season: MediaSeason, + #The year of the season (Winter 2017 would also include December 2016 releases). Requires season argument + seasonYear: Int, + #The order the results will be returned in + sort: [MediaSort], + #Filter by the source type of the media + source: MediaSource, + #Filter by the source type of the media + source_in: [MediaSource], + #Filter by the start date of the media + startDate: FuzzyDateInt, + #Filter by the start date of the media + startDate_greater: FuzzyDateInt, + #Filter by the start date of the media + startDate_lesser: FuzzyDateInt, + #Filter by the start date of the media + startDate_like: String, + #Filter by the media's current release status + status: MediaStatus, + #Filter by the media's current release status + status_in: [MediaStatus], + #Filter by the media's current release status + status_not: MediaStatus, + #Filter by the media's current release status + status_not_in: [MediaStatus], + #Filter by the media's tags + tag: String, + #Filter by the media's tags with in a tag category + tagCategory: String, + #Filter by the media's tags with in a tag category + tagCategory_in: [String], + #Filter by the media's tags with in a tag category + tagCategory_not_in: [String], + #Filter by the media's tags + tag_in: [String], + #Filter by the media's tags + tag_not_in: [String], + #Filter by the media's type + type: MediaType, + #Filter by the media's volume count + volumes: Int, + #Filter by the media's volume count + volumes_greater: Int, + #Filter by the media's volume count + volumes_lesser: Int + ): [Media] + mediaList( + #Limit to only entries also on the auth user's list. Requires user id or name arguments. + compareWithAuthList: Boolean, + #Filter by the date the user completed the media + completedAt: FuzzyDateInt, + #Filter by the date the user completed the media + completedAt_greater: FuzzyDateInt, + #Filter by the date the user completed the media + completedAt_lesser: FuzzyDateInt, + #Filter by the date the user completed the media + completedAt_like: String, + #Filter by a list entry's id + id: Int, + #Filter list entries to users who are being followed by the authenticated user + isFollowing: Boolean, + #Filter by the media id of the list entry + mediaId: Int, + #Filter by note words and #tags + notes: String, + #Filter by note words and #tags + notes_like: String, + #The order the results will be returned in + sort: [MediaListSort], + #Filter by the date the user started the media + startedAt: FuzzyDateInt, + #Filter by the date the user started the media + startedAt_greater: FuzzyDateInt, + #Filter by the date the user started the media + startedAt_lesser: FuzzyDateInt, + #Filter by the date the user started the media + startedAt_like: String, + #Filter by the watching/reading status + status: MediaListStatus, + #Filter by the watching/reading status + status_in: [MediaListStatus], + #Filter by the watching/reading status + status_not: MediaListStatus, + #Filter by the watching/reading status + status_not_in: [MediaListStatus], + #Filter by the list entries media type + type: MediaType, + #Filter by a user's id + userId: Int, + #Filter by a user's id + userId_in: [Int], + #Filter by a user's name + userName: String + ): [MediaList] + mediaTrends( + #Filter by score + averageScore: Int, + #Filter by score + averageScore_greater: Int, + #Filter by score + averageScore_lesser: Int, + #Filter by score + averageScore_not: Int, + #Filter by date + date: Int, + #Filter by date + date_greater: Int, + #Filter by date + date_lesser: Int, + #Filter by episode number + episode: Int, + #Filter by episode number + episode_greater: Int, + #Filter by episode number + episode_lesser: Int, + #Filter by episode number + episode_not: Int, + #Filter by the media id + mediaId: Int, + #Filter by the media id + mediaId_in: [Int], + #Filter by the media id + mediaId_not: Int, + #Filter by the media id + mediaId_not_in: [Int], + #Filter by popularity + popularity: Int, + #Filter by popularity + popularity_greater: Int, + #Filter by popularity + popularity_lesser: Int, + #Filter by popularity + popularity_not: Int, + #Filter to stats recorded while the media was releasing + releasing: Boolean, + #The order the results will be returned in + sort: [MediaTrendSort], + #Filter by trending amount + trending: Int, + #Filter by trending amount + trending_greater: Int, + #Filter by trending amount + trending_lesser: Int, + #Filter by trending amount + trending_not: Int + ): [MediaTrend] + notifications( + #Reset the unread notification count to 0 on load + resetNotificationCount: Boolean, + #Filter by the type of notifications + type: NotificationType, + #Filter by the type of notifications + type_in: [NotificationType] + ): [NotificationUnion] + "The pagination information" + pageInfo: PageInfo + reviews( + #Filter by Review id + id: Int, + #Filter by media id + mediaId: Int, + #Filter by media type + mediaType: MediaType, + #The order the results will be returned in + sort: [ReviewSort], + #Filter by media id + userId: Int + ): [Review] + staff( + #Filter by the staff id + id: Int, + #Filter by the staff id + id_in: [Int], + #Filter by the staff id + id_not: Int, + #Filter by the staff id + id_not_in: [Int], + #Filter by search query + search: String, + #The order the results will be returned in + sort: [StaffSort] + ): [Staff] + studios( + #Filter by the studio id + id: Int, + #Filter by the studio id + id_in: [Int], + #Filter by the studio id + id_not: Int, + #Filter by the studio id + id_not_in: [Int], + #Filter by search query + search: String, + #The order the results will be returned in + sort: [StudioSort] + ): [Studio] + threadComments( + #Filter by the comment id + id: Int, + #The order the results will be returned in + sort: [ThreadCommentSort], + #Filter by the thread id + threadId: Int, + #Filter by the user id of the comment's creator + userId: Int + ): [ThreadComment] + threads( + #Filter by thread category id + categoryId: Int, + #Filter by the thread id + id: Int, + #Filter by the thread id + id_in: [Int], + #Filter by thread media id category + mediaCategoryId: Int, + #Filter by the user id of the last user to comment on the thread + replyUserId: Int, + #Filter by search query + search: String, + #The order the results will be returned in + sort: [ThreadSort], + #Filter by if the currently authenticated user's subscribed threads + subscribed: Boolean, + #Filter by the user id of the thread's creator + userId: Int + ): [Thread] + users( + #Filter by the user id + id: Int, + #Filter by the name of the user + name: String, + #Filter by search query + search: String, + #The order the results will be returned in + sort: [UserSort] + ): [User] +} + +type PageInfo { + "The current page" + currentPage: Int + "If there is another page" + hasNextPage: Boolean + "The last page" + lastPage: Int + "The count on a page" + perPage: Int + "The total number of items" + total: Int +} + +"Provides the parsed markdown as html" +type ParsedMarkdown { + "The parsed markdown as html" + html: String +} + +type Query { + "Activity query" + Activity( + #Filter by the time the activity was created + createdAt: Int, + #Filter by the time the activity was created + createdAt_greater: Int, + #Filter by the time the activity was created + createdAt_lesser: Int, + #Filter activity to only activity with replies + hasReplies: Boolean, + #Filter activity to only activity with replies or is of type text + hasRepliesOrTypeText: Boolean, + #Filter by the activity id + id: Int, + #Filter by the activity id + id_in: [Int], + #Filter by the activity id + id_not: Int, + #Filter by the activity id + id_not_in: [Int], + #Filter activity to users who are being followed by the authenticated user + isFollowing: Boolean, + #Filter by the associated media id of the activity + mediaId: Int, + #Filter by the associated media id of the activity + mediaId_in: [Int], + #Filter by the associated media id of the activity + mediaId_not: Int, + #Filter by the associated media id of the activity + mediaId_not_in: [Int], + #Filter by the id of the user who sent a message + messengerId: Int, + #Filter by the id of the user who sent a message + messengerId_in: [Int], + #Filter by the id of the user who sent a message + messengerId_not: Int, + #Filter by the id of the user who sent a message + messengerId_not_in: [Int], + #The order the results will be returned in + sort: [ActivitySort], + #Filter by the type of activity + type: ActivityType, + #Filter by the type of activity + type_in: [ActivityType], + #Filter by the type of activity + type_not: ActivityType, + #Filter by the type of activity + type_not_in: [ActivityType], + #Filter by the owner user id + userId: Int, + #Filter by the owner user id + userId_in: [Int], + #Filter by the owner user id + userId_not: Int, + #Filter by the owner user id + userId_not_in: [Int] + ): ActivityUnion + "Activity reply query" + ActivityReply( + #Filter by the parent id + activityId: Int, + #Filter by the reply id + id: Int + ): ActivityReply + "Airing schedule query" + AiringSchedule( + #Filter by the time of airing + airingAt: Int, + #Filter by the time of airing + airingAt_greater: Int, + #Filter by the time of airing + airingAt_lesser: Int, + #Filter by the airing episode number + episode: Int, + #Filter by the airing episode number + episode_greater: Int, + #Filter by the airing episode number + episode_in: [Int], + #Filter by the airing episode number + episode_lesser: Int, + #Filter by the airing episode number + episode_not: Int, + #Filter by the airing episode number + episode_not_in: [Int], + #Filter by the id of the airing schedule item + id: Int, + #Filter by the id of the airing schedule item + id_in: [Int], + #Filter by the id of the airing schedule item + id_not: Int, + #Filter by the id of the airing schedule item + id_not_in: [Int], + #Filter by the id of associated media + mediaId: Int, + #Filter by the id of associated media + mediaId_in: [Int], + #Filter by the id of associated media + mediaId_not: Int, + #Filter by the id of associated media + mediaId_not_in: [Int], + #Filter to episodes that haven't yet aired + notYetAired: Boolean, + #The order the results will be returned in + sort: [AiringSort] + ): AiringSchedule + AniChartUser: AniChartUser + "Character query" + Character( + #Filter by character id + id: Int, + #Filter by character id + id_in: [Int], + #Filter by character id + id_not: Int, + #Filter by character id + id_not_in: [Int], + #Filter by search query + search: String, + #The order the results will be returned in + sort: [CharacterSort] + ): Character + "Follow query" + Follower( + #The order the results will be returned in + sort: [UserSort], + #User id of the follower/followed + userId: Int! + ): User + "Follow query" + Following( + #The order the results will be returned in + sort: [UserSort], + #User id of the follower/followed + userId: Int! + ): User + "Collection of all the possible media genres" + GenreCollection: [String] + "Provide AniList markdown to be converted to html (Requires auth)" + Markdown( + #The markdown to be parsed to html + markdown: String! + ): ParsedMarkdown + "Media query" + Media( + #Filter by the media's average score + averageScore: Int, + #Filter by the media's average score + averageScore_greater: Int, + #Filter by the media's average score + averageScore_lesser: Int, + #Filter by the media's average score + averageScore_not: Int, + #Filter by the media's chapter count + chapters: Int, + #Filter by the media's chapter count + chapters_greater: Int, + #Filter by the media's chapter count + chapters_lesser: Int, + #Filter by the media's country of origin + countryOfOrigin: CountryCode, + #Filter by the media's episode length + duration: Int, + #Filter by the media's episode length + duration_greater: Int, + #Filter by the media's episode length + duration_lesser: Int, + #Filter by the end date of the media + endDate: FuzzyDateInt, + #Filter by the end date of the media + endDate_greater: FuzzyDateInt, + #Filter by the end date of the media + endDate_lesser: FuzzyDateInt, + #Filter by the end date of the media + endDate_like: String, + #Filter by amount of episodes the media has + episodes: Int, + #Filter by amount of episodes the media has + episodes_greater: Int, + #Filter by amount of episodes the media has + episodes_lesser: Int, + #Filter by the media's format + format: MediaFormat, + #Filter by the media's format + format_in: [MediaFormat], + #Filter by the media's format + format_not: MediaFormat, + #Filter by the media's format + format_not_in: [MediaFormat], + #Filter by the media's genres + genre: String, + #Filter by the media's genres + genre_in: [String], + #Filter by the media's genres + genre_not_in: [String], + #Filter by the media id + id: Int, + #Filter by the media's MyAnimeList id + idMal: Int, + #Filter by the media's MyAnimeList id + idMal_in: [Int], + #Filter by the media's MyAnimeList id + idMal_not: Int, + #Filter by the media's MyAnimeList id + idMal_not_in: [Int], + #Filter by the media id + id_in: [Int], + #Filter by the media id + id_not: Int, + #Filter by the media id + id_not_in: [Int], + #Filter by if the media's intended for 18+ adult audiences + isAdult: Boolean, + #Filter media by sites with a online streaming or reading license + licensedBy: String, + #Filter media by sites with a online streaming or reading license + licensedBy_in: [String], + #Filter by the media on the authenticated user's lists + onList: Boolean, + #Filter by the number of users with this media on their list + popularity: Int, + #Filter by the number of users with this media on their list + popularity_greater: Int, + #Filter by the number of users with this media on their list + popularity_lesser: Int, + #Filter by the number of users with this media on their list + popularity_not: Int, + #Filter by search query + search: String, + #Filter by the season the media was released in + season: MediaSeason, + #The year of the season (Winter 2017 would also include December 2016 releases). Requires season argument + seasonYear: Int, + #The order the results will be returned in + sort: [MediaSort], + #Filter by the source type of the media + source: MediaSource, + #Filter by the source type of the media + source_in: [MediaSource], + #Filter by the start date of the media + startDate: FuzzyDateInt, + #Filter by the start date of the media + startDate_greater: FuzzyDateInt, + #Filter by the start date of the media + startDate_lesser: FuzzyDateInt, + #Filter by the start date of the media + startDate_like: String, + #Filter by the media's current release status + status: MediaStatus, + #Filter by the media's current release status + status_in: [MediaStatus], + #Filter by the media's current release status + status_not: MediaStatus, + #Filter by the media's current release status + status_not_in: [MediaStatus], + #Filter by the media's tags + tag: String, + #Filter by the media's tags with in a tag category + tagCategory: String, + #Filter by the media's tags with in a tag category + tagCategory_in: [String], + #Filter by the media's tags with in a tag category + tagCategory_not_in: [String], + #Filter by the media's tags + tag_in: [String], + #Filter by the media's tags + tag_not_in: [String], + #Filter by the media's type + type: MediaType, + #Filter by the media's volume count + volumes: Int, + #Filter by the media's volume count + volumes_greater: Int, + #Filter by the media's volume count + volumes_lesser: Int + ): Media + "Media list query" + MediaList( + #Limit to only entries also on the auth user's list. Requires user id or name arguments. + compareWithAuthList: Boolean, + #Filter by the date the user completed the media + completedAt: FuzzyDateInt, + #Filter by the date the user completed the media + completedAt_greater: FuzzyDateInt, + #Filter by the date the user completed the media + completedAt_lesser: FuzzyDateInt, + #Filter by the date the user completed the media + completedAt_like: String, + #Filter by a list entry's id + id: Int, + #Filter list entries to users who are being followed by the authenticated user + isFollowing: Boolean, + #Filter by the media id of the list entry + mediaId: Int, + #Filter by note words and #tags + notes: String, + #Filter by note words and #tags + notes_like: String, + #The order the results will be returned in + sort: [MediaListSort], + #Filter by the date the user started the media + startedAt: FuzzyDateInt, + #Filter by the date the user started the media + startedAt_greater: FuzzyDateInt, + #Filter by the date the user started the media + startedAt_lesser: FuzzyDateInt, + #Filter by the date the user started the media + startedAt_like: String, + #Filter by the watching/reading status + status: MediaListStatus, + #Filter by the watching/reading status + status_in: [MediaListStatus], + #Filter by the watching/reading status + status_not: MediaListStatus, + #Filter by the watching/reading status + status_not_in: [MediaListStatus], + #Filter by the list entries media type + type: MediaType, + #Filter by a user's id + userId: Int, + #Filter by a user's id + userId_in: [Int], + #Filter by a user's name + userName: String + ): MediaList + "Media list collection query, provides list pre-grouped by status & custom lists. User ID and Media Type arguments required." + MediaListCollection( + #Which chunk of list entries to load + chunk: Int, + #Filter by the date the user completed the media + completedAt: FuzzyDateInt, + #Filter by the date the user completed the media + completedAt_greater: FuzzyDateInt, + #Filter by the date the user completed the media + completedAt_lesser: FuzzyDateInt, + #Filter by the date the user completed the media + completedAt_like: String, + #Always return completed list entries in one group, overriding the user's split completed option. + forceSingleCompletedList: Boolean, + #Filter by note words and #tags + notes: String, + #Filter by note words and #tags + notes_like: String, + #The amount of entries per chunk, max 500 + perChunk: Int, + #The order the results will be returned in + sort: [MediaListSort], + #Filter by the date the user started the media + startedAt: FuzzyDateInt, + #Filter by the date the user started the media + startedAt_greater: FuzzyDateInt, + #Filter by the date the user started the media + startedAt_lesser: FuzzyDateInt, + #Filter by the date the user started the media + startedAt_like: String, + #Filter by the watching/reading status + status: MediaListStatus, + #Filter by the watching/reading status + status_in: [MediaListStatus], + #Filter by the watching/reading status + status_not: MediaListStatus, + #Filter by the watching/reading status + status_not_in: [MediaListStatus], + #Filter by the list entries media type + type: MediaType, + #Filter by a user's id + userId: Int, + #Filter by a user's name + userName: String + ): MediaListCollection + "Collection of all the possible media tags" + MediaTagCollection( + #Mod Only + status: Int + ): [MediaTag] + "Media Trend query" + MediaTrend( + #Filter by score + averageScore: Int, + #Filter by score + averageScore_greater: Int, + #Filter by score + averageScore_lesser: Int, + #Filter by score + averageScore_not: Int, + #Filter by date + date: Int, + #Filter by date + date_greater: Int, + #Filter by date + date_lesser: Int, + #Filter by episode number + episode: Int, + #Filter by episode number + episode_greater: Int, + #Filter by episode number + episode_lesser: Int, + #Filter by episode number + episode_not: Int, + #Filter by the media id + mediaId: Int, + #Filter by the media id + mediaId_in: [Int], + #Filter by the media id + mediaId_not: Int, + #Filter by the media id + mediaId_not_in: [Int], + #Filter by popularity + popularity: Int, + #Filter by popularity + popularity_greater: Int, + #Filter by popularity + popularity_lesser: Int, + #Filter by popularity + popularity_not: Int, + #Filter to stats recorded while the media was releasing + releasing: Boolean, + #The order the results will be returned in + sort: [MediaTrendSort], + #Filter by trending amount + trending: Int, + #Filter by trending amount + trending_greater: Int, + #Filter by trending amount + trending_lesser: Int, + #Filter by trending amount + trending_not: Int + ): MediaTrend + "Notification query" + Notification( + #Reset the unread notification count to 0 on load + resetNotificationCount: Boolean, + #Filter by the type of notifications + type: NotificationType, + #Filter by the type of notifications + type_in: [NotificationType] + ): NotificationUnion + Page( + #The page number + page: Int, + #The amount of entries per page, max 50 + perPage: Int + ): Page + "Review query" + Review( + #Filter by Review id + id: Int, + #Filter by media id + mediaId: Int, + #Filter by media type + mediaType: MediaType, + #The order the results will be returned in + sort: [ReviewSort], + #Filter by media id + userId: Int + ): Review + "Staff query" + Staff( + #Filter by the staff id + id: Int, + #Filter by the staff id + id_in: [Int], + #Filter by the staff id + id_not: Int, + #Filter by the staff id + id_not_in: [Int], + #Filter by search query + search: String, + #The order the results will be returned in + sort: [StaffSort] + ): Staff + "Studio query" + Studio( + #Filter by the studio id + id: Int, + #Filter by the studio id + id_in: [Int], + #Filter by the studio id + id_not: Int, + #Filter by the studio id + id_not_in: [Int], + #Filter by search query + search: String, + #The order the results will be returned in + sort: [StudioSort] + ): Studio + "Thread query" + Thread( + #Filter by thread category id + categoryId: Int, + #Filter by the thread id + id: Int, + #Filter by the thread id + id_in: [Int], + #Filter by thread media id category + mediaCategoryId: Int, + #Filter by the user id of the last user to comment on the thread + replyUserId: Int, + #Filter by search query + search: String, + #The order the results will be returned in + sort: [ThreadSort], + #Filter by if the currently authenticated user's subscribed threads + subscribed: Boolean, + #Filter by the user id of the thread's creator + userId: Int + ): Thread + "Comment query" + ThreadComment( + #Filter by the comment id + id: Int, + #The order the results will be returned in + sort: [ThreadCommentSort], + #Filter by the thread id + threadId: Int, + #Filter by the user id of the comment's creator + userId: Int + ): [ThreadComment] + "User query" + User( + #Filter by the user id + id: Int, + #Filter by the name of the user + name: String, + #Filter by search query + search: String, + #The order the results will be returned in + sort: [UserSort] + ): User + "Get the currently authenticated user" + Viewer: User +} + +"Notification for when new media is added to the site" +type RelatedMediaAdditionNotification { + "The notification context text" + context: String + "The time the notification was created at" + createdAt: Int + "The id of the Notification" + id: Int! + "The associated media of the airing schedule" + media: Media + "The id of the new media" + mediaId: Int! + "The type of notification" + type: NotificationType +} + +type Report { + "When the entry data was created" + createdAt: Int + id: Int! + reason: String + reported: User + reporter: User +} + +"A Review that features in an anime or manga" +type Review { + "The main review body text" + body( + #Return the string in pre-parsed html instead of markdown + asHtml: Boolean + ): String + "The time of the thread creation" + createdAt: Int! + "The id of the review" + id: Int! + "The media the review is of" + media: Media + "The id of the review's media" + mediaId: Int! + "For which type of media the review is for" + mediaType: MediaType + "If the review is not yet publicly published and is only viewable by creator" + private: Boolean + "The total user rating of the review" + rating: Int + "The amount of user ratings of the review" + ratingAmount: Int + "The review score of the media" + score: Int + "The url for the review page on the AniList website" + siteUrl: String + "A short summary of the review" + summary: String + "The time of the thread last update" + updatedAt: Int! + "The creator of the review" + user: User + "The id of the review's creator" + userId: Int! + "The rating of the review by currently authenticated user" + userRating: ReviewRating +} + +type ReviewConnection { + edges: [ReviewEdge] + nodes: [Review] + "The pagination information" + pageInfo: PageInfo +} + +"Review connection edge" +type ReviewEdge { + node: Review +} + +"Feed of mod edit activity" +type RevisionHistory { + "The action taken on the objects" + action: RevisionHistoryAction + "A JSON object of the fields that changed" + changes: Json + "The character the mod feed entry references" + character: Character + "When the mod feed entry was created" + createdAt: Int + "The id of the media" + id: Int! + "The media the mod feed entry references" + media: Media + "The staff member the mod feed entry references" + staff: Staff + "The studio the mod feed entry references" + studio: Studio + "The user who made the edit to the object" + user: User +} + +"A user's list score distribution." +type ScoreDistribution { + "The amount of list entries with this score" + amount: Int + score: Int +} + +"Voice actors or production staff" +type Staff { + "Characters voiced by the actor" + characters( + #The page + page: Int, + #The amount of entries per page, max 25 + perPage: Int, + sort: [CharacterSort] + ): CharacterConnection + "A general description of the staff member" + description( + #Return the string in pre-parsed html instead of markdown + asHtml: Boolean + ): String + "The amount of user's who have favourited the staff member" + favourites: Int + "The id of the staff member" + id: Int! + "The staff images" + image: StaffImage + "If the staff member is marked as favourite by the currently authenticated user" + isFavourite: Boolean! + "The primary language of the staff member" + language: StaffLanguage + "The names of the staff member" + name: StaffName + "The url for the staff page on the AniList website" + siteUrl: String + "Staff member that the submission is referencing" + staff: Staff + "Media where the staff member has a production role" + staffMedia( + #The page + page: Int, + #The amount of entries per page, max 25 + perPage: Int, + sort: [MediaSort], + type: MediaType + ): MediaConnection + "Inner details of submission status" + submissionNotes: String + "Status of the submission" + submissionStatus: Int + "Submitter for the submission" + submitter: User + "When the staff's data was last updated" + updatedAt: Int +} + +type StaffConnection { + edges: [StaffEdge] + nodes: [Staff] + "The pagination information" + pageInfo: PageInfo +} + +"Staff connection edge" +type StaffEdge { + "The order the staff should be displayed from the users favourites" + favouriteOrder: Int + "The id of the connection" + id: Int + node: Staff + "The role of the staff member in the production of the media" + role: String +} + +type StaffImage { + "The person's image of media at its largest size" + large: String + "The person's image of media at medium size" + medium: String +} + +"The names of the staff member" +type StaffName { + "The person's given name" + first: String + "The person's surname" + last: String + "The person's full name in their native language" + native: String +} + +"User's staff statistics" +type StaffStats { + amount: Int + meanScore: Int + staff: Staff + "The amount of time in minutes the staff member has been watched by the user" + timeWatched: Int +} + +"A submission for a staff that features in an anime or manga" +type StaffSubmission { + createdAt: Int + "The id of the submission" + id: Int! + "Inner details of submission status" + notes: String + "Staff that the submission is referencing" + staff: Staff + "Status of the submission" + status: SubmissionStatus + "The staff submission changes" + submission: Staff + "Submitter for the submission" + submitter: User +} + +"The distribution of the watching/reading status of media or a user's list" +type StatusDistribution { + "The amount of entries with this status" + amount: Int + "The day the activity took place (Unix timestamp)" + status: MediaListStatus +} + +"Animation or production company" +type Studio { + "The amount of user's who have favourited the studio" + favourites: Int + "The id of the studio" + id: Int! + "If the studio is marked as favourite by the currently authenticated user" + isFavourite: Boolean! + "The media the studio has worked on" + media( + #If the studio was the primary animation studio of the media + isMain: Boolean, + #The page + page: Int, + #The amount of entries per page, max 25 + perPage: Int, + #The order the results will be returned in + sort: [MediaSort] + ): MediaConnection + "The name of the studio" + name: String! + "The url for the studio page on the AniList website" + siteUrl: String +} + +type StudioConnection { + edges: [StudioEdge] + nodes: [Studio] + "The pagination information" + pageInfo: PageInfo +} + +"Studio connection edge" +type StudioEdge { + "The order the character should be displayed from the users favourites" + favouriteOrder: Int + "The id of the connection" + id: Int + "If the studio is the main animation studio of the anime" + isMain: Boolean! + node: Studio +} + +"User's studio statistics" +type StudioStats { + amount: Int + meanScore: Int + studio: Studio + "The amount of time in minutes the studio's works have been watched by the user" + timeWatched: Int +} + +"User's tag statistics" +type TagStats { + amount: Int + meanScore: Int + tag: MediaTag + "The amount of time in minutes the tag has been watched by the user" + timeWatched: Int +} + +"User text activity" +type TextActivity { + "The time the activity was created at" + createdAt: Int! + "The id of the activity" + id: Int! + "The users who liked the activity" + likes: [User] + "The written replies to the activity" + replies: [ActivityReply] + "The number of activity replies" + replyCount: Int! + "The url for the activity page on the AniList website" + siteUrl: String + "The status text (Markdown)" + text( + #Return the string in pre-parsed html instead of markdown + asHtml: Boolean + ): String + "The type of activity" + type: ActivityType + "The user who created the activity" + user: User + "The user id of the activity's creator" + userId: Int +} + +"Forum Thread" +type Thread { + "The text body of the thread (Markdown)" + body( + #Return the string in pre-parsed html instead of markdown + asHtml: Boolean + ): String + "The categories of the thread" + categories: [ThreadCategory] + "The time of the thread creation" + createdAt: Int! + "The id of the thread" + id: Int! + "If the thread is locked and can receive comments" + isLocked: Boolean + "If the thread is stickied and should be displayed at the top of the page" + isSticky: Boolean + "If the currently authenticated user is subscribed to the thread" + isSubscribed: Boolean + "The users who liked the thread" + likes: [User] + "The media categories of the thread" + mediaCategories: [Media] + "The time of the last reply" + repliedAt: Int + "The id of the most recent comment on the thread" + replyCommentId: Int + "The number of comments on the thread" + replyCount: Int + "The user to last reply to the thread" + replyUser: User + "The id of the user who most recently commented on the thread" + replyUserId: Int + "The url for the thread page on the AniList website" + siteUrl: String + "The title of the thread" + title: String + "The time of the thread last update" + updatedAt: Int! + "The owner of the thread" + user: User + "The id of the thread owner user" + userId: Int! + "The number of times users have viewed the thread" + viewCount: Int +} + +"A forum thread category" +type ThreadCategory { + "The id of the category" + id: Int! + "The name of the category" + name: String! +} + +"Forum Thread Comment" +type ThreadComment { + "The comment's child reply comments" + childComments: Json + "The text content of the comment (Markdown)" + comment( + #Return the string in pre-parsed html instead of markdown + asHtml: Boolean + ): String + "The time of the comments creation" + createdAt: Int! + "The id of the comment" + id: Int! + "The users who liked the comment" + likes: [User] + "The url for the comment page on the AniList website" + siteUrl: String + "The thread the comment belongs to" + thread: Thread + "The id of thread the comment belongs to" + threadId: Int + "The time of the comments last update" + updatedAt: Int! + "The user who created the comment" + user: User + "The user id of the comment's owner" + userId: Int +} + +"Notification for when a thread comment is liked" +type ThreadCommentLikeNotification { + "The thread comment that was liked" + comment: ThreadComment + "The id of the activity which was liked" + commentId: Int! + "The notification context text" + context: String + "The time the notification was created at" + createdAt: Int + "The id of the Notification" + id: Int! + "The thread that the relevant comment belongs to" + thread: Thread + "The type of notification" + type: NotificationType + "The user who liked the activity" + user: User + "The id of the user who liked to the activity" + userId: Int! +} + +"Notification for when authenticated user is @ mentioned in a forum thread comment" +type ThreadCommentMentionNotification { + "The thread comment that included the @ mention" + comment: ThreadComment + "The id of the comment where mentioned" + commentId: Int! + "The notification context text" + context: String + "The time the notification was created at" + createdAt: Int + "The id of the Notification" + id: Int! + "The thread that the relevant comment belongs to" + thread: Thread + "The type of notification" + type: NotificationType + "The user who mentioned the authenticated user" + user: User + "The id of the user who mentioned the authenticated user" + userId: Int! +} + +"Notification for when a user replies to your forum thread comment" +type ThreadCommentReplyNotification { + "The reply thread comment" + comment: ThreadComment + "The id of the reply comment" + commentId: Int! + "The notification context text" + context: String + "The time the notification was created at" + createdAt: Int + "The id of the Notification" + id: Int! + "The thread that the relevant comment belongs to" + thread: Thread + "The type of notification" + type: NotificationType + "The user who replied to the activity" + user: User + "The id of the user who create the comment reply" + userId: Int! +} + +"Notification for when a user replies to a subscribed forum thread" +type ThreadCommentSubscribedNotification { + "The reply thread comment" + comment: ThreadComment + "The id of the new comment in the subscribed thread" + commentId: Int! + "The notification context text" + context: String + "The time the notification was created at" + createdAt: Int + "The id of the Notification" + id: Int! + "The thread that the relevant comment belongs to" + thread: Thread + "The type of notification" + type: NotificationType + "The user who replied to the subscribed thread" + user: User + "The id of the user who commented on the thread" + userId: Int! +} + +"Notification for when a thread is liked" +type ThreadLikeNotification { + "The liked thread comment" + comment: ThreadComment + "The notification context text" + context: String + "The time the notification was created at" + createdAt: Int + "The id of the Notification" + id: Int! + "The thread that the relevant comment belongs to" + thread: Thread + "The id of the thread which was liked" + threadId: Int! + "The type of notification" + type: NotificationType + "The user who liked the activity" + user: User + "The id of the user who liked to the activity" + userId: Int! +} + +"A user" +type User { + "The bio written by user (Markdown)" + about( + #Return the string in pre-parsed html instead of markdown + asHtml: Boolean + ): String + "The user's avatar images" + avatar: UserAvatar + "The user's banner images" + bannerImage: String + bans: Json + "Custom donation badge text" + donatorBadge: String + "The donation tier of the user" + donatorTier: Int + "The users favourites" + favourites( + #Deprecated. Use page arguments on each favourite field instead. + page: Int + ): Favourites + "The id of the user" + id: Int! + "If the user is blocked by the authenticated user" + isBlocked: Boolean + "If the authenticated user if following this user" + isFollowing: Boolean + "The user's media list options" + mediaListOptions: MediaListOptions + "If the user is a moderator or data moderator" + moderatorStatus: String + "The name of the user" + name: String! + "The user's general options" + options: UserOptions + "The url for the user page on the AniList website" + siteUrl: String + "The user's statistics" + stats: UserStats + "The number of unread notifications the user has" + unreadNotificationCount: Int + "When the user's data was last updated" + updatedAt: Int +} + +"A user's activity history stats." +type UserActivityHistory { + "The amount of activity on the day" + amount: Int + "The day the activity took place (Unix timestamp)" + date: Int + "The level of activity represented on a 1-10 scale" + level: Int +} + +"A user's avatars" +type UserAvatar { + "The avatar of user at its largest size" + large: String + "The avatar of user at medium size" + medium: String +} + +"A user's general options" +type UserOptions { + "Whether the user receives notifications when a show they are watching aires" + airingNotifications: Boolean + "Whether the user has enabled viewing of 18+ content" + displayAdultContent: Boolean + "Notification options" + notificationOptions: [NotificationOption] + "Profile highlight color (blue, purple, pink, orange, red, green, gray)" + profileColor: String + "The language the user wants to see media titles in" + titleLanguage: UserTitleLanguage +} + +"A user's statistics" +type UserStats { + activityHistory: [UserActivityHistory] + animeListScores: ListScoreStats + animeScoreDistribution: [ScoreDistribution] + animeStatusDistribution: [StatusDistribution] + "The amount of manga chapters the user has read" + chaptersRead: Int + favouredActors: [StaffStats] + favouredFormats: [FormatStats] + favouredGenres: [GenreStats] + favouredGenresOverview: [GenreStats] + favouredStaff: [StaffStats] + favouredStudios: [StudioStats] + favouredTags: [TagStats] + favouredYears: [YearStats] + mangaListScores: ListScoreStats + mangaScoreDistribution: [ScoreDistribution] + mangaStatusDistribution: [StatusDistribution] + "The amount of anime the user has watched in minutes" + watchedTime: Int +} + +"User's year statistics" +type YearStats { + amount: Int + meanScore: Int + year: Int +} + +"Activity sort enums" +enum ActivitySort { + ID + ID_DESC +} + +"Activity type enum." +enum ActivityType { + #A anime list update activity + ANIME_LIST + #A manga list update activity + MANGA_LIST + #Anime & Manga list update, only used in query arguments + MEDIA_LIST + #A text message activity sent to another user + MESSAGE + #A text activity + TEXT +} + +"Airing schedule sort enums" +enum AiringSort { + EPISODE + EPISODE_DESC + ID + ID_DESC + MEDIA_ID + MEDIA_ID_DESC + TIME + TIME_DESC +} + +"The role the character plays in the media" +enum CharacterRole { + #A background character in the media + BACKGROUND + #A primary character role in the media + MAIN + #A supporting character role in the media + SUPPORTING +} + +"Character sort enums" +enum CharacterSort { + FAVOURITES + FAVOURITES_DESC + ID + ID_DESC + ROLE + ROLE_DESC + SEARCH_MATCH +} + +"Types that can be liked" +enum LikeableType { + ACTIVITY + ACTIVITY_REPLY + THREAD + THREAD_COMMENT +} + +"The format the media was released in" +enum MediaFormat { + #Professionally published manga with more than one chapter + MANGA + #Anime movies with a theatrical release + MOVIE + #Short anime released as a music video + MUSIC + #Written books released as a series of light novels + NOVEL + #(Original Net Animation) Anime that have been originally released online or are only available through streaming services. + ONA + #Manga with just one chapter + ONE_SHOT + #(Original Video Animation) Anime that have been released directly on DVD/Blu-ray without originally going through a theatrical release or television broadcast + OVA + #Special episodes that have been included in DVD/Blu-ray releases, picture dramas, pilots, etc + SPECIAL + #Anime broadcast on television + TV + #Anime which are under 15 minutes in length and broadcast on television + TV_SHORT +} + +"Media list sort enums" +enum MediaListSort { + ADDED_TIME + ADDED_TIME_DESC + FINISHED_ON + FINISHED_ON_DESC + MEDIA_ID + MEDIA_ID_DESC + MEDIA_POPULARITY + MEDIA_POPULARITY_DESC + MEDIA_TITLE_ENGLISH + MEDIA_TITLE_ENGLISH_DESC + MEDIA_TITLE_NATIVE + MEDIA_TITLE_NATIVE_DESC + MEDIA_TITLE_ROMAJI + MEDIA_TITLE_ROMAJI_DESC + PRIORITY + PRIORITY_DESC + PROGRESS + PROGRESS_DESC + PROGRESS_VOLUMES + PROGRESS_VOLUMES_DESC + REPEAT + REPEAT_DESC + SCORE + SCORE_DESC + STARTED_ON + STARTED_ON_DESC + STATUS + STATUS_DESC + UPDATED_TIME + UPDATED_TIME_DESC +} + +"Media list watching/reading status enum." +enum MediaListStatus { + #Finished watching/reading + COMPLETED + #Currently watching/reading + CURRENT + #Stopped watching/reading before completing + DROPPED + #Paused watching/reading + PAUSED + #Planning to watch/read + PLANNING + #Re-watching/reading + REPEATING +} + +"The type of ranking" +enum MediaRankType { + #Ranking is based on the media's popularity + POPULAR + #Ranking is based on the media's ratings/score + RATED +} + +"Type of relation media has to its parent." +enum MediaRelation { + #An adaption of this media into a different format + ADAPTATION + #An alternative version of the same media + ALTERNATIVE + #Shares at least 1 character + CHARACTER + #Version 2 only. + COMPILATION + #Version 2 only. + CONTAINS + #Other + OTHER + #The media a side story is from + PARENT + #Released before the relation + PREQUEL + #Released after the relation + SEQUEL + #A side story of the parent media + SIDE_STORY + #Version 2 only. The source material the media was adapted from + SOURCE + #An alternative version of the media with a different primary focus + SPIN_OFF + #A shortened and summarized version + SUMMARY +} + +enum MediaSeason { + #Months September to November + FALL + #Months March to May + SPRING + #Months June to August + SUMMER + #Months December to February + WINTER +} + +"Media sort enums" +enum MediaSort { + CHAPTERS + CHAPTERS_DESC + DURATION + DURATION_DESC + END_DATE + END_DATE_DESC + EPISODES + EPISODES_DESC + FAVOURITES + FAVOURITES_DESC + FORMAT + FORMAT_DESC + ID + ID_DESC + POPULARITY + POPULARITY_DESC + SCORE + SCORE_DESC + SEARCH_MATCH + START_DATE + START_DATE_DESC + STATUS + STATUS_DESC + TITLE_ENGLISH + TITLE_ENGLISH_DESC + TITLE_NATIVE + TITLE_NATIVE_DESC + TITLE_ROMAJI + TITLE_ROMAJI_DESC + TRENDING + TRENDING_DESC + TYPE + TYPE_DESC + UPDATED_AT + UPDATED_AT_DESC + VOLUMES + VOLUMES_DESC +} + +"Source type the media was adapted from" +enum MediaSource { + #Version 2 only. Japanese Anime + ANIME + #Version 2 only. Self-published works + DOUJINSHI + #Written work published in volumes + LIGHT_NOVEL + #Asian comic book + MANGA + #Version 2 only. Written works not published in volumes + NOVEL + #An original production not based of another work + ORIGINAL + #Other + OTHER + #Video game + VIDEO_GAME + #Video game driven primary by text and narrative + VISUAL_NOVEL +} + +"The current releasing status of the media" +enum MediaStatus { + #Ended before the work could be finished + CANCELLED + #Has completed and is no longer being released + FINISHED + #To be released at a later date + NOT_YET_RELEASED + #Currently releasing + RELEASING +} + +"Media trend sort enums" +enum MediaTrendSort { + DATE + DATE_DESC + EPISODE + EPISODE_DESC + ID + ID_DESC + MEDIA_ID + MEDIA_ID_DESC + POPULARITY + POPULARITY_DESC + SCORE + SCORE_DESC + TRENDING + TRENDING_DESC +} + +"Media type enum, anime or manga." +enum MediaType { + #Japanese Anime + ANIME + #Asian comic + MANGA +} + +"Notification type enum" +enum NotificationType { + #A user has liked your activity + ACTIVITY_LIKE + #A user has mentioned you in their activity + ACTIVITY_MENTION + #A user has sent you message + ACTIVITY_MESSAGE + #A user has replied to your activity + ACTIVITY_REPLY + #A user has liked your activity reply + ACTIVITY_REPLY_LIKE + #A user has replied to activity you have also replied to + ACTIVITY_REPLY_SUBSCRIBED + #An anime you are currently watching has aired + AIRING + #A user has followed you + FOLLOWING + #A new anime or manga has been added to the site where its related media is on the user's list + RELATED_MEDIA_ADDITION + #A user has liked your forum comment + THREAD_COMMENT_LIKE + #A user has mentioned you in a forum comment + THREAD_COMMENT_MENTION + #A user has replied to your forum comment + THREAD_COMMENT_REPLY + #A user has liked your forum thread + THREAD_LIKE + #A user has commented in one of your subscribed forum threads + THREAD_SUBSCRIBED +} + +"Review rating enums" +enum ReviewRating { + DOWN_VOTE + NO_VOTE + UP_VOTE +} + +"Review sort enums" +enum ReviewSort { + CREATED_AT + CREATED_AT_DESC + ID + ID_DESC + RATING + RATING_DESC + SCORE + SCORE_DESC + UPDATED_AT + UPDATED_AT_DESC +} + +"Revision history actions" +enum RevisionHistoryAction { + CREATE + EDIT +} + +"Media list scoring type" +enum ScoreFormat { + #An integer from 0-10 + POINT_10 + #An integer from 0-100 + POINT_100 + #A float from 0-10 with 1 decimal place + POINT_10_DECIMAL + #An integer from 0-3. Should be represented in Smileys. 0 => No Score, 1 => :(, 2 => :|, 3 => :) + POINT_3 + #An integer from 0-5. Should be represented in Stars + POINT_5 +} + +"The primary language of the voice actor" +enum StaffLanguage { + #English + ENGLISH + #French + FRENCH + #German + GERMAN + #Hebrew + HEBREW + #Hungarian + HUNGARIAN + #Italian + ITALIAN + #Japanese + JAPANESE + #Korean + KOREAN + #Portuguese + PORTUGUESE + #Spanish + SPANISH +} + +"Staff sort enums" +enum StaffSort { + FAVOURITES + FAVOURITES_DESC + ID + ID_DESC + LANGUAGE + LANGUAGE_DESC + ROLE + ROLE_DESC + SEARCH_MATCH +} + +"Studio sort enums" +enum StudioSort { + FAVOURITES + FAVOURITES_DESC + ID + ID_DESC + NAME + NAME_DESC + SEARCH_MATCH +} + +"Submission status" +enum SubmissionStatus { + ACCEPTED + PARTIALLY_ACCEPTED + PENDING + REJECTED +} + +"Thread comments sort enums" +enum ThreadCommentSort { + ID + ID_DESC +} + +"Thread sort enums" +enum ThreadSort { + CREATED_AT + CREATED_AT_DESC + ID + ID_DESC + IS_STICKY + REPLIED_AT + REPLIED_AT_DESC + REPLY_COUNT + REPLY_COUNT_DESC + SEARCH_MATCH + TITLE + TITLE_DESC + UPDATED_AT + UPDATED_AT_DESC + VIEW_COUNT + VIEW_COUNT_DESC +} + +"User sort enums" +enum UserSort { + CHAPTERS_READ + CHAPTERS_READ_DESC + ID + ID_DESC + SEARCH_MATCH + USERNAME + USERNAME_DESC + WATCHED_TIME + WATCHED_TIME_DESC +} + +"The language the user wants to see media titles in" +enum UserTitleLanguage { + #The official english title + ENGLISH + #The official english title, stylised by media creator + ENGLISH_STYLISED + #Official title in it's native language + NATIVE + #Official title in it's native language, stylised by media creator + NATIVE_STYLISED + #The romanization of the native language title + ROMAJI + #The romanization of the native language title, stylised by media creator + ROMAJI_STYLISED +} + +input AiringScheduleInput { + airingAt: Int + episode: Int + timeUntilAiring: Int +} + +input AniChartHighlightInput { + highlight: String + mediaId: Int +} + +"The names of the character" +input CharacterNameInput { + "Other names the character might be referred by" + alternative: [String] + "The character's given name" + first: String + "The character's surname" + last: String + "The character's full name in their native language" + native: String +} + +"Date object that allows for incomplete date values (fuzzy)" +input FuzzyDateInput { + "Numeric Day (24)" + day: Int + "Numeric Month (3)" + month: Int + "Numeric Year (2017)" + year: Int +} + +"An external link to another site related to the media" +input MediaExternalLinkInput { + "The id of the external link" + id: Int! + "The site location of the external link" + site: String! + "The url of the external link" + url: String! +} + +"A user's list options for anime or manga lists" +input MediaListOptionsInput { + "The names of the user's advanced scoring sections" + advancedScoring: [String] + "If advanced scoring is enabled" + advancedScoringEnabled: Boolean + "The names of the user's custom lists" + customLists: [String] + "The order each list should be displayed in" + sectionOrder: [String] + "If the completed sections of the list should be separated by format" + splitCompletedSectionByFormat: Boolean + "list theme" + theme: String +} + +"The official titles of the media in various languages" +input MediaTitleInput { + "The official english title" + english: String + "Official title in it's native language" + native: String + "The romanization of the native language title" + romaji: String +} + +"Notification option input" +input NotificationOptionInput { + "Whether this type of notification is enabled" + enabled: Boolean + "The type of notification" + type: NotificationType +} + +"The names of the staff member" +input StaffNameInput { + "The person's given name" + first: String + "The person's surname" + last: String + "The person's full name in their native language" + native: String +} + + +scalar Json + +"ISO 3166-1 alpha-2 country code" +scalar CountryCode + +"8 digit long date integer (YYYYMMDD). Unknown dates represented by 0. E.g. 2016: 20160000, May 1976: 19760500" +scalar FuzzyDateInt \ No newline at end of file From 6821de06bd69c374e1b4f27bfa5be413a197ba6a Mon Sep 17 00:00:00 2001 From: Maxwell Date: Sun, 12 May 2019 20:45:47 +0200 Subject: [PATCH 08/17] Updated Gradle Wrapper --- gradle/wrapper/gradle-wrapper.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 4598db787..e00bf576f 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Fri Feb 01 17:49:01 SAST 2019 +#Sat Apr 20 10:23:30 SAST 2019 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip From 6ef3ac3c49652cc148f23552f8a4c5c6260240d0 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Sun, 12 May 2019 20:46:06 +0200 Subject: [PATCH 09/17] Updated Dependencies --- app/build.gradle | 15 +++++---------- build.gradle | 12 ++++++------ 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 415691ac9..5355a5dcc 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -100,7 +100,7 @@ dependencies { implementation "com.google.firebase:firebase-core:${rootProject.firebase}" /** Crash Analytics */ - implementation('com.crashlytics.sdk.android:crashlytics:2.7.1@aar') { + implementation('com.crashlytics.sdk.android:crashlytics:2.9.9@aar') { transitive = true } @@ -112,7 +112,7 @@ dependencies { exclude group: 'stax', module: 'stax-api' exclude group: 'stax', module: 'stax' } - implementation "com.squareup.okhttp3:logging-interceptor:3.12.1" + implementation 'com.squareup.okhttp3:logging-interceptor:3.14.1' /** Glide Libraries */ implementation "com.github.bumptech.glide:glide:${rootProject.glide}" @@ -136,7 +136,7 @@ dependencies { kapt "io.objectbox:objectbox-processor:${rootProject.objectBox}" /** Pretty Time */ - implementation 'org.ocpsoft.prettytime:prettytime:4.0.1.Final' + implementation 'org.ocpsoft.prettytime:prettytime:4.0.2.Final' /** Smart Tab Layout */ implementation 'com.ogaclejapan.smarttablayout:library:1.7.0' @@ -145,7 +145,7 @@ dependencies { implementation 'com.annimon:stream:1.2.1' /** Highly Customizable Video Player */ - implementation 'cn.jzvd:jiaozivideoplayer:6.4.0' + implementation 'cn.jzvd:jiaozivideoplayer:7.0_preview' /** Photo View */ implementation 'com.github.chrisbanes:PhotoView:2.1.3' @@ -155,16 +155,11 @@ dependencies { /** Rich Text Markdown Parser */ implementation "ru.noties.markwon:core:$rootProject.markwon" - implementation "ru.noties.markwon:ext-strikethrough:$rootProject.markwon" - implementation "ru.noties.markwon:ext-tables:$rootProject.markwon" - implementation "ru.noties.markwon:ext-tasklist:$rootProject.markwon" implementation "ru.noties.markwon:html:$rootProject.markwon" - implementation "ru.noties.markwon:image-gif:$rootProject.markwon" implementation "ru.noties.markwon:image-okhttp:$rootProject.markwon" - implementation "ru.noties.markwon:image-svg:$rootProject.markwon" /** Tap Target Prompt */ - implementation 'uk.co.samuelwall:material-tap-target-prompt:2.12.1' + implementation 'uk.co.samuelwall:material-tap-target-prompt:2.14.0' /** Circular Progress View */ implementation 'com.github.rahatarmanahmed:circularprogressview:2.5.0' diff --git a/build.gradle b/build.gradle index 199121453..c2822a808 100644 --- a/build.gradle +++ b/build.gradle @@ -5,18 +5,18 @@ buildscript { compileSdk = 28 targetSdk = 28 minSdk = 17 - versionCode = 103 - versionName = '1.4.0' + versionCode = 104 + versionName = '1.4.1' butterKnife = '8.8.1' glide = '4.9.0' - retrofit = '2.4.0' + retrofit = '2.5.0' supportLibrary = '27.1.1' firebase = '16.0.8' objectBox = '2.3.3' architecture = '1.1.1' workManager = '1.0.1' emojify = '1.4' - kotlin = '1.3.30' + kotlin = '1.3.31' // testing libraries mockito = '2.18.3' hemcrest = '1.3' @@ -30,13 +30,13 @@ buildscript { maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' } } dependencies { - classpath 'com.android.tools.build:gradle:3.3.2' + classpath 'com.android.tools.build:gradle:3.4.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${rootProject.kotlin}" // Google Play Services classpath 'com.google.gms:google-services:4.2.0' // Crash Analytics - classpath 'io.fabric.tools:gradle:1.27.1' + classpath 'io.fabric.tools:gradle:1.28.1' // Object Box classpath "io.objectbox:objectbox-gradle-plugin:${rootProject.objectBox}" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${rootProject.kotlin}" From 47c5fc9390301c834ed3da8170e474eb393701a8 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Sun, 12 May 2019 20:46:52 +0200 Subject: [PATCH 10/17] Upcomming Release Information --- app/.meta/version.json | 4 ++-- app/release/output.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/.meta/version.json b/app/.meta/version.json index dfb15c12e..26845eb12 100644 --- a/app/.meta/version.json +++ b/app/.meta/version.json @@ -1,7 +1,7 @@ { - "code": 103, + "code": 104, "migration": false, "releaseNotes": "", - "version": "1.4.0", + "version": "1.4.1", "appId": "com.mxt.anitrend" } diff --git a/app/release/output.json b/app/release/output.json index e068d817c..c0d2acd50 100644 --- a/app/release/output.json +++ b/app/release/output.json @@ -1 +1 @@ -[{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":103,"versionName":"1.4.0","enabled":true,"outputFile":"anitrend_v1.4.0_rc_103.apk","fullName":"release","baseName":"release"},"path":"anitrend_v1.4.0_rc_103.apk","properties":{}}] \ No newline at end of file +[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":104,"versionName":"1.4.1","enabled":true,"outputFile":"anitrend_v1.4.1_rc_104.apk","fullName":"release","baseName":"release"},"path":"anitrend_v1.4.1_rc_104.apk","properties":{}}] \ No newline at end of file From d57b9035544d67951c35db2bb4d237bb6484001e Mon Sep 17 00:00:00 2001 From: Maxwell Date: Sun, 12 May 2019 20:48:07 +0200 Subject: [PATCH 11/17] Notification With Related Media Added & Refactoring --- app/src/main/assets/changelog.md | 1 + .../Notifications/UserNotifications.graphql | 21 +- app/src/main/java/com/mxt/anitrend/App.kt | 24 +- .../pager/detail/AnimePageAdapter.java | 2 +- .../pager/detail/MangaPageAdapter.java | 2 +- .../pager/detail/ProfilePageAdapter.java | 4 +- .../adapter/pager/index/FeedPageAdapter.java | 6 +- .../adapter/pager/index/MangaPageAdapter.java | 4 +- .../pager/index/MediaListPageAdapter.java | 2 +- .../pager/index/SeasonPageAdapter.java | 8 +- .../pager/index/TrendingPageAdapter.java | 4 +- .../recycler/detail/CommentAdapter.java | 2 +- .../adapter/recycler/detail/GenreAdapter.java | 2 +- .../adapter/recycler/detail/GiphyAdapter.java | 2 +- .../adapter/recycler/detail/LinkAdapter.java | 2 +- .../recycler/detail/NotificationAdapter.java | 215 ------- .../recycler/detail/NotificationAdapter.kt | 216 +++++++ .../adapter/recycler/detail/RankAdapter.java | 4 +- .../adapter/recycler/detail/TagAdapter.java | 2 +- .../recycler/group/GroupActorAdapter.java | 4 +- .../recycler/group/GroupCharacterAdapter.java | 4 +- .../recycler/group/GroupSeriesAdapter.java | 4 +- .../recycler/group/GroupStaffRoleAdapter.java | 4 +- .../adapter/recycler/index/FeedAdapter.java | 6 +- .../adapter/recycler/index/MediaAdapter.java | 4 +- .../recycler/index/MediaListAdapter.java | 2 +- .../adapter/recycler/index/StaffAdapter.java | 2 +- .../adapter/recycler/index/StudioAdapter.java | 2 +- .../adapter/recycler/index/UserAdapter.java | 2 +- .../base/custom/activity/ActivityBase.java | 18 +- .../custom/fragment/FragmentBaseComment.java | 6 +- .../custom/fragment/FragmentBaseList.java | 12 +- .../custom/fragment/FragmentChannelBase.java | 10 +- .../base/custom/glide/GlideAppModule.java | 4 +- .../custom/recycler/RecyclerViewAdapter.java | 2 +- .../base/custom/sheet/BottomSheetBase.java | 12 +- .../custom/sheet/BottomSheetGiphyList.java | 8 +- .../base/custom/sheet/BottomSheetList.java | 6 +- .../custom/view/container/CardViewBase.java | 2 +- .../custom/view/editor/ComposerWidget.java | 6 +- .../view/image/AppCompatTintImageView.java | 6 +- .../custom/view/image/AspectImageView.java | 2 +- .../view/image/AvatarIndicatorView.java | 4 +- .../custom/view/image/BrandImageView.java | 4 +- .../base/custom/view/text/AiringTextView.java | 4 +- .../base/custom/view/text/PageIndicator.java | 6 +- .../custom/view/text/RangeDateTextView.java | 4 +- .../base/custom/view/text/RatingTextView.java | 20 +- .../custom/view/text/RichMarkdownTextView.kt | 19 +- .../view/text/SeriesProgressTextView.java | 4 +- .../view/text/SeriesYearTypeTextView.java | 8 +- .../custom/view/text/SpoilerTagTextView.java | 2 +- .../custom/view/widget/AboutPanelWidget.java | 4 +- .../view/widget/AutoIncrementWidget.java | 12 +- .../custom/view/widget/CommentWidget.java | 2 +- .../custom/view/widget/CustomProgress.java | 2 +- .../view/widget/CustomSeriesAnimeManage.java | 12 +- .../view/widget/CustomSeriesManageBase.java | 2 +- .../view/widget/CustomSeriesMangaManage.java | 12 +- .../view/widget/FavouriteToolbarWidget.java | 14 +- .../custom/view/widget/FavouriteWidget.java | 16 +- .../custom/view/widget/FollowStateWidget.java | 10 +- .../custom/view/widget/FuzzyDateWidget.java | 4 +- .../custom/view/widget/MentionWidget.java | 2 +- .../view/widget/ProfileStatsWidget.java | 6 +- .../custom/view/widget/ProgressWidget.java | 4 +- .../base/custom/view/widget/ScoreWidget.java | 6 +- .../view/widget/SeriesStatusWidget.java | 10 +- .../view/widget/StatusContentWidget.java | 4 +- .../view/widget/StatusDeleteWidget.java | 8 +- .../custom/view/widget/StatusEditWidget.java | 2 +- .../base/custom/view/widget/UsersWidget.java | 2 +- .../base/custom/view/widget/VoteWidget.java | 22 +- .../base/custom/viewmodel/ViewModelBase.java | 130 ----- .../base/custom/viewmodel/ViewModelBase.kt | 104 ++++ .../com/mxt/anitrend/data/DatabaseHelper.kt | 45 +- .../api/interceptor/AuthInterceptor.java | 44 -- .../model/api/interceptor/AuthInterceptor.kt | 40 ++ .../api/interceptor/CacheInterceptor.java | 48 -- .../model/api/interceptor/CacheInterceptor.kt | 37 ++ .../interceptor/NetworkCacheInterceptor.java | 48 -- .../interceptor/NetworkCacheInterceptor.kt | 38 ++ .../anitrend/model/api/retro/WebFactory.java | 6 +- .../model/entity/anilist/MediaRank.java | 16 +- .../entity/container/body/EdgeContainer.java | 2 +- .../entity/container/body/GraphContainer.java | 2 +- .../entity/container/body/PageContainer.java | 2 +- .../entity/group/RecyclerHeaderItem.java | 4 +- .../presenter/base/BasePresenter.java | 18 +- .../presenter/fragment/MediaPresenter.java | 10 +- .../anitrend/service/DownloaderService.java | 36 -- .../mxt/anitrend/service/DownloaderService.kt | 35 ++ .../anitrend/service/JobDispatcherService.kt | 36 +- .../mxt/anitrend/service/TagGenreService.java | 95 ---- .../mxt/anitrend/service/TagGenreService.kt | 84 +++ .../com/mxt/anitrend/util/ActionModeUtil.java | 2 +- .../mxt/anitrend/util/ApplicationPref.java | 355 ------------ .../com/mxt/anitrend/util/ApplicationPref.kt | 297 ++++++++++ .../com/mxt/anitrend/util/CenterSnapUtil.java | 54 -- .../com/mxt/anitrend/util/CenterSnapUtil.kt | 43 ++ .../java/com/mxt/anitrend/util/ChartUtil.java | 103 ---- .../java/com/mxt/anitrend/util/ChartUtil.kt | 99 ++++ .../com/mxt/anitrend/util/CompatUtil.java | 536 ------------------ .../java/com/mxt/anitrend/util/CompatUtil.kt | 515 +++++++++++++++++ .../java/com/mxt/anitrend/util/DateUtil.java | 246 -------- .../java/com/mxt/anitrend/util/DateUtil.kt | 260 +++++++++ .../com/mxt/anitrend/util/DialogUtil.java | 18 +- .../com/mxt/anitrend/util/EpisodeUtil.java | 37 -- .../java/com/mxt/anitrend/util/EpisodeUtil.kt | 36 ++ .../java/com/mxt/anitrend/util/ErrorUtil.java | 76 --- .../java/com/mxt/anitrend/util/ErrorUtil.kt | 69 +++ .../java/com/mxt/anitrend/util/GraphUtil.java | 57 -- .../java/com/mxt/anitrend/util/GraphUtil.kt | 59 ++ .../com/mxt/anitrend/util/GroupingUtil.java | 226 -------- .../com/mxt/anitrend/util/GroupingUtil.kt | 232 ++++++++ .../mxt/anitrend/util/IntentBundleUtil.java | 115 ---- .../com/mxt/anitrend/util/IntentBundleUtil.kt | 103 ++++ .../java/com/mxt/anitrend/util/KeyUtil.java | 4 +- .../com/mxt/anitrend/util/LocaleUtil.java | 56 -- .../java/com/mxt/anitrend/util/LocaleUtil.kt | 53 ++ .../mxt/anitrend/util/MediaActionUtil.java | 4 +- .../mxt/anitrend/util/MediaDialogUtil.java | 8 +- .../com/mxt/anitrend/util/MediaListUtil.java | 6 +- .../java/com/mxt/anitrend/util/MediaUtil.java | 8 +- .../mxt/anitrend/util/NotificationUtil.java | 82 --- .../com/mxt/anitrend/util/NotificationUtil.kt | 101 ++++ .../com/mxt/anitrend/util/NotifyUtil.java | 52 +- .../java/com/mxt/anitrend/util/RegexUtil.kt | 23 +- .../com/mxt/anitrend/util/TapTargetUtil.java | 18 +- .../com/mxt/anitrend/util/TutorialUtil.java | 12 +- .../base/AppCompatPreferenceActivity.java | 2 +- .../activity/base/GiphyPreviewActivity.java | 2 +- .../activity/base/ImagePreviewActivity.java | 14 +- .../view/activity/base/SettingsActivity.java | 12 +- .../activity/base/SharedContentActivity.java | 14 +- .../activity/base/VideoPlayerActivity.java | 2 +- .../view/activity/base/WelcomeActivity.java | 6 +- .../activity/detail/CharacterActivity.java | 2 +- .../view/activity/detail/MediaActivity.java | 10 +- .../activity/detail/MediaListActivity.java | 2 +- .../view/activity/detail/ProfileActivity.java | 6 +- .../view/activity/detail/StaffActivity.java | 2 +- .../view/activity/detail/StudioActivity.java | 2 +- .../view/activity/index/LoginActivity.java | 2 +- .../view/activity/index/MainActivity.java | 8 +- .../view/activity/index/SplashActivity.java | 4 +- .../fragment/detail/BrowseReviewFragment.java | 12 +- .../detail/CharacterOverviewFragment.java | 6 +- .../view/fragment/detail/CommentFragment.java | 20 +- .../detail/MediaOverviewFragment.java | 22 +- .../fragment/detail/MediaStaffFragment.java | 6 +- .../fragment/detail/MediaStatsFragment.java | 16 +- .../fragment/detail/MessageFeedFragment.java | 6 +- .../fragment/detail/NotificationFragment.java | 33 +- .../view/fragment/detail/ReviewFragment.java | 6 +- .../detail/StaffOverviewFragment.java | 6 +- .../fragment/detail/StudioMediaFragment.java | 12 +- .../fragment/detail/UserOverviewFragment.java | 12 +- .../favourite/CharacterFavouriteFragment.java | 6 +- .../favourite/MediaFavouriteFragment.java | 8 +- .../favourite/StaffFavouriteFragment.java | 4 +- .../favourite/StudioFavouriteFragment.java | 2 +- .../group/CharacterActorsFragment.java | 8 +- .../group/MediaCharacterFragment.java | 6 +- .../fragment/group/MediaFormatFragment.java | 6 +- .../fragment/group/MediaRelationFragment.java | 6 +- .../group/MediaStaffRoleFragment.java | 6 +- .../fragment/list/AiringListFragment.java | 4 +- .../view/fragment/list/FeedListFragment.java | 14 +- .../fragment/list/MediaBrowseFragment.java | 34 +- .../view/fragment/list/MediaListFragment.java | 22 +- .../fragment/list/SuggestionListFragment.java | 10 +- .../view/fragment/list/WatchListFragment.java | 6 +- .../search/CharacterSearchFragment.java | 6 +- .../fragment/search/MediaSearchFragment.java | 4 +- .../fragment/search/StaffSearchFragment.java | 4 +- .../fragment/search/StudioSearchFragment.java | 2 +- .../fragment/search/UserSearchFragment.java | 4 +- .../view/sheet/BottomReviewReader.java | 2 +- .../view/sheet/BottomSheetComposer.java | 2 +- .../anitrend/view/sheet/BottomSheetGiphy.java | 2 +- .../view/sheet/BottomSheetListUsers.java | 14 +- .../anitrend/view/sheet/BottomSheetUsers.java | 4 +- app/src/main/res/layout/adapter_comment.xml | 2 +- .../main/res/layout/adapter_feed_message.xml | 2 +- .../main/res/layout/adapter_feed_progress.xml | 2 +- .../main/res/layout/adapter_feed_status.xml | 2 +- .../main/res/layout/adapter_media_header.xml | 4 +- .../main/res/layout/adapter_series_review.xml | 2 +- app/src/main/res/layout/adapter_staff.xml | 2 +- .../res/layout/custom_review_template.xml | 2 +- .../res/layout/fragment_series_overview.xml | 25 +- .../main/res/layout/fragment_series_stats.xml | 8 +- .../res/layout/fragment_staff_overview.xml | 2 +- app/src/main/res/values-ar/strings.xml | 16 + app/src/main/res/values-de/strings.xml | 16 + app/src/main/res/values-es/strings.xml | 16 + app/src/main/res/values-fr/strings.xml | 16 + app/src/main/res/values-it/strings.xml | 16 + app/src/main/res/values-nl/strings.xml | 16 + app/src/main/res/values-pl/strings.xml | 16 + app/src/main/res/values-pt/strings.xml | 16 + app/src/main/res/values-sv/strings.xml | 16 + app/src/main/res/values/strings.xml | 1 + 204 files changed, 3205 insertions(+), 3153 deletions(-) delete mode 100644 app/src/main/java/com/mxt/anitrend/adapter/recycler/detail/NotificationAdapter.java create mode 100644 app/src/main/java/com/mxt/anitrend/adapter/recycler/detail/NotificationAdapter.kt delete mode 100644 app/src/main/java/com/mxt/anitrend/base/custom/viewmodel/ViewModelBase.java create mode 100644 app/src/main/java/com/mxt/anitrend/base/custom/viewmodel/ViewModelBase.kt delete mode 100644 app/src/main/java/com/mxt/anitrend/model/api/interceptor/AuthInterceptor.java create mode 100644 app/src/main/java/com/mxt/anitrend/model/api/interceptor/AuthInterceptor.kt delete mode 100644 app/src/main/java/com/mxt/anitrend/model/api/interceptor/CacheInterceptor.java create mode 100644 app/src/main/java/com/mxt/anitrend/model/api/interceptor/CacheInterceptor.kt delete mode 100644 app/src/main/java/com/mxt/anitrend/model/api/interceptor/NetworkCacheInterceptor.java create mode 100644 app/src/main/java/com/mxt/anitrend/model/api/interceptor/NetworkCacheInterceptor.kt delete mode 100644 app/src/main/java/com/mxt/anitrend/service/DownloaderService.java create mode 100644 app/src/main/java/com/mxt/anitrend/service/DownloaderService.kt delete mode 100644 app/src/main/java/com/mxt/anitrend/service/TagGenreService.java create mode 100644 app/src/main/java/com/mxt/anitrend/service/TagGenreService.kt delete mode 100644 app/src/main/java/com/mxt/anitrend/util/ApplicationPref.java create mode 100644 app/src/main/java/com/mxt/anitrend/util/ApplicationPref.kt delete mode 100644 app/src/main/java/com/mxt/anitrend/util/CenterSnapUtil.java create mode 100644 app/src/main/java/com/mxt/anitrend/util/CenterSnapUtil.kt delete mode 100644 app/src/main/java/com/mxt/anitrend/util/ChartUtil.java create mode 100644 app/src/main/java/com/mxt/anitrend/util/ChartUtil.kt delete mode 100644 app/src/main/java/com/mxt/anitrend/util/CompatUtil.java create mode 100644 app/src/main/java/com/mxt/anitrend/util/CompatUtil.kt delete mode 100644 app/src/main/java/com/mxt/anitrend/util/DateUtil.java create mode 100644 app/src/main/java/com/mxt/anitrend/util/DateUtil.kt delete mode 100644 app/src/main/java/com/mxt/anitrend/util/EpisodeUtil.java create mode 100644 app/src/main/java/com/mxt/anitrend/util/EpisodeUtil.kt delete mode 100644 app/src/main/java/com/mxt/anitrend/util/ErrorUtil.java create mode 100644 app/src/main/java/com/mxt/anitrend/util/ErrorUtil.kt delete mode 100644 app/src/main/java/com/mxt/anitrend/util/GraphUtil.java create mode 100644 app/src/main/java/com/mxt/anitrend/util/GraphUtil.kt delete mode 100644 app/src/main/java/com/mxt/anitrend/util/GroupingUtil.java create mode 100644 app/src/main/java/com/mxt/anitrend/util/GroupingUtil.kt delete mode 100644 app/src/main/java/com/mxt/anitrend/util/IntentBundleUtil.java create mode 100644 app/src/main/java/com/mxt/anitrend/util/IntentBundleUtil.kt delete mode 100644 app/src/main/java/com/mxt/anitrend/util/LocaleUtil.java create mode 100644 app/src/main/java/com/mxt/anitrend/util/LocaleUtil.kt delete mode 100644 app/src/main/java/com/mxt/anitrend/util/NotificationUtil.java create mode 100644 app/src/main/java/com/mxt/anitrend/util/NotificationUtil.kt diff --git a/app/src/main/assets/changelog.md b/app/src/main/assets/changelog.md index 51b0e950b..575e15f32 100644 --- a/app/src/main/assets/changelog.md +++ b/app/src/main/assets/changelog.md @@ -5,6 +5,7 @@ which can result in authentication errors [read more](https://github.com/square/ #### Enhancements - Reintroduced emoji support +- Spoiler tags support (Mittens) #### Bug Fixes - Multiple translations fixed diff --git a/app/src/main/assets/graphql/User/Query/Notifications/UserNotifications.graphql b/app/src/main/assets/graphql/User/Query/Notifications/UserNotifications.graphql index 99149b989..0f51a265c 100644 --- a/app/src/main/assets/graphql/User/Query/Notifications/UserNotifications.graphql +++ b/app/src/main/assets/graphql/User/Query/Notifications/UserNotifications.graphql @@ -33,7 +33,7 @@ query UserNotifications($page: Int, $perPage: Int, $type: NotificationType, $typ type createdAt context - activityId + activityId user { ...userBase } @@ -58,16 +58,6 @@ query UserNotifications($page: Int, $perPage: Int, $type: NotificationType, $typ ...userBase } } - ... on ActivityReplySubscribedNotification { - id - type - createdAt - context - activityId - user { - ...userBase - } - } ... on ActivityLikeNotification { id type @@ -133,6 +123,15 @@ query UserNotifications($page: Int, $perPage: Int, $type: NotificationType, $typ ...userBase } } + ... on RelatedMediaAdditionNotification { + id + type + createdAt + context + media { + ...mediaBase + } + } } } } diff --git a/app/src/main/java/com/mxt/anitrend/App.kt b/app/src/main/java/com/mxt/anitrend/App.kt index eb37afdf4..cb86a6231 100644 --- a/app/src/main/java/com/mxt/anitrend/App.kt +++ b/app/src/main/java/com/mxt/anitrend/App.kt @@ -24,6 +24,10 @@ import org.greenrobot.eventbus.EventBus class App : MultiDexApplication() { + val applicationPref by lazy { + ApplicationPref(this) + } + /** * @return Application global registered firebase analytics * @@ -36,7 +40,7 @@ class App : MultiDexApplication() { * * @see com.mxt.anitrend.data.DatabaseHelper */ - var boxStore: BoxStore? = null + lateinit var boxStore: BoxStore private set /** * Get application global registered fabric instance, depending on @@ -54,9 +58,9 @@ class App : MultiDexApplication() { .build() } - private fun setCrashAnalytics(pref: ApplicationPref) { + private fun setCrashAnalytics() { if (!BuildConfig.DEBUG) - if (pref.isCrashReportsEnabled!!) { + if (applicationPref.isCrashReportsEnabled!!) { val crashlyticsCore = CrashlyticsCore.Builder() .build() @@ -67,15 +71,15 @@ class App : MultiDexApplication() { } } - private fun initApp(pref: ApplicationPref) { + private fun initApp() { EventBus.builder().logNoSubscriberMessages(BuildConfig.DEBUG) .sendNoSubscriberEvent(BuildConfig.DEBUG) .sendSubscriberExceptionEvent(BuildConfig.DEBUG) .throwSubscriberException(BuildConfig.DEBUG) .installDefaultEventBus() - if (pref.isUsageAnalyticsEnabled!!) { + if (applicationPref.isUsageAnalyticsEnabled == true) { analytics = FirebaseAnalytics.getInstance(this).apply { - setAnalyticsCollectionEnabled(pref.isUsageAnalyticsEnabled!!) + setAnalyticsCollectionEnabled(applicationPref.isUsageAnalyticsEnabled!!) } } JobSchedulerUtil.scheduleJob(applicationContext) @@ -99,14 +103,14 @@ class App : MultiDexApplication() { override fun onCreate() { super.onCreate() - val pref = ApplicationPref(this) - setCrashAnalytics(pref) + setCrashAnalytics() setupBoxStore() - initApp(pref) + initApp() } override fun attachBaseContext(base: Context) { - super.attachBaseContext(LocaleUtil.onAttach(base)) + val appPrefs = ApplicationPref(base) + super.attachBaseContext(LocaleUtil.onAttach(base, appPrefs)) MultiDex.install(this) } } diff --git a/app/src/main/java/com/mxt/anitrend/adapter/pager/detail/AnimePageAdapter.java b/app/src/main/java/com/mxt/anitrend/adapter/pager/detail/AnimePageAdapter.java index cdadb2d3c..2a9f0f687 100644 --- a/app/src/main/java/com/mxt/anitrend/adapter/pager/detail/AnimePageAdapter.java +++ b/app/src/main/java/com/mxt/anitrend/adapter/pager/detail/AnimePageAdapter.java @@ -58,7 +58,7 @@ public Fragment getItem(int position) { case 5: return MediaStaffFragment.newInstance(getParams()); case 6: - return MediaFeedFragment.newInstance(getParams(), GraphUtil.getDefaultQuery(true) + return MediaFeedFragment.newInstance(getParams(), GraphUtil.INSTANCE.getDefaultQuery(true) .putVariable(KeyUtil.arg_mediaId, getParams().getLong(KeyUtil.arg_id)) .putVariable(KeyUtil.arg_type, KeyUtil.ANIME_LIST) .putVariable(KeyUtil.arg_isFollowing, true)); diff --git a/app/src/main/java/com/mxt/anitrend/adapter/pager/detail/MangaPageAdapter.java b/app/src/main/java/com/mxt/anitrend/adapter/pager/detail/MangaPageAdapter.java index b5515e42c..32984bd54 100644 --- a/app/src/main/java/com/mxt/anitrend/adapter/pager/detail/MangaPageAdapter.java +++ b/app/src/main/java/com/mxt/anitrend/adapter/pager/detail/MangaPageAdapter.java @@ -55,7 +55,7 @@ public Fragment getItem(int position) { case 4: return MediaStaffFragment.newInstance(getParams()); case 5: - return MediaFeedFragment.newInstance(getParams(), GraphUtil.getDefaultQuery(true) + return MediaFeedFragment.newInstance(getParams(), GraphUtil.INSTANCE.getDefaultQuery(true) .putVariable(KeyUtil.arg_mediaId, getParams().getLong(KeyUtil.arg_id)) .putVariable(KeyUtil.arg_type, KeyUtil.MANGA_LIST) .putVariable(KeyUtil.arg_isFollowing, true)); diff --git a/app/src/main/java/com/mxt/anitrend/adapter/pager/detail/ProfilePageAdapter.java b/app/src/main/java/com/mxt/anitrend/adapter/pager/detail/ProfilePageAdapter.java index 325a89fab..45042b73b 100644 --- a/app/src/main/java/com/mxt/anitrend/adapter/pager/detail/ProfilePageAdapter.java +++ b/app/src/main/java/com/mxt/anitrend/adapter/pager/detail/ProfilePageAdapter.java @@ -33,10 +33,10 @@ public Fragment getItem(int position) { case 0: return UserOverviewFragment.newInstance(getParams()); case 1: - return UserFeedFragment.newInstance(getParams(), GraphUtil.getDefaultQuery(true) + return UserFeedFragment.newInstance(getParams(), GraphUtil.INSTANCE.getDefaultQuery(true) .putVariable(KeyUtil.arg_type, KeyUtil.MEDIA_LIST)); case 2: - return UserFeedFragment.newInstance(getParams(), GraphUtil.getDefaultQuery(true) + return UserFeedFragment.newInstance(getParams(), GraphUtil.INSTANCE.getDefaultQuery(true) .putVariable(KeyUtil.arg_type, KeyUtil.TEXT)); } return null; diff --git a/app/src/main/java/com/mxt/anitrend/adapter/pager/index/FeedPageAdapter.java b/app/src/main/java/com/mxt/anitrend/adapter/pager/index/FeedPageAdapter.java index 7c12569e5..65635e88f 100644 --- a/app/src/main/java/com/mxt/anitrend/adapter/pager/index/FeedPageAdapter.java +++ b/app/src/main/java/com/mxt/anitrend/adapter/pager/index/FeedPageAdapter.java @@ -31,16 +31,16 @@ public Fragment getItem(int position) { switch (position) { case 0: - return FeedListFragment.newInstance(getParams(), GraphUtil.getDefaultQuery(true) + return FeedListFragment.newInstance(getParams(), GraphUtil.INSTANCE.getDefaultQuery(true) .putVariable(KeyUtil.arg_isFollowing, true) .putVariable(KeyUtil.arg_type, KeyUtil.MEDIA_LIST)); case 1: - return FeedListFragment.newInstance(getParams(), GraphUtil.getDefaultQuery(true) + return FeedListFragment.newInstance(getParams(), GraphUtil.INSTANCE.getDefaultQuery(true) .putVariable(KeyUtil.arg_isFollowing, true) .putVariable(KeyUtil.arg_type, KeyUtil.TEXT) .putVariable(KeyUtil.arg_asHtml, false)); case 2: - return FeedListFragment.newInstance(getParams(), GraphUtil.getDefaultQuery(true) + return FeedListFragment.newInstance(getParams(), GraphUtil.INSTANCE.getDefaultQuery(true) .putVariable(KeyUtil.arg_isFollowing, false) .putVariable(KeyUtil.arg_isMixed, true) .putVariable(KeyUtil.arg_asHtml, false)); diff --git a/app/src/main/java/com/mxt/anitrend/adapter/pager/index/MangaPageAdapter.java b/app/src/main/java/com/mxt/anitrend/adapter/pager/index/MangaPageAdapter.java index 870ff9550..8573a2c8b 100644 --- a/app/src/main/java/com/mxt/anitrend/adapter/pager/index/MangaPageAdapter.java +++ b/app/src/main/java/com/mxt/anitrend/adapter/pager/index/MangaPageAdapter.java @@ -33,10 +33,10 @@ public Fragment getItem(int position) { switch (position) { case 0: - return MediaBrowseFragment.newInstance(getParams(), GraphUtil.getDefaultQuery(true) + return MediaBrowseFragment.newInstance(getParams(), GraphUtil.INSTANCE.getDefaultQuery(true) .putVariable(KeyUtil.arg_mediaType, KeyUtil.MANGA)); case 1: - return MediaLatestList.newInstance(getParams(), GraphUtil.getDefaultQuery(true) + return MediaLatestList.newInstance(getParams(), GraphUtil.INSTANCE.getDefaultQuery(true) .putVariable(KeyUtil.arg_mediaType, KeyUtil.MANGA) .putVariable(KeyUtil.arg_sort, KeyUtil.ID + KeyUtil.DESC)); } diff --git a/app/src/main/java/com/mxt/anitrend/adapter/pager/index/MediaListPageAdapter.java b/app/src/main/java/com/mxt/anitrend/adapter/pager/index/MediaListPageAdapter.java index 5d5221da0..1d1390fef 100644 --- a/app/src/main/java/com/mxt/anitrend/adapter/pager/index/MediaListPageAdapter.java +++ b/app/src/main/java/com/mxt/anitrend/adapter/pager/index/MediaListPageAdapter.java @@ -29,7 +29,7 @@ public MediaListPageAdapter(FragmentManager fragmentManager, Context context) { */ @Override public Fragment getItem(int position) { - return MediaListFragment.newInstance(getParams(), GraphUtil.getDefaultQuery(false) + return MediaListFragment.newInstance(getParams(), GraphUtil.INSTANCE.getDefaultQuery(false) .putVariable(KeyUtil.arg_statusIn, KeyUtil.MediaListStatus[position])); } } diff --git a/app/src/main/java/com/mxt/anitrend/adapter/pager/index/SeasonPageAdapter.java b/app/src/main/java/com/mxt/anitrend/adapter/pager/index/SeasonPageAdapter.java index 81740a0d3..864f4d966 100644 --- a/app/src/main/java/com/mxt/anitrend/adapter/pager/index/SeasonPageAdapter.java +++ b/app/src/main/java/com/mxt/anitrend/adapter/pager/index/SeasonPageAdapter.java @@ -30,19 +30,19 @@ public Fragment getItem(int position) { switch (position) { case 0: - return MediaBrowseFragment.newInstance(getParams(), GraphUtil.getDefaultQuery(true) + return MediaBrowseFragment.newInstance(getParams(), GraphUtil.INSTANCE.getDefaultQuery(true) .putVariable(KeyUtil.arg_mediaType, KeyUtil.ANIME) .putVariable(KeyUtil.arg_season, KeyUtil.WINTER)); case 1: - return MediaBrowseFragment.newInstance(getParams(), GraphUtil.getDefaultQuery(true) + return MediaBrowseFragment.newInstance(getParams(), GraphUtil.INSTANCE.getDefaultQuery(true) .putVariable(KeyUtil.arg_mediaType, KeyUtil.ANIME) .putVariable(KeyUtil.arg_season, KeyUtil.SPRING)); case 2: - return MediaBrowseFragment.newInstance(getParams(), GraphUtil.getDefaultQuery(true) + return MediaBrowseFragment.newInstance(getParams(), GraphUtil.INSTANCE.getDefaultQuery(true) .putVariable(KeyUtil.arg_mediaType, KeyUtil.ANIME) .putVariable(KeyUtil.arg_season, KeyUtil.SUMMER)); case 3: - return MediaBrowseFragment.newInstance(getParams(), GraphUtil.getDefaultQuery(true) + return MediaBrowseFragment.newInstance(getParams(), GraphUtil.INSTANCE.getDefaultQuery(true) .putVariable(KeyUtil.arg_mediaType, KeyUtil.ANIME) .putVariable(KeyUtil.arg_season, KeyUtil.FALL)); } diff --git a/app/src/main/java/com/mxt/anitrend/adapter/pager/index/TrendingPageAdapter.java b/app/src/main/java/com/mxt/anitrend/adapter/pager/index/TrendingPageAdapter.java index 8e7fafc04..37243f0b4 100644 --- a/app/src/main/java/com/mxt/anitrend/adapter/pager/index/TrendingPageAdapter.java +++ b/app/src/main/java/com/mxt/anitrend/adapter/pager/index/TrendingPageAdapter.java @@ -30,11 +30,11 @@ public TrendingPageAdapter(FragmentManager fragmentManager, Context context) { public Fragment getItem(int position) { switch (position) { case 0: - return MediaLatestList.newInstance(getParams(), GraphUtil.getDefaultQuery(true) + return MediaLatestList.newInstance(getParams(), GraphUtil.INSTANCE.getDefaultQuery(true) .putVariable(KeyUtil.arg_mediaType, KeyUtil.ANIME) .putVariable(KeyUtil.arg_sort, KeyUtil.TRENDING + KeyUtil.DESC)); case 1: - return MediaLatestList.newInstance(getParams(), GraphUtil.getDefaultQuery(true) + return MediaLatestList.newInstance(getParams(), GraphUtil.INSTANCE.getDefaultQuery(true) .putVariable(KeyUtil.arg_mediaType, KeyUtil.ANIME) .putVariable(KeyUtil.arg_sort, KeyUtil.ID + KeyUtil.DESC)); } diff --git a/app/src/main/java/com/mxt/anitrend/adapter/recycler/detail/CommentAdapter.java b/app/src/main/java/com/mxt/anitrend/adapter/recycler/detail/CommentAdapter.java index 31804d347..b53b134b1 100644 --- a/app/src/main/java/com/mxt/anitrend/adapter/recycler/detail/CommentAdapter.java +++ b/app/src/main/java/com/mxt/anitrend/adapter/recycler/detail/CommentAdapter.java @@ -31,7 +31,7 @@ public CommentAdapter(Context context) { @NonNull @Override public RecyclerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - return new CommentViewHolder(AdapterCommentBinding.inflate(CompatUtil.getLayoutInflater(parent.getContext()), parent, false)); + return new CommentViewHolder(AdapterCommentBinding.inflate(CompatUtil.INSTANCE.getLayoutInflater(parent.getContext()), parent, false)); } @Override diff --git a/app/src/main/java/com/mxt/anitrend/adapter/recycler/detail/GenreAdapter.java b/app/src/main/java/com/mxt/anitrend/adapter/recycler/detail/GenreAdapter.java index 1bbafc365..83d00fa0e 100644 --- a/app/src/main/java/com/mxt/anitrend/adapter/recycler/detail/GenreAdapter.java +++ b/app/src/main/java/com/mxt/anitrend/adapter/recycler/detail/GenreAdapter.java @@ -30,7 +30,7 @@ public GenreAdapter(Context context) { @NonNull @Override public RecyclerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - return new GenreViewHolder(AdapterGenreBinding.inflate(CompatUtil.getLayoutInflater(parent.getContext()), parent, false)); + return new GenreViewHolder(AdapterGenreBinding.inflate(CompatUtil.INSTANCE.getLayoutInflater(parent.getContext()), parent, false)); } @Override diff --git a/app/src/main/java/com/mxt/anitrend/adapter/recycler/detail/GiphyAdapter.java b/app/src/main/java/com/mxt/anitrend/adapter/recycler/detail/GiphyAdapter.java index 265276290..a5ec02025 100644 --- a/app/src/main/java/com/mxt/anitrend/adapter/recycler/detail/GiphyAdapter.java +++ b/app/src/main/java/com/mxt/anitrend/adapter/recycler/detail/GiphyAdapter.java @@ -36,7 +36,7 @@ public GiphyAdapter(Context context) { @NonNull @Override public RecyclerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - return new GiphyViewHolder(AdapterGiphyBinding.inflate(CompatUtil.getLayoutInflater(parent.getContext()), parent, false)); + return new GiphyViewHolder(AdapterGiphyBinding.inflate(CompatUtil.INSTANCE.getLayoutInflater(parent.getContext()), parent, false)); } @Override diff --git a/app/src/main/java/com/mxt/anitrend/adapter/recycler/detail/LinkAdapter.java b/app/src/main/java/com/mxt/anitrend/adapter/recycler/detail/LinkAdapter.java index fffcf977d..a6b91a15a 100644 --- a/app/src/main/java/com/mxt/anitrend/adapter/recycler/detail/LinkAdapter.java +++ b/app/src/main/java/com/mxt/anitrend/adapter/recycler/detail/LinkAdapter.java @@ -30,7 +30,7 @@ public LinkAdapter(Context context) { @NonNull @Override public RecyclerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - return new LinkViewHolder(AdapterLinkBinding.inflate(CompatUtil.getLayoutInflater(parent.getContext()), parent, false)); + return new LinkViewHolder(AdapterLinkBinding.inflate(CompatUtil.INSTANCE.getLayoutInflater(parent.getContext()), parent, false)); } @Override diff --git a/app/src/main/java/com/mxt/anitrend/adapter/recycler/detail/NotificationAdapter.java b/app/src/main/java/com/mxt/anitrend/adapter/recycler/detail/NotificationAdapter.java deleted file mode 100644 index a2adf676d..000000000 --- a/app/src/main/java/com/mxt/anitrend/adapter/recycler/detail/NotificationAdapter.java +++ /dev/null @@ -1,215 +0,0 @@ -package com.mxt.anitrend.adapter.recycler.detail; - -import android.content.Context; -import android.support.annotation.NonNull; -import android.view.View; -import android.view.ViewGroup; -import android.widget.Adapter; -import android.widget.Filter; - -import com.bumptech.glide.Glide; -import com.mxt.anitrend.R; -import com.mxt.anitrend.adapter.recycler.shared.UnresolvedViewHolder; -import com.mxt.anitrend.base.custom.recycler.RecyclerViewAdapter; -import com.mxt.anitrend.base.custom.recycler.RecyclerViewHolder; -import com.mxt.anitrend.base.custom.view.image.AspectImageView; -import com.mxt.anitrend.databinding.AdapterNotificationBinding; -import com.mxt.anitrend.databinding.CustomRecyclerUnresolvedBinding; -import com.mxt.anitrend.model.entity.anilist.Notification; -import com.mxt.anitrend.model.entity.base.NotificationHistory; -import com.mxt.anitrend.model.entity.base.NotificationHistory_; -import com.mxt.anitrend.util.CompatUtil; -import com.mxt.anitrend.util.DateUtil; -import com.mxt.anitrend.util.KeyUtil; - -import butterknife.OnClick; -import butterknife.OnLongClick; -import io.objectbox.Box; - -/** - * Created by max on 2017/12/06. - * Notification adapter - */ - -public class NotificationAdapter extends RecyclerViewAdapter { - - private Box historyBox; - - public NotificationAdapter(Context context) { - super(context); - historyBox = presenter.getDatabase().getBoxStore(NotificationHistory.class); - } - - @NonNull - @Override - public RecyclerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, @KeyUtil.RecyclerViewType int viewType) { - if (viewType == KeyUtil.RECYCLER_TYPE_CONTENT) - return new NotificationHolder(AdapterNotificationBinding.inflate(CompatUtil.getLayoutInflater(parent.getContext()), parent, false)); - return new UnresolvedViewHolder<>(CustomRecyclerUnresolvedBinding.inflate(CompatUtil.getLayoutInflater(parent.getContext()), parent, false)); - } - - /** - * Return the view type of the item at position for the purposes - * of view recycling. - * - *

The default implementation of this method returns 0, making the assumption of - * a single view type for the adapter. Unlike ListView adapters, types need not - * be contiguous. Consider using id resources to uniquely identify item view types. - * - * @param position position to query - * @return integer value identifying the type of the view needed to represent the item at - * position. Type codes need not be contiguous. - */ - @Override - public int getItemViewType(int position) { - final Notification notification = data.get(position); - if (!CompatUtil.equals(notification.getType(), KeyUtil.AIRING) && notification.getUser() == null) - return KeyUtil.RECYCLER_TYPE_ERROR; - return KeyUtil.RECYCLER_TYPE_CONTENT; - } - - /** - *

Returns a filter that can be used to constrain data with a filtering - * pattern.

- *

- *

This method is usually implemented by {@link Adapter} - * classes.

- * - * @return a filter used to constrain data - */ - @Override - public Filter getFilter() { - return null; - } - - protected class NotificationHolder extends RecyclerViewHolder { - - private AdapterNotificationBinding binding; - - /** - * Default constructor which includes binding with butter knife - * - * @param binding - */ - public NotificationHolder(AdapterNotificationBinding binding) { - super(binding.getRoot()); - this.binding = binding; - } - - /** - * Load image, text, buttons, etc. in this method from the given parameter - *
- * - * @param model Is the model at the current adapter position - */ - @Override - public void onBindViewHolder(Notification model) { - NotificationHistory notificationHistory = historyBox.query() - .equal(NotificationHistory_.id, model.getId()) - .build().findFirst(); - - if(notificationHistory != null) - binding.notificationIndicator.setVisibility(View.GONE); - else - binding.notificationIndicator.setVisibility(View.VISIBLE); - - binding.notificationTime.setText(DateUtil.getPrettyDateUnix(model.getCreatedAt())); - - if(!CompatUtil.equals(model.getType(), KeyUtil.AIRING)) { - if (model.getUser() != null && model.getUser().getAvatar() != null) - AspectImageView.setImage(binding.notificationImg, model.getUser().getAvatar().getLarge()); - } - else - AspectImageView.setImage(binding.notificationImg, model.getMedia().getCoverImage().getLarge()); - - switch (model.getType()) { - case KeyUtil.ACTIVITY_MESSAGE: - binding.notificationSubject.setText(R.string.notification_user_activity_message); - binding.notificationHeader.setText(model.getUser().getName()); - binding.notificationContent.setText(model.getContext()); - break; - case KeyUtil.FOLLOWING: - binding.notificationSubject.setText(R.string.notification_user_follow_activity); - binding.notificationHeader.setText(model.getUser().getName()); - binding.notificationContent.setText(model.getContext()); - break; - case KeyUtil.ACTIVITY_MENTION: - binding.notificationSubject.setText(R.string.notification_user_activity_mention); - binding.notificationHeader.setText(model.getUser().getName()); - binding.notificationContent.setText(model.getContext()); - break; - case KeyUtil.THREAD_COMMENT_MENTION: - binding.notificationSubject.setText(R.string.notification_user_comment_forum); - binding.notificationHeader.setText(model.getUser().getName()); - binding.notificationContent.setText(model.getContext()); - break; - case KeyUtil.THREAD_SUBSCRIBED: - binding.notificationSubject.setText(R.string.notification_user_comment_forum); - binding.notificationHeader.setText(model.getUser().getName()); - binding.notificationContent.setText(model.getContext()); - break; - case KeyUtil.THREAD_COMMENT_REPLY: - binding.notificationSubject.setText(R.string.notification_user_comment_forum); - binding.notificationHeader.setText(model.getUser().getName()); - binding.notificationContent.setText(model.getContext()); - break; - case KeyUtil.AIRING: - binding.notificationSubject.setText(R.string.notification_series); - binding.notificationHeader.setText(model.getMedia().getTitle().getUserPreferred()); - binding.notificationContent.setText(context.getString(R.string.notification_episode, - String.valueOf(model.getEpisode()), model.getMedia().getTitle().getUserPreferred())); - break; - case KeyUtil.ACTIVITY_LIKE: - binding.notificationSubject.setText(R.string.notification_user_like_activity); - binding.notificationHeader.setText(model.getUser().getName()); - binding.notificationContent.setText(model.getContext()); - break; - case KeyUtil.ACTIVITY_REPLY: - case KeyUtil.ACTIVITY_REPLY_SUBSCRIBED: - binding.notificationSubject.setText(R.string.notification_user_reply_activity); - binding.notificationHeader.setText(model.getUser().getName()); - binding.notificationContent.setText(model.getContext()); - break; - case KeyUtil.ACTIVITY_REPLY_LIKE: - binding.notificationSubject.setText(R.string.notification_user_like_reply); - binding.notificationHeader.setText(model.getUser().getName()); - binding.notificationContent.setText(model.getContext()); - break; - case KeyUtil.THREAD_LIKE: - binding.notificationSubject.setText(R.string.notification_user_like_activity); - binding.notificationHeader.setText(model.getUser().getName()); - binding.notificationContent.setText(model.getContext()); - break; - case KeyUtil.THREAD_COMMENT_LIKE: - binding.notificationSubject.setText(R.string.notification_user_like_comment); - binding.notificationHeader.setText(model.getUser().getName()); - binding.notificationContent.setText(model.getContext()); - break; - } - binding.executePendingBindings(); - } - - /** - * If any image views are used within the view holder, clear any pending async img requests - * by using Glide.clear(ImageView) or Glide.with(context).clear(view) if using Glide v4.0 - *
- * - * @see Glide - */ - @Override - public void onViewRecycled() { - Glide.with(getContext()).clear(binding.notificationImg); - binding.unbind(); - } - - @Override @OnClick({R.id.container, R.id.notification_img}) - public void onClick(View v) { - performClick(clickListener, data, v); - } - - @Override @OnLongClick(R.id.container) - public boolean onLongClick(View v) { - return performLongClick(clickListener, data, v); - } - } -} diff --git a/app/src/main/java/com/mxt/anitrend/adapter/recycler/detail/NotificationAdapter.kt b/app/src/main/java/com/mxt/anitrend/adapter/recycler/detail/NotificationAdapter.kt new file mode 100644 index 000000000..460b46577 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/adapter/recycler/detail/NotificationAdapter.kt @@ -0,0 +1,216 @@ +package com.mxt.anitrend.adapter.recycler.detail + +import android.content.Context +import android.view.View +import android.view.ViewGroup +import android.widget.Adapter +import android.widget.Filter + +import com.bumptech.glide.Glide +import com.mxt.anitrend.R +import com.mxt.anitrend.adapter.recycler.shared.UnresolvedViewHolder +import com.mxt.anitrend.base.custom.recycler.RecyclerViewAdapter +import com.mxt.anitrend.base.custom.recycler.RecyclerViewHolder +import com.mxt.anitrend.base.custom.view.image.AspectImageView +import com.mxt.anitrend.databinding.AdapterNotificationBinding +import com.mxt.anitrend.databinding.CustomRecyclerUnresolvedBinding +import com.mxt.anitrend.model.entity.anilist.Notification +import com.mxt.anitrend.model.entity.base.NotificationHistory +import com.mxt.anitrend.model.entity.base.NotificationHistory_ +import com.mxt.anitrend.util.CompatUtil +import com.mxt.anitrend.util.DateUtil +import com.mxt.anitrend.util.KeyUtil + +import butterknife.OnClick +import butterknife.OnLongClick +import io.objectbox.Box + +/** + * Created by max on 2017/12/06. + * Notification adapter + */ + +class NotificationAdapter(context: Context) : RecyclerViewAdapter(context) { + + private val historyBox: Box by lazy { + presenter.database.getBoxStore(NotificationHistory::class.java) + } + + override fun onCreateViewHolder(parent: ViewGroup, @KeyUtil.RecyclerViewType viewType: Int): RecyclerViewHolder { + return when (viewType) { + KeyUtil.RECYCLER_TYPE_CONTENT -> + NotificationHolder(AdapterNotificationBinding.inflate(CompatUtil.getLayoutInflater(parent.context), parent, false)) + else -> + UnresolvedViewHolder(CustomRecyclerUnresolvedBinding.inflate(CompatUtil.getLayoutInflater(parent.context), parent, false)) + } + } + + /** + * Return the view type of the item at `position` for the purposes + * of view recycling. + * + * + * The default implementation of this method returns 0, making the assumption of + * a single view type for the adapter. Unlike ListView adapters, types need not + * be contiguous. Consider using id resources to uniquely identify item view types. + * + * @param position position to query + * @return integer value identifying the type of the view needed to represent the item at + * `position`. Type codes need not be contiguous. + */ + override fun getItemViewType(position: Int): Int { + val notification = data[position] + return when (notification.user) { + null -> { + when (notification?.type) { + KeyUtil.AIRING, KeyUtil.RELATED_MEDIA_ADDITION -> KeyUtil.RECYCLER_TYPE_CONTENT + else -> KeyUtil.RECYCLER_TYPE_ERROR + } + } + else -> KeyUtil.RECYCLER_TYPE_CONTENT + } + } + + /** + * + * Returns a filter that can be used to constrain data with a filtering + * pattern. + * + * + * + * This method is usually implemented by [Adapter] + * classes. + * + * @return a filter used to constrain data + */ + override fun getFilter(): Filter? { + return null + } + + /** + * Default constructor which includes binding with butter knife + * + * @param binding + */ + inner class NotificationHolder( + private val binding: AdapterNotificationBinding + ) : RecyclerViewHolder(binding.root) { + + /** + * Load image, text, buttons, etc. in this method from the given parameter + *

+ * + * @param model Is the model at the current adapter position + */ + override fun onBindViewHolder(model: Notification) { + val notificationHistory = historyBox.query() + .equal(NotificationHistory_.id, model.id) + .build().findFirst() + + if (notificationHistory != null) + binding.notificationIndicator.visibility = View.GONE + else + binding.notificationIndicator.visibility = View.VISIBLE + + binding.notificationTime.text = DateUtil.getPrettyDateUnix(model.createdAt) + + if (!CompatUtil.equals(model.type, KeyUtil.AIRING)) { + if (model.user != null && model.user.avatar != null) + AspectImageView.setImage(binding.notificationImg, model.user.avatar.large) + } else + AspectImageView.setImage(binding.notificationImg, model.media.coverImage.large) + + when (model.type) { + KeyUtil.ACTIVITY_MESSAGE -> { + binding.notificationSubject.setText(R.string.notification_user_activity_message) + binding.notificationHeader.text = model.user.name + binding.notificationContent.text = model.context + } + KeyUtil.FOLLOWING -> { + binding.notificationSubject.setText(R.string.notification_user_follow_activity) + binding.notificationHeader.text = model.user.name + binding.notificationContent.text = model.context + } + KeyUtil.ACTIVITY_MENTION -> { + binding.notificationSubject.setText(R.string.notification_user_activity_mention) + binding.notificationHeader.text = model.user.name + binding.notificationContent.text = model.context + } + KeyUtil.THREAD_COMMENT_MENTION -> { + binding.notificationSubject.setText(R.string.notification_user_comment_forum) + binding.notificationHeader.text = model.user.name + binding.notificationContent.text = model.context + } + KeyUtil.THREAD_SUBSCRIBED -> { + binding.notificationSubject.setText(R.string.notification_user_comment_forum) + binding.notificationHeader.text = model.user.name + binding.notificationContent.text = model.context + } + KeyUtil.THREAD_COMMENT_REPLY -> { + binding.notificationSubject.setText(R.string.notification_user_comment_forum) + binding.notificationHeader.text = model.user.name + binding.notificationContent.text = model.context + } + KeyUtil.AIRING -> { + binding.notificationSubject.setText(R.string.notification_series) + binding.notificationHeader.text = model.media.title.userPreferred + binding.notificationContent.text = context.getString(R.string.notification_episode, + model.episode.toString(), model.media.title.userPreferred) + } + KeyUtil.ACTIVITY_LIKE -> { + binding.notificationSubject.setText(R.string.notification_user_like_activity) + binding.notificationHeader.text = model.user.name + binding.notificationContent.text = model.context + } + KeyUtil.ACTIVITY_REPLY, KeyUtil.ACTIVITY_REPLY_SUBSCRIBED -> { + binding.notificationSubject.setText(R.string.notification_user_reply_activity) + binding.notificationHeader.text = model.user.name + binding.notificationContent.text = model.context + } + KeyUtil.ACTIVITY_REPLY_LIKE -> { + binding.notificationSubject.setText(R.string.notification_user_like_reply) + binding.notificationHeader.text = model.user.name + binding.notificationContent.text = model.context + } + KeyUtil.THREAD_LIKE -> { + binding.notificationSubject.setText(R.string.notification_user_like_activity) + binding.notificationHeader.text = model.user.name + binding.notificationContent.text = model.context + } + KeyUtil.THREAD_COMMENT_LIKE -> { + binding.notificationSubject.setText(R.string.notification_user_like_comment) + binding.notificationHeader.text = model.user.name + binding.notificationContent.text = model.context + } + KeyUtil.RELATED_MEDIA_ADDITION -> { + binding.notificationSubject.setText(R.string.notification_media_added) + binding.notificationHeader.text = model.media.title.userPreferred + binding.notificationContent.text = model.context + } + } + binding.executePendingBindings() + } + + /** + * If any image views are used within the view holder, clear any pending async img requests + * by using Glide.clear(ImageView) or Glide.with(context).clear(view) if using Glide v4.0 + *

+ * + * @see Glide + */ + override fun onViewRecycled() { + Glide.with(context).clear(binding.notificationImg) + binding.unbind() + } + + @OnClick(R.id.container, R.id.notification_img) + override fun onClick(v: View) { + performClick(clickListener, data, v) + } + + @OnLongClick(R.id.container) + override fun onLongClick(v: View): Boolean { + return performLongClick(clickListener, data, v) + } + } +} diff --git a/app/src/main/java/com/mxt/anitrend/adapter/recycler/detail/RankAdapter.java b/app/src/main/java/com/mxt/anitrend/adapter/recycler/detail/RankAdapter.java index 8dafc94a9..6c52f93e3 100644 --- a/app/src/main/java/com/mxt/anitrend/adapter/recycler/detail/RankAdapter.java +++ b/app/src/main/java/com/mxt/anitrend/adapter/recycler/detail/RankAdapter.java @@ -31,7 +31,7 @@ public RankAdapter(Context context) { @NonNull @Override public RecyclerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - return new RankViewHolder(AdapterRankingBinding.inflate(CompatUtil.getLayoutInflater(parent.getContext()), parent, false)); + return new RankViewHolder(AdapterRankingBinding.inflate(CompatUtil.INSTANCE.getLayoutInflater(parent.getContext()), parent, false)); } @Override @@ -62,7 +62,7 @@ public RankViewHolder(AdapterRankingBinding binding) { @Override public void onBindViewHolder(MediaRank model) { binding.setModel(model); - binding.rankingType.setImageDrawable(CompatUtil.getDrawable(getContext(), CompatUtil.equals(model.getType(), KeyUtil.RATED) ? + binding.rankingType.setImageDrawable(CompatUtil.INSTANCE.getDrawable(getContext(), CompatUtil.INSTANCE.equals(model.getType(), KeyUtil.RATED) ? R.drawable.ic_star_yellow_700_24dp : R.drawable.ic_favorite_red_700_24dp )); binding.executePendingBindings(); } diff --git a/app/src/main/java/com/mxt/anitrend/adapter/recycler/detail/TagAdapter.java b/app/src/main/java/com/mxt/anitrend/adapter/recycler/detail/TagAdapter.java index 4afcf1650..3d286fb81 100644 --- a/app/src/main/java/com/mxt/anitrend/adapter/recycler/detail/TagAdapter.java +++ b/app/src/main/java/com/mxt/anitrend/adapter/recycler/detail/TagAdapter.java @@ -30,7 +30,7 @@ public TagAdapter(Context context) { @NonNull @Override public RecyclerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - return new TagViewHolder(AdapterTagBinding.inflate(CompatUtil.getLayoutInflater(parent.getContext()), parent, false)); + return new TagViewHolder(AdapterTagBinding.inflate(CompatUtil.INSTANCE.getLayoutInflater(parent.getContext()), parent, false)); } @Override diff --git a/app/src/main/java/com/mxt/anitrend/adapter/recycler/group/GroupActorAdapter.java b/app/src/main/java/com/mxt/anitrend/adapter/recycler/group/GroupActorAdapter.java index 6d480369a..af51464a0 100644 --- a/app/src/main/java/com/mxt/anitrend/adapter/recycler/group/GroupActorAdapter.java +++ b/app/src/main/java/com/mxt/anitrend/adapter/recycler/group/GroupActorAdapter.java @@ -42,8 +42,8 @@ public void setMediaClickListener(ItemClickListener mediaClickList @Override public RecyclerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, @KeyUtil.RecyclerViewType int viewType) { if (viewType == KeyUtil.RECYCLER_TYPE_HEADER) - return new GroupMediaViewHolder(AdapterMediaHeaderBinding.inflate(CompatUtil.getLayoutInflater(parent.getContext()), parent, false), mediaClickListener); - return new StaffViewHolder(AdapterStaffBinding.inflate(CompatUtil.getLayoutInflater(parent.getContext()), parent, false)); + return new GroupMediaViewHolder(AdapterMediaHeaderBinding.inflate(CompatUtil.INSTANCE.getLayoutInflater(parent.getContext()), parent, false), mediaClickListener); + return new StaffViewHolder(AdapterStaffBinding.inflate(CompatUtil.INSTANCE.getLayoutInflater(parent.getContext()), parent, false)); } @Override diff --git a/app/src/main/java/com/mxt/anitrend/adapter/recycler/group/GroupCharacterAdapter.java b/app/src/main/java/com/mxt/anitrend/adapter/recycler/group/GroupCharacterAdapter.java index 74cf24438..1f5fc7cef 100644 --- a/app/src/main/java/com/mxt/anitrend/adapter/recycler/group/GroupCharacterAdapter.java +++ b/app/src/main/java/com/mxt/anitrend/adapter/recycler/group/GroupCharacterAdapter.java @@ -35,8 +35,8 @@ public GroupCharacterAdapter(Context context) { @Override public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, @KeyUtil.RecyclerViewType int viewType) { if (viewType == KeyUtil.RECYCLER_TYPE_HEADER) - return new GroupTitleViewHolder(AdapterEntityGroupBinding.inflate(CompatUtil.getLayoutInflater(parent.getContext()), parent, false)); - return new CharacterViewHolder(AdapterCharacterBinding.inflate(CompatUtil.getLayoutInflater(parent.getContext()), parent, false)); + return new GroupTitleViewHolder(AdapterEntityGroupBinding.inflate(CompatUtil.INSTANCE.getLayoutInflater(parent.getContext()), parent, false)); + return new CharacterViewHolder(AdapterCharacterBinding.inflate(CompatUtil.INSTANCE.getLayoutInflater(parent.getContext()), parent, false)); } @Override diff --git a/app/src/main/java/com/mxt/anitrend/adapter/recycler/group/GroupSeriesAdapter.java b/app/src/main/java/com/mxt/anitrend/adapter/recycler/group/GroupSeriesAdapter.java index 0f0a9b0cf..2afa63e3d 100644 --- a/app/src/main/java/com/mxt/anitrend/adapter/recycler/group/GroupSeriesAdapter.java +++ b/app/src/main/java/com/mxt/anitrend/adapter/recycler/group/GroupSeriesAdapter.java @@ -35,8 +35,8 @@ public GroupSeriesAdapter(Context context) { @Override public RecyclerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, @KeyUtil.RecyclerViewType int viewType) { if (viewType == KeyUtil.RECYCLER_TYPE_HEADER) - return new GroupTitleViewHolder(AdapterEntityGroupBinding.inflate(CompatUtil.getLayoutInflater(parent.getContext()), parent, false)); - return new SeriesViewHolder(AdapterSeriesBinding.inflate(CompatUtil.getLayoutInflater(parent.getContext()), parent, false)); + return new GroupTitleViewHolder(AdapterEntityGroupBinding.inflate(CompatUtil.INSTANCE.getLayoutInflater(parent.getContext()), parent, false)); + return new SeriesViewHolder(AdapterSeriesBinding.inflate(CompatUtil.INSTANCE.getLayoutInflater(parent.getContext()), parent, false)); } @Override diff --git a/app/src/main/java/com/mxt/anitrend/adapter/recycler/group/GroupStaffRoleAdapter.java b/app/src/main/java/com/mxt/anitrend/adapter/recycler/group/GroupStaffRoleAdapter.java index 99888344b..cd488201f 100644 --- a/app/src/main/java/com/mxt/anitrend/adapter/recycler/group/GroupStaffRoleAdapter.java +++ b/app/src/main/java/com/mxt/anitrend/adapter/recycler/group/GroupStaffRoleAdapter.java @@ -35,8 +35,8 @@ public GroupStaffRoleAdapter(Context context) { @Override public RecyclerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, @KeyUtil.RecyclerViewType int viewType) { if (viewType == KeyUtil.RECYCLER_TYPE_HEADER) - return new GroupTitleViewHolder(AdapterEntityGroupBinding.inflate(CompatUtil.getLayoutInflater(parent.getContext()), parent, false)); - return new StaffViewHolder(AdapterStaffBinding.inflate(CompatUtil.getLayoutInflater(parent.getContext()), parent, false)); + return new GroupTitleViewHolder(AdapterEntityGroupBinding.inflate(CompatUtil.INSTANCE.getLayoutInflater(parent.getContext()), parent, false)); + return new StaffViewHolder(AdapterStaffBinding.inflate(CompatUtil.INSTANCE.getLayoutInflater(parent.getContext()), parent, false)); } @Override diff --git a/app/src/main/java/com/mxt/anitrend/adapter/recycler/index/FeedAdapter.java b/app/src/main/java/com/mxt/anitrend/adapter/recycler/index/FeedAdapter.java index 28c1aac49..1c5f19d2c 100644 --- a/app/src/main/java/com/mxt/anitrend/adapter/recycler/index/FeedAdapter.java +++ b/app/src/main/java/com/mxt/anitrend/adapter/recycler/index/FeedAdapter.java @@ -74,11 +74,11 @@ public int getItemViewType(int position) { FeedList model = data.get(position); if(model == null || TextUtils.isEmpty(model.getType())) return -1; - if(CompatUtil.equals(model.getType(), KeyUtil.TEXT)) + if(CompatUtil.INSTANCE.equals(model.getType(), KeyUtil.TEXT)) return FEED_STATUS; - else if(CompatUtil.equals(model.getType(), KeyUtil.MESSAGE)) + else if(CompatUtil.INSTANCE.equals(model.getType(), KeyUtil.MESSAGE)) return FEED_MESSAGE; - else if(CompatUtil.equals(model.getType(), KeyUtil.MEDIA_LIST) && model.getLikes() == null) + else if(CompatUtil.INSTANCE.equals(model.getType(), KeyUtil.MEDIA_LIST) && model.getLikes() == null) return FEED_LIST; return FEED_PROGRESS; } diff --git a/app/src/main/java/com/mxt/anitrend/adapter/recycler/index/MediaAdapter.java b/app/src/main/java/com/mxt/anitrend/adapter/recycler/index/MediaAdapter.java index 5c5139676..4a7e88cc7 100644 --- a/app/src/main/java/com/mxt/anitrend/adapter/recycler/index/MediaAdapter.java +++ b/app/src/main/java/com/mxt/anitrend/adapter/recycler/index/MediaAdapter.java @@ -41,7 +41,7 @@ public MediaAdapter(Context context, boolean isCompatType) { @Override public RecyclerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, @KeyUtil.RecyclerViewType int viewType) { if(isCompatType) - return new MediaViewHolder(AdapterSeriesBinding.inflate(CompatUtil.getLayoutInflater(parent.getContext()), parent, false)); + return new MediaViewHolder(AdapterSeriesBinding.inflate(CompatUtil.INSTANCE.getLayoutInflater(parent.getContext()), parent, false)); if(viewType == KeyUtil.RECYCLER_TYPE_ANIME) return new AnimeViewHolder(AdapterAnimeBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false)); return new MangaViewHolder(AdapterMangaBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false)); @@ -49,7 +49,7 @@ public RecyclerViewHolder onCreateViewHolder(@NonNull ViewGroup paren @Override public @KeyUtil.RecyclerViewType int getItemViewType(int position) { - if(CompatUtil.equals(data.get(position).getType(), KeyUtil.ANIME)) + if(CompatUtil.INSTANCE.equals(data.get(position).getType(), KeyUtil.ANIME)) return KeyUtil.RECYCLER_TYPE_ANIME; return KeyUtil.RECYCLER_TYPE_MANGA; } diff --git a/app/src/main/java/com/mxt/anitrend/adapter/recycler/index/MediaListAdapter.java b/app/src/main/java/com/mxt/anitrend/adapter/recycler/index/MediaListAdapter.java index 278827794..4785c09c3 100644 --- a/app/src/main/java/com/mxt/anitrend/adapter/recycler/index/MediaListAdapter.java +++ b/app/src/main/java/com/mxt/anitrend/adapter/recycler/index/MediaListAdapter.java @@ -49,7 +49,7 @@ public Filter getFilter() { @Override protected FilterResults performFiltering(CharSequence constraint) { FilterResults results = new FilterResults(); - if(CompatUtil.isEmpty(clone)) + if(CompatUtil.INSTANCE.isEmpty(clone)) clone = data; String filter = constraint.toString(); if(TextUtils.isEmpty(filter)) { diff --git a/app/src/main/java/com/mxt/anitrend/adapter/recycler/index/StaffAdapter.java b/app/src/main/java/com/mxt/anitrend/adapter/recycler/index/StaffAdapter.java index f13ac4775..d0828f4a4 100644 --- a/app/src/main/java/com/mxt/anitrend/adapter/recycler/index/StaffAdapter.java +++ b/app/src/main/java/com/mxt/anitrend/adapter/recycler/index/StaffAdapter.java @@ -30,7 +30,7 @@ public StaffAdapter(Context context) { @NonNull @Override public RecyclerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - return new StaffViewHolder(AdapterStaffBinding.inflate(CompatUtil.getLayoutInflater(parent.getContext()), parent, false)); + return new StaffViewHolder(AdapterStaffBinding.inflate(CompatUtil.INSTANCE.getLayoutInflater(parent.getContext()), parent, false)); } @Override diff --git a/app/src/main/java/com/mxt/anitrend/adapter/recycler/index/StudioAdapter.java b/app/src/main/java/com/mxt/anitrend/adapter/recycler/index/StudioAdapter.java index 0ec672fe5..38f4bfa6c 100644 --- a/app/src/main/java/com/mxt/anitrend/adapter/recycler/index/StudioAdapter.java +++ b/app/src/main/java/com/mxt/anitrend/adapter/recycler/index/StudioAdapter.java @@ -29,7 +29,7 @@ public StudioAdapter(Context context) { @NonNull @Override public RecyclerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - return new StudioViewHolder(AdapterStudioBinding.inflate(CompatUtil.getLayoutInflater(parent.getContext()), parent, false)); + return new StudioViewHolder(AdapterStudioBinding.inflate(CompatUtil.INSTANCE.getLayoutInflater(parent.getContext()), parent, false)); } @Override diff --git a/app/src/main/java/com/mxt/anitrend/adapter/recycler/index/UserAdapter.java b/app/src/main/java/com/mxt/anitrend/adapter/recycler/index/UserAdapter.java index 388317634..6f8dd1a48 100644 --- a/app/src/main/java/com/mxt/anitrend/adapter/recycler/index/UserAdapter.java +++ b/app/src/main/java/com/mxt/anitrend/adapter/recycler/index/UserAdapter.java @@ -44,7 +44,7 @@ public Filter getFilter() { @Override protected FilterResults performFiltering(CharSequence constraint) { FilterResults results = new FilterResults(); - if(CompatUtil.isEmpty(clone)) + if(CompatUtil.INSTANCE.isEmpty(clone)) clone = data; String filter = constraint.toString(); if(TextUtils.isEmpty(filter)) { diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/activity/ActivityBase.java b/app/src/main/java/com/mxt/anitrend/base/custom/activity/ActivityBase.java index 9504bed4c..4b202838e 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/activity/ActivityBase.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/activity/ActivityBase.java @@ -79,9 +79,10 @@ public abstract class ActivityBase extends AppComp private boolean isClosing; - private App application; private CommonPresenter presenter; + private ApplicationPref applicationPref; + private @StyleRes int style; /** @@ -89,8 +90,10 @@ public abstract class ActivityBase extends AppComp * override this method and set your own theme style. */ protected void configureActivity() { - ApplicationPref applicationPref = new ApplicationPref(this); - if(!CompatUtil.isLightTheme((style = applicationPref.getTheme())) && applicationPref.isBlackThemeEnabled()) + if (applicationPref == null) + applicationPref = ((App)getApplicationContext()).getApplicationPref(); + style = applicationPref.getTheme(); + if(!CompatUtil.INSTANCE.isLightTheme(style) && applicationPref.isBlackThemeEnabled()) setTheme(R.style.AppThemeBlack); else setTheme(style); @@ -98,14 +101,17 @@ protected void configureActivity() { @Override protected void attachBaseContext(Context base) { - super.attachBaseContext(LocaleUtil.onAttach(base)); + if (applicationPref == null) + applicationPref = new ApplicationPref(base); + super.attachBaseContext(LocaleUtil.INSTANCE.onAttach(base, applicationPref)); } @Override protected void onCreate(@Nullable Bundle savedInstanceState) { TAG = this.toString(); configureActivity(); super.onCreate(savedInstanceState); - intentBundleUtil = new IntentBundleUtil(getIntent(), this); + intentBundleUtil = new IntentBundleUtil(getIntent()); + intentBundleUtil.checkIntentData(this); AnalyticsUtil.logCurrentScreen(this, TAG); } @@ -414,7 +420,7 @@ public boolean onQueryTextSubmit(String query) { Intent intent = new Intent(this, SearchActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.putExtra(KeyUtil.arg_search, query); - CompatUtil.startRevealAnim(this, mSearchView, intent); + CompatUtil.INSTANCE.startRevealAnim(this, mSearchView, intent); return true; } NotifyUtil.makeText(this, R.string.text_search_empty, Toast.LENGTH_SHORT).show(); diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/fragment/FragmentBaseComment.java b/app/src/main/java/com/mxt/anitrend/base/custom/fragment/FragmentBaseComment.java index 86e220408..22dfd6a31 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/fragment/FragmentBaseComment.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/fragment/FragmentBaseComment.java @@ -217,7 +217,7 @@ public void showError(String error) { } else { showLoading(); - stateLayout.showError(CompatUtil.getDrawable(getContext(), R.drawable.ic_emoji_cry), + stateLayout.showError(CompatUtil.INSTANCE.getDrawable(getContext(), R.drawable.ic_emoji_cry), error, getString(R.string.try_again), stateLayoutOnClick); } } @@ -239,7 +239,7 @@ public void showEmpty(String message) { } else { showLoading(); - stateLayout.showError(CompatUtil.getDrawable(getContext(), R.drawable.ic_emoji_sweat), + stateLayout.showError(CompatUtil.INSTANCE.getDrawable(getContext(), R.drawable.ic_emoji_sweat), message, getString(R.string.try_again), stateLayoutOnClick); } } @@ -324,7 +324,7 @@ else if(swipeRefreshLayout.isLoading()) */ @Override public void onChanged(@Nullable FeedList content) { - if(content != null && !CompatUtil.isEmpty(content.getReplies())) { + if(content != null && !CompatUtil.INSTANCE.isEmpty(content.getReplies())) { if(isPager && !swipeRefreshLayout.isRefreshing()) { if (mAdapter.getItemCount() < 1) mAdapter.onItemsInserted(content.getReplies()); diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/fragment/FragmentBaseList.java b/app/src/main/java/com/mxt/anitrend/base/custom/fragment/FragmentBaseList.java index ce52d76b1..f37d4bf35 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/fragment/FragmentBaseList.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/fragment/FragmentBaseList.java @@ -93,7 +93,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c mLayoutManager = new StaggeredGridLayoutManager(getResources().getInteger(mColumnSize), StaggeredGridLayoutManager.VERTICAL); recyclerView.setLayoutManager(mLayoutManager); swipeRefreshLayout.setOnRefreshAndLoadListener(this); - CompatUtil.configureSwipeRefreshLayout(swipeRefreshLayout, getActivity()); + CompatUtil.INSTANCE.configureSwipeRefreshLayout(swipeRefreshLayout, getActivity()); return root; } @@ -216,7 +216,7 @@ public void showError(String error) { } else { showLoading(); - stateLayout.showError(CompatUtil.getDrawable(getContext(), R.drawable.ic_emoji_cry), + stateLayout.showError(CompatUtil.INSTANCE.getDrawable(getContext(), R.drawable.ic_emoji_cry), error, getString(R.string.try_again), stateLayoutOnClick); } } @@ -237,7 +237,7 @@ public void showEmpty(String message) { } else { showLoading(); - stateLayout.showError(CompatUtil.getDrawable(getContext(), R.drawable.ic_emoji_sweat), + stateLayout.showError(CompatUtil.INSTANCE.getDrawable(getContext(), R.drawable.ic_emoji_sweat), message, getString(R.string.try_again), stateLayoutOnClick); } } @@ -272,7 +272,7 @@ public void setLimitReached() { */ @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - if(getPresenter() != null && isFilterable && GraphUtil.isKeyFilter(key)) { + if(getPresenter() != null && isFilterable && GraphUtil.INSTANCE.isKeyFilter(key)) { showLoading(); if(mAdapter != null) mAdapter.clearDataSet(); @@ -305,7 +305,7 @@ public void onLoadMore() { @Subscribe(threadMode = ThreadMode.MAIN) public void onSearch(String query) { if(isAlive() && mAdapter != null && mAdapter.getFilter() != null && !isPager) { - if(!CompatUtil.equals(this.query, query)) { + if(!CompatUtil.INSTANCE.equals(this.query, query)) { this.query = query; mAdapter.getFilter().filter(query); } @@ -346,7 +346,7 @@ else if(swipeRefreshLayout.isLoading()) * @param content The main data model for the class */ protected void onPostProcessed(@Nullable List content) { - if(!CompatUtil.isEmpty(content)) { + if(!CompatUtil.INSTANCE.isEmpty(content)) { if(isPager && !swipeRefreshLayout.isRefreshing()) { if (mAdapter.getItemCount() < 1) mAdapter.onItemsInserted(content); diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/fragment/FragmentChannelBase.java b/app/src/main/java/com/mxt/anitrend/base/custom/fragment/FragmentChannelBase.java index 8ed559768..0e37d1b36 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/fragment/FragmentChannelBase.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/fragment/FragmentChannelBase.java @@ -94,7 +94,7 @@ public void onCreate(@Nullable Bundle savedInstanceState) { isPopular = getArguments().getBoolean(KeyUtil.arg_popular); externalLinks = getArguments().getParcelableArrayList(KeyUtil.arg_list_model); if(externalLinks != null) - targetLink = EpisodeUtil.episodeSupport(externalLinks); + targetLink = EpisodeUtil.INSTANCE.episodeSupport(externalLinks); } mColumnSize = R.integer.single_list_x1; } @@ -114,7 +114,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c recyclerView.setLayoutManager(mLayoutManager); swipeRefreshLayout.setOnRefreshAndLoadListener(this); - CompatUtil.configureSwipeRefreshLayout(swipeRefreshLayout, getActivity()); + CompatUtil.INSTANCE.configureSwipeRefreshLayout(swipeRefreshLayout, getActivity()); return root; } @@ -222,7 +222,7 @@ public void showError(String error) { } else { showLoading(); - stateLayout.showError(CompatUtil.getDrawable(getContext(), R.drawable.ic_emoji_cry), + stateLayout.showError(CompatUtil.INSTANCE.getDrawable(getContext(), R.drawable.ic_emoji_cry), error, getString(R.string.try_again), stateLayoutOnClick); } } @@ -243,7 +243,7 @@ public void showEmpty(String message) { } else { showLoading(); - stateLayout.showError(CompatUtil.getDrawable(getContext(), R.drawable.ic_emoji_sweat), + stateLayout.showError(CompatUtil.INSTANCE.getDrawable(getContext(), R.drawable.ic_emoji_sweat), message, getString(R.string.try_again), stateLayoutOnClick); } } @@ -365,7 +365,7 @@ public void onItemClick(View target, IntPair data) { case NEUTRAL: if(getActivity() != null) { intent = new Intent(getActivity(), SearchActivity.class); - intent.putExtra(KeyUtil.arg_search, EpisodeUtil.getActualTile(data.getSecond().getTitle())); + intent.putExtra(KeyUtil.arg_search, EpisodeUtil.INSTANCE.getActualTile(data.getSecond().getTitle())); getActivity().startActivity(intent); } break; diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/glide/GlideAppModule.java b/app/src/main/java/com/mxt/anitrend/base/custom/glide/GlideAppModule.java index 699ca5069..6ed68b899 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/glide/GlideAppModule.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/glide/GlideAppModule.java @@ -36,7 +36,7 @@ public boolean isManifestParsingEnabled() { @Override public void applyOptions(@NonNull Context context, @NonNull GlideBuilder builder) { - boolean isLowRamDevice = CompatUtil.isLowRamDevice(context); + boolean isLowRamDevice = CompatUtil.INSTANCE.isLowRamDevice(context); MemorySizeCalculator calculator = new MemorySizeCalculator.Builder(context) .setMemoryCacheScreens(isLowRamDevice? 1 : 2).build(); @@ -59,7 +59,7 @@ public void applyOptions(@NonNull Context context, @NonNull GlideBuilder builder .format(isLowRamDevice ? DecodeFormat.PREFER_RGB_565 : DecodeFormat.PREFER_ARGB_8888) .timeout(KeyUtil.GLIDE_REQUEST_TIMEOUT) .diskCacheStrategy(DiskCacheStrategy.AUTOMATIC) - .error(CompatUtil.getDrawable(context, R.drawable.ic_emoji_sweat)); + .error(CompatUtil.INSTANCE.getDrawable(context, R.drawable.ic_emoji_sweat)); builder.setDefaultRequestOptions(options); } diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/recycler/RecyclerViewAdapter.java b/app/src/main/java/com/mxt/anitrend/base/custom/recycler/RecyclerViewAdapter.java index ffa58cb8e..8b883f0a5 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/recycler/RecyclerViewAdapter.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/recycler/RecyclerViewAdapter.java @@ -46,7 +46,7 @@ public abstract class RecyclerViewAdapter extends RecyclerView.Adapter(); } diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/sheet/BottomSheetBase.java b/app/src/main/java/com/mxt/anitrend/base/custom/sheet/BottomSheetBase.java index be153724f..6435518aa 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/sheet/BottomSheetBase.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/sheet/BottomSheetBase.java @@ -110,9 +110,9 @@ public void onStart() { super.onStart(); toolbarTitle.setText(mTitle); if(bottomSheetBehavior.getState() == BottomSheetBehavior.STATE_EXPANDED) - toolbarState.setImageDrawable(CompatUtil.getTintedDrawable(getContext(), R.drawable.ic_keyboard_arrow_down_grey_600_24dp)); + toolbarState.setImageDrawable(CompatUtil.INSTANCE.getTintedDrawable(getContext(), R.drawable.ic_keyboard_arrow_down_grey_600_24dp)); else - toolbarState.setImageDrawable(CompatUtil.getTintedDrawable(getContext(), R.drawable.ic_close_grey_600_24dp)); + toolbarState.setImageDrawable(CompatUtil.INSTANCE.getTintedDrawable(getContext(), R.drawable.ic_close_grey_600_24dp)); toolbarState.setOnClickListener(view -> { switch (bottomSheetBehavior.getState()) { case BottomSheetBehavior.STATE_EXPANDED: @@ -123,7 +123,7 @@ public void onStart() { break; } }); - toolbarSearch.setImageDrawable(CompatUtil.getTintedDrawable(getContext(), R.drawable.ic_search_grey_600_24dp)); + toolbarSearch.setImageDrawable(CompatUtil.INSTANCE.getTintedDrawable(getContext(), R.drawable.ic_search_grey_600_24dp)); toolbarSearch.setOnClickListener(view -> searchView.showSearch(true)); searchView.setCursorDrawable(R.drawable.material_search_cursor); } @@ -159,7 +159,7 @@ protected void createBottomSheetBehavior(View contentView) { if (coordinatorBehavior instanceof BottomSheetBehavior) { bottomSheetBehavior = (BottomSheetBehavior) coordinatorBehavior; - bottomSheetBehavior.setPeekHeight(CompatUtil.dipToPx(KeyUtil.PEEK_HEIGHT)); + bottomSheetBehavior.setPeekHeight(CompatUtil.INSTANCE.dipToPx(KeyUtil.PEEK_HEIGHT)); bottomSheetBehavior.setBottomSheetCallback(bottomSheetCallback); } } @@ -185,12 +185,12 @@ public void onDestroyView() { @Override public void onStateCollapsed() { - toolbarState.setImageDrawable(CompatUtil.getTintedDrawable(getContext(), R.drawable.ic_close_grey_600_24dp)); + toolbarState.setImageDrawable(CompatUtil.INSTANCE.getTintedDrawable(getContext(), R.drawable.ic_close_grey_600_24dp)); } @Override public void onStateExpanded() { - toolbarState.setImageDrawable(CompatUtil.getTintedDrawable(getContext(), R.drawable.ic_keyboard_arrow_down_grey_600_24dp)); + toolbarState.setImageDrawable(CompatUtil.INSTANCE.getTintedDrawable(getContext(), R.drawable.ic_keyboard_arrow_down_grey_600_24dp)); } /** diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/sheet/BottomSheetGiphyList.java b/app/src/main/java/com/mxt/anitrend/base/custom/sheet/BottomSheetGiphyList.java index 9e117d7a3..0b993f1b5 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/sheet/BottomSheetGiphyList.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/sheet/BottomSheetGiphyList.java @@ -160,7 +160,7 @@ protected void injectAdapter() { recyclerView.setAdapter(mAdapter); } if (mAdapter.getItemCount() < 1) - stateLayout.showEmpty(CompatUtil.getDrawable(getContext(), R.drawable.ic_new_releases_white_24dp, R.color.colorStateBlue), getString(R.string.layout_empty_response)); + stateLayout.showEmpty(CompatUtil.INSTANCE.getDrawable(getContext(), R.drawable.ic_new_releases_white_24dp, R.color.colorStateBlue), getString(R.string.layout_empty_response)); else stateLayout.showContent(); } @@ -221,7 +221,7 @@ public void onLoadMore() { */ @Override public void onChanged(@Nullable GiphyContainer content) { - if(content != null && !CompatUtil.isEmpty(content.getData())) { + if(content != null && !CompatUtil.INSTANCE.isEmpty(content.getData())) { if(isPager) { if (mAdapter.getItemCount() < 1) mAdapter.onItemsInserted(content.getData()); @@ -242,14 +242,14 @@ public void onChanged(@Nullable GiphyContainer content) { @Override public void showError(String error) { super.showError(error); - stateLayout.showError(CompatUtil.getDrawable(getContext(), R.drawable.ic_emoji_cry), + stateLayout.showError(CompatUtil.INSTANCE.getDrawable(getContext(), R.drawable.ic_emoji_cry), error, getString(R.string.try_again), stateLayoutOnClick); } @Override public void showEmpty(String message) { super.showEmpty(message); - stateLayout.showError(CompatUtil.getDrawable(getContext(), R.drawable.ic_emoji_sweat), + stateLayout.showError(CompatUtil.INSTANCE.getDrawable(getContext(), R.drawable.ic_emoji_sweat), message, getString(R.string.try_again) , stateLayoutOnClick); } diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/sheet/BottomSheetList.java b/app/src/main/java/com/mxt/anitrend/base/custom/sheet/BottomSheetList.java index 4480565ff..8d2c62e52 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/sheet/BottomSheetList.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/sheet/BottomSheetList.java @@ -93,7 +93,7 @@ protected void injectAdapter() { recyclerView.setAdapter(mAdapter); } if (mAdapter.getItemCount() < 1) - stateLayout.showEmpty(CompatUtil.getDrawable(getContext(), R.drawable.ic_new_releases_white_24dp, R.color.colorStateBlue), getString(R.string.layout_empty_response)); + stateLayout.showEmpty(CompatUtil.INSTANCE.getDrawable(getContext(), R.drawable.ic_new_releases_white_24dp, R.color.colorStateBlue), getString(R.string.layout_empty_response)); else stateLayout.showContent(); } @@ -159,7 +159,7 @@ public void onChanged(@Nullable List data) { public void showError(String error) { super.showError(error); stateLayout.showLoading(); - stateLayout.showError(CompatUtil.getDrawable(getContext(), R.drawable.ic_emoji_cry), + stateLayout.showError(CompatUtil.INSTANCE.getDrawable(getContext(), R.drawable.ic_emoji_cry), error, getString(R.string.try_again), stateLayoutOnClick); } @@ -167,7 +167,7 @@ public void showError(String error) { public void showEmpty(String message) { super.showEmpty(message); stateLayout.showLoading(); - stateLayout.showError(CompatUtil.getDrawable(getContext(), R.drawable.ic_emoji_sweat), + stateLayout.showError(CompatUtil.INSTANCE.getDrawable(getContext(), R.drawable.ic_emoji_sweat), message, getString(R.string.try_again) , stateLayoutOnClick); } } \ No newline at end of file diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/container/CardViewBase.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/container/CardViewBase.java index f1a1a99ef..02c389b9f 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/container/CardViewBase.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/container/CardViewBase.java @@ -51,7 +51,7 @@ protected void applyStyle(int contentPadding) { setUseCompatPadding(true); setPreventCornerOverlap(false); setContentPadding(contentPadding, contentPadding, contentPadding, contentPadding); - setCardBackgroundColor(CompatUtil.getColorFromAttr(getContext(), R.attr.cardColor)); + setCardBackgroundColor(CompatUtil.INSTANCE.getColorFromAttr(getContext(), R.attr.cardColor)); requestLayout(); } diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/editor/ComposerWidget.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/editor/ComposerWidget.java index bee516b4f..72d344036 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/editor/ComposerWidget.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/editor/ComposerWidget.java @@ -107,7 +107,7 @@ protected void onDetachedFromWindow() { @Override public void onInit() { presenter = new WidgetPresenter<>(getContext()); - binding = WidgetComposerBinding.inflate(CompatUtil.getLayoutInflater(getContext()), this, true); + binding = WidgetComposerBinding.inflate(CompatUtil.INSTANCE.getLayoutInflater(getContext()), this, true); binding.setOnClickListener(this); } @@ -174,7 +174,7 @@ public void startRequestData() { if (binding.widgetFlipper.getDisplayedChild() == WidgetPresenter.CONTENT_STATE) { binding.widgetFlipper.showNext(); - QueryContainerBuilder queryContainer = GraphUtil.getDefaultQuery(false); + QueryContainerBuilder queryContainer = GraphUtil.INSTANCE.getDefaultQuery(false); switch (requestType) { case KeyUtil.MUT_SAVE_TEXT_FEED: @@ -267,7 +267,7 @@ public void onResponse(@NonNull Call call, @NonNull Response(getContext()); - binding = WidgetAvatarIndicatorBinding.inflate(CompatUtil.getLayoutInflater(getContext()), this, true); + binding = WidgetAvatarIndicatorBinding.inflate(CompatUtil.INSTANCE.getLayoutInflater(getContext()), this, true); binding.setOnClickListener(this); checkLastSyncTime(); } @@ -83,7 +83,7 @@ public void onViewRecycled() { @Override @Subscribe(threadMode = ThreadMode.MAIN_ORDERED) public void onModelChanged(BaseConsumer consumer) { if(consumer.getRequestMode() == KeyUtil.USER_CURRENT_REQ) { - if (DateUtil.timeDifferenceSatisfied(KeyUtil.TIME_UNIT_MINUTES, mLastSynced, 15)) + if (DateUtil.INSTANCE.timeDifferenceSatisfied(KeyUtil.TIME_UNIT_MINUTES, mLastSynced, 15)) mLastSynced = System.currentTimeMillis(); checkLastSyncTime(); } diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/image/BrandImageView.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/image/BrandImageView.java index 4ff9e4ed3..8d76c2cf1 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/image/BrandImageView.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/image/BrandImageView.java @@ -63,10 +63,10 @@ public BrandImageView(Context context, AttributeSet attrs, int defStyleAttr) { public void onInit() { badge = new GifBadge(getContext()); badgeGravity = Gravity.END | Gravity.TOP; - CompatUtil.getScreenDimens(deviceDimens, getContext()); + CompatUtil.INSTANCE.getScreenDimens(deviceDimens, getContext()); spanSize = getResources().getInteger(R.integer.grid_giphy_x3); badgePadding = getContext().getResources().getDimensionPixelSize(R.dimen.lg_margin); - badge.setColorFilter(CompatUtil.getColorFromAttr(getContext(), R.attr.titleColor), PorterDuff.Mode.SRC_IN); + badge.setColorFilter(CompatUtil.INSTANCE.getColorFromAttr(getContext(), R.attr.titleColor), PorterDuff.Mode.SRC_IN); } @Override diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/text/AiringTextView.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/text/AiringTextView.java index f368e5c8d..f18810e31 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/text/AiringTextView.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/text/AiringTextView.java @@ -41,9 +41,9 @@ public void onInit() { public static void setAiring(AiringTextView view, @Nullable MediaBase mediaBase) { if(mediaBase != null) { if (mediaBase.getNextAiringEpisode() != null) - view.setText(DateUtil.getNextEpDate(mediaBase.getNextAiringEpisode())); + view.setText(DateUtil.INSTANCE.getNextEpDate(mediaBase.getNextAiringEpisode())); else - view.setText(CompatUtil.capitalizeWords(mediaBase.getStatus())); + view.setText(CompatUtil.INSTANCE.capitalizeWords(mediaBase.getStatus())); view.setVisibility(VISIBLE); } else { view.setVisibility(GONE); diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/text/PageIndicator.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/text/PageIndicator.java index 92432fc7e..311af41fd 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/text/PageIndicator.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/text/PageIndicator.java @@ -41,10 +41,10 @@ public PageIndicator(Context context, @Nullable AttributeSet attrs, int defStyle */ @Override public void onInit() { - int padding = CompatUtil.dipToPx(8); + int padding = CompatUtil.INSTANCE.dipToPx(8); - setTextColor(CompatUtil.getColor(getContext(), R.color.colorTextLight)); - setBackground(CompatUtil.getDrawable(getContext(), R.drawable.bubble_background)); + setTextColor(CompatUtil.INSTANCE.getColor(getContext(), R.color.colorTextLight)); + setBackground(CompatUtil.INSTANCE.getDrawable(getContext(), R.drawable.bubble_background)); setTextSize(TypedValue.COMPLEX_UNIT_SP, 10); setPadding(padding, padding, padding, padding); diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/text/RangeDateTextView.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/text/RangeDateTextView.java index 09f78fddc..8590bd05d 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/text/RangeDateTextView.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/text/RangeDateTextView.java @@ -28,11 +28,11 @@ public RangeDateTextView(Context context, AttributeSet attrs, int defStyleAttr) @BindingAdapter("startDate") public static void setStartDate(RangeDateTextView view, FuzzyDate fuzzyDate) { - view.setText(String.format("%s: %s", DateUtil.getStartTitle(fuzzyDate), DateUtil.convertDate(fuzzyDate))); + view.setText(String.format("%s: %s", DateUtil.INSTANCE.getStartTitle(fuzzyDate), DateUtil.INSTANCE.convertDate(fuzzyDate))); } @BindingAdapter("endDate") public static void setEndDate(RangeDateTextView view, FuzzyDate fuzzyDate) { - view.setText(String.format("%s: %s", DateUtil.getEndTitle(fuzzyDate), DateUtil.convertDate(fuzzyDate))); + view.setText(String.format("%s: %s", DateUtil.INSTANCE.getEndTitle(fuzzyDate), DateUtil.INSTANCE.convertDate(fuzzyDate))); } } diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/text/RatingTextView.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/text/RatingTextView.java index 9dad6070a..bc4342c5f 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/text/RatingTextView.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/text/RatingTextView.java @@ -58,7 +58,7 @@ public RatingTextView(Context context, AttributeSet attrs, int defStyleAttr, int */ @Override public void onInit() { - binding = CustomRatingWidgetBinding.inflate(CompatUtil.getLayoutInflater(getContext()), this, true); + binding = CustomRatingWidgetBinding.inflate(CompatUtil.INSTANCE.getLayoutInflater(getContext()), this, true); BasePresenter basePresenter = new BasePresenter(getContext()); if(basePresenter.getApplicationPref().isAuthenticated()) mediaListOptions = basePresenter.getDatabase().getCurrentUser().getMediaListOptions(); @@ -66,7 +66,7 @@ public void onInit() { private void setFavourState(boolean isFavourite) { @ColorRes int colorTint = isFavourite ? R.color.colorStateYellow : R.color.white; - Drawable drawable = CompatUtil.getDrawable(getContext(), R.drawable.ic_star_grey_600_24dp, colorTint); + Drawable drawable = CompatUtil.INSTANCE.getDrawable(getContext(), R.drawable.ic_star_grey_600_24dp, colorTint); binding.ratingFavourState.setImageDrawable(drawable); } @@ -124,19 +124,19 @@ private void setRating(MediaList mediaList) { int score = (int)mediaList.getScore(); switch (score) { case 0: - binding.ratingValue.setCompoundDrawablesWithIntrinsicBounds(CompatUtil.getDrawable(getContext(), + binding.ratingValue.setCompoundDrawablesWithIntrinsicBounds(CompatUtil.INSTANCE.getDrawable(getContext(), R.drawable.ic_face_white_18dp), null, null, null); break; case 1: - binding.ratingValue.setCompoundDrawablesWithIntrinsicBounds(CompatUtil.getDrawable(getContext(), + binding.ratingValue.setCompoundDrawablesWithIntrinsicBounds(CompatUtil.INSTANCE.getDrawable(getContext(), R.drawable.ic_sentiment_dissatisfied_white_18dp), null, null, null); break; case 2: - binding.ratingValue.setCompoundDrawablesWithIntrinsicBounds(CompatUtil.getDrawable(getContext(), + binding.ratingValue.setCompoundDrawablesWithIntrinsicBounds(CompatUtil.INSTANCE.getDrawable(getContext(), R.drawable.ic_sentiment_neutral_white_18dp), null, null, null); break; case 3: - binding.ratingValue.setCompoundDrawablesWithIntrinsicBounds(CompatUtil.getDrawable(getContext(), + binding.ratingValue.setCompoundDrawablesWithIntrinsicBounds(CompatUtil.INSTANCE.getDrawable(getContext(), R.drawable.ic_sentiment_satisfied_white_18dp), null, null, null); break; } @@ -167,16 +167,16 @@ private void setRating(MediaBase mediaBase) { case KeyUtil.POINT_3: binding.ratingValue.setText(""); if(mediaBase.getMeanScore() == 0) - binding.ratingValue.setCompoundDrawablesWithIntrinsicBounds(CompatUtil.getDrawable(getContext(), + binding.ratingValue.setCompoundDrawablesWithIntrinsicBounds(CompatUtil.INSTANCE.getDrawable(getContext(), R.drawable.ic_face_white_18dp), null, null, null); if(mediaBase.getMeanScore() > 0 && mediaBase.getMeanScore() <= 33) - binding.ratingValue.setCompoundDrawablesWithIntrinsicBounds(CompatUtil.getDrawable(getContext(), + binding.ratingValue.setCompoundDrawablesWithIntrinsicBounds(CompatUtil.INSTANCE.getDrawable(getContext(), R.drawable.ic_sentiment_dissatisfied_white_18dp), null, null, null); else if (mediaBase.getMeanScore() >= 34 && mediaBase.getMeanScore() <= 66) - binding.ratingValue.setCompoundDrawablesWithIntrinsicBounds(CompatUtil.getDrawable(getContext(), + binding.ratingValue.setCompoundDrawablesWithIntrinsicBounds(CompatUtil.INSTANCE.getDrawable(getContext(), R.drawable.ic_sentiment_neutral_white_18dp), null, null, null); else if (mediaBase.getMeanScore() >= 67 && mediaBase.getMeanScore() <= 100) - binding.ratingValue.setCompoundDrawablesWithIntrinsicBounds(CompatUtil.getDrawable(getContext(), + binding.ratingValue.setCompoundDrawablesWithIntrinsicBounds(CompatUtil.INSTANCE.getDrawable(getContext(), R.drawable.ic_sentiment_satisfied_white_18dp), null, null, null); break; } diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/text/RichMarkdownTextView.kt b/app/src/main/java/com/mxt/anitrend/base/custom/view/text/RichMarkdownTextView.kt index 8f295cf8b..2104005f8 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/text/RichMarkdownTextView.kt +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/text/RichMarkdownTextView.kt @@ -1,36 +1,26 @@ package com.mxt.anitrend.base.custom.view.text import android.content.Context -import android.databinding.BindingAdapter -import android.support.annotation.StringRes import android.support.v4.text.util.LinkifyCompat import android.support.v7.widget.AppCompatTextView -import android.text.Html import android.text.Spanned import android.text.method.LinkMovementMethod import android.text.util.Linkify import android.util.AttributeSet import android.widget.TextView import com.mxt.anitrend.base.interfaces.view.CustomView -import com.mxt.anitrend.binding.richMarkDown -import com.mxt.anitrend.model.api.retro.WebFactory import com.mxt.anitrend.util.MarkDownUtil import com.mxt.anitrend.util.RegexUtil -import org.commonmark.ext.gfm.strikethrough.StrikethroughExtension -import org.commonmark.ext.gfm.tables.TablesExtension import org.commonmark.parser.Parser import ru.noties.markwon.AbstractMarkwonPlugin import ru.noties.markwon.Markwon import ru.noties.markwon.MarkwonConfiguration import ru.noties.markwon.core.CorePlugin -import ru.noties.markwon.ext.tasklist.TaskListPlugin import ru.noties.markwon.html.HtmlPlugin import ru.noties.markwon.html.MarkwonHtmlParserImpl import ru.noties.markwon.image.AsyncDrawableScheduler import ru.noties.markwon.image.ImagesPlugin -import ru.noties.markwon.image.gif.GifPlugin import ru.noties.markwon.image.okhttp.OkHttpImagesPlugin -import ru.noties.markwon.syntax.SyntaxHighlight import java.util.Arrays.asList class RichMarkdownTextView : AppCompatTextView, CustomView { @@ -49,17 +39,12 @@ class RichMarkdownTextView : AppCompatTextView, CustomView { .usePlugins(asList( CorePlugin.create(), ImagesPlugin.create(context), - GifPlugin.create(), OkHttpImagesPlugin.create(), - TaskListPlugin.create(context), HtmlPlugin.create(), object: AbstractMarkwonPlugin() { @Override override fun configureParser(builder: Parser.Builder) { - builder.extensions(asList( - StrikethroughExtension.create(), - TablesExtension.create() - )) + } override fun configureConfiguration(builder: MarkwonConfiguration.Builder) { @@ -94,7 +79,7 @@ class RichMarkdownTextView : AppCompatTextView, CustomView { } - fun setMarkDownText(markDownText: String) { + fun setMarkDownText(markDownText: String?) { val strippedText = RegexUtil.removeTags(markDownText) val markdownSpan = MarkDownUtil.convert(strippedText, context, this) setText(markdownSpan, BufferType.SPANNABLE) diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/text/SeriesProgressTextView.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/text/SeriesProgressTextView.java index 32dce2a75..983c745c9 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/text/SeriesProgressTextView.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/text/SeriesProgressTextView.java @@ -34,7 +34,7 @@ public SeriesProgressTextView(Context context, AttributeSet attrs, int defStyleA public void setSeriesModel(MediaList mediaList, boolean isCurrentUser) { MediaBase model = mediaList.getMedia(); if (MediaUtil.isAnimeType(model)) { - if(CompatUtil.equals(model.getStatus(), KeyUtil.NOT_YET_RELEASED)) + if(CompatUtil.INSTANCE.equals(model.getStatus(), KeyUtil.NOT_YET_RELEASED)) setText(R.string.TBA); else { if (isCurrentUser && !MediaUtil.isIncrementLimitReached(mediaList)) @@ -45,7 +45,7 @@ public void setSeriesModel(MediaList mediaList, boolean isCurrentUser) { model.getEpisodes() < 1 ? "?" : model.getEpisodes())); } } else if (MediaUtil.isMangaType(model)) { - if(CompatUtil.equals(model.getStatus(), KeyUtil.NOT_YET_RELEASED)) + if(CompatUtil.INSTANCE.equals(model.getStatus(), KeyUtil.NOT_YET_RELEASED)) setText(R.string.TBA); else { if (isCurrentUser && !MediaUtil.isIncrementLimitReached(mediaList)) diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/text/SeriesYearTypeTextView.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/text/SeriesYearTypeTextView.java index e7581977b..f4622ee18 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/text/SeriesYearTypeTextView.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/text/SeriesYearTypeTextView.java @@ -43,20 +43,20 @@ public static void htmlText(SeriesYearTypeTextView seriesYearTypeTextView, Media String year = startDate.isValidDate() ? String.format(Locale.getDefault(), "%d", startDate.getYear()) : context.getString(R.string.tba_placeholder); switch (mediaBase.getType()) { case KeyUtil.ANIME: - if(CompatUtil.equals(mediaBase.getFormat(), KeyUtil.MOVIE)) - seriesYearTypeTextView.setText(String.format(Locale.getDefault(), "%s - %s", year, CompatUtil.capitalizeWords(mediaBase.getFormat()))); + if(CompatUtil.INSTANCE.equals(mediaBase.getFormat(), KeyUtil.MOVIE)) + seriesYearTypeTextView.setText(String.format(Locale.getDefault(), "%s - %s", year, CompatUtil.INSTANCE.capitalizeWords(mediaBase.getFormat()))); else { if(mediaBase.getEpisodes() > 0) seriesYearTypeTextView.setText(String.format(Locale.getDefault(), "%s - %s", year, context.getString(R.string.text_anime_episodes, mediaBase.getEpisodes()))); else - seriesYearTypeTextView.setText(String.format(Locale.getDefault(), "%s - %s", year, CompatUtil.capitalizeWords(mediaBase.getFormat()))); + seriesYearTypeTextView.setText(String.format(Locale.getDefault(), "%s - %s", year, CompatUtil.INSTANCE.capitalizeWords(mediaBase.getFormat()))); } break; case KeyUtil.MANGA: if(mediaBase.getChapters() > 0) seriesYearTypeTextView.setText(String.format(Locale.getDefault(), "%s - %s", year, context.getString(R.string.text_manga_chapters, mediaBase.getChapters()))); else - seriesYearTypeTextView.setText(String.format(Locale.getDefault(), "%s - %s", year, CompatUtil.capitalizeWords(mediaBase.getFormat()))); + seriesYearTypeTextView.setText(String.format(Locale.getDefault(), "%s - %s", year, CompatUtil.INSTANCE.capitalizeWords(mediaBase.getFormat()))); break; } } diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/text/SpoilerTagTextView.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/text/SpoilerTagTextView.java index 9f54fc531..2b49712b1 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/text/SpoilerTagTextView.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/text/SpoilerTagTextView.java @@ -23,6 +23,6 @@ public SpoilerTagTextView(Context context, AttributeSet attrs, int defStyleAttr) @BindingAdapter({"isSpoiler"}) public static void setIsSpoiler(SingleLineTextView view, Boolean isSpoiler) { - if (isSpoiler) view.setTextColor(CompatUtil.getColor(view.getContext(), R.color.colorStateOrange)); + if (isSpoiler) view.setTextColor(CompatUtil.INSTANCE.getColor(view.getContext(), R.color.colorStateOrange)); } } diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/AboutPanelWidget.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/AboutPanelWidget.java index cfc2be358..bb4e7e8f0 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/AboutPanelWidget.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/AboutPanelWidget.java @@ -93,11 +93,11 @@ public void onInit() { public void setUserId(long userId, Lifecycle lifecycle) { this.userId = userId; this.lifecycle = lifecycle; - queryContainer = GraphUtil.getDefaultQuery(false) + queryContainer = GraphUtil.INSTANCE.getDefaultQuery(false) .putVariable(KeyUtil.arg_id, userId) .putVariable(KeyUtil.arg_page_limit, 1); - if(DateUtil.timeDifferenceSatisfied(KeyUtil.TIME_UNIT_MINUTES, mLastSynced, 5)) { + if(DateUtil.INSTANCE.timeDifferenceSatisfied(KeyUtil.TIME_UNIT_MINUTES, mLastSynced, 5)) { binding.userFavouritesCount.setText(placeHolder); binding.userFollowersCount.setText(placeHolder); binding.userFollowingCount.setText(placeHolder); diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/AutoIncrementWidget.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/AutoIncrementWidget.java index 79d6c77eb..91a0c0a74 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/AutoIncrementWidget.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/AutoIncrementWidget.java @@ -68,7 +68,7 @@ public AutoIncrementWidget(Context context, AttributeSet attrs, int defStyleAttr @Override public void onInit() { presenter = new WidgetPresenter<>(getContext()); - binding = WidgetAutoIncrementerBinding.inflate(CompatUtil.getLayoutInflater(getContext()), this, true); + binding = WidgetAutoIncrementerBinding.inflate(CompatUtil.INSTANCE.getLayoutInflater(getContext()), this, true); binding.setOnClickEvent(this); } @@ -116,7 +116,7 @@ public void onResponse(@NonNull Call call, @NonNull Response call, @NonNull Response call, @NonNull Throwable throwabl private void updateModelState() { - if(model.getProgress() < 1 && CompatUtil.equals(model.getStatus(), KeyUtil.PLANNING)) { + if(model.getProgress() < 1 && CompatUtil.INSTANCE.equals(model.getStatus(), KeyUtil.PLANNING)) { model.setStatus(KeyUtil.CURRENT); - model.setStartedAt(DateUtil.getCurrentDate()); + model.setStartedAt(DateUtil.INSTANCE.getCurrentDate()); } model.setProgress(model.getProgress() + 1); if(MediaUtil.isIncrementLimitReached(model)) { model.setStatus(KeyUtil.COMPLETED); - model.setCompletedAt(DateUtil.getCurrentDate()); + model.setCompletedAt(DateUtil.INSTANCE.getCurrentDate()); } presenter.setParams(MediaListUtil.getMediaListParams(model, presenter.getDatabase() .getCurrentUser().getMediaListOptions().getScoreFormat())); diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/CommentWidget.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/CommentWidget.java index 950bb30ad..3af14cd72 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/CommentWidget.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/CommentWidget.java @@ -39,7 +39,7 @@ public CommentWidget(Context context, AttributeSet attrs, int defStyleAttr) { public void onInit() { final int padding = getResources().getDimensionPixelSize(R.dimen.spacing_small); setPadding(padding, padding, padding, padding); - setCompoundDrawablesWithIntrinsicBounds(CompatUtil.getDrawableTintAttr(getContext(), R.drawable.ic_mode_comment_grey_600_18dp, + setCompoundDrawablesWithIntrinsicBounds(CompatUtil.INSTANCE.getDrawableTintAttr(getContext(), R.drawable.ic_mode_comment_grey_600_18dp, R.attr.colorAccent),null, null, null); } diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/CustomProgress.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/CustomProgress.java index e9a3fcf6e..8b0b7897d 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/CustomProgress.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/CustomProgress.java @@ -54,7 +54,7 @@ public CustomProgress(Context context, AttributeSet attrs, int defStyleAttr, int */ @Override public void onInit() { - mColorFilter = new PorterDuffColorFilter(CompatUtil.getColorFromAttr(getContext(), R.attr.colorAccent), PorterDuff.Mode.SRC_IN); + mColorFilter = new PorterDuffColorFilter(CompatUtil.INSTANCE.getColorFromAttr(getContext(), R.attr.colorAccent), PorterDuff.Mode.SRC_IN); applyColorFilter(getProgressDrawable()); applyColorFilter(getIndeterminateDrawable()); } diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/CustomSeriesAnimeManage.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/CustomSeriesAnimeManage.java index 36697c8dd..db2aa3e98 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/CustomSeriesAnimeManage.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/CustomSeriesAnimeManage.java @@ -48,7 +48,7 @@ public CustomSeriesAnimeManage(Context context, AttributeSet attrs, int defStyle @Override public void onInit() { super.onInit(); - binding = CustomActionAnimeBinding.inflate(CompatUtil.getLayoutInflater(getContext()), this, true); + binding = CustomActionAnimeBinding.inflate(CompatUtil.INSTANCE.getLayoutInflater(getContext()), this, true); } /** @@ -85,9 +85,9 @@ protected void bindFields() { binding.diaCurrentStatus.setAdapter(getIconArrayAdapter()); if (!TextUtils.isEmpty(model.getStatus())) - binding.diaCurrentStatus.setSelection(CompatUtil.constructListFrom(KeyUtil.MediaListStatus).indexOf(model.getStatus())); + binding.diaCurrentStatus.setSelection(CompatUtil.INSTANCE.constructListFrom(KeyUtil.MediaListStatus).indexOf(model.getStatus())); else - binding.diaCurrentStatus.setSelection(CompatUtil.constructListFrom(KeyUtil.MediaListStatus).indexOf(KeyUtil.PLANNING)); + binding.diaCurrentStatus.setSelection(CompatUtil.INSTANCE.constructListFrom(KeyUtil.MediaListStatus).indexOf(KeyUtil.PLANNING)); binding.diaCurrentPrivacy.setChecked(model.isHidden()); if (model.getMedia().getEpisodes() > 0) @@ -119,13 +119,13 @@ public void onItemSelected(AdapterView adapterView, View view, int i, long l) model.setStatus(KeyUtil.MediaListStatus[i]); switch (KeyUtil.MediaListStatus[i]) { case KeyUtil.CURRENT: - if (CompatUtil.equals(getSeriesModel().getStatus(), KeyUtil.NOT_YET_RELEASED)) + if (CompatUtil.INSTANCE.equals(getSeriesModel().getStatus(), KeyUtil.NOT_YET_RELEASED)) NotifyUtil.makeText(getContext(), R.string.warning_anime_not_airing, Toast.LENGTH_LONG).show(); break; case KeyUtil.PLANNING: break; case KeyUtil.COMPLETED: - if (!CompatUtil.equals(getSeriesModel().getStatus(), KeyUtil.FINISHED)) + if (!CompatUtil.INSTANCE.equals(getSeriesModel().getStatus(), KeyUtil.FINISHED)) NotifyUtil.makeText(getContext(), R.string.warning_anime_is_airing, Toast.LENGTH_LONG).show(); else { int total = getSeriesModel().getEpisodes(); @@ -135,7 +135,7 @@ public void onItemSelected(AdapterView adapterView, View view, int i, long l) } break; default: - if (CompatUtil.equals(getSeriesModel().getStatus(), KeyUtil.NOT_YET_RELEASED)) + if (CompatUtil.INSTANCE.equals(getSeriesModel().getStatus(), KeyUtil.NOT_YET_RELEASED)) NotifyUtil.makeText(getContext(), R.string.warning_anime_not_airing, Toast.LENGTH_LONG).show(); break; } diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/CustomSeriesManageBase.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/CustomSeriesManageBase.java index ce73123a2..585f38c2c 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/CustomSeriesManageBase.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/CustomSeriesManageBase.java @@ -70,7 +70,7 @@ public void onInit() { protected IconArrayAdapter getIconArrayAdapter() { IconArrayAdapter iconArrayAdapter = new IconArrayAdapter(getContext(), R.layout.adapter_spinner_item, R.id.spinner_text, - CompatUtil.getStringList(getContext(), R.array.media_list_status)); + CompatUtil.INSTANCE.getStringList(getContext(), R.array.media_list_status)); iconArrayAdapter.setIndexIconMap(indexIconMap); return iconArrayAdapter; } diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/CustomSeriesMangaManage.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/CustomSeriesMangaManage.java index 1dbc1bd8a..b076f7ff8 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/CustomSeriesMangaManage.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/CustomSeriesMangaManage.java @@ -48,7 +48,7 @@ public CustomSeriesMangaManage(Context context, AttributeSet attrs, int defStyle @Override public void onInit() { super.onInit(); - binding = CustomActionMangaBinding.inflate(CompatUtil.getLayoutInflater(getContext()), this, true); + binding = CustomActionMangaBinding.inflate(CompatUtil.INSTANCE.getLayoutInflater(getContext()), this, true); } /** @@ -85,9 +85,9 @@ protected void bindFields() { binding.diaCurrentStatus.setAdapter(getIconArrayAdapter()); if(!TextUtils.isEmpty(model.getStatus())) - binding.diaCurrentStatus.setSelection(CompatUtil.constructListFrom(KeyUtil.MediaListStatus).indexOf(model.getStatus())); + binding.diaCurrentStatus.setSelection(CompatUtil.INSTANCE.constructListFrom(KeyUtil.MediaListStatus).indexOf(model.getStatus())); else - binding.diaCurrentStatus.setSelection(CompatUtil.constructListFrom(KeyUtil.MediaListStatus).indexOf(KeyUtil.PLANNING)); + binding.diaCurrentStatus.setSelection(CompatUtil.INSTANCE.constructListFrom(KeyUtil.MediaListStatus).indexOf(KeyUtil.PLANNING)); binding.diaCurrentPrivacy.setChecked(model.isHidden()); @@ -123,13 +123,13 @@ public void onItemSelected(AdapterView adapterView, View view, int i, long l) model.setStatus(KeyUtil.MediaListStatus[i]); switch (KeyUtil.MediaListStatus[i]) { case KeyUtil.CURRENT: - if (CompatUtil.equals(getSeriesModel().getStatus(), KeyUtil.NOT_YET_RELEASED)) + if (CompatUtil.INSTANCE.equals(getSeriesModel().getStatus(), KeyUtil.NOT_YET_RELEASED)) NotifyUtil.makeText(getContext(), R.string.warning_manga_not_publishing, Toast.LENGTH_LONG).show(); break; case KeyUtil.PLANNING: break; case KeyUtil.COMPLETED: - if (!CompatUtil.equals(getSeriesModel().getStatus(), KeyUtil.FINISHED)) + if (!CompatUtil.INSTANCE.equals(getSeriesModel().getStatus(), KeyUtil.FINISHED)) NotifyUtil.makeText(getContext(), R.string.warning_manga_publishing, Toast.LENGTH_LONG).show(); else { int total = getSeriesModel().getChapters(); @@ -143,7 +143,7 @@ public void onItemSelected(AdapterView adapterView, View view, int i, long l) } break; default: - if (CompatUtil.equals(getSeriesModel().getStatus(), KeyUtil.NOT_YET_RELEASED)) + if (CompatUtil.INSTANCE.equals(getSeriesModel().getStatus(), KeyUtil.NOT_YET_RELEASED)) NotifyUtil.makeText(getContext(), R.string.warning_manga_not_publishing, Toast.LENGTH_LONG).show(); break; } diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/FavouriteToolbarWidget.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/FavouriteToolbarWidget.java index a57059d60..f31967d97 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/FavouriteToolbarWidget.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/FavouriteToolbarWidget.java @@ -73,8 +73,8 @@ public FavouriteToolbarWidget(@NonNull Context context, @Nullable AttributeSet a @Override public void onInit() { presenter = new WidgetPresenter<>(getContext()); - binding = WidgetToolbarFavouriteBinding.inflate(CompatUtil.getLayoutInflater(getContext()), this, true); - queryContainer = GraphUtil.getDefaultQuery(false) + binding = WidgetToolbarFavouriteBinding.inflate(CompatUtil.INSTANCE.getLayoutInflater(getContext()), this, true); + queryContainer = GraphUtil.INSTANCE.getDefaultQuery(false) .putVariable(KeyUtil.arg_page_limit, KeyUtil.SINGLE_ITEM_LIMIT); binding.setOnClickEvent(this); } @@ -166,11 +166,11 @@ else if (characterBase != null) isFavourite = characterBase.isFavourite(); if(isFavourite) - binding.widgetLike.setImageDrawable(requiresTint ? CompatUtil.getTintedDrawable(getContext(), - R.drawable.ic_favorite_white_24dp) : CompatUtil.getDrawable(getContext(), R.drawable.ic_favorite_white_24dp)); + binding.widgetLike.setImageDrawable(requiresTint ? CompatUtil.INSTANCE.getTintedDrawable(getContext(), + R.drawable.ic_favorite_white_24dp) : CompatUtil.INSTANCE.getDrawable(getContext(), R.drawable.ic_favorite_white_24dp)); else - binding.widgetLike.setImageDrawable(requiresTint ? CompatUtil.getTintedDrawable(getContext(), - R.drawable.ic_favorite_border_white_24dp) : CompatUtil.getDrawable(getContext(), R.drawable.ic_favorite_border_white_24dp)); + binding.widgetLike.setImageDrawable(requiresTint ? CompatUtil.INSTANCE.getTintedDrawable(getContext(), + R.drawable.ic_favorite_border_white_24dp) : CompatUtil.INSTANCE.getDrawable(getContext(), R.drawable.ic_favorite_border_white_24dp)); resetFlipperState(); } @@ -189,7 +189,7 @@ else if (characterBase != null) characterBase.toggleFavourite(); setIconType(); } else { - Log.e(toString(), ErrorUtil.getError(response)); + Log.e(toString(), ErrorUtil.INSTANCE.getError(response)); NotifyUtil.makeText(getContext(), R.string.text_error_request, Toast.LENGTH_SHORT).show(); } } catch (Exception e) { diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/FavouriteWidget.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/FavouriteWidget.java index 15403e435..f3d3943e5 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/FavouriteWidget.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/FavouriteWidget.java @@ -58,7 +58,7 @@ public FavouriteWidget(Context context, AttributeSet attrs, int defStyleAttr) { @Override public void onInit() { presenter = new WidgetPresenter<>(getContext()); - binding = WidgetFavouriteBinding.inflate(CompatUtil.getLayoutInflater(getContext()), this, true); + binding = WidgetFavouriteBinding.inflate(CompatUtil.INSTANCE.getLayoutInflater(getContext()), this, true); binding.setOnClickEvent(this); } @@ -84,7 +84,7 @@ public void setModel(List model) { } public void setRequestParams(@KeyUtil.LikeType String likeType, long modelId) { - QueryContainerBuilder queryContainer = GraphUtil.getDefaultQuery(false) + QueryContainerBuilder queryContainer = GraphUtil.INSTANCE.getDefaultQuery(false) .putVariable(KeyUtil.arg_id, modelId) .putVariable(KeyUtil.arg_type, likeType); presenter.getParams().putParcelable(KeyUtil.arg_graph_params, queryContainer); @@ -105,13 +105,13 @@ public void onClick(View view) { } private void setIconType() { - if(!CompatUtil.isEmpty(model) && model.contains(presenter.getDatabase().getCurrentUser())) - binding.widgetLike.setCompoundDrawablesWithIntrinsicBounds(CompatUtil.getDrawable(getContext(), + if(!CompatUtil.INSTANCE.isEmpty(model) && model.contains(presenter.getDatabase().getCurrentUser())) + binding.widgetLike.setCompoundDrawablesWithIntrinsicBounds(CompatUtil.INSTANCE.getDrawable(getContext(), R.drawable.ic_favorite_grey_600_18dp, R.color.colorStateRed), null, null, null); else - binding.widgetLike.setCompoundDrawablesWithIntrinsicBounds(CompatUtil.getDrawable(getContext(), + binding.widgetLike.setCompoundDrawablesWithIntrinsicBounds(CompatUtil.INSTANCE.getDrawable(getContext(), R.drawable.ic_favorite_grey_600_18dp), null, null, null); - binding.widgetLike.setText(WidgetPresenter.convertToText(CompatUtil.sizeOf(model))); + binding.widgetLike.setText(WidgetPresenter.convertToText(CompatUtil.INSTANCE.sizeOf(model))); resetFlipperState(); } @@ -128,13 +128,13 @@ private void setIconType() { public void onResponse(@NonNull Call> call, @NonNull Response> response) { try { if(response.isSuccessful()) { - if(!CompatUtil.isEmpty(model) && model.contains(presenter.getDatabase().getCurrentUser())) + if(!CompatUtil.INSTANCE.isEmpty(model) && model.contains(presenter.getDatabase().getCurrentUser())) model.remove(presenter.getDatabase().getCurrentUser()); else model.add(presenter.getDatabase().getCurrentUser()); setIconType(); } else { - Log.e(this.toString(), ErrorUtil.getError(response)); + Log.e(this.toString(), ErrorUtil.INSTANCE.getError(response)); resetFlipperState(); } } catch (Exception e) { diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/FollowStateWidget.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/FollowStateWidget.java index 7760af63f..d41f1d632 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/FollowStateWidget.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/FollowStateWidget.java @@ -57,7 +57,7 @@ public FollowStateWidget(Context context, AttributeSet attrs, int defStyleAttr) */ @Override public void onInit() { - binding = WidgetButtonStateBinding.inflate(CompatUtil.getLayoutInflater(getContext()),this, true); + binding = WidgetButtonStateBinding.inflate(CompatUtil.INSTANCE.getLayoutInflater(getContext()),this, true); presenter = new WidgetPresenter<>(getContext()); binding.setOnClickListener(this); } @@ -75,10 +75,10 @@ public void setUserModel(UserBase model) { private void setControlText() { if (model.isFollowing()) { - binding.buttonStateContainer.setCardBackgroundColor(CompatUtil.getColor(getContext(), R.color.colorAccentDark)); + binding.buttonStateContainer.setCardBackgroundColor(CompatUtil.INSTANCE.getColor(getContext(), R.color.colorAccentDark)); binding.buttonStateText.setText(R.string.following); } else { - binding.buttonStateContainer.setCardBackgroundColor(CompatUtil.getColor(getContext(), R.color.colorAccent)); + binding.buttonStateContainer.setCardBackgroundColor(CompatUtil.INSTANCE.getColor(getContext(), R.color.colorAccent)); binding.buttonStateText.setText(R.string.follow); } resetFlipperState(); @@ -106,7 +106,7 @@ public void onClick(View view) { case R.id.widget_flipper: if (binding.widgetFlipper.getDisplayedChild() == WidgetPresenter.CONTENT_STATE) { binding.widgetFlipper.showNext(); - QueryContainerBuilder queryContainer = GraphUtil.getDefaultQuery(false) + QueryContainerBuilder queryContainer = GraphUtil.INSTANCE.getDefaultQuery(false) .putVariable(KeyUtil.arg_userId, model.getId()); presenter.getParams().putParcelable(KeyUtil.arg_graph_params, queryContainer); presenter.requestData(KeyUtil.MUT_TOGGLE_FOLLOW, getContext(), this); @@ -134,7 +134,7 @@ public void onResponse(@NonNull Call call, @NonNull Response presenter.notifyAllListeners(new BaseConsumer<>(KeyUtil.MUT_TOGGLE_FOLLOW, model), false); setControlText(); } else { - Log.e(this.toString(), ErrorUtil.getError(response)); + Log.e(this.toString(), ErrorUtil.INSTANCE.getError(response)); setControlText(); } } catch (Exception e) { diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/FuzzyDateWidget.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/FuzzyDateWidget.java index 3dbce834c..f37c91e1a 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/FuzzyDateWidget.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/FuzzyDateWidget.java @@ -49,7 +49,7 @@ public FuzzyDateWidget(Context context, AttributeSet attrs, int defStyleAttr, in @Override public void onInit() { - binding = WidgetFuzzyDateBinding.inflate(CompatUtil.getLayoutInflater(getContext()),this, true); + binding = WidgetFuzzyDateBinding.inflate(CompatUtil.INSTANCE.getLayoutInflater(getContext()),this, true); binding.setOnClick(this); } @@ -59,7 +59,7 @@ public void setDate( @Nullable FuzzyDate fuzzyDate) { } private void updateDate() { - String convertedDate = DateUtil.convertDate(fuzzyDate); + String convertedDate = DateUtil.INSTANCE.convertDate(fuzzyDate); binding.setModel(convertedDate); binding.executePendingBindings(); } diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/MentionWidget.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/MentionWidget.java index 6cc3edc88..6e9be10f9 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/MentionWidget.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/MentionWidget.java @@ -32,7 +32,7 @@ public MentionWidget(Context context, AttributeSet attrs, int defStyleAttr) { public void onInit() { final int padding = getResources().getDimensionPixelSize(R.dimen.spacing_small); setPadding(padding, padding, padding, padding); - setImageDrawable(CompatUtil.getDrawable(getContext(), R.drawable.ic_reply_blue_600_18dp)); + setImageDrawable(CompatUtil.INSTANCE.getDrawable(getContext(), R.drawable.ic_reply_blue_600_18dp)); } /** diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/ProfileStatsWidget.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/ProfileStatsWidget.java index cce614fcd..c7550c813 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/ProfileStatsWidget.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/ProfileStatsWidget.java @@ -81,7 +81,7 @@ public ProfileStatsWidget(@NonNull Context context, @Nullable AttributeSet attrs @Override public void onInit() { presenter = new WidgetPresenter<>(getContext()); - queryContainer = GraphUtil.getDefaultQuery(false); + queryContainer = GraphUtil.INSTANCE.getDefaultQuery(false); binding = WidgetProfileStatsBinding.inflate(LayoutInflater.from(getContext()), this, true); // loading place holder data binding.userAnimeTime.setText(placeHolder); @@ -165,7 +165,7 @@ public void onResponse(@NonNull Call> call, @NonN updateUI(); } } else - Log.e(this.toString(), ErrorUtil.getError(response)); + Log.e(this.toString(), ErrorUtil.INSTANCE.getError(response)); } catch (Exception e) { e.printStackTrace(); } @@ -204,7 +204,7 @@ public String getMangaChaptersCount(long manga_chap) { public String getCount(List statusDistributions) { int totalCount = 0; - if(!CompatUtil.isEmpty(statusDistributions)) + if(!CompatUtil.INSTANCE.isEmpty(statusDistributions)) totalCount = Stream.of(statusDistributions) .mapToInt(StatusDistribution::getAmount) .sum(); diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/ProgressWidget.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/ProgressWidget.java index 95c4d8bca..dad6ef8ea 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/ProgressWidget.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/ProgressWidget.java @@ -52,8 +52,8 @@ public ProgressWidget(Context context, AttributeSet attrs, int defStyleAttr, int */ @Override public void onInit() { - binding = WidgetProgressBinding.inflate(CompatUtil.getLayoutInflater(getContext()),this, true); - binding.progressCurrent.setTextColor(CompatUtil.getColorFromAttr(getContext(), R.attr.contentColor)); + binding = WidgetProgressBinding.inflate(CompatUtil.INSTANCE.getLayoutInflater(getContext()),this, true); + binding.progressCurrent.setTextColor(CompatUtil.INSTANCE.getColorFromAttr(getContext(), R.attr.contentColor)); binding.progressMaximum.setVisibility(GONE); binding.setOnClick(this); setDefaultDeltaFactor(); diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/ScoreWidget.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/ScoreWidget.java index 8ccabd7f6..4a8a952a2 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/ScoreWidget.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/ScoreWidget.java @@ -93,7 +93,7 @@ protected void setDefaultDeltaFactor() { private void setScoreMaximum() { binding.progressMaximum.setVisibility(VISIBLE); - if (CompatUtil.equals(scoreFormat, KeyUtil.POINT_10_DECIMAL)) + if (CompatUtil.INSTANCE.equals(scoreFormat, KeyUtil.POINT_10_DECIMAL)) binding.progressMaximum.setText(String.format(Locale.getDefault(), "/ %.1f", scoreMaximum)); else binding.progressMaximum.setText(String.format(Locale.getDefault(), "/ %d", (int) scoreMaximum)); @@ -101,7 +101,7 @@ private void setScoreMaximum() { public void setScoreCurrent(float scoreCurrent) { this.scoreCurrent = scoreCurrent; - if (CompatUtil.equals(scoreFormat, KeyUtil.POINT_10_DECIMAL)) + if (CompatUtil.INSTANCE.equals(scoreFormat, KeyUtil.POINT_10_DECIMAL)) binding.progressCurrent.setText(String.format(Locale.getDefault(), "%.1f", scoreCurrent)); else binding.progressCurrent.setText(String.format(Locale.getDefault(), "%d", (int) scoreCurrent)); @@ -120,7 +120,7 @@ private boolean boundCheck(float delta) { private void scoreChange(float delta) { if (boundCheck(delta)) { scoreCurrent = delta; - if (CompatUtil.equals(scoreFormat, KeyUtil.POINT_10_DECIMAL)) + if (CompatUtil.INSTANCE.equals(scoreFormat, KeyUtil.POINT_10_DECIMAL)) binding.progressCurrent.setText(String.format(Locale.getDefault(), "%.1f", scoreCurrent)); else binding.progressCurrent.setText(String.format(Locale.getDefault(), "%d", (int) scoreCurrent)); diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/SeriesStatusWidget.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/SeriesStatusWidget.java index 1a7fcfff8..8349e3b46 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/SeriesStatusWidget.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/SeriesStatusWidget.java @@ -69,16 +69,16 @@ public static void setStatus(SeriesStatusWidget view, MediaBase model) { @KeyUtil.MediaStatus String mediaStatus = !TextUtils.isEmpty(model.getStatus()) ? model.getStatus() : KeyUtil.NOT_YET_RELEASED; switch (mediaStatus) { case KeyUtil.RELEASING: - view.setBackgroundColor(CompatUtil.getColor(view.getContext(), R.color.colorStateBlue)); + view.setBackgroundColor(CompatUtil.INSTANCE.getColor(view.getContext(), R.color.colorStateBlue)); break; case KeyUtil.FINISHED: - view.setBackgroundColor(CompatUtil.getColor(view.getContext(), R.color.colorStateGreen)); + view.setBackgroundColor(CompatUtil.INSTANCE.getColor(view.getContext(), R.color.colorStateGreen)); break; case KeyUtil.NOT_YET_RELEASED: - view.setBackgroundColor(CompatUtil.getColor(view.getContext(), R.color.colorStateOrange)); + view.setBackgroundColor(CompatUtil.INSTANCE.getColor(view.getContext(), R.color.colorStateOrange)); break; default: - view.setBackgroundColor(CompatUtil.getColor(view.getContext(), R.color.colorStateRed)); + view.setBackgroundColor(CompatUtil.INSTANCE.getColor(view.getContext(), R.color.colorStateRed)); break; } } @@ -103,7 +103,7 @@ public static void setStatus(SeriesStatusWidget view, MediaList mediaList) { public static void setAiringStatus(SeriesStatusWidget view, MediaList mediaList) { if(mediaList != null && mediaList.getMedia() != null && mediaList.getMedia().getNextAiringEpisode() != null) { if(mediaList.getMedia().getNextAiringEpisode().getEpisode() - mediaList.getProgress() > 1) { - view.setBackgroundColor(CompatUtil.getColor(view.getContext(), R.color.colorStateYellow)); + view.setBackgroundColor(CompatUtil.INSTANCE.getColor(view.getContext(), R.color.colorStateYellow)); return; } } diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/StatusContentWidget.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/StatusContentWidget.java index 36020bf3c..8ee5a3a2f 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/StatusContentWidget.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/StatusContentWidget.java @@ -90,7 +90,7 @@ public void setModel(FeedReply model) { findMediaAttachments(model.getReply()); } - public void setTextData(String textData) { + public void setTextData(@Nullable String textData) { binding.widgetStatusText.setMarkDownText(textData); findMediaAttachments(textData); } @@ -123,7 +123,7 @@ private void findMediaAttachments(@Nullable String value) { } private void constructAdditionalViews() { - if(!CompatUtil.isEmpty(contentLinks)) { + if(!CompatUtil.INSTANCE.isEmpty(contentLinks)) { RecyclerViewAdapter previewAdapter = new ImagePreviewAdapter(contentTypes, getContext()); previewAdapter.onItemsInserted(contentLinks); previewAdapter.setClickListener(this); diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/StatusDeleteWidget.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/StatusDeleteWidget.java index 19014b7c9..6d0d239bb 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/StatusDeleteWidget.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/StatusDeleteWidget.java @@ -56,15 +56,15 @@ public StatusDeleteWidget(Context context, AttributeSet attrs, int defStyleAttr) @Override public void onInit() { presenter = new WidgetPresenter<>(getContext()); - binding = WidgetDeleteBinding.inflate(CompatUtil.getLayoutInflater(getContext()), this, true); - binding.widgetDelete.setCompoundDrawablesWithIntrinsicBounds(CompatUtil.getDrawable(getContext(), + binding = WidgetDeleteBinding.inflate(CompatUtil.INSTANCE.getLayoutInflater(getContext()), this, true); + binding.widgetDelete.setCompoundDrawablesWithIntrinsicBounds(CompatUtil.INSTANCE.getDrawable(getContext(), R.drawable.ic_delete_red_600_18dp),null, null, null); binding.setOnClickEvent(this); } private void setParameters(long feedId, @KeyUtil.RequestType int requestType) { this.requestType = requestType; - QueryContainerBuilder queryContainer = GraphUtil.getDefaultQuery(false) + QueryContainerBuilder queryContainer = GraphUtil.INSTANCE.getDefaultQuery(false) .putVariable(KeyUtil.arg_id, feedId); presenter.getParams().putParcelable(KeyUtil.arg_graph_params, queryContainer); } @@ -133,7 +133,7 @@ else if (requestType == KeyUtil.MUT_DELETE_FEED_REPLY) } else NotifyUtil.makeText(getContext(), R.string.text_error_request, Toast.LENGTH_SHORT).show(); } else - Log.e(this.toString(), ErrorUtil.getError(response)); + Log.e(this.toString(), ErrorUtil.INSTANCE.getError(response)); } catch (Exception e) { e.printStackTrace(); } diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/StatusEditWidget.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/StatusEditWidget.java index 549d1dd6d..d11281e8a 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/StatusEditWidget.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/StatusEditWidget.java @@ -32,7 +32,7 @@ public StatusEditWidget(Context context, AttributeSet attrs, int defStyleAttr) { public void onInit() { final int padding = getResources().getDimensionPixelSize(R.dimen.spacing_small); setPadding(padding, padding, padding, padding); - setCompoundDrawablesWithIntrinsicBounds(CompatUtil.getDrawable(getContext(), + setCompoundDrawablesWithIntrinsicBounds(CompatUtil.INSTANCE.getDrawable(getContext(), R.drawable.ic_edit_green_600_18dp), null, null, null); } diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/UsersWidget.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/UsersWidget.java index 2240f1159..bf09f38d6 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/UsersWidget.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/UsersWidget.java @@ -32,7 +32,7 @@ public UsersWidget(Context context, AttributeSet attrs, int defStyleAttr) { public void onInit() { final int padding = getResources().getDimensionPixelSize(R.dimen.spacing_small); setPadding(padding, padding, padding, padding); - setCompoundDrawablesWithIntrinsicBounds(CompatUtil.getDrawableTintAttr(getContext(), + setCompoundDrawablesWithIntrinsicBounds(CompatUtil.INSTANCE.getDrawableTintAttr(getContext(), R.drawable.ic_people_grey_600_18dp, R.attr.colorAccent), null, null, null); } diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/VoteWidget.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/VoteWidget.java index d40b1400b..69d8a4f72 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/VoteWidget.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/VoteWidget.java @@ -66,7 +66,7 @@ public VoteWidget(@NonNull Context context, @Nullable AttributeSet attrs, int de } private void setParameters(@KeyUtil.ReviewRating String ratingType) { - QueryContainerBuilder queryContainer = GraphUtil.getDefaultQuery(false) + QueryContainerBuilder queryContainer = GraphUtil.INSTANCE.getDefaultQuery(false) .putVariable(KeyUtil.arg_id, model.getId()) .putVariable(KeyUtil.arg_rating, ratingType); presenter.getParams().putParcelable(KeyUtil.arg_graph_params, queryContainer); @@ -80,14 +80,14 @@ public void onClick(View view) { case R.id.widget_thumb_up_flipper: if (binding.widgetThumbUpFlipper.getDisplayedChild() == WidgetPresenter.CONTENT_STATE) { binding.widgetThumbUpFlipper.showNext(); - setParameters(CompatUtil.equals(model.getUserRating(), KeyUtil.UP_VOTE) ? KeyUtil.NO_VOTE : KeyUtil.UP_VOTE); + setParameters(CompatUtil.INSTANCE.equals(model.getUserRating(), KeyUtil.UP_VOTE) ? KeyUtil.NO_VOTE : KeyUtil.UP_VOTE); } else NotifyUtil.makeText(getContext(), R.string.busy_please_wait, Toast.LENGTH_SHORT).show(); break; case R.id.widget_thumb_down_flipper: if (binding.widgetThumbDownFlipper.getDisplayedChild() == WidgetPresenter.CONTENT_STATE) { binding.widgetThumbDownFlipper.showNext(); - setParameters(CompatUtil.equals(model.getUserRating(), KeyUtil.DOWN_VOTE) ? KeyUtil.NO_VOTE : KeyUtil.DOWN_VOTE); + setParameters(CompatUtil.INSTANCE.equals(model.getUserRating(), KeyUtil.DOWN_VOTE) ? KeyUtil.NO_VOTE : KeyUtil.DOWN_VOTE); } else NotifyUtil.makeText(getContext(), R.string.busy_please_wait, Toast.LENGTH_SHORT).show(); break; @@ -132,28 +132,28 @@ public void setModel(Review model, @ColorRes int colorStyle) { public void applyColorStyleTo(SingleLineTextView singleLineTextView, @DrawableRes int drawableItem) { if(colorStyle != 0) { - singleLineTextView.setCompoundDrawablesWithIntrinsicBounds(CompatUtil.getDrawable(getContext(), + singleLineTextView.setCompoundDrawablesWithIntrinsicBounds(CompatUtil.INSTANCE.getDrawable(getContext(), drawableItem, colorStyle), null, null, null); - singleLineTextView.setTextColor(CompatUtil.getColor(getContext(), colorStyle)); + singleLineTextView.setTextColor(CompatUtil.INSTANCE.getColor(getContext(), colorStyle)); } else { - singleLineTextView.setCompoundDrawablesWithIntrinsicBounds(CompatUtil.getDrawable(getContext(), + singleLineTextView.setCompoundDrawablesWithIntrinsicBounds(CompatUtil.INSTANCE.getDrawable(getContext(), drawableItem, R.color.colorGrey600), null, null, null); } } public void setReviewStatus() { if(colorStyle != 0) { - binding.widgetThumbUp.setTextColor(CompatUtil.getColor(getContext(), colorStyle)); - binding.widgetThumbDown.setTextColor(CompatUtil.getColor(getContext(), colorStyle)); + binding.widgetThumbUp.setTextColor(CompatUtil.INSTANCE.getColor(getContext(), colorStyle)); + binding.widgetThumbDown.setTextColor(CompatUtil.INSTANCE.getColor(getContext(), colorStyle)); } switch (model.getUserRating()) { case KeyUtil.UP_VOTE: - binding.widgetThumbUp.setCompoundDrawablesWithIntrinsicBounds(CompatUtil.getDrawable(getContext(), + binding.widgetThumbUp.setCompoundDrawablesWithIntrinsicBounds(CompatUtil.INSTANCE.getDrawable(getContext(), R.drawable.ic_thumb_up_grey_600_18dp, R.color.colorStateGreen), null, null, null); applyColorStyleTo(binding.widgetThumbDown, R.drawable.ic_thumb_down_grey_600_18dp); break; case KeyUtil.DOWN_VOTE: - binding.widgetThumbDown.setCompoundDrawablesWithIntrinsicBounds(CompatUtil.getDrawable(getContext(), + binding.widgetThumbDown.setCompoundDrawablesWithIntrinsicBounds(CompatUtil.INSTANCE.getDrawable(getContext(), R.drawable.ic_thumb_down_grey_600_18dp, R.color.colorStateOrange), null, null, null); applyColorStyleTo(binding.widgetThumbUp, R.drawable.ic_thumb_up_grey_600_18dp); break; @@ -188,7 +188,7 @@ public void onResponse(@NonNull Call call, @NonNull Response res this.model.setUserRating(model.getUserRating()); setReviewStatus(); } else { - Log.e(this.toString(), ErrorUtil.getError(response)); + Log.e(this.toString(), ErrorUtil.INSTANCE.getError(response)); resetFlipperState(); } } catch (Exception e) { diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/viewmodel/ViewModelBase.java b/app/src/main/java/com/mxt/anitrend/base/custom/viewmodel/ViewModelBase.java deleted file mode 100644 index b74aec322..000000000 --- a/app/src/main/java/com/mxt/anitrend/base/custom/viewmodel/ViewModelBase.java +++ /dev/null @@ -1,130 +0,0 @@ -package com.mxt.anitrend.base.custom.viewmodel; - -import android.arch.lifecycle.MutableLiveData; -import android.arch.lifecycle.ViewModel; -import android.content.Context; -import android.os.AsyncTask; -import android.os.Bundle; -import android.support.annotation.NonNull; - -import com.mxt.anitrend.R; -import com.mxt.anitrend.base.custom.async.RequestHandler; -import com.mxt.anitrend.base.interfaces.event.ResponseCallback; -import com.mxt.anitrend.base.interfaces.event.RetroCallback; -import com.mxt.anitrend.util.ErrorUtil; -import com.mxt.anitrend.util.KeyUtil; - -import io.objectbox.android.ObjectBoxLiveData; -import io.objectbox.query.Query; -import retrofit2.Call; -import retrofit2.Response; - -/** - * Created by max on 2017/10/14. - * View model abstraction contains the generic data model - */ - -public class ViewModelBase extends ViewModel implements RetroCallback { - - private ObjectBoxLiveData modelBox; - private MutableLiveData model; - private ResponseCallback state; - - private RequestHandler mLoader; - - private Bundle bundle; - - private String emptyMessage, errorMessage; - - public void setState(ResponseCallback state) { - this.state = state; - } - - public @NonNull MutableLiveData getModel() { - if(model == null) - model = new MutableLiveData<>(); - return model; - } - - public @NonNull ObjectBoxLiveData getModelBox(Query query) { - if(modelBox == null) - modelBox = new ObjectBoxLiveData<>(query); - return modelBox; - } - - public Bundle setParams(Bundle bundle) { - this.bundle = new Bundle(bundle); - return this.bundle; - } - - public Bundle getParams() { - if(bundle == null) - bundle = new Bundle(); - return bundle; - } - - public void setContext(Context context) { - if(context != null) { - emptyMessage = context.getString(R.string.layout_empty_response); - errorMessage = context.getString(R.string.text_error_request); - } - } - - /** - * Template to make requests for various data types from api, the - *
- * @param request_type the type of request to execute - */ - public void requestData(@KeyUtil.RequestType int request_type, Context context) { - mLoader = new RequestHandler<>(getParams(), this, request_type); - mLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, context); - } - - /** - * This method will be called when this ViewModel is no longer used and will be destroyed. - *

- * It is useful when ViewModel observes some data and you need to clear this subscription to - * prevent a leak of this ViewModel. - */ - @Override - protected void onCleared() { - if(mLoader != null && mLoader.getStatus() != AsyncTask.Status.FINISHED) - mLoader.cancel(true); - mLoader = null; - state = null; - super.onCleared(); - } - - /** - * Invoked for a received HTTP response. - *

- * Note: An HTTP response may still indicate an application-level failure such as a 404 or 500. - * Call {@link Response#isSuccessful()} to determine if the response indicates success. - * - * @param call the origination requesting object - * @param response the response from the network - */ - @Override - public void onResponse(@NonNull Call call, @NonNull Response response) { - T container; - if(response.isSuccessful() && (container = response.body()) != null) - getModel().setValue(container); - else if(state != null) { - state.showError(ErrorUtil.getError(response)); - } - } - - /** - * Invoked when a network exception occurred talking to the server or when an unexpected - * exception occurred creating the request or processing the response. - * - * @param call the origination requesting object - * @param throwable contains information about the error - */ - @Override - public void onFailure(@NonNull Call call, @NonNull Throwable throwable) { - if(state != null) - state.showEmpty(throwable.getMessage()); - throwable.printStackTrace(); - } -} diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/viewmodel/ViewModelBase.kt b/app/src/main/java/com/mxt/anitrend/base/custom/viewmodel/ViewModelBase.kt new file mode 100644 index 000000000..da8a084ed --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/base/custom/viewmodel/ViewModelBase.kt @@ -0,0 +1,104 @@ +package com.mxt.anitrend.base.custom.viewmodel + +import android.arch.lifecycle.MutableLiveData +import android.arch.lifecycle.ViewModel +import android.content.Context +import android.os.AsyncTask +import android.os.Bundle + +import com.mxt.anitrend.R +import com.mxt.anitrend.base.custom.async.RequestHandler +import com.mxt.anitrend.base.interfaces.event.ResponseCallback +import com.mxt.anitrend.base.interfaces.event.RetroCallback +import com.mxt.anitrend.util.ErrorUtil +import com.mxt.anitrend.util.KeyUtil + +import io.objectbox.android.ObjectBoxLiveData +import io.objectbox.query.Query +import retrofit2.Call +import retrofit2.Response + +/** + * Created by max on 2017/10/14. + * View model abstraction contains the generic data model + */ + +class ViewModelBase: ViewModel(), RetroCallback { + + val model by lazy { + MutableLiveData() + } + + var state: ResponseCallback? = null + + private var mLoader: RequestHandler? = null + + private var emptyMessage: String? = null + private var errorMessage: String? = null + + val params by lazy { + Bundle() + } + + fun setContext(context: Context?) { + context?.apply { + emptyMessage = getString(R.string.layout_empty_response) + errorMessage = getString(R.string.text_error_request) + } + } + + /** + * Template to make requests for various data types from api, the + *

+ * @param request_type the type of request to execute + */ + fun requestData(@KeyUtil.RequestType request_type: Int, context: Context) { + mLoader = RequestHandler(params, this, request_type) + mLoader?.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, context) + } + + /** + * This method will be called when this ViewModel is no longer used and will be destroyed. + * + * + * It is useful when ViewModel observes some data and you need to clear this subscription to + * prevent a leak of this ViewModel. + */ + override fun onCleared() { + if (mLoader?.status != AsyncTask.Status.FINISHED) + mLoader?.cancel(true) + mLoader = null + state = null + super.onCleared() + } + + /** + * Invoked for a received HTTP response. + * + * + * Note: An HTTP response may still indicate an application-level failure such as a 404 or 500. + * Call [Response.isSuccessful] to determine if the response indicates success. + * + * @param call the origination requesting object + * @param response the response from the network + */ + override fun onResponse(call: Call, response: Response) { + val container: T? = response.body() + if (response.isSuccessful && container != null) + model.setValue(container) + else + state?.showError(ErrorUtil.getError(response)) + } + + /** + * Invoked when a network exception occurred talking to the server or when an unexpected + * exception occurred creating the request or processing the response. + * + * @param call the origination requesting object + * @param throwable contains information about the error + */ + override fun onFailure(call: Call, throwable: Throwable) { + state?.showEmpty(throwable.message) + throwable.printStackTrace() + } +} diff --git a/app/src/main/java/com/mxt/anitrend/data/DatabaseHelper.kt b/app/src/main/java/com/mxt/anitrend/data/DatabaseHelper.kt index 086d3077d..a59f9e5e0 100644 --- a/app/src/main/java/com/mxt/anitrend/data/DatabaseHelper.kt +++ b/app/src/main/java/com/mxt/anitrend/data/DatabaseHelper.kt @@ -21,9 +21,11 @@ import io.objectbox.BoxStore * Database helper class */ -class DatabaseHelper(private val context: Context) : BoxQuery { +class DatabaseHelper(context: Context) : BoxQuery { - private var boxStore: BoxStore? = null + private val boxStore: BoxStore by lazy { + (context.applicationContext as App).boxStore + } // Frequently used instance variables private var user: User? = null @@ -35,11 +37,8 @@ class DatabaseHelper(private val context: Context) : BoxQuery { * @param classType Type of class which must not be a list instance * @return Box of type class requested */ - override fun getBoxStore(classType: Class): Box { - if (boxStore == null) - boxStore = (context.applicationContext as App).boxStore - return boxStore!!.boxFor(classType) - } + override fun getBoxStore(classType: Class): Box = + boxStore.boxFor(classType) /** * Used when the application is logging out a user preferably @@ -67,40 +66,50 @@ class DatabaseHelper(private val context: Context) : BoxQuery { * Get default authentication code */ override fun getAuthCode(): AuthBase? { - return getBoxStore(AuthBase::class.java).query() - .build().findFirst() + return getBoxStore(AuthBase::class.java) + .query() + .build() + .findFirst() } /** * Get web token */ override fun getWebToken(): WebToken? { - return getBoxStore(WebToken::class.java).query() - .build().findFirst() + return getBoxStore(WebToken::class.java) + .query() + .build() + .findFirst() } /** * Get the application version on github */ override fun getRemoteVersion(): VersionBase? { - return getBoxStore(VersionBase::class.java).query() - .build().findFirst() + return getBoxStore(VersionBase::class.java) + .query() + .build() + .findFirst() } /** * Gets all saved tags */ override fun getMediaTags(): List { - return getBoxStore(MediaTag::class.java).query() - .build().findLazy() + return getBoxStore(MediaTag::class.java) + .query() + .build() + .findLazy() } /** * Gets all saved genres */ override fun getGenreCollection(): List { - return getBoxStore(Genre::class.java).query() - .build().findLazy() + return getBoxStore(Genre::class.java) + .query() + .build() + .findLazy() } /** @@ -141,7 +150,7 @@ class DatabaseHelper(private val context: Context) : BoxQuery { */ override fun saveRemoteVersion(versionBase: VersionBase) { val versionBox = getBoxStore(VersionBase::class.java) - if (versionBox.count() > 0) + if (versionBox.count() != 0L) versionBox.removeAll() versionBase.lastChecked = System.currentTimeMillis() versionBox.put(versionBase) diff --git a/app/src/main/java/com/mxt/anitrend/model/api/interceptor/AuthInterceptor.java b/app/src/main/java/com/mxt/anitrend/model/api/interceptor/AuthInterceptor.java deleted file mode 100644 index 0ced0a083..000000000 --- a/app/src/main/java/com/mxt/anitrend/model/api/interceptor/AuthInterceptor.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.mxt.anitrend.model.api.interceptor; - -import android.content.Context; -import android.support.annotation.NonNull; -import android.util.Log; - -import com.mxt.anitrend.BuildConfig; -import com.mxt.anitrend.base.custom.async.WebTokenRequest; -import com.mxt.anitrend.util.ApplicationPref; - -import java.io.IOException; - -import okhttp3.Interceptor; -import okhttp3.Request; -import okhttp3.Response; - -/** - * Created by max on 2017/06/14. - * Auth injector interceptor - */ - -public class AuthInterceptor implements Interceptor { - - private ApplicationPref applicationPref; - - public AuthInterceptor(Context context) { - applicationPref = new ApplicationPref(context); - } - - @Override - public Response intercept(@NonNull Chain chain) throws IOException { - if (applicationPref.isAuthenticated()) { - if(WebTokenRequest.getInstance() != null) { - Request.Builder builder = chain.request().newBuilder() - .header(BuildConfig.HEADER_KEY, WebTokenRequest.getInstance().getHeader()); - Request request = builder.build(); - return chain.proceed(request); - } - else - Log.e("AuthInterceptor", "Authentication reference is null, this should not happen under normal conditions"); - } - return chain.proceed(chain.request()); - } -} diff --git a/app/src/main/java/com/mxt/anitrend/model/api/interceptor/AuthInterceptor.kt b/app/src/main/java/com/mxt/anitrend/model/api/interceptor/AuthInterceptor.kt new file mode 100644 index 000000000..6996a42d2 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/model/api/interceptor/AuthInterceptor.kt @@ -0,0 +1,40 @@ +package com.mxt.anitrend.model.api.interceptor + +import android.content.Context +import android.util.Log + +import com.mxt.anitrend.BuildConfig +import com.mxt.anitrend.base.custom.async.WebTokenRequest +import com.mxt.anitrend.util.ApplicationPref + +import java.io.IOException + +import okhttp3.Interceptor +import okhttp3.Request +import okhttp3.Response + +/** + * Created by max on 2017/06/14. + * Auth injector interceptor + */ + +class AuthInterceptor(context: Context) : Interceptor { + + private val applicationPref by lazy { + ApplicationPref(context) + } + + @Throws(IOException::class) + override fun intercept(chain: Interceptor.Chain): Response { + if (applicationPref.isAuthenticated) { + if (WebTokenRequest.getInstance() != null) { + val builder = chain.request().newBuilder() + .header(BuildConfig.HEADER_KEY, WebTokenRequest.getInstance().header) + val request = builder.build() + return chain.proceed(request) + } else + Log.e("AuthInterceptor", "Authentication reference is null, this should not happen under normal conditions") + } + return chain.proceed(chain.request()) + } +} diff --git a/app/src/main/java/com/mxt/anitrend/model/api/interceptor/CacheInterceptor.java b/app/src/main/java/com/mxt/anitrend/model/api/interceptor/CacheInterceptor.java deleted file mode 100644 index 8a71d7d26..000000000 --- a/app/src/main/java/com/mxt/anitrend/model/api/interceptor/CacheInterceptor.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.mxt.anitrend.model.api.interceptor; - -import android.content.Context; -import android.support.annotation.NonNull; - -import com.mxt.anitrend.util.CompatUtil; - -import java.io.IOException; -import java.util.concurrent.TimeUnit; - -import okhttp3.CacheControl; -import okhttp3.Interceptor; -import okhttp3.Request; -import okhttp3.Response; - -/** - * Created by max on 2017/06/14. - * cache injector interceptor - */ - -public class CacheInterceptor implements Interceptor { - - private CacheControl cacheControl = new CacheControl - .Builder().maxStale(3, TimeUnit.HOURS).build(); - - private Context mContext; - private boolean forceCache; - - public CacheInterceptor(Context mContext) { - this.mContext = mContext; - } - - public CacheInterceptor(Context mContext, boolean forceCache) { - this.mContext = mContext; - this.forceCache = forceCache; - } - - @Override - public Response intercept(@NonNull Chain chain) throws IOException { - if(CompatUtil.isOnline(mContext) || forceCache) { - Request original = chain.request().newBuilder() - .cacheControl(cacheControl).build(); - return chain.proceed(original); - } - - return chain.proceed(chain.request()); - } -} diff --git a/app/src/main/java/com/mxt/anitrend/model/api/interceptor/CacheInterceptor.kt b/app/src/main/java/com/mxt/anitrend/model/api/interceptor/CacheInterceptor.kt new file mode 100644 index 000000000..a68943ed5 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/model/api/interceptor/CacheInterceptor.kt @@ -0,0 +1,37 @@ +package com.mxt.anitrend.model.api.interceptor + +import android.content.Context + +import com.mxt.anitrend.util.CompatUtil + +import java.io.IOException +import java.util.concurrent.TimeUnit + +import okhttp3.CacheControl +import okhttp3.Interceptor +import okhttp3.Request +import okhttp3.Response + +/** + * Created by max on 2017/06/14. + * cache injector interceptor + */ + +class CacheInterceptor(private val context: Context?, private val forceCache: Boolean = false) : Interceptor { + + private val cacheControl by lazy { + CacheControl.Builder().maxStale(3, TimeUnit.HOURS).build() + } + + + @Throws(IOException::class) + override fun intercept(chain: Interceptor.Chain): Response { + if (CompatUtil.isOnline(context) || forceCache) { + val original = chain.request().newBuilder() + .cacheControl(cacheControl).build() + return chain.proceed(original) + } + + return chain.proceed(chain.request()) + } +} diff --git a/app/src/main/java/com/mxt/anitrend/model/api/interceptor/NetworkCacheInterceptor.java b/app/src/main/java/com/mxt/anitrend/model/api/interceptor/NetworkCacheInterceptor.java deleted file mode 100644 index 17aac6191..000000000 --- a/app/src/main/java/com/mxt/anitrend/model/api/interceptor/NetworkCacheInterceptor.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.mxt.anitrend.model.api.interceptor; - -import android.content.Context; -import android.support.annotation.NonNull; - -import com.mxt.anitrend.util.CompatUtil; - -import java.io.IOException; -import java.util.concurrent.TimeUnit; - -import okhttp3.CacheControl; -import okhttp3.Interceptor; -import okhttp3.Response; - -/** - * Created by max on 2017/07/17. - * Network cache injector interceptor - */ - -public class NetworkCacheInterceptor implements Interceptor { - - private static final String CACHE_CONTROL = "Cache-Control"; - private Context mContext; - private boolean forceCache; - - // re-write response header to force use of cache - private CacheControl cacheControl = new CacheControl.Builder() - .maxAge(4, TimeUnit.HOURS) - .build(); - - public NetworkCacheInterceptor(Context mContext) { - this.mContext = mContext; - } - - public NetworkCacheInterceptor(Context mContext, boolean forceCache) { - this.mContext = mContext; - this.forceCache = forceCache; - } - - @Override - public Response intercept(@NonNull Chain chain) throws IOException { - Response response = chain.proceed(chain.request()); - if(!CompatUtil.isOnline(mContext) || !forceCache) - return response.newBuilder().header(CACHE_CONTROL, - cacheControl.toString()).build(); - return response; - } -} diff --git a/app/src/main/java/com/mxt/anitrend/model/api/interceptor/NetworkCacheInterceptor.kt b/app/src/main/java/com/mxt/anitrend/model/api/interceptor/NetworkCacheInterceptor.kt new file mode 100644 index 000000000..5fda99720 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/model/api/interceptor/NetworkCacheInterceptor.kt @@ -0,0 +1,38 @@ +package com.mxt.anitrend.model.api.interceptor + +import android.content.Context + +import com.mxt.anitrend.util.CompatUtil + +import java.io.IOException +import java.util.concurrent.TimeUnit + +import okhttp3.CacheControl +import okhttp3.Interceptor +import okhttp3.Response + +/** + * Created by max on 2017/07/17. + * Network cache injector interceptor + */ + +class NetworkCacheInterceptor(private val context: Context?, private val forceCache: Boolean = false) : Interceptor { + + // re-write response header to force use of cache + private val cacheControl by lazy { + CacheControl.Builder() + .maxAge(4, TimeUnit.HOURS) + .build() + } + + @Throws(IOException::class) + override fun intercept(chain: Interceptor.Chain): Response { + val response = chain.proceed(chain.request()) + return if (!CompatUtil.isOnline(context) || !forceCache) response.newBuilder().header(CACHE_CONTROL, + cacheControl.toString()).build() else response + } + + companion object { + private const val CACHE_CONTROL = "Cache-Control" + } +} diff --git a/app/src/main/java/com/mxt/anitrend/model/api/retro/WebFactory.java b/app/src/main/java/com/mxt/anitrend/model/api/retro/WebFactory.java index 77b4859cd..a3730c113 100644 --- a/app/src/main/java/com/mxt/anitrend/model/api/retro/WebFactory.java +++ b/app/src/main/java/com/mxt/anitrend/model/api/retro/WebFactory.java @@ -108,7 +108,7 @@ public static EpisodeModel createCrunchyService(boolean feeds, Context context) .addConverterFactory(SimpleXmlConverterFactory.createNonStrict()) .client(createHttpClient(new CacheInterceptor(context, true), HttpLoggingInterceptor.Level.BASIC) .addNetworkInterceptor(new NetworkCacheInterceptor(context, true)) - .cache(CompatUtil.cacheProvider(context)).build()) + .cache(CompatUtil.INSTANCE.cacheProvider(context)).build()) .build(); return retrofit.create(EpisodeModel.class); } @@ -119,7 +119,7 @@ public static GiphyModel createGiphyService(Context context) { .addConverterFactory(GsonConverterFactory.create(gson)) .client(createHttpClient(new CacheInterceptor(context, true), HttpLoggingInterceptor.Level.BASIC) .addNetworkInterceptor(new NetworkCacheInterceptor(context, true)) - .cache(CompatUtil.cacheProvider(context)).build()) + .cache(CompatUtil.INSTANCE.cacheProvider(context)).build()) .build(); } return mGiphy.create(GiphyModel.class); @@ -147,7 +147,7 @@ public static RepositoryModel createRepositoryService() { Response response = refreshTokenCall.execute(); if(!response.isSuccessful()) - Log.e("requestCodeTokenSync", ErrorUtil.getError(response)); + Log.e("requestCodeTokenSync", ErrorUtil.INSTANCE.getError(response)); return response.body(); } catch (Exception ex) { ex.printStackTrace(); diff --git a/app/src/main/java/com/mxt/anitrend/model/entity/anilist/MediaRank.java b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/MediaRank.java index dfbdac0ef..116eb8bb2 100644 --- a/app/src/main/java/com/mxt/anitrend/model/entity/anilist/MediaRank.java +++ b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/MediaRank.java @@ -68,30 +68,30 @@ public String getTypeHtml() { if(year == 0) if(season != null) return String.format(Locale.getDefault(), "#%d %s %s (%s)", - rank, context.toUpperCase(), season.toUpperCase(), CompatUtil.capitalizeWords(format)); + rank, context.toUpperCase(), season.toUpperCase(), CompatUtil.INSTANCE.capitalizeWords(format)); else return String.format(Locale.getDefault(), "#%d %s (%s)", - rank, context.toUpperCase(), CompatUtil.capitalizeWords(format)); + rank, context.toUpperCase(), CompatUtil.INSTANCE.capitalizeWords(format)); if(season != null) return String.format(Locale.getDefault(), "#%d %s %s %d (%s)", - rank, context.toUpperCase(), season.toUpperCase(), year, CompatUtil.capitalizeWords(format)); + rank, context.toUpperCase(), season.toUpperCase(), year, CompatUtil.INSTANCE.capitalizeWords(format)); return String.format(Locale.getDefault(), "#%d %s %d (%s)", - rank, context.toUpperCase(), year, CompatUtil.capitalizeWords(format)); + rank, context.toUpperCase(), year, CompatUtil.INSTANCE.capitalizeWords(format)); } public String getTypeHtmlPlainTitle() { if(year == 0) if(season != null) return String.format(Locale.getDefault(), "%s %s (%s)", - context.toUpperCase(), season, CompatUtil.capitalizeWords(format)); + context.toUpperCase(), season, CompatUtil.INSTANCE.capitalizeWords(format)); else return String.format(Locale.getDefault(), "%s (%s)", - context.toUpperCase(), CompatUtil.capitalizeWords(format)); + context.toUpperCase(), CompatUtil.INSTANCE.capitalizeWords(format)); if(season != null) return String.format(Locale.getDefault(), "%s %s %d (%s)", - context.toUpperCase(), season, year, CompatUtil.capitalizeWords(format)); + context.toUpperCase(), season, year, CompatUtil.INSTANCE.capitalizeWords(format)); return String.format(Locale.getDefault(), "%s %d (%s)", - context.toUpperCase(), year, CompatUtil.capitalizeWords(format)); + context.toUpperCase(), year, CompatUtil.INSTANCE.capitalizeWords(format)); } public int getId() { diff --git a/app/src/main/java/com/mxt/anitrend/model/entity/container/body/EdgeContainer.java b/app/src/main/java/com/mxt/anitrend/model/entity/container/body/EdgeContainer.java index 359ff31b5..93570a44c 100644 --- a/app/src/main/java/com/mxt/anitrend/model/entity/container/body/EdgeContainer.java +++ b/app/src/main/java/com/mxt/anitrend/model/entity/container/body/EdgeContainer.java @@ -19,6 +19,6 @@ public List getEdges() { @Override public boolean isEmpty() { - return CompatUtil.isEmpty(edges); + return CompatUtil.INSTANCE.isEmpty(edges); } } diff --git a/app/src/main/java/com/mxt/anitrend/model/entity/container/body/GraphContainer.java b/app/src/main/java/com/mxt/anitrend/model/entity/container/body/GraphContainer.java index 108434afa..8c10202cc 100644 --- a/app/src/main/java/com/mxt/anitrend/model/entity/container/body/GraphContainer.java +++ b/app/src/main/java/com/mxt/anitrend/model/entity/container/body/GraphContainer.java @@ -19,6 +19,6 @@ public List getErrors() { } public boolean isEmpty() { - return data == null && !CompatUtil.isEmpty(errors); + return data == null && !CompatUtil.INSTANCE.isEmpty(errors); } } diff --git a/app/src/main/java/com/mxt/anitrend/model/entity/container/body/PageContainer.java b/app/src/main/java/com/mxt/anitrend/model/entity/container/body/PageContainer.java index d29422f81..d8a00102e 100644 --- a/app/src/main/java/com/mxt/anitrend/model/entity/container/body/PageContainer.java +++ b/app/src/main/java/com/mxt/anitrend/model/entity/container/body/PageContainer.java @@ -26,6 +26,6 @@ public List getPageData() { @Override public boolean isEmpty() { - return CompatUtil.isEmpty(pageData); + return CompatUtil.INSTANCE.isEmpty(pageData); } } diff --git a/app/src/main/java/com/mxt/anitrend/model/entity/group/RecyclerHeaderItem.java b/app/src/main/java/com/mxt/anitrend/model/entity/group/RecyclerHeaderItem.java index dd1d51460..e4158ffd0 100644 --- a/app/src/main/java/com/mxt/anitrend/model/entity/group/RecyclerHeaderItem.java +++ b/app/src/main/java/com/mxt/anitrend/model/entity/group/RecyclerHeaderItem.java @@ -31,7 +31,7 @@ public void setSize(int size) { } public String getTitle() { - return CompatUtil.capitalizeWords(title); + return CompatUtil.INSTANCE.capitalizeWords(title); } public void setTitle(String title) { @@ -41,7 +41,7 @@ public void setTitle(String title) { @Override public boolean equals(Object o) { if(o instanceof RecyclerHeaderItem) - return CompatUtil.equals(((RecyclerHeaderItem) o).title, title); + return CompatUtil.INSTANCE.equals(((RecyclerHeaderItem) o).title, title); return super.equals(o); } } diff --git a/app/src/main/java/com/mxt/anitrend/presenter/base/BasePresenter.java b/app/src/main/java/com/mxt/anitrend/presenter/base/BasePresenter.java index f8095db2c..1a29716cf 100644 --- a/app/src/main/java/com/mxt/anitrend/presenter/base/BasePresenter.java +++ b/app/src/main/java/com/mxt/anitrend/presenter/base/BasePresenter.java @@ -41,7 +41,7 @@ public final void checkGenresAndTags(FragmentActivity fragmentActivity) { } public String getThumbnail(List thumbnails) { - if(CompatUtil.isEmpty(thumbnails)) + if(CompatUtil.INSTANCE.isEmpty(thumbnails)) return null; return thumbnails.get(0).getUrl(); } @@ -57,10 +57,10 @@ public String getDuration(MediaContent mediaContent) { } public List getTopFavouriteGenres(int limit) { - if(CompatUtil.isEmpty(favouriteGenres)) { + if(CompatUtil.INSTANCE.isEmpty(favouriteGenres)) { UserStats userStats; if (getDatabase().getCurrentUser() != null && (userStats = getDatabase().getCurrentUser().getStats()) != null) { - if (!CompatUtil.isEmpty(userStats.getFavouredGenres())) { + if (!CompatUtil.INSTANCE.isEmpty(userStats.getFavouredGenres())) { favouriteGenres = Stream.of(userStats.getFavouredGenres()) .sortBy(genreStat -> - genreStat.getAmount()) .map(GenreStats::getGenre) @@ -73,10 +73,10 @@ public List getTopFavouriteGenres(int limit) { } public List getTopFavouriteTags(int limit) { - if(CompatUtil.isEmpty(favouriteTags)) { + if(CompatUtil.INSTANCE.isEmpty(favouriteTags)) { UserStats userStats; if (getDatabase().getCurrentUser() != null && (userStats = getDatabase().getCurrentUser().getStats()) != null) { - if (!CompatUtil.isEmpty(userStats.getFavouredTags())) { + if (!CompatUtil.INSTANCE.isEmpty(userStats.getFavouredTags())) { favouriteTags = Stream.of(userStats.getFavouredTags()) .sortBy(mediaTagStats -> - mediaTagStats.getAmount()) .map(s -> s.getTag().getName()) @@ -89,10 +89,10 @@ public List getTopFavouriteTags(int limit) { } public List getTopFavouriteYears(int limit) { - if(CompatUtil.isEmpty(favouriteYears)) { + if(CompatUtil.INSTANCE.isEmpty(favouriteYears)) { UserStats userStats; if (getDatabase().getCurrentUser() != null && (userStats = getDatabase().getCurrentUser().getStats()) != null) { - if (!CompatUtil.isEmpty(userStats.getFavouredTags())) { + if (!CompatUtil.INSTANCE.isEmpty(userStats.getFavouredTags())) { favouriteYears = Stream.of(userStats.getFavouredYears()) .sortBy(yearStats -> - yearStats.getAmount()) .map(y -> String.valueOf(y.getYear())) @@ -105,10 +105,10 @@ public List getTopFavouriteYears(int limit) { } public List getTopFormats(int limit) { - if(CompatUtil.isEmpty(favouriteFormats)) { + if(CompatUtil.INSTANCE.isEmpty(favouriteFormats)) { UserStats userStats; if (getDatabase().getCurrentUser() != null && (userStats = getDatabase().getCurrentUser().getStats()) != null) { - if (!CompatUtil.isEmpty(userStats.getFavouredFormats())) { + if (!CompatUtil.INSTANCE.isEmpty(userStats.getFavouredFormats())) { favouriteFormats = Stream.of(userStats.getFavouredFormats()) .sortBy(formatStats -> - formatStats.getAmount()) .map(FormatStats::getFormat) diff --git a/app/src/main/java/com/mxt/anitrend/presenter/fragment/MediaPresenter.java b/app/src/main/java/com/mxt/anitrend/presenter/fragment/MediaPresenter.java index dc8b91d11..38d7cc313 100644 --- a/app/src/main/java/com/mxt/anitrend/presenter/fragment/MediaPresenter.java +++ b/app/src/main/java/com/mxt/anitrend/presenter/fragment/MediaPresenter.java @@ -77,7 +77,7 @@ public List getMediaStats(List statusDistribution) .map(st -> new PieEntry( (float) ((st.getAmount()*100) / highestStatus), String.format(Locale.getDefault(), "%s: %s", - CompatUtil.capitalizeWords(st.getStatus()), MediaUtil.getFormattedCount(st.getAmount())))) + CompatUtil.INSTANCE.capitalizeWords(st.getStatus()), MediaUtil.getFormattedCount(st.getAmount())))) .sorted((p1, p2) -> p1.getLabel().compareTo(p2.getLabel())) .toList(); return Collections.emptyList(); @@ -98,19 +98,19 @@ public String getEpisodeDuration(Media media) { public String getMediaSeason(Media media) { if(media != null && media.getStartDate() != null && media.getStartDate().isValidDate()) - return DateUtil.getMediaSeason(media.getStartDate()); + return DateUtil.INSTANCE.getMediaSeason(media.getStartDate()); return getContext().getString(R.string.TBA); } public String getMediaSource(Media media) { if(media != null && !TextUtils.isEmpty(media.getSource())) - return CompatUtil.capitalizeWords(media.getSource()); + return CompatUtil.INSTANCE.capitalizeWords(media.getSource()); return getContext().getString(R.string.TBA); } public String getMediaStatus(Media media) { if(media != null && (!TextUtils.isEmpty(media.getStatus()))) - return CompatUtil.capitalizeWords(media.getStatus()); + return CompatUtil.INSTANCE.capitalizeWords(media.getStatus()); return getContext().getString(R.string.TBA); } @@ -147,7 +147,7 @@ public List buildGenres(Media media) { public String getMediaFormat(MediaBase media) { if(media != null && !TextUtils.isEmpty(media.getFormat())) - return CompatUtil.capitalizeWords(media.getFormat()); + return CompatUtil.INSTANCE.capitalizeWords(media.getFormat()); return getContext().getString(R.string.tba_placeholder); } diff --git a/app/src/main/java/com/mxt/anitrend/service/DownloaderService.java b/app/src/main/java/com/mxt/anitrend/service/DownloaderService.java deleted file mode 100644 index fc9e522a5..000000000 --- a/app/src/main/java/com/mxt/anitrend/service/DownloaderService.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.mxt.anitrend.service; - -import android.app.DownloadManager; -import android.content.Context; -import android.net.Uri; -import android.os.Environment; -import android.webkit.MimeTypeMap; - -import com.mxt.anitrend.R; -import com.mxt.anitrend.model.api.retro.base.RepositoryModel; -import com.mxt.anitrend.model.entity.base.VersionBase; - -import java.util.Locale; - -public class DownloaderService { - - /** - * Handles downloading of new version of AniTrend - * @see RepositoryModel#DOWNLOAD_LINK - */ - public static void downloadNewVersion(Context context, VersionBase versionBase) { - String downloadLink = String.format(RepositoryModel.DOWNLOAD_LINK, versionBase.getVersion()); - DownloadManager downloadManager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); - DownloadManager.Request request = new DownloadManager.Request(Uri.parse(downloadLink)); - request.setTitle(String.format(Locale.getDefault(), "anitrend_v%s_rc_%d.apk", versionBase.getVersion(), versionBase.getCode())); - request.allowScanningByMediaScanner(); - String ext = MimeTypeMap.getFileExtensionFromUrl(RepositoryModel.DOWNLOAD_LINK); - request.setMimeType(MimeTypeMap.getSingleton().getMimeTypeFromExtension(ext)); - request.setDescription(context.getString(R.string.text_downloading_update)); - request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, - String.format(Locale.getDefault(), "anitrend_v%s_rc_%d.apk", versionBase.getVersion(), versionBase.getCode())); - request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); - if(downloadManager != null) - downloadManager.enqueue(request); - } -} diff --git a/app/src/main/java/com/mxt/anitrend/service/DownloaderService.kt b/app/src/main/java/com/mxt/anitrend/service/DownloaderService.kt new file mode 100644 index 000000000..45db53eb3 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/service/DownloaderService.kt @@ -0,0 +1,35 @@ +package com.mxt.anitrend.service + +import android.app.DownloadManager +import android.content.Context +import android.net.Uri +import android.os.Environment +import android.webkit.MimeTypeMap + +import com.mxt.anitrend.R +import com.mxt.anitrend.model.api.retro.base.RepositoryModel +import com.mxt.anitrend.model.entity.base.VersionBase + +import java.util.Locale + +object DownloaderService { + + /** + * Handles downloading of new version of AniTrend + * @see RepositoryModel.DOWNLOAD_LINK + */ + fun downloadNewVersion(context: Context?, versionBase: VersionBase) { + val downloadLink = String.format(RepositoryModel.DOWNLOAD_LINK, versionBase.version) + val downloadManager = context?.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager? + val request = DownloadManager.Request(Uri.parse(downloadLink)) + request.setTitle(String.format(Locale.getDefault(), "anitrend_v%s_rc_%d.apk", versionBase.version, versionBase.code)) + request.allowScanningByMediaScanner() + val ext = MimeTypeMap.getFileExtensionFromUrl(RepositoryModel.DOWNLOAD_LINK) + request.setMimeType(MimeTypeMap.getSingleton().getMimeTypeFromExtension(ext)) + request.setDescription(context?.getString(R.string.text_downloading_update)) + request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, + String.format(Locale.getDefault(), "anitrend_v%s_rc_%d.apk", versionBase.version, versionBase.code)) + request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED) + downloadManager?.enqueue(request) + } +} diff --git a/app/src/main/java/com/mxt/anitrend/service/JobDispatcherService.kt b/app/src/main/java/com/mxt/anitrend/service/JobDispatcherService.kt index 12e547575..baca6c5e1 100644 --- a/app/src/main/java/com/mxt/anitrend/service/JobDispatcherService.kt +++ b/app/src/main/java/com/mxt/anitrend/service/JobDispatcherService.kt @@ -7,7 +7,6 @@ import com.mxt.anitrend.base.custom.consumer.BaseConsumer import com.mxt.anitrend.model.api.retro.WebFactory import com.mxt.anitrend.model.api.retro.anilist.UserModel import com.mxt.anitrend.model.entity.anilist.User -import com.mxt.anitrend.model.entity.container.body.GraphContainer import com.mxt.anitrend.presenter.base.BasePresenter import com.mxt.anitrend.util.GraphUtil import com.mxt.anitrend.util.KeyUtil @@ -16,8 +15,7 @@ import com.mxt.anitrend.util.NotificationUtil import androidx.work.ListenableWorker import androidx.work.Worker import androidx.work.WorkerParameters -import retrofit2.Call -import retrofit2.Response +import java.util.* /** * Created by Maxwell on 1/22/2017. @@ -28,6 +26,10 @@ class JobDispatcherService(context: Context, workerParams: WorkerParameters) : W BasePresenter(context) } + private val notificationUtil by lazy { + NotificationUtil(applicationContext) + } + /** * Override this method to do your actual background processing. This method is called on a * background thread - you are required to **synchronously** do your work and return the @@ -45,24 +47,26 @@ class JobDispatcherService(context: Context, workerParams: WorkerParameters) : W * dependent work will not execute if you use * [Result.failure] */ - override fun doWork(): ListenableWorker.Result { + override fun doWork(): Result { if (presenter.applicationPref.isAuthenticated) { val userModel = WebFactory.createService(UserModel::class.java, applicationContext) - val request = userModel.getCurrentUser(GraphUtil.getDefaultQuery(false)) + val userRequest = userModel.getCurrentUser(GraphUtil.getDefaultQuery(false)) try { - val response = request.execute() - val userGraphContainer: Any? = response.body() - if (response.isSuccessful && userGraphContainer != null) { + val userResponse = userRequest.execute() + val userGraphContainer: Any? = userResponse.body() + if (userResponse.isSuccessful && userGraphContainer != null) { val currentUser = userGraphContainer as User? - val previousUserData = presenter.database.currentUser - presenter.database.saveCurrentUser(currentUser) - if (previousUserData.unreadNotificationCount != currentUser!!.unreadNotificationCount) { - if (currentUser.unreadNotificationCount > 0) { - presenter.notifyAllListeners(BaseConsumer(KeyUtil.USER_CURRENT_REQ, currentUser), false) - NotificationUtil.createNotification(applicationContext, currentUser) + if (currentUser != null) { + val previousUserData = presenter.database.currentUser + presenter.database.saveCurrentUser(currentUser) + if (previousUserData.unreadNotificationCount != currentUser.unreadNotificationCount) { + if (currentUser.unreadNotificationCount != 0) { + presenter.notifyAllListeners(BaseConsumer(KeyUtil.USER_CURRENT_REQ, currentUser), false) + notificationUtil.createNotification(currentUser) + } } } - return ListenableWorker.Result.success() + return Result.success() } } catch (e: Exception) { e.message?.apply { @@ -72,6 +76,6 @@ class JobDispatcherService(context: Context, workerParams: WorkerParameters) : W } } - return ListenableWorker.Result.retry() + return Result.retry() } } diff --git a/app/src/main/java/com/mxt/anitrend/service/TagGenreService.java b/app/src/main/java/com/mxt/anitrend/service/TagGenreService.java deleted file mode 100644 index c4ec071ed..000000000 --- a/app/src/main/java/com/mxt/anitrend/service/TagGenreService.java +++ /dev/null @@ -1,95 +0,0 @@ -package com.mxt.anitrend.service; - -import android.app.IntentService; -import android.content.Intent; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.util.Log; - -import com.annimon.stream.Stream; -import com.google.firebase.analytics.FirebaseAnalytics; -import com.mxt.anitrend.base.interfaces.event.RetroCallback; -import com.mxt.anitrend.model.entity.anilist.Genre; -import com.mxt.anitrend.model.entity.anilist.MediaTag; -import com.mxt.anitrend.presenter.widget.WidgetPresenter; -import com.mxt.anitrend.util.CompatUtil; -import com.mxt.anitrend.util.ErrorUtil; -import com.mxt.anitrend.util.GraphUtil; -import com.mxt.anitrend.util.KeyUtil; - -import java.util.List; - -import retrofit2.Call; -import retrofit2.Response; - -/** - * Created by max on 2017/10/24. - * Genre & Tags Service - */ - -public class TagGenreService extends IntentService { - - private static final String ServiceName = "TagGenreService"; - - public TagGenreService() { - super(ServiceName); - } - - private void fetchAllMediaTags() { - WidgetPresenter> widgetPresenter = new WidgetPresenter<>(getApplicationContext()); - if(widgetPresenter.getDatabase().getBoxStore(MediaTag.class).count() < 1) { - widgetPresenter.getParams().putParcelable(KeyUtil.arg_graph_params, GraphUtil.getDefaultQuery(false)); - widgetPresenter.requestData(KeyUtil.MEDIA_TAG_REQ, getApplicationContext(), new RetroCallback>() { - @Override - public void onResponse(@NonNull Call> call, @NonNull Response> response) { - List responseBody; - if (response.isSuccessful() && (responseBody = response.body()) != null) - if (!CompatUtil.isEmpty(responseBody)) - widgetPresenter.getDatabase().saveMediaTags(responseBody); - else - Log.e(ServiceName, ErrorUtil.getError(response)); - } - - @Override - public void onFailure(@NonNull Call> call, @NonNull Throwable throwable) { - Log.e("fetchAllMediaTags", throwable.getMessage()); - throwable.printStackTrace(); - } - }); - } - } - - private void fetchAllMediaGenres() { - WidgetPresenter> widgetPresenter = new WidgetPresenter<>(getApplicationContext()); - if(widgetPresenter.getDatabase().getBoxStore(Genre.class).count() < 1) { - widgetPresenter.getParams().putParcelable(KeyUtil.arg_graph_params, GraphUtil.getDefaultQuery(false)); - widgetPresenter.requestData(KeyUtil.GENRE_COLLECTION_REQ, getApplicationContext(), new RetroCallback>() { - @Override - public void onResponse(@NonNull Call> call, @NonNull Response> response) { - List responseBody; - if (response.isSuccessful() && (responseBody = response.body()) != null) { - if (!CompatUtil.isEmpty(responseBody)) { - List genreList = Stream.of(responseBody) - .map(Genre::new) - .toList(); - widgetPresenter.getDatabase().saveGenreCollection(genreList); - } - } else - Log.e(ServiceName, ErrorUtil.getError(response)); - } - - @Override - public void onFailure(@NonNull Call> call, @NonNull Throwable throwable) { - Log.e("fetchAllMediaGenres", throwable.getMessage()); - throwable.printStackTrace(); - } - }); - } - } - - @Override - protected void onHandleIntent(@Nullable Intent intent) { - fetchAllMediaGenres(); - fetchAllMediaTags(); - } -} diff --git a/app/src/main/java/com/mxt/anitrend/service/TagGenreService.kt b/app/src/main/java/com/mxt/anitrend/service/TagGenreService.kt new file mode 100644 index 000000000..bffa0252b --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/service/TagGenreService.kt @@ -0,0 +1,84 @@ +package com.mxt.anitrend.service + +import android.app.IntentService +import android.content.Intent +import android.util.Log + +import com.annimon.stream.Stream +import com.google.firebase.analytics.FirebaseAnalytics +import com.mxt.anitrend.base.interfaces.event.RetroCallback +import com.mxt.anitrend.model.entity.anilist.Genre +import com.mxt.anitrend.model.entity.anilist.MediaTag +import com.mxt.anitrend.presenter.widget.WidgetPresenter +import com.mxt.anitrend.util.CompatUtil +import com.mxt.anitrend.util.ErrorUtil +import com.mxt.anitrend.util.GraphUtil +import com.mxt.anitrend.util.KeyUtil + +import retrofit2.Call +import retrofit2.Response + +/** + * Created by max on 2017/10/24. + * Genre & Tags Service + */ + +class TagGenreService : IntentService(ServiceName) { + + private fun fetchAllMediaTags() { + val widgetPresenter = WidgetPresenter>(applicationContext) + if (widgetPresenter.database.getBoxStore(MediaTag::class.java).count() < 1) { + widgetPresenter.params.putParcelable(KeyUtil.arg_graph_params, GraphUtil.getDefaultQuery(false)) + widgetPresenter.requestData(KeyUtil.MEDIA_TAG_REQ, applicationContext, object : RetroCallback> { + override fun onResponse(call: Call>, response: Response>) { + val responseBody: List? = response.body() + if (response.isSuccessful && responseBody != null) + if (!CompatUtil.isEmpty(responseBody)) + widgetPresenter.database.saveMediaTags(responseBody) + else + Log.e(ServiceName, ErrorUtil.getError(response)) + } + + override fun onFailure(call: Call>, throwable: Throwable) { + Log.e("fetchAllMediaTags", throwable.message) + throwable.printStackTrace() + } + }) + } + } + + private fun fetchAllMediaGenres() { + val widgetPresenter = WidgetPresenter>(applicationContext) + if (widgetPresenter.database.getBoxStore(Genre::class.java).count() < 1) { + widgetPresenter.params.putParcelable(KeyUtil.arg_graph_params, GraphUtil.getDefaultQuery(false)) + widgetPresenter.requestData(KeyUtil.GENRE_COLLECTION_REQ, applicationContext, object : RetroCallback> { + override fun onResponse(call: Call>, response: Response>) { + val responseBody: List? = response.body() + if (response.isSuccessful && responseBody != null) { + if (!CompatUtil.isEmpty(responseBody)) { + val genreList = Stream.of(responseBody!!) + .map { Genre(it) } + .toList() + widgetPresenter.database.saveGenreCollection(genreList) + } + } else + Log.e(ServiceName, ErrorUtil.getError(response)) + } + + override fun onFailure(call: Call>, throwable: Throwable) { + Log.e("fetchAllMediaGenres", throwable.message) + throwable.printStackTrace() + } + }) + } + } + + override fun onHandleIntent(intent: Intent?) { + fetchAllMediaGenres() + fetchAllMediaTags() + } + + companion object { + private const val ServiceName = "TagGenreService" + } +} diff --git a/app/src/main/java/com/mxt/anitrend/util/ActionModeUtil.java b/app/src/main/java/com/mxt/anitrend/util/ActionModeUtil.java index 8d0f61c72..03a000336 100644 --- a/app/src/main/java/com/mxt/anitrend/util/ActionModeUtil.java +++ b/app/src/main/java/com/mxt/anitrend/util/ActionModeUtil.java @@ -120,7 +120,7 @@ else if (viewHolder.itemView instanceof CheckBox) viewHolder.itemView.setBackgroundResource(R.drawable.selection_frame); } else { if (viewHolder.itemView instanceof CardView) - ((CardView)viewHolder.itemView).setCardBackgroundColor(CompatUtil.getColorFromAttr(viewHolder.getContext(), R.attr.cardColor)); + ((CardView)viewHolder.itemView).setCardBackgroundColor(CompatUtil.INSTANCE.getColorFromAttr(viewHolder.getContext(), R.attr.cardColor)); else if (viewHolder.itemView instanceof CheckBox) ((CheckBox) viewHolder.itemView).setChecked(false); else diff --git a/app/src/main/java/com/mxt/anitrend/util/ApplicationPref.java b/app/src/main/java/com/mxt/anitrend/util/ApplicationPref.java deleted file mode 100644 index 6eca7f5f2..000000000 --- a/app/src/main/java/com/mxt/anitrend/util/ApplicationPref.java +++ /dev/null @@ -1,355 +0,0 @@ -package com.mxt.anitrend.util; - -import android.content.Context; -import android.content.SharedPreferences; -import android.preference.PreferenceManager; -import android.support.annotation.IdRes; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.StyleRes; - -import com.mxt.anitrend.BuildConfig; -import com.mxt.anitrend.R; - -import java.util.Locale; -import java.util.Map; - -/** - * Created by max on 2017/09/16. - * Application preferences - */ - -public class ApplicationPref { - - private Context context; - - /** Base Application Values */ - private final String _versionCode = "_versionCode"; - private final String _freshInstall = "_freshInstall"; - private final String _isAuthenticated = "_isAuthenticated"; - - /** Application Base Options */ - public static final String _isLightTheme = "_isLightTheme"; - public static final String _updateChannel = "_updateChannel"; - - /** Api Keys */ - private static final String _genreFilter = "_genreFilter"; - private static final String _tagFilter = "_tagFilter"; - private static final String _sortOrder = "_sortOrder"; - private static final String _mediaStatus = "_mediaStatus"; - private static final String _mediaFormat = "_mediaFormat"; - private static final String _animeFormat = "_animeFormat"; - private static final String _mangaFormat = "_mangaFormat"; - private static final String _mediaSource = "_mediaSource"; - private static final String _airingSort = "_airingSort"; - private static final String _characterSort = "_characterSort"; - public static final String _mediaListSort = "_mediaListSort"; - private static final String _mediaSort = "_mediaSort"; - private static final String _mediaTrendSort = "_mediaTrendSort"; - private static final String _reviewSort = "_reviewSort"; - private static final String _staffSort = "_staffSort"; - - private SharedPreferences sharedPreferences; - - public ApplicationPref(Context context) { - this.context = context; - sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); - } - - public SharedPreferences getSharedPreferences() { - return sharedPreferences; - } - - public boolean isAuthenticated() { - return sharedPreferences.getBoolean(_isAuthenticated, false); - } - - public void setAuthenticated(boolean authenticated) { - SharedPreferences.Editor editor = sharedPreferences.edit(); - editor.putBoolean(_isAuthenticated, authenticated); - editor.apply(); - } - - public void toggleTheme() { - SharedPreferences.Editor editor = sharedPreferences.edit(); - editor.putInt(_isLightTheme, getTheme() == R.style.AppThemeLight ? R.style.AppThemeDark : R.style.AppThemeLight); - editor.apply(); - } - - public @StyleRes int getTheme() { - @StyleRes int style = sharedPreferences.getInt(_isLightTheme, R.style.AppThemeLight); - return style; - } - - public boolean isBlackThemeEnabled() { - return sharedPreferences.getBoolean(context.getString(R.string.pref_key_black_theme), false); - } - - // Returns the IDs of the startup page - public @IdRes int getStartupPage() { - String id = sharedPreferences.getString(context.getString(R.string.pref_key_startup_page), "4"); - switch (id){ - case "0": - return R.id.nav_home_feed; - case "1": - return R.id.nav_anime; - case "2": - return R.id.nav_manga; - case "3": - return R.id.nav_trending; - case "4": - return R.id.nav_airing; - case "5": - return R.id.nav_myanime; - case "6": - return R.id.nav_mymanga; - case "7": - return R.id.nav_hub; - case "8": - return R.id.nav_reviews; - } - return R.id.nav_airing; - } - - public boolean isFreshInstall() { - return sharedPreferences.getBoolean(_freshInstall, true); - } - - public void setFreshInstall() { - SharedPreferences.Editor editor = sharedPreferences.edit(); - editor.putBoolean(_freshInstall, false); - editor.apply(); - } - - public String getUserLanguage() { - return sharedPreferences.getString(context.getString(R.string.pref_key_selected_Language), Locale.getDefault().getLanguage()); - } - - //Returns amount of time in seconds - public int getSyncTime() { - return Integer.valueOf(sharedPreferences.getString(context.getString(R.string.pref_key_sync_frequency), "15")); - } - - public boolean isNotificationEnabled() { - return sharedPreferences.getBoolean(context.getString(R.string.pref_key_new_message_notifications), true); - } - - public String getNotificationsSound() { - return sharedPreferences.getString(context.getString(R.string.pref_key_ringtone), "DEFAULT_SOUND"); - } - - public Boolean isCrashReportsEnabled() { - return sharedPreferences.getBoolean(context.getString(R.string.pref_key_crash_reports), false); - } - - public Boolean isUsageAnalyticsEnabled() { - return sharedPreferences.getBoolean(context.getString(R.string.pref_key_crash_reports), false); - } - - public void saveSeasonYear(int year) { - SharedPreferences.Editor editor = sharedPreferences.edit(); - editor.putInt(KeyUtil.arg_seasonYear, year); - editor.apply(); - } - - public int getSeasonYear() { - return sharedPreferences.getInt(KeyUtil.arg_seasonYear, DateUtil.getCurrentYear(0)); - } - - - public boolean shouldShowTipFor(@KeyUtil.TapTargetType String tipType) { - return sharedPreferences.getBoolean(tipType, true); - } - - public void disableTipFor(@KeyUtil.TapTargetType String tipType) { - SharedPreferences.Editor editor = sharedPreferences.edit(); - editor.putBoolean(tipType, false); - editor.apply(); - } - - - public @KeyUtil.SortOrderType String getSortOrder() { - return sharedPreferences.getString(_sortOrder, KeyUtil.DESC); - } - - public void saveSortOrder(@KeyUtil.SortOrderType String sortOrder) { - SharedPreferences.Editor editor = sharedPreferences.edit(); - editor.putString(_sortOrder, sortOrder); - editor.apply(); - } - - - public @Nullable @KeyUtil.MediaStatus String getMediaStatus() { - return sharedPreferences.getString(_mediaStatus, null); - } - - public void setMediaStatus(@KeyUtil.MediaStatus String mediaStatus) { - SharedPreferences.Editor editor = sharedPreferences.edit(); - editor.putString(_mediaStatus, mediaStatus); - editor.apply(); - } - - - public @Nullable @KeyUtil.MediaFormat String getMediaFormat() { - return sharedPreferences.getString(_mediaFormat, null); - } - - public @Nullable @KeyUtil.AnimeFormat String getAnimeFormat() { - return sharedPreferences.getString(_animeFormat, null); - } - - public @Nullable @KeyUtil.MangaFormat String getMangaFormat() { - return sharedPreferences.getString(_mangaFormat, null); - } - - public void setMediaFormat(@KeyUtil.MediaFormat String mediaFormat) { - SharedPreferences.Editor editor = sharedPreferences.edit(); - editor.putString(_mediaFormat, mediaFormat); - editor.apply(); - } - - public void setAnimeFormat(@KeyUtil.AnimeFormat String animeFormat) { - SharedPreferences.Editor editor = sharedPreferences.edit(); - editor.putString(_animeFormat, animeFormat); - editor.apply(); - } - - public void setMangaFormat(@KeyUtil.MangaFormat String mangaFormat) { - SharedPreferences.Editor editor = sharedPreferences.edit(); - editor.putString(_mangaFormat, mangaFormat); - editor.apply(); - } - - - public @Nullable @KeyUtil.MediaSource String getMediaSource() { - return sharedPreferences.getString(_mediaSource, null); - } - - public void setMediaSource(@KeyUtil.MediaSource String mediaSource) { - SharedPreferences.Editor editor = sharedPreferences.edit(); - editor.putString(_mediaSource, mediaSource); - editor.apply(); - } - - - public @KeyUtil.AiringSort String getAiringSort() { - return sharedPreferences.getString(_airingSort, KeyUtil.EPISODE); - } - - public void setAiringSort(@KeyUtil.AiringSort String airingSort) { - SharedPreferences.Editor editor = sharedPreferences.edit(); - editor.putString(_airingSort, airingSort); - editor.apply(); - } - - - public @KeyUtil.CharacterSort String getCharacterSort() { - return sharedPreferences.getString(_characterSort, KeyUtil.ROLE); - } - - public void setCharacterSort(@KeyUtil.CharacterSort String characterSort) { - SharedPreferences.Editor editor = sharedPreferences.edit(); - editor.putString(_characterSort, characterSort); - editor.apply(); - } - - - public @KeyUtil.MediaListSort String getMediaListSort() { - return sharedPreferences.getString(_mediaListSort, KeyUtil.PROGRESS); - } - - public void setMediaListSort(@KeyUtil.MediaListSort String mediaListSort) { - SharedPreferences.Editor editor = sharedPreferences.edit(); - editor.putString(_mediaListSort, mediaListSort); - editor.apply(); - } - - - public @KeyUtil.MediaSort String getMediaSort() { - return sharedPreferences.getString(_mediaSort, KeyUtil.POPULARITY); - } - - public void setMediaSort(@KeyUtil.MediaSort String mediaSort) { - SharedPreferences.Editor editor = sharedPreferences.edit(); - editor.putString(_mediaSort, mediaSort); - editor.apply(); - } - - public @KeyUtil.MediaTrendSort String getMediaTrendSort() { - return sharedPreferences.getString(_mediaTrendSort, KeyUtil.TRENDING); - } - - public void setMediaTrendSort(@KeyUtil.MediaTrendSort String mediaTrendSort) { - SharedPreferences.Editor editor = sharedPreferences.edit(); - editor.putString(_mediaTrendSort, mediaTrendSort); - editor.apply(); - } - - - public @KeyUtil.ReviewSort String getReviewSort() { - return sharedPreferences.getString(_reviewSort, KeyUtil.ID); - } - - public void setReviewSort(@KeyUtil.ReviewSort String reviewSort) { - SharedPreferences.Editor editor = sharedPreferences.edit(); - editor.putString(_reviewSort, reviewSort); - editor.apply(); - } - - - public @KeyUtil.StaffSort String getStaffSort() { - return sharedPreferences.getString(_staffSort, KeyUtil.ROLE); - } - - public void setStaffSort(@KeyUtil.StaffSort String staffSort) { - SharedPreferences.Editor editor = sharedPreferences.edit(); - editor.putString(_staffSort, staffSort); - editor.apply(); - } - - public @KeyUtil.Channel String getUpdateChannel() { - return sharedPreferences.getString(_updateChannel, KeyUtil.STABLE); - } - - public void setUpdateChannel(@KeyUtil.Channel String channel) { - SharedPreferences.Editor editor = sharedPreferences.edit(); - editor.putString(_updateChannel, channel); - editor.apply(); - } - - public boolean isUpdated() { - return sharedPreferences.getInt(_versionCode, 1) < BuildConfig.VERSION_CODE; - } - - public void setUpdated() { - SharedPreferences.Editor editor = sharedPreferences.edit(); - editor.putInt(_versionCode, BuildConfig.VERSION_CODE); - editor.apply(); - } - - public void setSelectedGenres(@Nullable Map selectedIndices) { - String selected = new GenreTagUtil() - .convertToJson(selectedIndices); - SharedPreferences.Editor editor = sharedPreferences.edit(); - editor.putString(_genreFilter, selected); - editor.apply(); - } - - public @NonNull Map getSelectedGenres() { - String selected = sharedPreferences.getString(_genreFilter, null); - return new GenreTagUtil().convertToEntity(selected); - } - - public void setSelectedTags(@Nullable Map selectedIndices) { - String selected = new GenreTagUtil() - .convertToJson(selectedIndices); - SharedPreferences.Editor editor = sharedPreferences.edit(); - editor.putString(_tagFilter, selected); - editor.apply(); - } - - public @NonNull Map getSelectedTags() { - String selected = sharedPreferences.getString(_tagFilter, null); - return new GenreTagUtil().convertToEntity(selected); - } -} diff --git a/app/src/main/java/com/mxt/anitrend/util/ApplicationPref.kt b/app/src/main/java/com/mxt/anitrend/util/ApplicationPref.kt new file mode 100644 index 000000000..6c89988b9 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/util/ApplicationPref.kt @@ -0,0 +1,297 @@ +package com.mxt.anitrend.util + +import android.content.Context +import android.content.SharedPreferences +import android.preference.PreferenceManager +import android.support.annotation.IdRes +import android.support.annotation.StyleRes + +import com.mxt.anitrend.BuildConfig +import com.mxt.anitrend.R +import com.mxt.anitrend.util.ApplicationPref.Companion._isLightTheme + +import java.util.Locale + +/** + * Created by max on 2017/09/16. + * Application preferences + */ + +class ApplicationPref(private val context: Context) { + + /** Base Application Values */ + private val _versionCode = "_versionCode" + private val _freshInstall = "_freshInstall" + private val _isAuthenticated = "_isAuthenticated" + + val sharedPreferences: SharedPreferences by lazy { + PreferenceManager.getDefaultSharedPreferences(context) + } + + var isAuthenticated: Boolean + get() = sharedPreferences.getBoolean(_isAuthenticated, false) + set(authenticated) { + val editor = sharedPreferences.edit() + editor.putBoolean(_isAuthenticated, authenticated) + editor.apply() + } + + val theme: Int + @StyleRes get() = sharedPreferences.getInt(_isLightTheme, R.style.AppThemeLight) + + val isBlackThemeEnabled: Boolean + get() = sharedPreferences.getBoolean(context.getString(R.string.pref_key_black_theme), false) + + // Returns the IDs of the startup page + val startupPage: Int + @IdRes get() { + when (sharedPreferences.getString(context.getString(R.string.pref_key_startup_page), "4")) { + "0" -> return R.id.nav_home_feed + "1" -> return R.id.nav_anime + "2" -> return R.id.nav_manga + "3" -> return R.id.nav_trending + "4" -> return R.id.nav_airing + "5" -> return R.id.nav_myanime + "6" -> return R.id.nav_mymanga + "7" -> return R.id.nav_hub + "8" -> return R.id.nav_reviews + } + return R.id.nav_airing + } + + val isFreshInstall: Boolean + get() = sharedPreferences.getBoolean(_freshInstall, true) + + val userLanguage: String? + get() = sharedPreferences.getString(context.getString(R.string.pref_key_selected_Language), Locale.getDefault().language) + + //Returns amount of time in seconds + val syncTime: Int + get() = Integer.valueOf(sharedPreferences.getString(context.getString(R.string.pref_key_sync_frequency), "15")!!) + + val isNotificationEnabled: Boolean + get() = sharedPreferences.getBoolean(context.getString(R.string.pref_key_new_message_notifications), true) + + val notificationsSound: String? + get() = sharedPreferences.getString(context.getString(R.string.pref_key_ringtone), "DEFAULT_SOUND") + + val isCrashReportsEnabled: Boolean? + get() = sharedPreferences.getBoolean(context.getString(R.string.pref_key_crash_reports), false) + + val isUsageAnalyticsEnabled: Boolean? + get() = sharedPreferences.getBoolean(context.getString(R.string.pref_key_crash_reports), false) + + val seasonYear: Int + get() = sharedPreferences.getInt(KeyUtil.arg_seasonYear, DateUtil.getCurrentYear(0)) + + + val sortOrder: String? + @KeyUtil.SortOrderType get() = sharedPreferences.getString(_sortOrder, KeyUtil.DESC) + + + var mediaStatus: String? + @KeyUtil.MediaStatus get() = sharedPreferences.getString(_mediaStatus, null) + set(@KeyUtil.MediaStatus mediaStatus) { + val editor = sharedPreferences.edit() + editor.putString(_mediaStatus, mediaStatus) + editor.apply() + } + + + var mediaFormat: String? + @KeyUtil.MediaFormat get() = sharedPreferences.getString(_mediaFormat, null) + set(@KeyUtil.MediaFormat mediaFormat) { + val editor = sharedPreferences.edit() + editor.putString(_mediaFormat, mediaFormat) + editor.apply() + } + + var animeFormat: String? + @KeyUtil.AnimeFormat get() = sharedPreferences.getString(_animeFormat, null) + set(@KeyUtil.AnimeFormat animeFormat) { + val editor = sharedPreferences.edit() + editor.putString(_animeFormat, animeFormat) + editor.apply() + } + + var mangaFormat: String? + @KeyUtil.MangaFormat get() = sharedPreferences.getString(_mangaFormat, null) + set(@KeyUtil.MangaFormat mangaFormat) { + val editor = sharedPreferences.edit() + editor.putString(_mangaFormat, mangaFormat) + editor.apply() + } + + + var mediaSource: String? + @KeyUtil.MediaSource get() = sharedPreferences.getString(_mediaSource, null) + set(@KeyUtil.MediaSource mediaSource) { + val editor = sharedPreferences.edit() + editor.putString(_mediaSource, mediaSource) + editor.apply() + } + + + var airingSort: String? + @KeyUtil.AiringSort get() = sharedPreferences.getString(_airingSort, KeyUtil.EPISODE) + set(@KeyUtil.AiringSort airingSort) { + val editor = sharedPreferences.edit() + editor.putString(_airingSort, airingSort) + editor.apply() + } + + + var characterSort: String? + @KeyUtil.CharacterSort get() = sharedPreferences.getString(_characterSort, KeyUtil.ROLE) + set(@KeyUtil.CharacterSort characterSort) { + val editor = sharedPreferences.edit() + editor.putString(_characterSort, characterSort) + editor.apply() + } + + + var mediaListSort: String? + @KeyUtil.MediaListSort get() = sharedPreferences.getString(_mediaListSort, KeyUtil.PROGRESS) + set(@KeyUtil.MediaListSort mediaListSort) { + val editor = sharedPreferences.edit() + editor.putString(_mediaListSort, mediaListSort) + editor.apply() + } + + + var mediaSort: String? + @KeyUtil.MediaSort get() = sharedPreferences.getString(_mediaSort, KeyUtil.POPULARITY) + set(@KeyUtil.MediaSort mediaSort) { + val editor = sharedPreferences.edit() + editor.putString(_mediaSort, mediaSort) + editor.apply() + } + + var mediaTrendSort: String? + @KeyUtil.MediaTrendSort get() = sharedPreferences.getString(_mediaTrendSort, KeyUtil.TRENDING) + set(@KeyUtil.MediaTrendSort mediaTrendSort) { + val editor = sharedPreferences.edit() + editor.putString(_mediaTrendSort, mediaTrendSort) + editor.apply() + } + + + var reviewSort: String? + @KeyUtil.ReviewSort get() = sharedPreferences.getString(_reviewSort, KeyUtil.ID) + set(@KeyUtil.ReviewSort reviewSort) { + val editor = sharedPreferences.edit() + editor.putString(_reviewSort, reviewSort) + editor.apply() + } + + + var staffSort: String? + @KeyUtil.StaffSort get() = sharedPreferences.getString(_staffSort, KeyUtil.ROLE) + set(@KeyUtil.StaffSort staffSort) { + val editor = sharedPreferences.edit() + editor.putString(_staffSort, staffSort) + editor.apply() + } + + var updateChannel: String? + @KeyUtil.Channel get() = sharedPreferences.getString(_updateChannel, KeyUtil.STABLE) + set(@KeyUtil.Channel channel) { + val editor = sharedPreferences.edit() + editor.putString(_updateChannel, channel) + editor.apply() + } + + val isUpdated: Boolean + get() = sharedPreferences.getInt(_versionCode, 1) < BuildConfig.VERSION_CODE + + var selectedGenres: Map? + get() { + val selected = sharedPreferences.getString(_genreFilter, null) + return GenreTagUtil().convertToEntity(selected) + } + set(selectedIndices) { + val selected = GenreTagUtil() + .convertToJson(selectedIndices) + val editor = sharedPreferences.edit() + editor.putString(_genreFilter, selected) + editor.apply() + } + + var selectedTags: Map? + get() { + val selected = sharedPreferences.getString(_tagFilter, null) + return GenreTagUtil().convertToEntity(selected) + } + set(selectedIndices) { + val selected = GenreTagUtil() + .convertToJson(selectedIndices) + val editor = sharedPreferences.edit() + editor.putString(_tagFilter, selected) + editor.apply() + } + + fun toggleTheme() { + val editor = sharedPreferences.edit() + editor.putInt(_isLightTheme, if (theme == R.style.AppThemeLight) R.style.AppThemeDark else R.style.AppThemeLight) + editor.apply() + } + + fun setFreshInstall() { + val editor = sharedPreferences.edit() + editor.putBoolean(_freshInstall, false) + editor.apply() + } + + fun saveSeasonYear(year: Int) { + val editor = sharedPreferences.edit() + editor.putInt(KeyUtil.arg_seasonYear, year) + editor.apply() + } + + + fun shouldShowTipFor(@KeyUtil.TapTargetType tipType: String): Boolean { + return sharedPreferences.getBoolean(tipType, true) + } + + fun disableTipFor(@KeyUtil.TapTargetType tipType: String) { + val editor = sharedPreferences.edit() + editor.putBoolean(tipType, false) + editor.apply() + } + + fun saveSortOrder(@KeyUtil.SortOrderType sortOrder: String) { + val editor = sharedPreferences.edit() + editor.putString(_sortOrder, sortOrder) + editor.apply() + } + + fun setUpdated() { + val editor = sharedPreferences.edit() + editor.putInt(_versionCode, BuildConfig.VERSION_CODE) + editor.apply() + } + + companion object { + + /** Application Base Options */ + const val _isLightTheme = "_isLightTheme" + const val _updateChannel = "_updateChannel" + + /** Api Keys */ + private const val _genreFilter = "_genreFilter" + private const val _tagFilter = "_tagFilter" + private const val _sortOrder = "_sortOrder" + private const val _mediaStatus = "_mediaStatus" + private const val _mediaFormat = "_mediaFormat" + private const val _animeFormat = "_animeFormat" + private const val _mangaFormat = "_mangaFormat" + private const val _mediaSource = "_mediaSource" + private const val _airingSort = "_airingSort" + private const val _characterSort = "_characterSort" + const val _mediaListSort = "_mediaListSort" + private const val _mediaSort = "_mediaSort" + private const val _mediaTrendSort = "_mediaTrendSort" + private const val _reviewSort = "_reviewSort" + private const val _staffSort = "_staffSort" + } +} diff --git a/app/src/main/java/com/mxt/anitrend/util/CenterSnapUtil.java b/app/src/main/java/com/mxt/anitrend/util/CenterSnapUtil.java deleted file mode 100644 index c0616f418..000000000 --- a/app/src/main/java/com/mxt/anitrend/util/CenterSnapUtil.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.mxt.anitrend.util; - -import android.support.annotation.NonNull; -import android.support.v7.widget.PagerSnapHelper; -import android.support.v7.widget.RecyclerView; -import android.view.View; - -import com.mxt.anitrend.base.interfaces.view.CustomView; - -/** - * Created by max on 2018/08/11. - */ - -public class CenterSnapUtil extends PagerSnapHelper implements CustomView { - - private PositionChangeListener positionChangeListener; - - public CenterSnapUtil(PositionChangeListener positionChangeListener) { - this.positionChangeListener = positionChangeListener; - } - - @Override - public int[] calculateDistanceToFinalSnap(@NonNull RecyclerView.LayoutManager layoutManager, @NonNull View targetView) { - return super.calculateDistanceToFinalSnap(layoutManager, targetView); - } - - @Override - public int findTargetSnapPosition(RecyclerView.LayoutManager layoutManager, int velocityX, int velocityY) { - int position = super.findTargetSnapPosition(layoutManager, velocityX, velocityY); - if(positionChangeListener != null && position != RecyclerView.NO_POSITION) - positionChangeListener.onPageChanged(position + 1); - return position; - } - - /** - * Optionally included when constructing custom views - */ - @Override - public void onInit() { - - } - - /** - * Clean up any resources that won't be needed - */ - @Override - public void onViewRecycled() { - positionChangeListener = null; - } - - public interface PositionChangeListener { - void onPageChanged(int currentPage); - } -} diff --git a/app/src/main/java/com/mxt/anitrend/util/CenterSnapUtil.kt b/app/src/main/java/com/mxt/anitrend/util/CenterSnapUtil.kt new file mode 100644 index 000000000..7f93b74d1 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/util/CenterSnapUtil.kt @@ -0,0 +1,43 @@ +package com.mxt.anitrend.util + +import android.support.v7.widget.PagerSnapHelper +import android.support.v7.widget.RecyclerView +import android.view.View + +import com.mxt.anitrend.base.interfaces.view.CustomView + +/** + * Created by max on 2018/08/11. + */ + +class CenterSnapUtil(private var positionChangeListener: PositionChangeListener?) : PagerSnapHelper(), CustomView { + + override fun calculateDistanceToFinalSnap(layoutManager: RecyclerView.LayoutManager, targetView: View): IntArray? { + return super.calculateDistanceToFinalSnap(layoutManager, targetView) + } + + override fun findTargetSnapPosition(layoutManager: RecyclerView.LayoutManager, velocityX: Int, velocityY: Int): Int { + val position = super.findTargetSnapPosition(layoutManager, velocityX, velocityY) + if (positionChangeListener != null && position != RecyclerView.NO_POSITION) + positionChangeListener!!.onPageChanged(position + 1) + return position + } + + /** + * Optionally included when constructing custom views + */ + override fun onInit() { + + } + + /** + * Clean up any resources that won't be needed + */ + override fun onViewRecycled() { + positionChangeListener = null + } + + interface PositionChangeListener { + fun onPageChanged(currentPage: Int) + } +} diff --git a/app/src/main/java/com/mxt/anitrend/util/ChartUtil.java b/app/src/main/java/com/mxt/anitrend/util/ChartUtil.java deleted file mode 100644 index 4e4edec23..000000000 --- a/app/src/main/java/com/mxt/anitrend/util/ChartUtil.java +++ /dev/null @@ -1,103 +0,0 @@ -package com.mxt.anitrend.util; - -import android.content.Context; - -import com.github.mikephil.charting.charts.BarLineChartBase; -import com.github.mikephil.charting.components.AxisBase; -import com.github.mikephil.charting.components.XAxis; -import com.github.mikephil.charting.components.YAxis; -import com.github.mikephil.charting.formatter.IAxisValueFormatter; -import com.mxt.anitrend.R; - -import java.util.List; - -/** - * Created by max on 2018/02/24. - */ - -public class ChartUtil { - - public static class StepXAxisFormatter implements IAxisValueFormatter { - - private List dataModel; - private BarLineChartBase chartBase; - - public StepXAxisFormatter setChartBase(BarLineChartBase chartBase) { - this.chartBase = chartBase; - return this; - } - - public StepXAxisFormatter setDataModel(List dataModel) { - this.dataModel = dataModel; - return this; - } - - /** - * Called when a value from an axis is to be formatted - * before being drawn. For performance reasons, avoid excessive calculations - * and memory allocations inside this method. - * - * @param value the value to be formatted - * @param axis the axis the value belongs to - * @return formatted label value - */ - @Override - public String getFormattedValue(float value, AxisBase axis) { - int index = (int) value; - K model = dataModel.get(index); - return String.valueOf(model); - } - - public void build(Context context) { - XAxis xAxis = chartBase.getXAxis(); - xAxis.setPosition(XAxis.XAxisPosition.BOTTOM); - xAxis.setDrawGridLines(false); - xAxis.setGranularity(1); - if(dataModel.size() <= 10) - xAxis.setLabelCount(dataModel.size()); - xAxis.setTextColor(CompatUtil.getColorFromAttr(context, R.attr.titleColor)); - xAxis.setValueFormatter(this); - } - } - - public static class StepYAxisFormatter implements IAxisValueFormatter { - - private BarLineChartBase chartBase; - - public StepYAxisFormatter setChartBase(BarLineChartBase chartBase) { - this.chartBase = chartBase; - return this; - } - - /** - * Called when a value from an axis is to be formatted - * before being drawn. For performance reasons, avoid excessive calculations - * and memory allocations inside this method. - * - * @param value the value to be formatted - * @param axis the axis the value belongs to - * @return formatted label value - */ - @Override - public String getFormattedValue(float value, AxisBase axis) { - int formatted = (int) value; - return String.valueOf(formatted); - } - - public void build(Context context) { - chartBase.getLegend().setTextColor(CompatUtil.getColorFromAttr(context, R.attr.titleColor)); - - YAxis leftAxis = chartBase.getAxisLeft(); - leftAxis.setLabelCount(5, false); - leftAxis.setSpaceTop(15f); - leftAxis.setAxisMinimum(0f); - leftAxis.disableGridDashedLine(); - leftAxis.disableAxisLineDashedLine(); - leftAxis.setPosition(YAxis.YAxisLabelPosition.OUTSIDE_CHART); - leftAxis.setTextColor(CompatUtil.getColorFromAttr(context, R.attr.titleColor)); - leftAxis.setValueFormatter(this); - - chartBase.getAxisRight().setEnabled(false); - } - } -} diff --git a/app/src/main/java/com/mxt/anitrend/util/ChartUtil.kt b/app/src/main/java/com/mxt/anitrend/util/ChartUtil.kt new file mode 100644 index 000000000..484b25995 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/util/ChartUtil.kt @@ -0,0 +1,99 @@ +package com.mxt.anitrend.util + +import android.content.Context + +import com.github.mikephil.charting.charts.BarLineChartBase +import com.github.mikephil.charting.components.AxisBase +import com.github.mikephil.charting.components.XAxis +import com.github.mikephil.charting.components.YAxis +import com.github.mikephil.charting.formatter.IAxisValueFormatter +import com.mxt.anitrend.R + +/** + * Created by max on 2018/02/24. + */ + +class ChartUtil { + + class StepXAxisFormatter : IAxisValueFormatter { + + private lateinit var dataModel: List + private lateinit var chartBase: BarLineChartBase<*> + + fun setChartBase(chartBase: BarLineChartBase<*>): StepXAxisFormatter<*> { + this.chartBase = chartBase + return this + } + + fun setDataModel(dataModel: List): StepXAxisFormatter { + this.dataModel = dataModel + return this + } + + /** + * Called when a value from an axis is to be formatted + * before being drawn. For performance reasons, avoid excessive calculations + * and memory allocations inside this method. + * + * @param value the value to be formatted + * @param axis the axis the value belongs to + * @return formatted label value + */ + override fun getFormattedValue(value: Float, axis: AxisBase): String { + val index = value.toInt() + val model = dataModel[index] + return model.toString() + } + + fun build(context: Context) { + val xAxis = chartBase.xAxis + xAxis.position = XAxis.XAxisPosition.BOTTOM + xAxis.setDrawGridLines(false) + xAxis.granularity = 1f + if (dataModel.size <= 10) + xAxis.labelCount = dataModel.size + xAxis.textColor = CompatUtil.getColorFromAttr(context, R.attr.titleColor) + xAxis.valueFormatter = this + } + } + + class StepYAxisFormatter : IAxisValueFormatter { + + private lateinit var chartBase: BarLineChartBase<*> + + fun setChartBase(chartBase: BarLineChartBase<*>): StepYAxisFormatter { + this.chartBase = chartBase + return this + } + + /** + * Called when a value from an axis is to be formatted + * before being drawn. For performance reasons, avoid excessive calculations + * and memory allocations inside this method. + * + * @param value the value to be formatted + * @param axis the axis the value belongs to + * @return formatted label value + */ + override fun getFormattedValue(value: Float, axis: AxisBase): String { + val formatted = value.toInt() + return formatted.toString() + } + + fun build(context: Context) { + chartBase.legend.textColor = CompatUtil.getColorFromAttr(context, R.attr.titleColor) + + val leftAxis = chartBase.axisLeft + leftAxis.setLabelCount(5, false) + leftAxis.spaceTop = 15f + leftAxis.axisMinimum = 0f + leftAxis.disableGridDashedLine() + leftAxis.disableAxisLineDashedLine() + leftAxis.setPosition(YAxis.YAxisLabelPosition.OUTSIDE_CHART) + leftAxis.textColor = CompatUtil.getColorFromAttr(context, R.attr.titleColor) + leftAxis.valueFormatter = this + + chartBase.axisRight.isEnabled = false + } + } +} diff --git a/app/src/main/java/com/mxt/anitrend/util/CompatUtil.java b/app/src/main/java/com/mxt/anitrend/util/CompatUtil.java deleted file mode 100644 index 0892cd6ee..000000000 --- a/app/src/main/java/com/mxt/anitrend/util/CompatUtil.java +++ /dev/null @@ -1,536 +0,0 @@ -package com.mxt.anitrend.util; - -import android.app.Activity; -import android.app.ActivityManager; -import android.content.Context; -import android.content.Intent; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.graphics.Point; -import android.graphics.drawable.Drawable; -import android.net.ConnectivityManager; -import android.net.NetworkInfo; -import android.support.annotation.ArrayRes; -import android.support.annotation.AttrRes; -import android.support.annotation.ColorInt; -import android.support.annotation.ColorRes; -import android.support.annotation.DrawableRes; -import android.support.annotation.Nullable; -import android.support.annotation.StringRes; -import android.support.annotation.StyleRes; -import android.support.v4.app.ActivityCompat; -import android.support.v4.app.ActivityManagerCompat; -import android.support.v4.app.ActivityOptionsCompat; -import android.support.v4.app.FragmentActivity; -import android.support.v4.content.ContextCompat; -import android.support.v4.graphics.drawable.DrawableCompat; -import android.support.v4.util.Pair; -import android.support.v4.view.ViewCompat; -import android.support.v7.content.res.AppCompatResources; -import android.text.TextUtils; -import android.util.DisplayMetrics; -import android.view.LayoutInflater; -import android.view.View; -import android.view.WindowManager; -import android.view.inputmethod.InputMethodManager; -import android.widget.Toast; - -import com.annimon.stream.IntPair; -import com.annimon.stream.Optional; -import com.annimon.stream.Stream; -import com.mxt.anitrend.R; -import com.mxt.anitrend.base.custom.view.container.CustomSwipeRefreshLayout; -import com.mxt.anitrend.model.entity.anilist.meta.ImageBase; -import com.mxt.anitrend.view.activity.base.ImagePreviewActivity; - -import java.io.File; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Objects; - -import okhttp3.Cache; - -/** - * Created by max on 2017/09/16. - * Utility class that contains helpful functions - */ -@SuppressWarnings("unused") -public class CompatUtil { - - private static final int CACHE_LIMIT = 1024 * 1024 * 250; - - public static void hideKeyboard(FragmentActivity activity) { - if(activity != null) { - InputMethodManager inputMethodManager = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE); - if (inputMethodManager != null) - inputMethodManager.hideSoftInputFromWindow(activity.getWindow().getDecorView().getWindowToken(), 0); - } - } - - public static boolean isOnline(Context context) { - ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); - NetworkInfo networkInfo = null; - if(connectivityManager != null) - networkInfo = connectivityManager.getActiveNetworkInfo(); - return networkInfo != null && networkInfo.isAvailable() && networkInfo.isConnected(); - } - - public static Cache cacheProvider(Context context) { - Cache cache = null; - try { - cache = new Cache(new File(context.getCacheDir(), "response-cache"), CACHE_LIMIT); - } catch (Exception e) { - e.printStackTrace(); - } - return cache; - } - - public static void imagePreview(FragmentActivity activity, View view, String imageUri, int errorMessage) { - if (imageUri != null && !imageUri.isEmpty()) { - Intent intent = new Intent(activity, ImagePreviewActivity.class); - intent.putExtra(KeyUtil.arg_model, imageUri); - CompatUtil.startSharedImageTransition(activity, view, intent, R.string.transition_image_preview); - } else { - NotifyUtil.makeText(activity, errorMessage, Toast.LENGTH_SHORT).show(); - } - } - - /** - * Avoids resource not found when using vector drawables in API levels < Lollipop - * - * @param resource The resource id of the drawable or vector drawable - * @see DrawableRes - * - * @param context Any valid application context - * @see Context - * - * @return Drawable - * @see Drawable - */ - public static Drawable getDrawable(Context context, @DrawableRes int resource) { - return AppCompatResources.getDrawable(context, resource); - } - - /** - * Avoids resource not found when using vector drawables in API levels < Lollipop - * and tints the drawable depending on the current selected theme, images loaded - * from this method apply the {@link Drawable#mutate()} to assure that the state - * of each drawable is not shared - * - * @param resource The resource id of the drawable or vector drawable - * @see DrawableRes - * - * @param context Any valid application context - * @see Context - * - * @return Drawable - * @see Drawable - */ - public static Drawable getTintedDrawable(Context context, @DrawableRes int resource) { - Drawable drawable = DrawableCompat.wrap(Objects.requireNonNull(AppCompatResources.getDrawable(context, resource))).mutate(); - DrawableCompat.setTint(drawable, getColorFromAttr(context, R.attr.titleColor)); - return drawable; - } - - /** - * Avoids resource not found when using vector drawables in API levels < Lollipop - * Also images loaded from this method apply the {@link Drawable#mutate()} to assure - * that the state of each drawable is not shared - * - * @param resource The resource id of the drawable or vector drawable - * @see DrawableRes - * - * @param context Any valid application context - * @see Context - * - * @param tint A specific color to tint the drawable - * - * @return Drawable - * @see Drawable - */ - public static Drawable getDrawable(Context context, @DrawableRes int resource, @ColorRes int tint) { - Drawable drawable = DrawableCompat.wrap(Objects.requireNonNull(AppCompatResources.getDrawable(context, resource))).mutate(); - if(tint != 0) - DrawableCompat.setTint(drawable, getColor(context, tint)); - return drawable; - } - - /** - * Avoids resource not found when using vector drawables in API levels < Lollipop - * Also images loaded from this method apply the {@link Drawable#mutate()} to assure - * that the state of each drawable is not shared - * - * @param resource The resource id of the drawable or vector drawable - * @see DrawableRes - * - * @param context Any valid application context - * @see Context - * - * @param attribute Type of attribute resource - * - * @return Drawable - * @see Drawable - */ - public static Drawable getDrawableTintAttr(Context context, @DrawableRes int resource, @AttrRes int attribute) { - Drawable drawable = DrawableCompat.wrap(Objects.requireNonNull(AppCompatResources.getDrawable(context, resource))).mutate(); - DrawableCompat.setTint(drawable, getColorFromAttr(context, attribute)); - return drawable; - } - - /** - * Returns a color from a defined attribute - * - * @param context Any valid application context - * @see Context - * - * @param attribute Type of attribute resource - * - * @return Color Integer - */ - public static @ColorInt int getColorFromAttr(Context context, @AttrRes int attribute) { - TypedArray colorAttribute = context.obtainStyledAttributes(new int[] {attribute}); - @ColorInt int color = colorAttribute.getColor(0, 0); - colorAttribute.recycle(); - return color; - } - - /** - * Get screen dimensions for the current device configuration - */ - public static void getScreenDimens(Point deviceDimens, Context context) { - WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); - if(windowManager != null) - windowManager.getDefaultDisplay().getSize(deviceDimens); - } - - /** - * Starts a shared transition of activities connected by views - *
- * - * @param base The calling activity - * @param target The view from the calling activity with transition name - * @param data Intent with bundle and or activity to start - */ - @Deprecated - public static void startSharedTransitionActivity(FragmentActivity base, View target, Intent data) { - /*Pair participants = new Pair<>(target, ViewCompat.getTransitionName(target)); - ActivityOptionsCompat transitionActivityOptions = ActivityOptionsCompat - .makeSceneTransitionAnimation(base, participants); - ActivityCompat.startActivity(base, data, transitionActivityOptions.toBundle());*/ - base.startActivity(data); - } - - /** - * Starts a shared transition of activities connected by views - * by making use of the provided transition name - *
- * - * @param base The calling activity - * @param target The view from the calling activity with transition name - * @param data Intent with bundle and or activity to start - */ - public static void startSharedImageTransition(@Nullable FragmentActivity base, View target, Intent data, @StringRes int transitionName) { - ViewCompat.setTransitionName(target, Objects.requireNonNull(base).getString(transitionName)); - ActivityOptionsCompat transition = ActivityOptionsCompat.makeSceneTransitionAnimation(base, target, ViewCompat.getTransitionName(target)); - base.startActivity(data, transition.toBundle()); - } - - /** - * Starts a reveal animation for a target view from an activity implementation - * - * @param activity Typically a fragment activity descendant - * @param target View which the reveal transition show be anchored to - * @param finish true to allow the calling activity to be finished - * @param data Intent data for the target activity to receive - */ - @Deprecated - public static void startRevealAnim(final FragmentActivity activity, View target, final Intent data, final boolean finish) { - activity.startActivity(data); - if (finish) - activity.finish(); - } - - /** - * Starts a reveal animation for a target view from an activity without - * closing the calling activity - * - * @param activity Typically a fragment activity descendant - * @param target View which the reveal transition show be anchored to - * @param data Intent data for the target activity to receive - */ - public static void startRevealAnim(FragmentActivity activity, View target, Intent data) { - startRevealAnim(activity, target, data, false); - } - - public static boolean isLightTheme(@StyleRes int theme) { - return theme == R.style.AppThemeLight; - } - - public static boolean isLightTheme(Context context) { - return new ApplicationPref(context).getTheme() == R.style.AppThemeLight; - } - - public static int dipToPx(float dpValue) { - final float scale = Resources.getSystem().getDisplayMetrics().density; - return (int) (dpValue * scale + 0.5f); - } - - public static int pxToDip(float pxValue) { - final float scale = Resources.getSystem().getDisplayMetrics().density; - return (int) (pxValue / scale + 0.5f); - } - - public static int spToPx(float spValue) { - float scaledDensity = Resources.getSystem().getDisplayMetrics().scaledDensity; - return Math.round(spValue * scaledDensity); - } - - /** - * Return true if the smallest width in DP of the device is equal or greater than the given - * value. - */ - public static boolean isScreenSw(int swDp) { - DisplayMetrics displayMetrics = Resources.getSystem().getDisplayMetrics(); - float widthDp = displayMetrics.widthPixels / displayMetrics.density; - float heightDp = displayMetrics.heightPixels / displayMetrics.density; - float screenSw = Math.min(widthDp, heightDp); - return screenSw >= swDp; - } - - /** - * Return true if the width in DP of the device is equal or greater than the given value - */ - public static boolean isScreenW(int widthDp) { - DisplayMetrics displayMetrics = Resources.getSystem().getDisplayMetrics(); - float screenWidth = displayMetrics.widthPixels / displayMetrics.density; - return screenWidth >= widthDp; - } - - public static int getColor(Context context, @ColorRes int color) { - return ContextCompat.getColor(context, color); - } - - public static LayoutInflater getLayoutInflater(Context context) { - return (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - } - - /** - * Credits - * @author hamakn - * https://gist.github.com/hamakn/8939eb68a920a6d7a498 - * */ - public static int getStatusBarHeight(Resources resources) { - int statusBarHeight = 0; - int resourceId = resources.getIdentifier("status_bar_height", "dimen", "android"); - if (resourceId > 0) - statusBarHeight = resources.getDimensionPixelSize(resourceId); - return statusBarHeight; - } - - /** - * Credits - * @author hamakn - * https://gist.github.com/hamakn/8939eb68a920a6d7a498 - * */ - public static int getActionBarHeight(FragmentActivity fragmentActivity) { - final TypedArray styledAttributes = fragmentActivity.getTheme().obtainStyledAttributes( - new int[] { android.R.attr.actionBarSize } - ); - styledAttributes.recycle(); - return (int) styledAttributes.getDimension(0, 0); - } - - - /** - * Credits - * @author hamakn - * https://gist.github.com/hamakn/8939eb68a920a6d7a498 - * */ - private static int getNavigationBarHeight(Resources resources) { - int navigationBarHeight = 0; - int resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android"); - if (resourceId > 0) - navigationBarHeight = resources.getDimensionPixelSize(resourceId); - return navigationBarHeight; - } - - /** - * Configure our swipe refresh layout - */ - public static void configureSwipeRefreshLayout(CustomSwipeRefreshLayout swipeRefreshLayout, FragmentActivity fragmentActivity) { - if(fragmentActivity != null) { - swipeRefreshLayout.setDragTriggerDistance(CustomSwipeRefreshLayout.DIRECTION_BOTTOM, (getNavigationBarHeight(fragmentActivity.getResources()) + dipToPx(16f))); - swipeRefreshLayout.setProgressBackgroundColorSchemeColor(getColorFromAttr(fragmentActivity, R.attr.rootColor)); - swipeRefreshLayout.setColorSchemeColors(getColorFromAttr(fragmentActivity, R.attr.contentColor)); - swipeRefreshLayout.setVisibility(View.GONE); - swipeRefreshLayout.setPermitRefresh(true); - swipeRefreshLayout.setPermitLoad(false); - } - } - - /** - * Get List from a given array res - * @return list of the array - */ - public static List getStringList(Context context, @ArrayRes int arrayRes) { - String[] array = context.getResources().getStringArray(arrayRes); - return constructListFrom(array); - } - - /** - * Get List from a given array type - * @return list of the array - */ - @SafeVarargs - public static List constructListFrom(T... array) { - return Arrays.asList(array); - } - - /** - * Gets the index of any type of collection guaranteed that an equals override for the class - * of type T is implemented. - * - * @param collection the child collection item to search - * @param target the item to search - * @return 0 if no result was found - */ - public static int getIndexOf(Collection collection, T target) { - if(collection != null && target != null) { - Optional> pairOptional = Stream.of(collection) - .findIndexed(((index, value) -> value != null && value.equals(target))); - if (pairOptional.isPresent()) - return pairOptional.get().getFirst(); - } - return 0; - } - - /** - * Gets the index of any type of collection guaranteed that an equals override for the class - * of type T is implemented. - * - * @param collection the child collection item to search - * @param target the item to search - * @return 0 if no result was found - */ - public static int getIndexOf(T[] collection, T target) { - if(collection != null && target != null) { - Optional> pairOptional = Stream.of(collection) - .findIndexed(((index, value) -> value != null && value.equals(target))); - if (pairOptional.isPresent()) - return pairOptional.get().getFirst(); - } - return 0; - } - - /** - * Gets the index of any type of collection guaranteed that an - * equals override for the class of type T is implemented. - *
- * @see Object#equals(Object) - * - * @param collection the child collection item to search - * @param target the item to search - * @return Optional result object - *
- * - * @see Optional for information on how to handle return - * @see IntPair - */ - public static Optional> findIndexOf(Collection collection, T target) { - if(!isEmpty(collection) && target != null) - return Stream.of(collection) - .findIndexed((index, value) -> value != null && value.equals(target)); - return Optional.empty(); - } - - /** - * Gets the index of any type of collection guaranteed that an - * equals override for the class of type T is implemented. - *
- * @see Object#equals(Object) - * - * @param collection the child collection item to search - * @param target the item to search - * @return Optional result object - *
- * - * @see Optional for information on how to handle return - * @see IntPair - */ - public static Optional> findIndexOf(T[] collection, T target) { - if(collection != null && target != null) - return Stream.of(collection) - .findIndexed((index, value) ->value != null && value.equals(target)); - return Optional.empty(); - } - - - /** - * Sorts a given map by the order of the of the keys in the map in descending order - * @see ComparatorUtil#getKeyComparator() for logic on how comparator handles this - */ - public static List> getKeyFilteredMap(Map map) { - return Stream.of(map).sorted(ComparatorUtil.getKeyComparator()).toList(); - } - - public static boolean isLowRamDevice(Context context) { - ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); - boolean isLowRamDevice = false; - if (activityManager != null) - isLowRamDevice = ActivityManagerCompat.isLowRamDevice(activityManager); - return isLowRamDevice; - } - - /** - * Capitalize words for text view consumption - */ - public static String capitalizeWords(String input) { - if(!TextUtils.isEmpty(input)) { - List exceptions = constructListFrom(KeyUtil.TV, KeyUtil.ONA, KeyUtil.OVA); - StringBuilder result = new StringBuilder(input.length()); - String[] words = input.split("_|\\s"); - int index = 0; - for (String word : words) { - if (!TextUtils.isEmpty(word)) { - if(exceptions.contains(word)) - result.append(word); - else { - char starting = Character.toUpperCase(word.charAt(0)); - result.append(starting).append(word.substring(1).toLowerCase()); - } - } - if (index != word.length() - 1) - result.append(" "); - index++; - } - return result.toString(); - } - return ""; - } - - /** - * Get a list from a given array of strings - * @return list of capitalized strings - */ - public static List capitalizeWords(String... strings) { - return Stream.of(strings) - .map(CompatUtil::capitalizeWords) - .toList(); - } - - public static boolean isEmpty(@Nullable T collection) { - return collection == null || collection.isEmpty(); - } - - public static int sizeOf(@Nullable T collection) { - if(isEmpty(collection)) - return 0; - return collection.size(); - } - - public static boolean equals(Object a, Object b) { - return (a != null && a.equals(b)); - } -} \ No newline at end of file diff --git a/app/src/main/java/com/mxt/anitrend/util/CompatUtil.kt b/app/src/main/java/com/mxt/anitrend/util/CompatUtil.kt new file mode 100644 index 000000000..f725a2be0 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/util/CompatUtil.kt @@ -0,0 +1,515 @@ +package com.mxt.anitrend.util + +import android.app.Activity +import android.app.ActivityManager +import android.content.Context +import android.content.Intent +import android.content.res.Resources +import android.graphics.Point +import android.graphics.drawable.Drawable +import android.net.ConnectivityManager +import android.net.NetworkInfo +import android.support.annotation.* +import android.support.v4.app.ActivityManagerCompat +import android.support.v4.app.ActivityOptionsCompat +import android.support.v4.app.FragmentActivity +import android.support.v4.content.ContextCompat +import android.support.v4.graphics.drawable.DrawableCompat +import android.support.v4.view.ViewCompat +import android.support.v7.content.res.AppCompatResources +import android.text.TextUtils +import android.view.LayoutInflater +import android.view.View +import android.view.WindowManager +import android.view.inputmethod.InputMethodManager +import android.widget.Toast +import com.annimon.stream.IntPair +import com.annimon.stream.Optional +import com.annimon.stream.Stream +import com.mxt.anitrend.R +import com.mxt.anitrend.base.custom.view.container.CustomSwipeRefreshLayout +import com.mxt.anitrend.view.activity.base.ImagePreviewActivity +import okhttp3.Cache +import java.io.File +import java.util.* + +/** + * Created by max on 2017/09/16. + * Utility class that contains helpful functions + */ +object CompatUtil { + + private const val CACHE_LIMIT = 1024 * 1024 * 250 + + fun hideKeyboard(activity: FragmentActivity?) { + val inputMethodManager = activity?.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager? + inputMethodManager?.hideSoftInputFromWindow(activity?.window?.decorView?.windowToken, 0) + } + + fun isOnline(context: Context?): Boolean { + val connectivityManager = context?.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager? + val networkInfo: NetworkInfo? = connectivityManager?.activeNetworkInfo + return networkInfo != null && networkInfo.isAvailable && networkInfo.isConnected + } + + fun cacheProvider(context: Context): Cache? { + var cache: Cache? = null + try { + cache = Cache(File(context.cacheDir, "response-cache"), CACHE_LIMIT.toLong()) + } catch (e: Exception) { + e.printStackTrace() + } + + return cache + } + + fun imagePreview(activity: FragmentActivity?, view: View, imageUri: String?, errorMessage: Int) { + if (!imageUri.isNullOrBlank()) { + val intent = Intent(activity, ImagePreviewActivity::class.java) + intent.putExtra(KeyUtil.arg_model, imageUri) + startSharedImageTransition(activity, view, intent, R.string.transition_image_preview) + } else { + NotifyUtil.makeText(activity, errorMessage, Toast.LENGTH_SHORT).show() + } + } + + /** + * Avoids resource not found when using vector drawables in API levels < Lollipop + * + * @param resource The resource id of the drawable or vector drawable + * @see DrawableRes + * + * + * @param context Any valid application context + * @see Context + * + * + * @return Drawable + * @see Drawable + */ + fun getDrawable(context: Context, @DrawableRes resource: Int): Drawable? { + return AppCompatResources.getDrawable(context, resource) + } + + /** + * Avoids resource not found when using vector drawables in API levels < Lollipop + * and tints the drawable depending on the current selected theme, images loaded + * from this method apply the [Drawable.mutate] to assure that the state + * of each drawable is not shared + * + * @param resource The resource id of the drawable or vector drawable + * @see DrawableRes + * + * + * @param context Any valid application context + * @see Context + * + * + * @return Drawable + * @see Drawable + */ + fun getTintedDrawable(context: Context, @DrawableRes resource: Int): Drawable { + val drawable = DrawableCompat.wrap(Objects.requireNonNull(AppCompatResources.getDrawable(context, resource))).mutate() + DrawableCompat.setTint(drawable, getColorFromAttr(context, R.attr.titleColor)) + return drawable + } + + /** + * Avoids resource not found when using vector drawables in API levels < Lollipop + * Also images loaded from this method apply the [Drawable.mutate] to assure + * that the state of each drawable is not shared + * + * @param resource The resource id of the drawable or vector drawable + * @see DrawableRes + * + * + * @param context Any valid application context + * @see Context + * + * + * @param tint A specific color to tint the drawable + * + * @return Drawable + * @see Drawable + */ + fun getDrawable(context: Context, @DrawableRes resource: Int, @ColorRes tint: Int): Drawable { + val drawable = DrawableCompat.wrap(Objects.requireNonNull(AppCompatResources.getDrawable(context, resource))).mutate() + if (tint != 0) + DrawableCompat.setTint(drawable, getColor(context, tint)) + return drawable + } + + /** + * Avoids resource not found when using vector drawables in API levels < Lollipop + * Also images loaded from this method apply the [Drawable.mutate] to assure + * that the state of each drawable is not shared + * + * @param resource The resource id of the drawable or vector drawable + * @see DrawableRes + * + * + * @param context Any valid application context + * @see Context + * + * + * @param attribute Type of attribute resource + * + * @return Drawable + * @see Drawable + */ + fun getDrawableTintAttr(context: Context, @DrawableRes resource: Int, @AttrRes attribute: Int): Drawable { + val drawable = DrawableCompat.wrap(Objects.requireNonNull(AppCompatResources.getDrawable(context, resource))).mutate() + DrawableCompat.setTint(drawable, getColorFromAttr(context, attribute)) + return drawable + } + + /** + * Returns a color from a defined attribute + * + * @param context Any valid application context + * @see Context + * + * + * @param attribute Type of attribute resource + * + * @return Color Integer + */ + @ColorInt + fun getColorFromAttr(context: Context, @AttrRes attribute: Int): Int { + val colorAttribute = context.obtainStyledAttributes(intArrayOf(attribute)) + @ColorInt val color = colorAttribute.getColor(0, 0) + colorAttribute.recycle() + return color + } + + /** + * Get screen dimensions for the current device configuration + */ + fun getScreenDimens(deviceDimens: Point, context: Context?) { + val windowManager = context?.getSystemService(Context.WINDOW_SERVICE) as WindowManager? + windowManager?.defaultDisplay?.getSize(deviceDimens) + } + + /** + * Starts a shared transition of activities connected by views + *

+ * + * @param base The calling activity + * @param target The view from the calling activity with transition name + * @param data Intent with bundle and or activity to start + */ + @Deprecated("") + fun startSharedTransitionActivity(base: FragmentActivity?, target: View, data: Intent) { + /*Pair participants = new Pair<>(target, ViewCompat.getTransitionName(target)); + ActivityOptionsCompat transitionActivityOptions = ActivityOptionsCompat + .makeSceneTransitionAnimation(base, participants); + ActivityCompat.startActivity(base, data, transitionActivityOptions.toBundle());*/ + base?.startActivity(data) + } + + /** + * Starts a shared transition of activities connected by views + * by making use of the provided transition name + *

+ * + * @param base The calling activity + * @param target The view from the calling activity with transition name + * @param data Intent with bundle and or activity to start + */ + fun startSharedImageTransition(base: FragmentActivity?, target: View, data: Intent, @StringRes transitionName: Int) { + ViewCompat.setTransitionName(target, Objects.requireNonNull(base).getString(transitionName)) + val transition = ActivityOptionsCompat.makeSceneTransitionAnimation(base!!, target, ViewCompat.getTransitionName(target)!!) + base.startActivity(data, transition.toBundle()) + } + + /** + * Starts a reveal animation for a target view from an activity implementation + * + * @param activity Typically a fragment activity descendant + * @param target View which the reveal transition show be anchored to + * @param finish true to allow the calling activity to be finished + * @param data Intent data for the target activity to receive + */ + @Deprecated("") + fun startRevealAnim(activity: FragmentActivity?, target: View, data: Intent, finish: Boolean) { + activity?.startActivity(data) + if (finish) + activity?.finish() + } + + /** + * Starts a reveal animation for a target view from an activity without + * closing the calling activity + * + * @param activity Typically a fragment activity descendant + * @param target View which the reveal transition show be anchored to + * @param data Intent data for the target activity to receive + */ + fun startRevealAnim(activity: FragmentActivity?, target: View, data: Intent) { + startRevealAnim(activity, target, data, false) + } + + fun isLightTheme(@StyleRes theme: Int): Boolean { + return theme == R.style.AppThemeLight + } + + fun isLightTheme(context: Context): Boolean { + return ApplicationPref(context).theme == R.style.AppThemeLight + } + + fun dipToPx(dpValue: Float): Int { + val scale = Resources.getSystem().displayMetrics.density + return (dpValue * scale + 0.5f).toInt() + } + + fun pxToDip(pxValue: Float): Int { + val scale = Resources.getSystem().displayMetrics.density + return (pxValue / scale + 0.5f).toInt() + } + + fun spToPx(spValue: Float): Int { + val scaledDensity = Resources.getSystem().displayMetrics.scaledDensity + return Math.round(spValue * scaledDensity) + } + + /** + * Return true if the smallest width in DP of the device is equal or greater than the given + * value. + */ + fun isScreenSw(swDp: Int): Boolean { + val displayMetrics = Resources.getSystem().displayMetrics + val widthDp = displayMetrics.widthPixels / displayMetrics.density + val heightDp = displayMetrics.heightPixels / displayMetrics.density + val screenSw = Math.min(widthDp, heightDp) + return screenSw >= swDp + } + + /** + * Return true if the width in DP of the device is equal or greater than the given value + */ + fun isScreenW(widthDp: Int): Boolean { + val displayMetrics = Resources.getSystem().displayMetrics + val screenWidth = displayMetrics.widthPixels / displayMetrics.density + return screenWidth >= widthDp + } + + fun getColor(context: Context, @ColorRes color: Int): Int { + return ContextCompat.getColor(context, color) + } + + fun getLayoutInflater(context: Context): LayoutInflater { + return context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater + } + + /** + * Credits + * @author hamakn + * https://gist.github.com/hamakn/8939eb68a920a6d7a498 + */ + fun getStatusBarHeight(resources: Resources): Int { + var statusBarHeight = 0 + val resourceId = resources.getIdentifier("status_bar_height", "dimen", "android") + if (resourceId > 0) + statusBarHeight = resources.getDimensionPixelSize(resourceId) + return statusBarHeight + } + + /** + * Credits + * @author hamakn + * https://gist.github.com/hamakn/8939eb68a920a6d7a498 + */ + fun getActionBarHeight(fragmentActivity: FragmentActivity?): Int? { + val styledAttributes = fragmentActivity?.theme?.obtainStyledAttributes( + intArrayOf(android.R.attr.actionBarSize) + ) + styledAttributes?.recycle() + return styledAttributes?.getDimension(0, 0f)?.toInt() + } + + + /** + * Credits + * @author hamakn + * https://gist.github.com/hamakn/8939eb68a920a6d7a498 + */ + private fun getNavigationBarHeight(resources: Resources): Int { + var navigationBarHeight = 0 + val resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android") + if (resourceId > 0) + navigationBarHeight = resources.getDimensionPixelSize(resourceId) + return navigationBarHeight + } + + /** + * Configure our swipe refresh layout + */ + fun configureSwipeRefreshLayout(swipeRefreshLayout: CustomSwipeRefreshLayout, fragmentActivity: FragmentActivity?) { + fragmentActivity?.also { + swipeRefreshLayout.setDragTriggerDistance(CustomSwipeRefreshLayout.DIRECTION_BOTTOM, getNavigationBarHeight(it.resources) + dipToPx(16f)) + swipeRefreshLayout.setProgressBackgroundColorSchemeColor(getColorFromAttr(it, R.attr.rootColor)) + swipeRefreshLayout.setColorSchemeColors(getColorFromAttr(it, R.attr.contentColor)) + swipeRefreshLayout.visibility = View.GONE + swipeRefreshLayout.setPermitRefresh(true) + swipeRefreshLayout.setPermitLoad(false) + } + } + + /** + * Get List from a given array res + * @return list of the array + */ + fun getStringList(context: Context?, @ArrayRes arrayRes: Int): List { + val array = context?.resources?.getStringArray(arrayRes) + if (array != null) + return constructListFrom(*array) + return Collections.emptyList() + } + + /** + * Get List from a given array type + * @return list of the array + */ + @SafeVarargs + fun constructListFrom(vararg array: T): List = + Arrays.asList(*array) + + + /** + * Gets the index of any type of collection guaranteed that an equals override for the class + * of type T is implemented. + * + * @param collection the child collection item to search + * @param target the item to search + * @return 0 if no result was found + */ + fun getIndexOf(collection: Collection?, target: T?): Int { + if (collection != null && target != null) { + val pairOptional = Stream.of(collection) + .findIndexed { _, value -> value != null && value == target } + if (pairOptional.isPresent) + return pairOptional.get().first + } + return 0 + } + + /** + * Gets the index of any type of collection guaranteed that an equals override for the class + * of type T is implemented. + * + * @param collection the child collection item to search + * @param target the item to search + * @return 0 if no result was found + */ + fun getIndexOf(collection: Array?, target: T?): Int { + if (collection != null && target != null) { + val pairOptional = Stream.of(*collection) + .findIndexed { _, value -> value != null && value == target } + if (pairOptional.isPresent) + return pairOptional.get().first + } + return 0 + } + + /** + * Gets the index of any type of collection guaranteed that an + * equals override for the class of type T is implemented. + *

+ * @see Object.equals + * @param collection the child collection item to search + * @param target the item to search + * @return Optional result object + *

+ * + * @see Optional for information on how to handle return + * + * @see IntPair + */ + fun findIndexOf(collection: Collection, target: T?): Optional> { + return if (!isEmpty(collection) && target != null) Stream.of(collection) + .findIndexed { _, value -> value != null && value == target } else Optional.empty() + } + + /** + * Gets the index of any type of collection guaranteed that an + * equals override for the class of type T is implemented. + *

+ * @see Object.equals + * @param collection the child collection item to search + * @param target the item to search + * @return Optional result object + *

+ * + * @see Optional for information on how to handle return + * + * @see IntPair + */ + fun findIndexOf(collection: Array?, target: T?): Optional> { + return if (collection != null && target != null) Stream.of(*collection) + .findIndexed { _, value -> value != null && value == target } + else Optional.empty() + } + + + /** + * Sorts a given map by the order of the of the keys in the map in descending order + * @see ComparatorUtil.getKeyComparator + */ + fun getKeyFilteredMap(map: Map): List> { + return Stream.of(map).sorted(ComparatorUtil.getKeyComparator()).toList() + } + + fun isLowRamDevice(context: Context?): Boolean { + val activityManager = context?.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager + return ActivityManagerCompat.isLowRamDevice(activityManager) + } + + /** + * Capitalize words for text view consumption + */ + fun capitalizeWords(input: String): String { + if (!TextUtils.isEmpty(input)) { + val exceptions = constructListFrom(KeyUtil.TV, KeyUtil.ONA, KeyUtil.OVA) + val result = StringBuilder(input.length) + val words = input.split("_|\\s".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() + var index = 0 + for (word in words) { + if (!TextUtils.isEmpty(word)) { + if (exceptions.contains(word)) + result.append(word) + else { + val starting = Character.toUpperCase(word[0]) + result.append(starting).append(word.substring(1).toLowerCase()) + } + } + if (index != word.length - 1) + result.append(" ") + index++ + } + return result.toString() + } + return "" + } + + /** + * Get a list from a given array of strings + * @return list of capitalized strings + */ + fun capitalizeWords(vararg strings: String): List { + return Stream.of(*strings) + .map { capitalizeWords(it) } + .toList() + } + + fun > isEmpty(collection: T?): Boolean { + return collection == null || collection.isEmpty() + } + + fun > sizeOf(collection: T?): Int { + return if (isEmpty(collection)) 0 else collection!!.size + } + + fun equals(a: Any?, b: Any): Boolean { + return a != null && a == b + } +} \ No newline at end of file diff --git a/app/src/main/java/com/mxt/anitrend/util/DateUtil.java b/app/src/main/java/com/mxt/anitrend/util/DateUtil.java deleted file mode 100644 index c5dd7b8e6..000000000 --- a/app/src/main/java/com/mxt/anitrend/util/DateUtil.java +++ /dev/null @@ -1,246 +0,0 @@ -package com.mxt.anitrend.util; - -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; - -import com.annimon.stream.Collectors; -import com.annimon.stream.IntStream; -import com.mxt.anitrend.model.entity.anilist.meta.AiringSchedule; -import com.mxt.anitrend.model.entity.anilist.meta.FuzzyDate; - -import org.ocpsoft.prettytime.PrettyTime; - -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.Date; -import java.util.GregorianCalendar; -import java.util.List; -import java.util.Locale; -import java.util.concurrent.TimeUnit; - -/** - * Created by max on 2017/06/09. - * Class to provide any calendar functionality - */ - -public class DateUtil { - - private static final String seasons[] = { - KeyUtil.WINTER, KeyUtil.WINTER, - KeyUtil.SPRING, KeyUtil.SPRING, KeyUtil.SPRING, - KeyUtil.SUMMER, KeyUtil.SUMMER, KeyUtil.SUMMER, - KeyUtil.FALL, KeyUtil.FALL, KeyUtil.FALL, - KeyUtil.WINTER - }; - - private static final String dateOutputFormat = "MMM dd, yyyy", dateInputFormat = "yyyy/MM/dd"; - - /** - * Gets current season title - *
- * - * @return Season name - */ - public static @KeyUtil.MediaSeason String getCurrentSeason() { - int month = Calendar.getInstance().get(Calendar.MONTH); - return seasons[month]; - } - - public static String getMediaSeason(FuzzyDate fuzzyDate){ - SimpleDateFormat format = new SimpleDateFormat(dateInputFormat,Locale.getDefault()); - try { - Date converted = format.parse(String.valueOf(fuzzyDate)); - Calendar calendar = new GregorianCalendar(Locale.getDefault()); - calendar.setTime(converted); - - return String.format(Locale.getDefault(),"%s %d", - CompatUtil.capitalizeWords(seasons[calendar.get(Calendar.MONTH)]), - calendar.get(Calendar.YEAR)); - - } catch (ParseException e) { - e.printStackTrace(); - } - return String.valueOf(fuzzyDate); - } - - /** - * Gets the current season title for menu - *
- * - * @return Season name - */ - public static int getMenuSelect() { - String value = seasons[Calendar.getInstance().get(Calendar.MONTH)]; - return CompatUtil.constructListFrom(KeyUtil.MediaSeason).indexOf(value); - } - - /** - * Gets the current year + delta, if the season for the year is winter later in the year - * then the result would be the current year plus the delta - *
- * - * @return current year with a given delta - */ - public static int getCurrentYear(int delta) { - if(Calendar.getInstance().get(Calendar.MONTH) >= 11 && getCurrentSeason().equals(KeyUtil.WINTER)) - return Calendar.getInstance().get(Calendar.YEAR) + delta; - return Calendar.getInstance().get(Calendar.YEAR) + delta; - } - - /** - * Converts unix time representation into current readable time - *
- * - * @return A time format of {@link DateUtil#dateOutputFormat} - */ - public static @Nullable String convertDate(long value) { - try { - if(value != 0) - return new SimpleDateFormat(dateOutputFormat, Locale.getDefault()).format(new Date(value*1000L)); - }catch (Exception ex) { - ex.printStackTrace(); - } - return null; - } - - /** - * Converts unix time representation into current readable time - *
- * - * @return A time format of {@link DateUtil#dateOutputFormat} - */ - public static @Nullable String convertDate(FuzzyDate fuzzyDate) { - try { - if(fuzzyDate != null && fuzzyDate.isValidDate()) { - SimpleDateFormat simpleDateFormat = new SimpleDateFormat(dateInputFormat, Locale.getDefault()); - Date converted = simpleDateFormat.parse(String.valueOf(fuzzyDate)); - return new SimpleDateFormat(dateOutputFormat,Locale.getDefault()).format(converted); - } - }catch (Exception ex) { - ex.printStackTrace(); - } - return "TBA"; - } - - /** - * Checks if the given data is newer than the current data on the device - */ - private static boolean isNewerDate(FuzzyDate fuzzyDate) throws ParseException { - SimpleDateFormat format = new SimpleDateFormat(dateInputFormat,Locale.getDefault()); - Date converted = format.parse(String.valueOf(fuzzyDate)); - return converted.getTime() > System.currentTimeMillis(); - } - - /** - * Returns appropriate title for ends or ended - *
- * @param fuzzyDate - fuzzy date - */ - public static String getEndTitle(FuzzyDate fuzzyDate) { - if(fuzzyDate == null || !fuzzyDate.isValidDate()) - return "Ends"; - - try { - return isNewerDate(fuzzyDate)? "Ends":"Ended"; - } catch (ParseException e) { - e.printStackTrace(); - } - return "Ends"; - } - - /** - * Returns appropriate title for starts or started - *
- * @param fuzzyDate - fuzzy date - */ - public static String getStartTitle(FuzzyDate fuzzyDate){ - if(fuzzyDate == null || !fuzzyDate.isValidDate()) - return "Starts"; - - try { - return isNewerDate(fuzzyDate)? "Starts":"Started"; - } catch (ParseException e) { - e.printStackTrace(); - } - return "Starts"; - } - - /** - * Formats the epotch time to a pretty data - *
- * @return string such as "EP 6 AiringSchedule in 2 hours" - * @param airingSchedule - the current airingSchedule object of a series - */ - public static @NonNull String getNextEpDate(@NonNull AiringSchedule airingSchedule){ - PrettyTime prettyTime = new PrettyTime(Locale.getDefault()); - String from_now = prettyTime.format(new Date(System.currentTimeMillis()+(airingSchedule.getTimeUntilAiring() * 1000L))); - return String.format(Locale.getDefault(), "EP %d: %s", airingSchedule.getEpisode(), from_now); - } - - /** - * Unix time stamps dates - *
- * @param date - a unix timestamp - */ - public static @NonNull String getPrettyDateUnix(long date) { - PrettyTime prettyTime = new PrettyTime(Locale.getDefault()); - return prettyTime.format(new Date(date * 1000L)); - } - - /** - * Creates a range of years from the given begin year to the end delta - * @param start Starting year - * @param endDelta End difference plus or minus the current year - */ - public static List getYearRanges(int start, int endDelta) { - return IntStream.rangeClosed(start, getCurrentYear(endDelta)) - .boxed().collect(Collectors.toList()); - } - - /** - * Returns the current month - */ - public static int getMonth() { - return Calendar.getInstance().get(Calendar.MONTH); - } - - /** - * Returns the current date - */ - public static int getDate() { - return Calendar.getInstance().get(Calendar.DATE); - } - - - /** - * Get the current fuzzy date - */ - public static @NonNull FuzzyDate getCurrentDate() { - Calendar calendar = Calendar.getInstance(); - return new FuzzyDate(calendar.get(Calendar.DAY_OF_MONTH), calendar.get(Calendar.MONTH) + 1, calendar.get(Calendar.YEAR)); - } - - /** - * Checks if the time given has a difference greater than or equal to the target time - *
- * @param conversionTarget type of comparison between the epoch time and target - * @param epochTime time to compare against the current system clock - * @param target unit to compare against - */ - public static boolean timeDifferenceSatisfied(@KeyUtil.TimeTargetType int conversionTarget, long epochTime, int target) { - long currentTime = System.currentTimeMillis(); - TimeUnit defaultSystemUnit = TimeUnit.MILLISECONDS; - switch (conversionTarget) { - case KeyUtil.TIME_UNIT_DAYS: - return defaultSystemUnit.toDays(currentTime - epochTime) >= target; - case KeyUtil.TIME_UNIT_HOURS: - return defaultSystemUnit.toHours(currentTime - epochTime) >= target; - case KeyUtil.TIME_UNIT_MINUTES: - return defaultSystemUnit.toMinutes(currentTime - epochTime) >= target; - case KeyUtil.TIME_UNITS_SECONDS: - return defaultSystemUnit.toSeconds(currentTime - epochTime) >= target; - } - return false; - } -} diff --git a/app/src/main/java/com/mxt/anitrend/util/DateUtil.kt b/app/src/main/java/com/mxt/anitrend/util/DateUtil.kt new file mode 100644 index 000000000..ec926bf89 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/util/DateUtil.kt @@ -0,0 +1,260 @@ +package com.mxt.anitrend.util + +import android.support.annotation.IntRange +import com.annimon.stream.Collectors +import com.annimon.stream.IntStream +import com.mxt.anitrend.model.entity.anilist.meta.AiringSchedule +import com.mxt.anitrend.model.entity.anilist.meta.FuzzyDate + +import org.ocpsoft.prettytime.PrettyTime + +import java.text.ParseException +import java.text.SimpleDateFormat +import java.util.Calendar +import java.util.Date +import java.util.GregorianCalendar +import java.util.Locale +import java.util.concurrent.TimeUnit + +/** + * Created by max on 2017/06/09. + * Class to provide any calendar functionality + */ + +object DateUtil { + + private val seasons by lazy { + arrayOf( + KeyUtil.WINTER, KeyUtil.WINTER, + KeyUtil.SPRING, KeyUtil.SPRING, KeyUtil.SPRING, + KeyUtil.SUMMER, KeyUtil.SUMMER, KeyUtil.SUMMER, + KeyUtil.FALL, KeyUtil.FALL, KeyUtil.FALL, + KeyUtil.WINTER + ) + } + + private const val dateOutputFormat = "MMM dd, yyyy" + private const val dateInputFormat = "yyyy/MM/dd" + + /** + * Gets current season title + *

+ * + * @return Season name + */ + val currentSeason: String + @KeyUtil.MediaSeason get() { + val month = Calendar.getInstance().get(Calendar.MONTH) + return seasons[month] + } + + /** + * Gets the current season title for menu + *

+ * + * @return Season name + */ + val menuSelect: Int + @IntRange(from = 0, to = 4) get() { + val season = seasons[Calendar.getInstance().get(Calendar.MONTH)] + return CompatUtil.constructListFrom(*KeyUtil.MediaSeason).indexOf(season) + } + + /** + * Returns the current month + */ + val month: Int + @IntRange(from = 0, to = 11) get() = + Calendar.getInstance().get(Calendar.MONTH) + + /** + * Returns the current date + */ + val date: Int + @IntRange(from = 0, to = 31) get() = + Calendar.getInstance().get(Calendar.DATE) + + /** + * Returns the current year + */ + val year: Int + get() = Calendar.getInstance().get(Calendar.YEAR) + + /** + * Get the current fuzzy date + */ + val currentDate: FuzzyDate + get() = FuzzyDate(date, month + 1, year) + + + fun getMediaSeason(fuzzyDate: FuzzyDate): String { + val format = SimpleDateFormat(dateInputFormat, Locale.getDefault()) + try { + val converted = format.parse(fuzzyDate.toString()) + val calendar = GregorianCalendar(Locale.getDefault()) + calendar.time = converted + + return String.format(Locale.getDefault(), "%s %d", + CompatUtil.capitalizeWords(seasons[calendar.get(Calendar.MONTH)]), + calendar.get(Calendar.YEAR)) + + } catch (e: ParseException) { + e.printStackTrace() + } + + return fuzzyDate.toString() + } + + /** + * Gets the current year + delta, if the season for the year is winter later in the year + * then the result would be the current year plus the delta + *

+ * + * @return current year with a given delta + */ + fun getCurrentYear(delta: Int = 0): Int { + return if (month >= 11 && currentSeason == KeyUtil.WINTER) + year + delta + else year + } + + /** + * Converts unix time representation into current readable time + *

+ * + * @return A time format of [DateUtil.dateOutputFormat] + */ + fun convertDate(value: Long): String? { + try { + if (value != 0L) + return SimpleDateFormat(dateOutputFormat, Locale.getDefault()).format(Date(value * 1000L)) + } catch (ex: Exception) { + ex.printStackTrace() + } + + return null + } + + /** + * Converts unix time representation into current readable time + *

+ * + * @return A time format of [DateUtil.dateOutputFormat] + */ + fun convertDate(fuzzyDate: FuzzyDate?): String? { + try { + if (fuzzyDate != null && fuzzyDate.isValidDate) { + val simpleDateFormat = SimpleDateFormat(dateInputFormat, Locale.getDefault()) + val converted = simpleDateFormat.parse(fuzzyDate.toString()) + return SimpleDateFormat(dateOutputFormat, Locale.getDefault()).format(converted) + } + } catch (ex: Exception) { + ex.printStackTrace() + } + + return "TBA" + } + + /** + * Checks if the given data is newer than the current data on the device + */ + @Throws(ParseException::class) + private fun isNewerDate(fuzzyDate: FuzzyDate): Boolean { + val format = SimpleDateFormat(dateInputFormat, Locale.getDefault()) + val converted = format.parse(fuzzyDate.toString()) + return converted.time > System.currentTimeMillis() + } + + /** + * Returns appropriate title for ends or ended + *

+ * @param fuzzyDate - fuzzy date + */ + fun getEndTitle(fuzzyDate: FuzzyDate?): String { + if (fuzzyDate == null || !fuzzyDate.isValidDate) + return "Ends" + + try { + return if (isNewerDate(fuzzyDate)) "Ends" else "Ended" + } catch (e: ParseException) { + e.printStackTrace() + } + + return "Ends" + } + + /** + * Returns appropriate title for starts or started + *

+ * @param fuzzyDate - fuzzy date + */ + fun getStartTitle(fuzzyDate: FuzzyDate?): String { + if (fuzzyDate == null || !fuzzyDate.isValidDate) + return "Starts" + + try { + return if (isNewerDate(fuzzyDate)) "Starts" else "Started" + } catch (e: ParseException) { + e.printStackTrace() + } + + return "Starts" + } + + /** + * Formats the epotch time to a pretty data + *

+ * @return string such as "EP 6 AiringSchedule in 2 hours" + * @param airingSchedule - the current airingSchedule object of a series + */ + fun getNextEpDate(airingSchedule: AiringSchedule): String { + val prettyTime = PrettyTime(Locale.getDefault()) + val fromNow = prettyTime.format(Date( + System.currentTimeMillis() + airingSchedule.timeUntilAiring * 1000L) + ) + return String.format(Locale.getDefault(), "EP %d: %s", airingSchedule.episode, fromNow) + } + + /** + * Unix time stamps dates + *

+ * @param date - a unix timestamp + */ + fun getPrettyDateUnix(date: Long): String { + val prettyTime = PrettyTime(Locale.getDefault()) + return prettyTime.format(Date(date * 1000L)) + } + + /** + * Creates a range of years from the given begin year to the end delta + * @param start Starting year + * @param endDelta End difference plus or minus the current year + */ + fun getYearRanges(start: Int, endDelta: Int): List { + return IntStream.rangeClosed(start, getCurrentYear(endDelta)) + .boxed().collect(Collectors.toList()) + } + + /** + * Checks if the time given has a difference greater than or equal to the target time + *

+ * @param conversionTarget type of comparison between the epoch time and target + * @param epochTime time to compare against the current system clock + * @param target unit to compare against + */ + fun timeDifferenceSatisfied(@KeyUtil.TimeTargetType conversionTarget: Int, epochTime: Long, target: Int): Boolean { + val currentTime = System.currentTimeMillis() + val defaultSystemUnit = TimeUnit.MILLISECONDS + when (conversionTarget) { + KeyUtil.TIME_UNIT_DAYS -> + return defaultSystemUnit.toDays(currentTime - epochTime) >= target + KeyUtil.TIME_UNIT_HOURS -> + return defaultSystemUnit.toHours(currentTime - epochTime) >= target + KeyUtil.TIME_UNIT_MINUTES -> + return defaultSystemUnit.toMinutes(currentTime - epochTime) >= target + KeyUtil.TIME_UNITS_SECONDS -> + return defaultSystemUnit.toSeconds(currentTime - epochTime) >= target + } + return false + } +} diff --git a/app/src/main/java/com/mxt/anitrend/util/DialogUtil.java b/app/src/main/java/com/mxt/anitrend/util/DialogUtil.java index 11372fe7d..ff5e0d7c8 100644 --- a/app/src/main/java/com/mxt/anitrend/util/DialogUtil.java +++ b/app/src/main/java/com/mxt/anitrend/util/DialogUtil.java @@ -157,7 +157,7 @@ public static void createMessage(Context context, @StringRes int title, @StringR createDefaultDialog(context).title(title) .positiveText(R.string.Ok) .negativeText(R.string.Cancel) - .icon(CompatUtil.getTintedDrawable(context, R.drawable.ic_new_releases_white_24dp)) + .icon(CompatUtil.INSTANCE.getTintedDrawable(context, R.drawable.ic_new_releases_white_24dp)) .content(new SpannedString(context.getString(content))) .autoDismiss(true).onAny(singleButtonCallback).show(); } @@ -165,7 +165,7 @@ public static void createMessage(Context context, @StringRes int title, @StringR public static void createMessage(Context context, String title, String content) { createDefaultDialog(context).title(title) .positiveText(R.string.Close) - .icon(CompatUtil.getTintedDrawable(context, R.drawable.ic_new_releases_white_24dp)) + .icon(CompatUtil.INSTANCE.getTintedDrawable(context, R.drawable.ic_new_releases_white_24dp)) .content(MarkDownUtil.INSTANCE.convert(content)) .autoDismiss(true).show(); } @@ -175,7 +175,7 @@ public static void createMessage(Context context, String title, String content, .positiveText(positive) .negativeText(negative) .neutralText(neutral) - .icon(CompatUtil.getTintedDrawable(context, R.drawable.ic_new_releases_white_24dp)) + .icon(CompatUtil.INSTANCE.getTintedDrawable(context, R.drawable.ic_new_releases_white_24dp)) .content(MarkDownUtil.INSTANCE.convert(content)) .autoDismiss(true).onAny(singleButtonCallback).show(); } @@ -184,7 +184,7 @@ public static void createMessage(Context context, String title, String content, createDefaultDialog(context).title(title) .positiveText(positive) .negativeText(negative) - .icon(CompatUtil.getTintedDrawable(context, R.drawable.ic_new_releases_white_24dp)) + .icon(CompatUtil.INSTANCE.getTintedDrawable(context, R.drawable.ic_new_releases_white_24dp)) .content(MarkDownUtil.INSTANCE.convert(content)) .autoDismiss(true).onAny(singleButtonCallback).show(); } @@ -193,12 +193,12 @@ public static void createTagMessage(Context context, String title, String conten MaterialDialog.Builder builder = createDefaultDialog(context).title(title) .positiveText(positive) .negativeText(negative) - .icon(CompatUtil.getTintedDrawable(context, R.drawable.ic_new_releases_white_24dp)) + .icon(CompatUtil.INSTANCE.getTintedDrawable(context, R.drawable.ic_new_releases_white_24dp)) .content(MarkDownUtil.INSTANCE.convert(content)) .autoDismiss(true).onAny(singleButtonCallback); - if (isSpoiler) builder.icon(CompatUtil.getDrawable(context, R.drawable.ic_spoiler_tag)); - else builder.icon(CompatUtil.getDrawable(context, R.drawable.ic_loyalty_white_24dp)); + if (isSpoiler) builder.icon(CompatUtil.INSTANCE.getDrawable(context, R.drawable.ic_spoiler_tag)); + else builder.icon(CompatUtil.INSTANCE.getDrawable(context, R.drawable.ic_loyalty_white_24dp)); builder.show(); } @@ -209,7 +209,7 @@ public static void createCheckList(Context context, @StringRes int title, Co .positiveText(R.string.Ok) .negativeText(R.string.Reset) .neutralText(R.string.Cancel) - .icon(CompatUtil.getTintedDrawable(context, R.drawable.ic_new_releases_white_24dp)) + .icon(CompatUtil.INSTANCE.getTintedDrawable(context, R.drawable.ic_new_releases_white_24dp)) .itemsCallbackMultiChoice(selectedIndices,listCallbackMultiChoice) .autoDismiss(true).onAny(singleButtonCallback).show(); } @@ -252,6 +252,6 @@ static MaterialDialog.Builder createDefaultDialog(Context context) { .positiveColorRes(R.color.colorStateGreen) .negativeColorRes(R.color.colorStateOrange) .neutralColorRes(R.color.colorStateBlue) - .theme(CompatUtil.isLightTheme(context)?Theme.LIGHT:Theme.DARK); + .theme(CompatUtil.INSTANCE.isLightTheme(context)?Theme.LIGHT:Theme.DARK); } } diff --git a/app/src/main/java/com/mxt/anitrend/util/EpisodeUtil.java b/app/src/main/java/com/mxt/anitrend/util/EpisodeUtil.java deleted file mode 100644 index 2731f28f0..000000000 --- a/app/src/main/java/com/mxt/anitrend/util/EpisodeUtil.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.mxt.anitrend.util; - -import com.mxt.anitrend.model.entity.anilist.ExternalLink; - -import java.util.List; - -/** - * Created by max on 2017/11/04. - * Episode list helper that check for crunchy feeds - */ - -public class EpisodeUtil { - - private static final String crunchyStandard = "crunchyroll", feedStandard = "feedburner"; - - public static String episodeSupport(List links) { - for (ExternalLink link : links) - if(link.getUrl().contains(crunchyStandard)) - return linkStripper(link.getUrl()); - else if(link.getUrl().contains(feedStandard)) - return link.getUrl(); - return null; - } - - private static String linkStripper(String link) { - int lastIndex = link.lastIndexOf("/") + 1; - String stripped = link.substring(lastIndex); - return String.format("%s.rss", stripped); - } - - /** - * Gets the series title without description - */ - public static String getActualTile(String episodeTitle) { - return episodeTitle.replaceAll("((.- Episode)|(.Season)).*", ""); - } -} diff --git a/app/src/main/java/com/mxt/anitrend/util/EpisodeUtil.kt b/app/src/main/java/com/mxt/anitrend/util/EpisodeUtil.kt new file mode 100644 index 000000000..02d4c4b7c --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/util/EpisodeUtil.kt @@ -0,0 +1,36 @@ +package com.mxt.anitrend.util + +import com.mxt.anitrend.model.entity.anilist.ExternalLink + +/** + * Created by max on 2017/11/04. + * Episode list helper that check for crunchy feeds + */ + +object EpisodeUtil { + + private const val crunchyStandard = "crunchyroll" + private const val feedStandard = "feedburner" + + fun episodeSupport(links: List): String? { + for (link in links) + if (link.url.contains(crunchyStandard)) + return linkStripper(link.url) + else if (link.url.contains(feedStandard)) + return link.url + return null + } + + private fun linkStripper(link: String): String { + val lastIndex = link.lastIndexOf("/") + 1 + val stripped = link.substring(lastIndex) + return String.format("%s.rss", stripped) + } + + /** + * Gets the series title without description + */ + fun getActualTile(episodeTitle: String): String { + return episodeTitle.replace("((.- Episode)|(.Season)).*".toRegex(), "") + } +} diff --git a/app/src/main/java/com/mxt/anitrend/util/ErrorUtil.java b/app/src/main/java/com/mxt/anitrend/util/ErrorUtil.java deleted file mode 100644 index 3646b317c..000000000 --- a/app/src/main/java/com/mxt/anitrend/util/ErrorUtil.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.mxt.anitrend.util; - -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.text.TextUtils; -import android.util.Log; - -import com.google.gson.reflect.TypeToken; -import com.mxt.anitrend.model.api.retro.WebFactory; -import com.mxt.anitrend.model.entity.container.attribute.GraphError; -import com.mxt.anitrend.model.entity.container.body.GraphContainer; - -import java.lang.reflect.Type; -import java.util.List; - -import okhttp3.Headers; -import okhttp3.ResponseBody; -import retrofit2.Response; - -/** - * Created by max on 2017/06/15. - * ResponseError utility class - */ - -public class ErrorUtil { - - private static final int HTTP_LIMIT_REACHED = 429; - - private static final String TAG = "ErrorUtil"; - private static final String Retry_After = "Retry-After"; - private static final String RateLimit_Limit = "X-RateLimit-Limit"; - private static final String RateLimit_Remaining = "X-RateLimit-Remaining"; - - /** - * Converts the response error response into an object. - * - * @return The error object, or null if an exception was encountered - * @see Error - */ - public static @NonNull String getError(@Nullable Response response) { - try { - if(response != null) { - Headers headers = response.headers(); - ResponseBody responseBody = response.errorBody(); - String message, error; - if (response.code() != HTTP_LIMIT_REACHED) { - if (responseBody != null && !TextUtils.isEmpty(message = responseBody.string())) - if (!TextUtils.isEmpty(error = getGraphQLError(message))) - return error; - } else { - error = String.format("%s of %s requests remaining, please retry after %s seconds", - headers.get(RateLimit_Remaining), headers.get(RateLimit_Limit), headers.get(Retry_After)); - return error; - } - } - } catch (Exception ex) { - ex.printStackTrace(); - return "Unexpected error encountered"; - } - return "Unable to provide information regarding error!"; - } - - private static @Nullable String getGraphQLError(String errorJson) { - Log.e(TAG, errorJson); - Type tokenType = new TypeToken>(){}.getType(); - GraphContainer graphContainer = WebFactory.gson.fromJson(errorJson, tokenType); - List errors = graphContainer.getErrors(); - if (!CompatUtil.isEmpty(errors)) { - StringBuilder builder = new StringBuilder(); - for (GraphError error : errors) - builder.append(error.toString()); - return builder.toString(); - } - return null; - } -} diff --git a/app/src/main/java/com/mxt/anitrend/util/ErrorUtil.kt b/app/src/main/java/com/mxt/anitrend/util/ErrorUtil.kt new file mode 100644 index 000000000..2cc74fb45 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/util/ErrorUtil.kt @@ -0,0 +1,69 @@ +package com.mxt.anitrend.util + +import android.util.Log +import com.google.gson.reflect.TypeToken +import com.mxt.anitrend.model.api.retro.WebFactory +import com.mxt.anitrend.model.entity.container.body.GraphContainer +import retrofit2.Response + +/** + * Created by max on 2017/06/15. + * ResponseError utility class + */ + +object ErrorUtil { + + private const val HTTP_LIMIT_REACHED = 429 + + private const val TAG = "ErrorUtil" + private const val Retry_After = "Retry-After" + private const val RateLimit_Limit = "X-RateLimit-Limit" + private const val RateLimit_Remaining = "X-RateLimit-Remaining" + + /** + * Converts the response error response into an object. + * + * @return The error object, or null if an exception was encountered + * @see Error + */ + fun getError(response: Response<*>?): String { + try { + if (response != null) { + val headers = response.headers() + val responseBody = response.errorBody() + val message = responseBody?.string() + var error = getGraphQLError(message) + if (response.code() != HTTP_LIMIT_REACHED) { + if (responseBody != null && !message.isNullOrBlank()) + if (!error.isNullOrBlank()) + return error + } else { + error = String.format("%s of %s requests remaining, please retry after %s seconds", + headers.get(RateLimit_Remaining), headers.get(RateLimit_Limit), headers.get(Retry_After)) + return error + } + } + } catch (ex: Exception) { + ex.printStackTrace() + return "Unexpected error encountered" + } + + return "Unable to provide information regarding error!" + } + + private fun getGraphQLError(errorJson: String?): String? { + return errorJson?.let { + Log.e(TAG, it) + val tokenType = object : TypeToken>() {}.type + val graphContainer = WebFactory.gson.fromJson>(it, tokenType) + val errors = graphContainer.errors + if (!CompatUtil.isEmpty(errors)) { + val builder = StringBuilder() + for (error in errors) + builder.append(error.toString()) + return@let builder.toString() + } + null + } + } +} diff --git a/app/src/main/java/com/mxt/anitrend/util/GraphUtil.java b/app/src/main/java/com/mxt/anitrend/util/GraphUtil.java deleted file mode 100644 index 1d83e7871..000000000 --- a/app/src/main/java/com/mxt/anitrend/util/GraphUtil.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.mxt.anitrend.util; - -import android.text.TextUtils; - -import com.annimon.stream.Stream; -import com.mxt.anitrend.model.entity.anilist.FeedList; -import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder; -import com.mxt.anitrend.presenter.base.BasePresenter; - -import java.util.List; - -/** - * Created by max on 2018/03/22. - * Graph request helper class - */ - -public class GraphUtil { - - /** - * Builder provider helper method, that provides a default GraphQL Query and Variable Builder - * @param includePaging if one of the variables should container a page limit - */ - public static QueryContainerBuilder getDefaultQuery(boolean includePaging) { - QueryContainerBuilder queryContainer = new QueryContainerBuilder(); - if(includePaging) - queryContainer.putVariable(KeyUtil.arg_page_limit, KeyUtil.PAGING_LIMIT); - return queryContainer; - } - - /** - * Constructs an array from multiple arguments, usually for soring of items - */ - public static String[] getMultipleParams(String... params) { - return params; - } - - - /** - * Used to check if the newly applied preference key is a should trigger an application refresh - */ - public static boolean isKeyFilter(String preferenceKey) { - return !CompatUtil.equals(preferenceKey, ApplicationPref._isLightTheme) && - !CompatUtil.equals(preferenceKey, ApplicationPref._updateChannel); - } - - /** - * Remove empty json object responses, to resolve undefined content errors - */ - public static List filterFeedList(BasePresenter presenter, List feedLists) { - List filteredList = Stream.of(feedLists) - .filter(f -> f != null && !TextUtils.isEmpty(f.getType())) - .toList(); - if(presenter.getPageInfo() != null) - presenter.getPageInfo().setPerPage(filteredList.size()); - return filteredList; - } -} diff --git a/app/src/main/java/com/mxt/anitrend/util/GraphUtil.kt b/app/src/main/java/com/mxt/anitrend/util/GraphUtil.kt new file mode 100644 index 000000000..92afcf6e0 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/util/GraphUtil.kt @@ -0,0 +1,59 @@ +package com.mxt.anitrend.util + +import android.text.TextUtils + +import com.annimon.stream.Stream +import com.mxt.anitrend.model.entity.anilist.FeedList +import com.mxt.anitrend.model.entity.anilist.Notification +import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder +import com.mxt.anitrend.presenter.base.BasePresenter + +/** + * Created by max on 2018/03/22. + * Graph request helper class + */ + +object GraphUtil { + + /** + * Builder provider helper method, that provides a default GraphQL Query and Variable Builder + * @param includePaging if one of the variables should container a page limit + */ + fun getDefaultQuery(includePaging: Boolean): QueryContainerBuilder { + val queryContainer = QueryContainerBuilder() + if (includePaging) + queryContainer.putVariable(KeyUtil.arg_page_limit, KeyUtil.PAGING_LIMIT) + return queryContainer + } + + /** + * Used to check if the newly applied preference key is a should trigger an application refresh + */ + fun isKeyFilter(preferenceKey: String): Boolean { + return !CompatUtil.equals(preferenceKey, ApplicationPref._isLightTheme) && !CompatUtil.equals(preferenceKey, ApplicationPref._updateChannel) + } + + /** + * Remove empty json object responses, to resolve undefined content errors + */ + fun filterFeedList(presenter: BasePresenter, feedLists: List): List { + val filteredList = Stream.of(feedLists) + .filter { f -> f != null && !TextUtils.isEmpty(f.type) } + .toList() + if (presenter.pageInfo != null) + presenter.pageInfo!!.perPage = filteredList.size + return filteredList + } + + /** + * Remove empty json object responses, to resolve undefined content errors + */ + fun filterNotificationList(presenter: BasePresenter, notifications: List): List { + val filteredList = Stream.of(notifications) + .filter { f -> f != null && f.activityId != 0L } + .toList() + if (presenter.pageInfo != null) + presenter.pageInfo!!.perPage = filteredList.size + return filteredList + } +} diff --git a/app/src/main/java/com/mxt/anitrend/util/GroupingUtil.java b/app/src/main/java/com/mxt/anitrend/util/GroupingUtil.java deleted file mode 100644 index 17e028ea5..000000000 --- a/app/src/main/java/com/mxt/anitrend/util/GroupingUtil.java +++ /dev/null @@ -1,226 +0,0 @@ -package com.mxt.anitrend.util; - -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.text.TextUtils; - -import com.annimon.stream.Collectors; -import com.annimon.stream.Stream; -import com.mxt.anitrend.model.entity.anilist.edge.CharacterEdge; -import com.mxt.anitrend.model.entity.anilist.edge.MediaEdge; -import com.mxt.anitrend.model.entity.anilist.edge.StaffEdge; -import com.mxt.anitrend.model.entity.base.MediaBase; -import com.mxt.anitrend.model.entity.base.StaffBase; -import com.mxt.anitrend.model.entity.container.body.EdgeContainer; -import com.mxt.anitrend.model.entity.group.RecyclerHeaderItem; -import com.mxt.anitrend.model.entity.group.RecyclerItem; -import com.mxt.anitrend.view.fragment.group.CharacterActorsFragment; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -/** - * Created by max on 2018/02/18. - * Utils for group various types of media - */ - -public class GroupingUtil { - - /** - * Groups media by the media format, assuming that the media has be sorted by format - * @see KeyUtil.MediaFormat - *
- * - * Only to be used when the sort type is @{@link KeyUtil.MediaSort#FORMAT} - * which is the default sort type for the request @{@link KeyUtil#STAFF_MEDIA_REQ} - *
- * - * @param edges The potential external model response which needs to be grouped - * @param model The current model item/s containing all data minus current mediaItems - */ - public static List groupMediaByFormat(@NonNull List edges, @Nullable List model) { - List entityMap = !CompatUtil.isEmpty(model) ? new ArrayList<>(model) : new ArrayList<>(); - - Map> map = Stream.of(edges) - .filter(value -> !TextUtils.isEmpty(value.getFormat())) - .collect(Collectors.groupingBy(MediaBase::getFormat)); - - for (Map.Entry> entry: CompatUtil.getKeyFilteredMap(map)) { - RecyclerHeaderItem recyclerHeaderItem = new RecyclerHeaderItem(entry.getKey(), entry.getValue().size()); - if(!entityMap.contains(recyclerHeaderItem)) - entityMap.add(recyclerHeaderItem); - entityMap.addAll(entry.getValue()); - } - return getDifference(model, entityMap); - } - - /** - * Groups media by the media format, assuming that the media has be sorted by language - * @see KeyUtil.StaffSort - *
- * - * Only to be used when the sort type is @{@link KeyUtil.StaffSort#LANGUAGE} - * which is the default sort type for the request @{@link KeyUtil#STAFF_MEDIA_REQ} - *
- * - * @param edges The potential external model response which needs to be grouped - * @param model The current model item/s containing all data minus current mediaItems - */ - public static List groupStaffByLanguage(@NonNull List edges, @Nullable List model) { - List entityMap = !CompatUtil.isEmpty(model) ? new ArrayList<>(model) : new ArrayList<>(); - - Map> map = Stream.of(edges) - .filter(value -> !TextUtils.isEmpty(value.getLanguage())) - .collect(Collectors.groupingBy(StaffBase::getLanguage)); - - for (Map.Entry> entry: CompatUtil.getKeyFilteredMap(map)) { - RecyclerHeaderItem recyclerHeaderItem = new RecyclerHeaderItem(entry.getKey(), entry.getValue().size()); - if(!entityMap.contains(recyclerHeaderItem)) { - entityMap.add(recyclerHeaderItem); - } - entityMap.addAll(entry.getValue()); - } - return getDifference(model, entityMap); - } - - /** - * Groups edge container items their media/node and the character role - * N.B. In this use case the main model is not used to check for existence - * of a given role because the voiceActors and characterRoles are grouped by media - *
- * - * @see CharacterActorsFragment restricted and should only be used by this - * @see EdgeContainer - *
- * - * @param edges The potential external model response which needs to be grouped - */ - public static List groupActorMediaEdge(List edges) { - List entityMap = new ArrayList<>(); - for (MediaEdge edge : edges) { - if(edge.getNode() != null) { - if(!TextUtils.isEmpty(edge.getCharacterRole())) - edge.getNode().setSubGroupTitle(edge.getCharacterRole()); - edge.getNode().setContentType(KeyUtil.RECYCLER_TYPE_HEADER); - entityMap.add(edge.getNode()); - } - if(!CompatUtil.isEmpty(edge.getVoiceActors())) - entityMap.addAll(edge.getVoiceActors()); - } - return entityMap; - } - - /** - * Groups edge container items their media/node and the media relation type - * @see MediaEdge - *
- * - * @param edges The potential external model response which needs to be grouped - */ - public static List groupMediaByRelationType(List edges) { - List entityMap = new ArrayList<>(); - for (MediaEdge edge: edges) { - RecyclerHeaderItem recyclerHeaderItem = new RecyclerHeaderItem(edge.getRelationType()); - if(!entityMap.contains(recyclerHeaderItem)) { - long totalItems = Stream.of(edges).map(MediaEdge::getRelationType) - .filter(role -> CompatUtil.equals(role, edge.getRelationType())) - .count(); - recyclerHeaderItem.setSize((int) totalItems); - entityMap.add(recyclerHeaderItem); - } - entityMap.add(edge.getNode()); - } - return entityMap; - } - /** - * Groups characters by role, assuming that the characters have been sorted by format - * @see KeyUtil.CharacterRole - *
- * - * Only to be used when the sort type is @{@link KeyUtil.CharacterSort#ROLE} - * which is the default sort type for the request @{@link KeyUtil#CHARACTER_ACTORS_REQ} - *
- * - * @param edges The potential external model response which needs to be grouped - * @param model The current model item/s containing all data minus current mediaItems - */ - public static List groupCharactersByRole(List edges, @Nullable List model) { - List entityMap = !CompatUtil.isEmpty(model) ? new ArrayList<>(model) : new ArrayList<>(); - for (CharacterEdge edge: edges) { - RecyclerHeaderItem recyclerHeaderItem = new RecyclerHeaderItem(edge.getRole()); - if(!entityMap.contains(recyclerHeaderItem)) { - long totalItems = Stream.of(edges).map(CharacterEdge::getRole) - .filter(role -> CompatUtil.equals(role, edge.getRole())) - .count(); - recyclerHeaderItem.setSize((int) totalItems); - entityMap.add(recyclerHeaderItem); - } - entityMap.add(edge.getNode()); - } - return getDifference(model, entityMap); - } - - /** - * Groups media by the staff role, assuming that the staff has be sorted by role - *
- * - * @param edges The potential external model response which needs to be grouped - * @param model The current model item/s containing all data minus current mediaItems - */ - public static List groupStaffByRole(List edges, @Nullable List model) { - List entityMap = !CompatUtil.isEmpty(model) ? new ArrayList<>(model) : new ArrayList<>(); - for (StaffEdge edge: edges) { - RecyclerHeaderItem recyclerHeaderItem = new RecyclerHeaderItem(edge.getRole()); - if(!entityMap.contains(recyclerHeaderItem)) { - long totalItems = Stream.of(edges).map(StaffEdge::getRole) - .filter(role -> CompatUtil.equals(role, edge.getRole())) - .count(); - recyclerHeaderItem.setSize((int) totalItems); - entityMap.add(recyclerHeaderItem); - } - entityMap.add(edge.getNode()); - } - return getDifference(model, entityMap); - } - - /** - * Groups media by the staff role, assuming that the staff items have be sorted by format - *
- * - * @param edges The potential external model response which needs to be grouped - * @param model The current model item/s containing all data minus current mediaItems - */ - public static List groupMediaByStaffRole(List edges, @Nullable List model) { - List entityMap = !CompatUtil.isEmpty(model) ? new ArrayList<>(model) : new ArrayList<>(); - for (MediaEdge edge: edges) { - RecyclerHeaderItem recyclerHeaderItem = new RecyclerHeaderItem(edge.getStaffRole()); - if(!entityMap.contains(recyclerHeaderItem)) { - long totalItems = Stream.of(edges).map(MediaEdge::getStaffRole) - .filter(role -> CompatUtil.equals(role, edge.getStaffRole())) - .count(); - recyclerHeaderItem.setSize((int) totalItems); - entityMap.add(recyclerHeaderItem); - } - entityMap.add(edge.getNode()); - } - return getDifference(model, entityMap); - } - - /** - * Returns only new items that were not previously added to the list - *
- * - * @param model Existing items thus far from a paginated result set - * @param recyclerItems Model that holds all grouped items including previously stored results - */ - private static List getDifference(@Nullable List model, List recyclerItems) { - if(!CompatUtil.isEmpty(model)) - return recyclerItems.subList(model.size(), recyclerItems.size()); - return recyclerItems; - } - - public static List wrapInGroup(List data) { - return new ArrayList<>(data); - } -} diff --git a/app/src/main/java/com/mxt/anitrend/util/GroupingUtil.kt b/app/src/main/java/com/mxt/anitrend/util/GroupingUtil.kt new file mode 100644 index 000000000..9d7771ed6 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/util/GroupingUtil.kt @@ -0,0 +1,232 @@ +package com.mxt.anitrend.util + +import android.text.TextUtils + +import com.annimon.stream.Collectors +import com.annimon.stream.Stream +import com.annimon.stream.function.Function +import com.mxt.anitrend.model.entity.anilist.edge.CharacterEdge +import com.mxt.anitrend.model.entity.anilist.edge.MediaEdge +import com.mxt.anitrend.model.entity.anilist.edge.StaffEdge +import com.mxt.anitrend.model.entity.base.MediaBase +import com.mxt.anitrend.model.entity.base.StaffBase +import com.mxt.anitrend.model.entity.container.body.EdgeContainer +import com.mxt.anitrend.model.entity.group.RecyclerHeaderItem +import com.mxt.anitrend.model.entity.group.RecyclerItem +import com.mxt.anitrend.view.fragment.group.CharacterActorsFragment + +import java.util.ArrayList + +/** + * Created by max on 2018/02/18. + * Utils for group various types of media + */ + +object GroupingUtil { + + /** + * Groups media by the media format, assuming that the media has be sorted by format + * @see KeyUtil.MediaFormat + *

+ * + * Only to be used when the sort type is @{@link KeyUtil.MediaSort.FORMAT} + * which is the default sort type for the request @{@link KeyUtil.STAFF_MEDIA_REQ} + *

+ * + * + * @param edges The potential external model response which needs to be grouped + * @param model The current model item/s containing all data minus current mediaItems + */ + fun groupMediaByFormat(edges: List, model: List?): List { + val entityMap = if (!CompatUtil.isEmpty(model)) ArrayList(model!!) else ArrayList() + + val map = edges.filter { + !it.format.isNullOrBlank() + }.groupBy { + it.format + } + + for ((key, value) in CompatUtil.getKeyFilteredMap(map)) { + val recyclerHeaderItem = RecyclerHeaderItem(key, value.size) + if (!entityMap.contains(recyclerHeaderItem)) + entityMap.add(recyclerHeaderItem) + entityMap.addAll(value) + } + return getDifference(model, entityMap) + } + + /** + * Groups media by the media format, assuming that the media has be sorted by language + * @see KeyUtil.StaffSort + *

+ * + * Only to be used when the sort type is @{@link KeyUtil.StaffSort.LANGUAGE} + * which is the default sort type for the request @{@link KeyUtil.STAFF_MEDIA_REQ} + *

+ * + * + * @param edges The potential external model response which needs to be grouped + * @param model The current model item/s containing all data minus current mediaItems + */ + fun groupStaffByLanguage(edges: List, model: List?): List { + val entityMap = if (!CompatUtil.isEmpty(model)) ArrayList(model!!) else ArrayList() + + val map = edges.filter { + !it.language.isNullOrBlank() + }.groupBy { + it.language + } + + for ((key, value) in CompatUtil.getKeyFilteredMap(map)) { + val recyclerHeaderItem = RecyclerHeaderItem(key, value.size) + if (!entityMap.contains(recyclerHeaderItem)) { + entityMap.add(recyclerHeaderItem) + } + entityMap.addAll(value) + } + return getDifference(model, entityMap) + } + + /** + * Groups edge container items their media/node and the character role + * N.B. In this use case the main model is not used to check for existence + * of a given role because the voiceActors and characterRoles are grouped by media + *

+ * + * @see CharacterActorsFragment restricted and should only be used by this + * + * @see EdgeContainer + *

+ * + * + * @param edges The potential external model response which needs to be grouped + */ + fun groupActorMediaEdge(edges: List): List { + val entityMap = ArrayList() + for (edge in edges) { + if (edge.node != null) { + if (!edge.characterRole.isNullOrBlank()) + edge.node.subGroupTitle = edge.characterRole + edge.node.contentType = KeyUtil.RECYCLER_TYPE_HEADER + entityMap.add(edge.node) + } + if (!CompatUtil.isEmpty(edge.voiceActors)) + entityMap.addAll(edge.voiceActors) + } + return entityMap + } + + /** + * Groups edge container items their media/node and the media relation type + * @see MediaEdge + *

+ * + * + * @param edges The potential external model response which needs to be grouped + */ + fun groupMediaByRelationType(edges: List): List { + val entityMap = ArrayList() + for (edge in edges) { + val recyclerHeaderItem = RecyclerHeaderItem(edge.relationType) + if (!entityMap.contains(recyclerHeaderItem)) { + val totalItems = Stream.of(edges).map { it.relationType } + .filter { role -> CompatUtil.equals(role, edge.relationType) } + .count() + recyclerHeaderItem.size = totalItems.toInt() + entityMap.add(recyclerHeaderItem) + } + entityMap.add(edge.node) + } + return entityMap + } + + /** + * Groups characters by role, assuming that the characters have been sorted by format + * @see KeyUtil.CharacterRole + *

+ * + * Only to be used when the sort type is @{@link KeyUtil.CharacterSort.ROLE} + * which is the default sort type for the request @{@link KeyUtil.CHARACTER_ACTORS_REQ} + *

+ * + * + * @param edges The potential external model response which needs to be grouped + * @param model The current model item/s containing all data minus current mediaItems + */ + fun groupCharactersByRole(edges: List, model: List?): List { + val entityMap = if (!CompatUtil.isEmpty(model)) ArrayList(model!!) else ArrayList() + for (edge in edges) { + val recyclerHeaderItem = RecyclerHeaderItem(edge.role) + if (!entityMap.contains(recyclerHeaderItem)) { + val totalItems = Stream.of(edges).map{ it.role } + .filter { role -> CompatUtil.equals(role, edge.role) } + .count() + recyclerHeaderItem.size = totalItems.toInt() + entityMap.add(recyclerHeaderItem) + } + entityMap.add(edge.node) + } + return getDifference(model, entityMap) + } + + /** + * Groups media by the staff role, assuming that the staff has be sorted by role + *

+ * + * @param edges The potential external model response which needs to be grouped + * @param model The current model item/s containing all data minus current mediaItems + */ + fun groupStaffByRole(edges: List, model: List?): List { + val entityMap = if (!CompatUtil.isEmpty(model)) ArrayList(model!!) else ArrayList() + for (edge in edges) { + val recyclerHeaderItem = RecyclerHeaderItem(edge.role) + if (!entityMap.contains(recyclerHeaderItem)) { + val totalItems = Stream.of(edges).map { it.role } + .filter { role -> CompatUtil.equals(role, edge.role) } + .count() + recyclerHeaderItem.size = totalItems.toInt() + entityMap.add(recyclerHeaderItem) + } + entityMap.add(edge.node) + } + return getDifference(model, entityMap) + } + + /** + * Groups media by the staff role, assuming that the staff items have be sorted by format + *

+ * + * @param edges The potential external model response which needs to be grouped + * @param model The current model item/s containing all data minus current mediaItems + */ + fun groupMediaByStaffRole(edges: List, model: List?): List { + val entityMap = if (!CompatUtil.isEmpty(model)) ArrayList(model!!) else ArrayList() + for (edge in edges) { + val recyclerHeaderItem = RecyclerHeaderItem(edge.staffRole) + if (!entityMap.contains(recyclerHeaderItem)) { + val totalItems = Stream.of(edges).map { it.staffRole } + .filter { role -> CompatUtil.equals(role, edge.staffRole) } + .count() + recyclerHeaderItem.size = totalItems.toInt() + entityMap.add(recyclerHeaderItem) + } + entityMap.add(edge.node) + } + return getDifference(model, entityMap) + } + + /** + * Returns only new items that were not previously added to the list + *

+ * + * @param model Existing items thus far from a paginated result set + * @param recyclerItems Model that holds all grouped items including previously stored results + */ + private fun getDifference(model: List?, recyclerItems: List): List { + return if (!CompatUtil.isEmpty(model)) recyclerItems.subList(model!!.size, recyclerItems.size) else recyclerItems + } + + fun wrapInGroup(data: List): List { + return ArrayList(data) + } +} diff --git a/app/src/main/java/com/mxt/anitrend/util/IntentBundleUtil.java b/app/src/main/java/com/mxt/anitrend/util/IntentBundleUtil.java deleted file mode 100644 index f233f7e10..000000000 --- a/app/src/main/java/com/mxt/anitrend/util/IntentBundleUtil.java +++ /dev/null @@ -1,115 +0,0 @@ -package com.mxt.anitrend.util; - -import android.content.Intent; -import android.net.Uri; -import android.os.Build; -import android.support.annotation.Nullable; -import android.support.v4.app.FragmentActivity; -import android.support.v4.app.ShareCompat; -import android.text.TextUtils; - -import java.util.regex.Matcher; - -/** - * Created by max on 2017/12/01. - * Intent data formatter and helper methods - */ - -public class IntentBundleUtil { - - private ShareCompat.IntentReader sharedIntent; - private Matcher deepLinkMatcher; - private String INTENT_ACTION; - - public IntentBundleUtil(Intent intent, FragmentActivity context) { - if(intent != null) { - if(intent.hasExtra(KeyUtil.arg_shortcut_used) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) - ShortcutUtil.reportShortcutUsage(context, intent.getIntExtra(KeyUtil.arg_shortcut_used, KeyUtil.SHORTCUT_SEARCH)); - checkIntentData(intent, context); - } - } - - private boolean hasAction(Intent intent) { - return (INTENT_ACTION = intent.getAction()) != null; - } - - private @Nullable Uri hasData(Intent intent) { - return intent.getData(); - } - - private @Nullable String[] hasDepth(String key) { - if(key.contains("/")) - return key.split("/"); - return null; - } - - private void injectIntentParams(Intent intent) { - String type = deepLinkMatcher.group(1); - int groupLimit = deepLinkMatcher.groupCount(); - String lastKey = deepLinkMatcher.group(groupLimit); - String[] splitKeys; - switch (type) { - case KeyUtil.DEEP_LINK_USER: - if(TextUtils.isDigitsOnly(lastKey)) - intent.putExtra(KeyUtil.arg_id, Long.valueOf(lastKey)); - else { - if (lastKey.contains("/")) - lastKey = lastKey.replace("/", ""); - intent.putExtra(KeyUtil.arg_userName, lastKey); - } - break; - case KeyUtil.DEEP_LINK_MANGA: - if ((splitKeys = hasDepth(lastKey)) != null) - intent.putExtra(KeyUtil.arg_id, Long.valueOf(splitKeys[0])); - else - intent.putExtra(KeyUtil.arg_id, Long.valueOf(lastKey)); - intent.putExtra(KeyUtil.arg_mediaType, KeyUtil.MANGA); - break; - case KeyUtil.DEEP_LINK_ANIME: - if ((splitKeys = hasDepth(lastKey)) != null) - intent.putExtra(KeyUtil.arg_id, Long.valueOf(splitKeys[0])); - else - intent.putExtra(KeyUtil.arg_id, Long.valueOf(lastKey)); - intent.putExtra(KeyUtil.arg_mediaType, KeyUtil.ANIME); - break; - case KeyUtil.DEEP_LINK_CHARACTER: - if ((splitKeys = hasDepth(lastKey)) != null) - intent.putExtra(KeyUtil.arg_id, Long.valueOf(splitKeys[0])); - else - intent.putExtra(KeyUtil.arg_id, Long.valueOf(lastKey)); - break; - case KeyUtil.DEEP_LINK_ACTOR: - if ((splitKeys = hasDepth(lastKey)) != null) - intent.putExtra(KeyUtil.arg_id, Long.valueOf(splitKeys[0])); - else - intent.putExtra(KeyUtil.arg_id, Long.valueOf(lastKey)); - break; - case KeyUtil.DEEP_LINK_STAFF: - if ((splitKeys = hasDepth(lastKey)) != null) - intent.putExtra(KeyUtil.arg_id, Long.valueOf(splitKeys[0])); - else - intent.putExtra(KeyUtil.arg_id, Long.valueOf(lastKey)); - break; - case KeyUtil.DEEP_LINK_STUDIO: - if ((splitKeys = hasDepth(lastKey)) != null) - intent.putExtra(KeyUtil.arg_id, Long.valueOf(splitKeys[0])); - else - intent.putExtra(KeyUtil.arg_id, Long.valueOf(lastKey)); - break; - } - } - - private void checkIntentData(Intent intent, FragmentActivity context) { - Uri INTENT_DATA; - if (hasAction(intent) && INTENT_ACTION.equals(Intent.ACTION_SEND)) - sharedIntent = ShareCompat.IntentReader.from(context); - else - if ((INTENT_DATA = hasData(intent)) != null) - if((deepLinkMatcher = RegexUtil.INSTANCE.findIntentKeys(INTENT_DATA.getPath())) != null) - injectIntentParams(intent); - } - - public @Nullable ShareCompat.IntentReader getSharedIntent() { - return sharedIntent; - } -} diff --git a/app/src/main/java/com/mxt/anitrend/util/IntentBundleUtil.kt b/app/src/main/java/com/mxt/anitrend/util/IntentBundleUtil.kt new file mode 100644 index 000000000..f2fe9cb6c --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/util/IntentBundleUtil.kt @@ -0,0 +1,103 @@ +package com.mxt.anitrend.util + +import android.content.Intent +import android.net.Uri +import android.os.Build +import android.support.v4.app.FragmentActivity +import android.support.v4.app.ShareCompat +import android.text.TextUtils + +import java.util.regex.Matcher + +/** + * Created by max on 2017/12/01. + * Intent data formatter and helper methods + */ + +class IntentBundleUtil(private val intent: Intent) { + + var sharedIntent: ShareCompat.IntentReader? = null + + private val deepLinkMatcher: Matcher? by lazy { + RegexUtil.findIntentKeys(intentData?.path) + } + + private val intentAction: String? by lazy { + intent.action + } + + private val intentData: Uri? by lazy { + intent.data + } + + private fun hasDepth(key: String): Array? { + return if (key.contains("/")) + key.split("/".toRegex()) + .dropLastWhile { + it.isEmpty() + }.toTypedArray() + else null + } + + private fun injectIntentParams() { + deepLinkMatcher?.also { + val type = it.group(1) + val groupLimit = it.groupCount() + + var lastKey = it.group(groupLimit) + val splitKeys: Array? = hasDepth(lastKey) + + when (type) { + KeyUtil.DEEP_LINK_USER -> when { + TextUtils.isDigitsOnly(lastKey) -> intent?.putExtra(KeyUtil.arg_id, lastKey) + else -> { + if (lastKey.contains("/")) + lastKey = lastKey.replace("/", "") + intent?.putExtra(KeyUtil.arg_userName, lastKey) + } + } + KeyUtil.DEEP_LINK_MANGA -> { + if (splitKeys != null) + intent?.putExtra(KeyUtil.arg_id, splitKeys[0]) + else + intent?.putExtra(KeyUtil.arg_id, lastKey) + intent?.putExtra(KeyUtil.arg_mediaType, KeyUtil.MANGA) + } + KeyUtil.DEEP_LINK_ANIME -> { + if (splitKeys != null) + intent?.putExtra(KeyUtil.arg_id, splitKeys[0]) + else + intent?.putExtra(KeyUtil.arg_id, lastKey) + intent?.putExtra(KeyUtil.arg_mediaType, KeyUtil.ANIME) + } + KeyUtil.DEEP_LINK_CHARACTER -> if (splitKeys != null) + intent?.putExtra(KeyUtil.arg_id, splitKeys[0]) + else + intent?.putExtra(KeyUtil.arg_id, lastKey) + KeyUtil.DEEP_LINK_ACTOR -> if (splitKeys != null) + intent?.putExtra(KeyUtil.arg_id, splitKeys[0]) + else + intent?.putExtra(KeyUtil.arg_id, lastKey) + KeyUtil.DEEP_LINK_STAFF -> if (splitKeys != null) + intent?.putExtra(KeyUtil.arg_id, splitKeys[0]) + else + intent?.putExtra(KeyUtil.arg_id, lastKey) + KeyUtil.DEEP_LINK_STUDIO -> if (splitKeys != null) + intent?.putExtra(KeyUtil.arg_id, splitKeys[0]) + else + intent?.putExtra(KeyUtil.arg_id, lastKey) + } + } + } + + fun checkIntentData(context: FragmentActivity) { + if (context.intent?.hasExtra(KeyUtil.arg_shortcut_used) == true && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) + ShortcutUtil.reportShortcutUsage(context, context.intent.getIntExtra(KeyUtil.arg_shortcut_used, KeyUtil.SHORTCUT_SEARCH)) + + if (!intentAction.isNullOrEmpty() && intentAction == Intent.ACTION_SEND) + sharedIntent = ShareCompat.IntentReader.from(context) + else if (deepLinkMatcher != null) + injectIntentParams() + } +} + diff --git a/app/src/main/java/com/mxt/anitrend/util/KeyUtil.java b/app/src/main/java/com/mxt/anitrend/util/KeyUtil.java index a40e31ec6..b6027d040 100644 --- a/app/src/main/java/com/mxt/anitrend/util/KeyUtil.java +++ b/app/src/main/java/com/mxt/anitrend/util/KeyUtil.java @@ -440,14 +440,14 @@ public interface KeyUtil { // ------------------------------------------------------------------------------------ String ACTIVITY_MESSAGE = "ACTIVITY_MESSAGE", FOLLOWING = "FOLLOWING", ACTIVITY_MENTION = "ACTIVITY_MENTION", - ACTIVITY_REPLY_SUBSCRIBED = "ACTIVITY_REPLY_SUBSCRIBED", + ACTIVITY_REPLY_SUBSCRIBED = "ACTIVITY_REPLY_SUBSCRIBED", RELATED_MEDIA_ADDITION = "RELATED_MEDIA_ADDITION", THREAD_COMMENT_MENTION = "THREAD_COMMENT_MENTION", THREAD_SUBSCRIBED = "THREAD_SUBSCRIBED", THREAD_COMMENT_REPLY = "THREAD_COMMENT_REPLY", AIRING = "AIRING", ACTIVITY_LIKE = "ACTIVITY_LIKE", ACTIVITY_REPLY_LIKE = "ACTIVITY_REPLY_LIKE", THREAD_LIKE = "THREAD_LIKE", THREAD_COMMENT_LIKE = "THREAD_COMMENT_LIKE"; @StringDef({ACTIVITY_MESSAGE, ACTIVITY_REPLY, ACTIVITY_REPLY_SUBSCRIBED, FOLLOWING, ACTIVITY_MENTION, - THREAD_COMMENT_MENTION, THREAD_SUBSCRIBED, THREAD_COMMENT_REPLY, + THREAD_COMMENT_MENTION, THREAD_SUBSCRIBED, THREAD_COMMENT_REPLY, RELATED_MEDIA_ADDITION, AIRING, ACTIVITY_LIKE, ACTIVITY_REPLY_LIKE, THREAD_LIKE, THREAD_COMMENT_LIKE }) @interface NotificationType {} diff --git a/app/src/main/java/com/mxt/anitrend/util/LocaleUtil.java b/app/src/main/java/com/mxt/anitrend/util/LocaleUtil.java deleted file mode 100644 index 97abc6340..000000000 --- a/app/src/main/java/com/mxt/anitrend/util/LocaleUtil.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.mxt.anitrend.util; - -import android.annotation.TargetApi; -import android.content.Context; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.os.Build; - -import java.util.Locale; - -/** - * This class is used to change the application locale. - * - * Created by gunhansancar on 07/10/15. - */ -public class LocaleUtil { - - public static Context onAttach(Context context) { - String language = new ApplicationPref(context).getUserLanguage(); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - return updateResources(context, language); - } - - return updateResourcesLegacy(context, language); - } - - @TargetApi(Build.VERSION_CODES.N) - private static Context updateResources(Context context, String language) { - Locale locale = new Locale(language); - Locale.setDefault(locale); - - Configuration configuration = context.getResources().getConfiguration(); - configuration.setLocale(locale); - configuration.setLayoutDirection(locale); - - return context.createConfigurationContext(configuration); - } - - @SuppressWarnings("deprecation") - private static Context updateResourcesLegacy(Context context, String language) { - Locale locale = new Locale(language); - Locale.setDefault(locale); - Resources resources = context.getResources(); - - Configuration configuration = resources.getConfiguration(); - configuration.locale = locale; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - configuration.setLayoutDirection(locale); - } - - resources.updateConfiguration(configuration, resources.getDisplayMetrics()); - - return context; - } -} \ No newline at end of file diff --git a/app/src/main/java/com/mxt/anitrend/util/LocaleUtil.kt b/app/src/main/java/com/mxt/anitrend/util/LocaleUtil.kt new file mode 100644 index 000000000..056c69442 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/util/LocaleUtil.kt @@ -0,0 +1,53 @@ +package com.mxt.anitrend.util + +import android.annotation.TargetApi +import android.content.Context +import android.os.Build +import com.mxt.anitrend.App + +import java.util.Locale + +/** + * This class is used to change the application locale. + * + * Created by gunhansancar on 07/10/15. + */ +object LocaleUtil { + + fun onAttach(context: Context, applicationPref: ApplicationPref): Context { + val language = applicationPref.userLanguage + + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + updateResources(context, language) + } else updateResourcesLegacy(context, language) + + } + + @TargetApi(Build.VERSION_CODES.N) + private fun updateResources(context: Context, language: String?): Context { + val locale = Locale(language) + Locale.setDefault(locale) + + val configuration = context.resources.configuration + configuration.setLocale(locale) + configuration.setLayoutDirection(locale) + + return context.createConfigurationContext(configuration) + } + + private fun updateResourcesLegacy(context: Context, language: String?): Context { + val locale = Locale(language) + Locale.setDefault(locale) + val resources = context.resources + + val configuration = resources.configuration + configuration.locale = locale + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + configuration.setLayoutDirection(locale) + } + + resources.updateConfiguration(configuration, resources.displayMetrics) + + return context + } +} \ No newline at end of file diff --git a/app/src/main/java/com/mxt/anitrend/util/MediaActionUtil.java b/app/src/main/java/com/mxt/anitrend/util/MediaActionUtil.java index e9e61c6d8..e6c571442 100644 --- a/app/src/main/java/com/mxt/anitrend/util/MediaActionUtil.java +++ b/app/src/main/java/com/mxt/anitrend/util/MediaActionUtil.java @@ -50,7 +50,7 @@ private void actionPicker() { // No need to add the parameter onList otherwise we'd have to handle an error code 404, // Instead we'd rather check if the the media has a non null mediaList item - QueryContainerBuilder queryContainerBuilder = GraphUtil.getDefaultQuery(false) + QueryContainerBuilder queryContainerBuilder = GraphUtil.INSTANCE.getDefaultQuery(false) .putVariable(KeyUtil.arg_id, mediaId) .putVariable(KeyUtil.arg_scoreFormat, mediaListOptions.getScoreFormat()); @@ -94,7 +94,7 @@ public void onResponse(@NonNull Call call, @NonNull Response call, @NonNull Response(requestType, responseBody), false); NotifyUtil.makeText(context, context.getString(R.string.text_changes_saved), R.drawable.ic_check_circle_white_24dp, Toast.LENGTH_SHORT).show(); } else { - Log.e(this.toString(), ErrorUtil.getError(response)); + Log.e(this.toString(), ErrorUtil.INSTANCE.getError(response)); NotifyUtil.makeText(context, context.getString(R.string.text_error_request), R.drawable.ic_warning_white_18dp, Toast.LENGTH_SHORT).show(); } } catch (Exception e) { @@ -147,7 +147,7 @@ public void onResponse(@NonNull Call call, @NonNull Response call, @NonNull Throwable throwa * @param context from a fragment activity derived class */ private static CustomSeriesManageBase buildManagerType(Context context, @KeyUtil.MediaType String seriesType) { - if(CompatUtil.equals(seriesType, KeyUtil.ANIME)) + if(CompatUtil.INSTANCE.equals(seriesType, KeyUtil.ANIME)) return new CustomSeriesAnimeManage(context); return new CustomSeriesMangaManage(context); } @@ -185,7 +185,7 @@ private static CustomSeriesManageBase buildManagerType(Context context, @KeyUtil */ private static MaterialDialog.Builder createSeriesManageDialog(Context context, boolean isNewEntry, String title) { MaterialDialog.Builder materialBuilder = createDefaultDialog(context) - .icon(CompatUtil.getDrawableTintAttr(context, isNewEntry ? R.drawable.ic_fiber_new_white_24dp : R.drawable.ic_border_color_white_24dp, R.attr.colorAccent)) + .icon(CompatUtil.INSTANCE.getDrawableTintAttr(context, isNewEntry ? R.drawable.ic_fiber_new_white_24dp : R.drawable.ic_border_color_white_24dp, R.attr.colorAccent)) .title(Html.fromHtml(context.getString(isNewEntry ? R.string.dialog_add_title : R.string.dialog_edit_title, title))) .positiveText(isNewEntry? R.string.Add: R.string.Update) .neutralText(R.string.Cancel) diff --git a/app/src/main/java/com/mxt/anitrend/util/MediaListUtil.java b/app/src/main/java/com/mxt/anitrend/util/MediaListUtil.java index 7e72c4b74..77b976ee2 100644 --- a/app/src/main/java/com/mxt/anitrend/util/MediaListUtil.java +++ b/app/src/main/java/com/mxt/anitrend/util/MediaListUtil.java @@ -23,7 +23,7 @@ public class MediaListUtil { * @param model the current media list item */ public static Bundle getMediaListParams(@NonNull MediaList model, @KeyUtil.ScoreFormat String scoreFormat) { - QueryContainerBuilder queryContainer = GraphUtil.getDefaultQuery(false) + QueryContainerBuilder queryContainer = GraphUtil.INSTANCE.getDefaultQuery(false) .putVariable(KeyUtil.arg_scoreFormat, scoreFormat); if (model.getId() > 0) @@ -41,7 +41,7 @@ public static Bundle getMediaListParams(@NonNull MediaList model, @KeyUtil.Score if (model.getAdvancedScores() != null) queryContainer.putVariable(KeyUtil.arg_listAdvancedScore, model.getAdvancedScores()); - if (!CompatUtil.isEmpty(model.getCustomLists())) { + if (!CompatUtil.INSTANCE.isEmpty(model.getCustomLists())) { List enabledCustomLists = Stream.of(model.getCustomLists()) .filter(CustomList::isEnabled) .map(CustomList::getName) @@ -62,7 +62,7 @@ public static Bundle getMediaListParams(@NonNull MediaList model, @KeyUtil.Score * Checks if the sorting should be done on titles */ public static boolean isTitleSort(@KeyUtil.MediaListSort String mediaSort) { - return CompatUtil.equals(mediaSort, KeyUtil.TITLE); + return CompatUtil.INSTANCE.equals(mediaSort, KeyUtil.TITLE); } /** diff --git a/app/src/main/java/com/mxt/anitrend/util/MediaUtil.java b/app/src/main/java/com/mxt/anitrend/util/MediaUtil.java index 8723c5a57..9013a53ac 100644 --- a/app/src/main/java/com/mxt/anitrend/util/MediaUtil.java +++ b/app/src/main/java/com/mxt/anitrend/util/MediaUtil.java @@ -17,11 +17,11 @@ public class MediaUtil { public static boolean isAnimeType(T series) { - return (series != null && CompatUtil.equals(series.getType(), KeyUtil.ANIME)); + return (series != null && CompatUtil.INSTANCE.equals(series.getType(), KeyUtil.ANIME)); } public static boolean isMangaType(T series) { - return (series != null && CompatUtil.equals(series.getType(), KeyUtil.MANGA)); + return (series != null && CompatUtil.INSTANCE.equals(series.getType(), KeyUtil.MANGA)); } public static boolean isIncrementLimitReached(MediaList model) { @@ -34,7 +34,7 @@ public static boolean isIncrementLimitReached(MediaList model) { public static boolean isAllowedStatus(MediaList model) { MediaBase mediaBase = model.getMedia(); - return !CompatUtil.equals(mediaBase.getStatus(), KeyUtil.NOT_YET_RELEASED); + return !CompatUtil.INSTANCE.equals(mediaBase.getStatus(), KeyUtil.NOT_YET_RELEASED); } public static String getMediaTitle(T series) { @@ -56,7 +56,7 @@ public static List mapMediaTrend(List mediaTrends) { public static List getAiringMedia(List mediaLists) { if(mediaLists != null) return Stream.of(mediaLists) - .filter(media -> CompatUtil.equals(media.getMedia().getStatus(), KeyUtil.RELEASING)) + .filter(media -> CompatUtil.INSTANCE.equals(media.getMedia().getStatus(), KeyUtil.RELEASING)) .toList(); return Collections.emptyList(); } diff --git a/app/src/main/java/com/mxt/anitrend/util/NotificationUtil.java b/app/src/main/java/com/mxt/anitrend/util/NotificationUtil.java deleted file mode 100644 index 0d0439343..000000000 --- a/app/src/main/java/com/mxt/anitrend/util/NotificationUtil.java +++ /dev/null @@ -1,82 +0,0 @@ -package com.mxt.anitrend.util; - -import android.app.NotificationChannel; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.content.Context; -import android.content.Intent; -import android.graphics.Color; -import android.net.Uri; -import android.os.Build; -import android.support.v4.app.NotificationCompat; - -import com.mxt.anitrend.R; -import com.mxt.anitrend.model.entity.anilist.User; -import com.mxt.anitrend.view.activity.detail.NotificationActivity; - -import static android.support.v4.app.NotificationCompat.PRIORITY_DEFAULT; - -/** - * Created by max on 1/22/2017. - * NotificationUtil - */ - -public final class NotificationUtil { - - private static final int NOTIFICATION_ID = 0x00000111; - - private static PendingIntent multiContentIntent(Context context){ - // PendingIntent.FLAG_UPDATE_CURRENT will update notification - Intent activityStart = new Intent(context, NotificationActivity.class); - return PendingIntent.getActivity(context, NOTIFICATION_ID, activityStart, PendingIntent.FLAG_UPDATE_CURRENT); - } - - private static String getNotificationSound(Context context) { - ApplicationPref applicationPref = new ApplicationPref(context); - return applicationPref.getNotificationsSound(); - } - - public static void createNotification(Context context, User userGraphContainer) { - - NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); - - NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context, KeyUtil.CHANNEL_TITLE) - .setSmallIcon(R.drawable.ic_new_releases) - .setSound(Uri.parse(getNotificationSound(context))) - .setAutoCancel(true) - .setPriority(PRIORITY_DEFAULT); - - // Create the NotificationChannel, but only on API 26+ because - // the NotificationChannel class is new and not in the support library - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - //define the importance level of the notification - int importance = NotificationManager.IMPORTANCE_DEFAULT; - - //build the actual notification channel, giving it a unique ID and name - NotificationChannel channel = - new NotificationChannel(KeyUtil.CHANNEL_TITLE, KeyUtil.CHANNEL_TITLE, importance); - - //we can optionally add a description for the channel - String description = "A channel which shows notifications about events on AniTrend"; - channel.setDescription(description); - - //we can optionally set notification LED colour - channel.setLightColor(Color.MAGENTA); - - // Register the channel with the system - if (notificationManager != null) - notificationManager.createNotificationChannel(channel); - } - - int notificationCount = userGraphContainer.getUnreadNotificationCount(); - - if(notificationCount > 0) { - notificationBuilder.setContentIntent(multiContentIntent(context)) - .setContentTitle(context.getString(R.string.alerter_notification_title)) - .setContentText(context.getString(notificationCount > 1 ? R.string.text_notifications : R.string.text_notification, notificationCount)); - - if(notificationManager != null) - notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build()); - } - } -} diff --git a/app/src/main/java/com/mxt/anitrend/util/NotificationUtil.kt b/app/src/main/java/com/mxt/anitrend/util/NotificationUtil.kt new file mode 100644 index 000000000..fd2c692a1 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/util/NotificationUtil.kt @@ -0,0 +1,101 @@ +package com.mxt.anitrend.util + +import android.app.NotificationChannel +import android.app.NotificationManager +import android.app.PendingIntent +import android.content.Context +import android.content.Intent +import android.graphics.Color +import android.net.Uri +import android.os.Build +import android.support.v4.app.NotificationCompat +import android.support.v4.app.NotificationCompat.PRIORITY_DEFAULT +import android.support.v4.app.NotificationCompat.PRIORITY_HIGH +import com.mxt.anitrend.R +import com.mxt.anitrend.model.entity.anilist.User +import com.mxt.anitrend.view.activity.detail.NotificationActivity + +/** + * Created by max on 1/22/2017. + * NotificationUtil + */ + +class NotificationUtil(private val context: Context) { + + private var defaultNotificationId = 0x00000011 + + private val applicationPref by lazy { + ApplicationPref(context) + } + + private val notificationManager by lazy { + context.getSystemService( + Context.NOTIFICATION_SERVICE + ) as NotificationManager? + } + + private fun multiContentIntent(): PendingIntent { + // PendingIntent.FLAG_UPDATE_CURRENT will update notification + val targetActivity = Intent( + context, + NotificationActivity::class.java + ) + return PendingIntent.getActivity( + context, + defaultNotificationId, + targetActivity, + PendingIntent.FLAG_UPDATE_CURRENT + ) + } + + private fun getNotificationSound(): String? { + return applicationPref.notificationsSound + } + + fun createNotification(userGraphContainer: User) { + + val notificationBuilder = NotificationCompat.Builder(context, KeyUtil.CHANNEL_ID) + .setSmallIcon(R.drawable.ic_new_releases) + .setSound(Uri.parse(getNotificationSound())) + .setAutoCancel(true) + .setPriority(PRIORITY_HIGH) + + // Create the NotificationChannel, but only on API 26+ because + // the NotificationChannel class is new and not in the support library + when { + Build.VERSION.SDK_INT >= Build.VERSION_CODES.O -> { + //define the importance level of the notification + val importance = NotificationManager.IMPORTANCE_DEFAULT + + //build the actual notification channel, giving it a unique ID and name + val channel = NotificationChannel( + KeyUtil.CHANNEL_ID, KeyUtil.CHANNEL_TITLE, importance + ).apply { + //we can optionally add a description for the channel + description = "A channel which shows notifications about events on AniTrend" + + //we can optionally set notification LED colour + lightColor = Color.MAGENTA + } + + // Register the channel with the system + notificationManager?.createNotificationChannel(channel) + } + } + + val notificationCount = userGraphContainer.unreadNotificationCount + + if (notificationCount > 0) { + notificationBuilder.setContentIntent(multiContentIntent()) + .setContentTitle(context.getString(R.string.alerter_notification_title)) + .setContentText(context.getString( + when (notificationCount > 1) { + true -> R.string.text_notifications + else -> R.string.text_notification + }, notificationCount) + ) + + notificationManager?.notify(defaultNotificationId.inc(), notificationBuilder.build()) + } + } +} diff --git a/app/src/main/java/com/mxt/anitrend/util/NotifyUtil.java b/app/src/main/java/com/mxt/anitrend/util/NotifyUtil.java index c54a5b25e..92e6a4868 100644 --- a/app/src/main/java/com/mxt/anitrend/util/NotifyUtil.java +++ b/app/src/main/java/com/mxt/anitrend/util/NotifyUtil.java @@ -32,8 +32,8 @@ public class NotifyUtil { public static void createAlerter(FragmentActivity activity, String title, String text, @DrawableRes int icon, @ColorRes int backgroundColor, @KeyUtil.AlerterDuration long duration) { Alerter.create(activity).setTitle(title).setText(text) - .setIcon(CompatUtil.getDrawable(activity, icon, R.color.white)) - .setProgressColorInt(CompatUtil.getColor(activity, R.color.white)) + .setIcon(CompatUtil.INSTANCE.getDrawable(activity, icon, R.color.white)) + .setProgressColorInt(CompatUtil.INSTANCE.getColor(activity, R.color.white)) .setBackgroundColorRes(backgroundColor) .enableIconPulse(true).enableSwipeToDismiss() .enableVibration(true).setDuration(duration == 0 ? KeyUtil.DURATION_SHORT : duration) @@ -47,8 +47,8 @@ public static void createAlerter(FragmentActivity activity, String title, String public static void createAlerter(FragmentActivity activity, @StringRes int title, @StringRes int text, @DrawableRes int icon, @ColorRes int backgroundColor, @KeyUtil.AlerterDuration long duration) { Alerter.create(activity).setTitle(title).setText(text) - .setIcon(CompatUtil.getDrawable(activity, icon, R.color.white)) - .setProgressColorInt(CompatUtil.getColor(activity, R.color.white)) + .setIcon(CompatUtil.INSTANCE.getDrawable(activity, icon, R.color.white)) + .setProgressColorInt(CompatUtil.INSTANCE.getColor(activity, R.color.white)) .setBackgroundColorRes(backgroundColor) .enableIconPulse(true).enableSwipeToDismiss() .enableVibration(true).setDuration(duration == 0 ? KeyUtil.DURATION_SHORT : duration) @@ -61,7 +61,7 @@ public static void createAlerter(FragmentActivity activity, @StringRes int title */ public static void createAlerter(FragmentActivity activity, String title, String text, @DrawableRes int icon, @ColorRes int backgroundColor) { Alerter.create(activity).setTitle(title).setText(text) - .setIcon(CompatUtil.getDrawable(activity, icon, R.color.white)) + .setIcon(CompatUtil.INSTANCE.getDrawable(activity, icon, R.color.white)) .setBackgroundColorRes(backgroundColor) .enableIconPulse(true).enableSwipeToDismiss() .enableVibration(true).setDuration(KeyUtil.DURATION_SHORT) @@ -73,7 +73,7 @@ public static void createAlerter(FragmentActivity activity, String title, String */ public static void createAlerter(FragmentActivity activity, @StringRes int title, @StringRes int text, @DrawableRes int icon, @ColorRes int backgroundColor) { Alerter.create(activity).setTitle(title).setText(text) - .setIcon(CompatUtil.getDrawable(activity, icon, R.color.white)) + .setIcon(CompatUtil.INSTANCE.getDrawable(activity, icon, R.color.white)) .setBackgroundColorRes(backgroundColor) .enableIconPulse(true).enableSwipeToDismiss() .enableVibration(true).setDuration(KeyUtil.DURATION_SHORT) @@ -85,7 +85,7 @@ public static void createAlerter(FragmentActivity activity, @StringRes int title */ public static void createAlerter(FragmentActivity activity, @StringRes int title, @StringRes int text, @DrawableRes int icon, @ColorRes int backgroundColor, View.OnClickListener clickListener) { Alerter.create(activity).setTitle(title).setText(text) - .setIcon(CompatUtil.getDrawable(activity, icon, R.color.white)) + .setIcon(CompatUtil.INSTANCE.getDrawable(activity, icon, R.color.white)) .setBackgroundColorRes(backgroundColor) .enableIconPulse(true).enableSwipeToDismiss() .enableVibration(true).setDuration(KeyUtil.DURATION_SHORT) @@ -98,7 +98,7 @@ public static void createAlerter(FragmentActivity activity, @StringRes int title */ public static void createLoginToast(FragmentActivity context, User user) { Toast notification = new Toast(context); - CustomAuthToastBinding binding = CustomAuthToastBinding.inflate(CompatUtil.getLayoutInflater(context)); + CustomAuthToastBinding binding = CustomAuthToastBinding.inflate(CompatUtil.INSTANCE.getLayoutInflater(context)); binding.setModel(user); notification.setView(binding.getRoot()); notification.setGravity(Gravity.BOTTOM | Gravity.FILL_HORIZONTAL, 0, 0); @@ -108,44 +108,44 @@ public static void createLoginToast(FragmentActivity context, User user) { public static Toast makeText(Context context, @StringRes int stringRes, @DrawableRes int drawableRes, int duration) { Toast toast = new Toast(context); - CustomToastBinding binding = CustomToastBinding.inflate(CompatUtil.getLayoutInflater(context)); + CustomToastBinding binding = CustomToastBinding.inflate(CompatUtil.INSTANCE.getLayoutInflater(context)); binding.toastText.setText(context.getString(stringRes)); - binding.toastIcon.setImageDrawable(CompatUtil.getTintedDrawable(context, drawableRes)); + binding.toastIcon.setImageDrawable(CompatUtil.INSTANCE.getTintedDrawable(context, drawableRes)); toast.setView(binding.getRoot()); - toast.setGravity(Gravity.BOTTOM | Gravity.FILL_HORIZONTAL, 0, CompatUtil.dipToPx(32)); + toast.setGravity(Gravity.BOTTOM | Gravity.FILL_HORIZONTAL, 0, CompatUtil.INSTANCE.dipToPx(32)); toast.setDuration(duration); return toast; } public static Toast makeText(Context context, @StringRes int stringRes, int duration) { Toast toast = new Toast(context); - CustomToastBinding binding = CustomToastBinding.inflate(CompatUtil.getLayoutInflater(context)); + CustomToastBinding binding = CustomToastBinding.inflate(CompatUtil.INSTANCE.getLayoutInflater(context)); binding.toastText.setText(context.getString(stringRes)); - binding.toastIcon.setImageDrawable(CompatUtil.getTintedDrawable(context, R.drawable.ic_new_releases_white_24dp)); + binding.toastIcon.setImageDrawable(CompatUtil.INSTANCE.getTintedDrawable(context, R.drawable.ic_new_releases_white_24dp)); toast.setView(binding.getRoot()); - toast.setGravity(Gravity.BOTTOM | Gravity.FILL_HORIZONTAL, 0, CompatUtil.dipToPx(32)); + toast.setGravity(Gravity.BOTTOM | Gravity.FILL_HORIZONTAL, 0, CompatUtil.INSTANCE.dipToPx(32)); toast.setDuration(duration); return toast; } public static Toast makeText(Context context, String stringRes, @DrawableRes int drawableRes, int duration) { Toast toast = new Toast(context); - CustomToastBinding binding = CustomToastBinding.inflate(CompatUtil.getLayoutInflater(context)); + CustomToastBinding binding = CustomToastBinding.inflate(CompatUtil.INSTANCE.getLayoutInflater(context)); binding.toastText.setText(stringRes); - binding.toastIcon.setImageDrawable(CompatUtil.getTintedDrawable(context, drawableRes)); + binding.toastIcon.setImageDrawable(CompatUtil.INSTANCE.getTintedDrawable(context, drawableRes)); toast.setView(binding.getRoot()); - toast.setGravity(Gravity.BOTTOM | Gravity.FILL_HORIZONTAL, 0, CompatUtil.dipToPx(32)); + toast.setGravity(Gravity.BOTTOM | Gravity.FILL_HORIZONTAL, 0, CompatUtil.INSTANCE.dipToPx(32)); toast.setDuration(duration); return toast; } public static Toast makeText(Context context, String stringRes, int duration) { Toast toast = new Toast(context); - CustomToastBinding binding = CustomToastBinding.inflate(CompatUtil.getLayoutInflater(context)); + CustomToastBinding binding = CustomToastBinding.inflate(CompatUtil.INSTANCE.getLayoutInflater(context)); binding.toastText.setText(stringRes); - binding.toastIcon.setImageDrawable(CompatUtil.getTintedDrawable(context, R.drawable.ic_new_releases_white_24dp)); + binding.toastIcon.setImageDrawable(CompatUtil.INSTANCE.getTintedDrawable(context, R.drawable.ic_new_releases_white_24dp)); toast.setView(binding.getRoot()); - toast.setGravity(Gravity.BOTTOM | Gravity.FILL_HORIZONTAL, 0, CompatUtil.dipToPx(32)); + toast.setGravity(Gravity.BOTTOM | Gravity.FILL_HORIZONTAL, 0, CompatUtil.INSTANCE.dipToPx(32)); toast.setDuration(duration); return toast; } @@ -153,11 +153,11 @@ public static Toast makeText(Context context, String stringRes, int duration) { public static Snackbar make(View parent, String stringRes, int duration) { Snackbar snackbar = Snackbar.make(parent, stringRes, duration); View snackBarContainer = snackbar.getView(); - snackBarContainer.setBackgroundColor(CompatUtil.getColorFromAttr(parent.getContext(), R.attr.colorPrimaryDark)); + snackBarContainer.setBackgroundColor(CompatUtil.INSTANCE.getColorFromAttr(parent.getContext(), R.attr.colorPrimaryDark)); TextView mainTextView = snackBarContainer.findViewById(android.support.design.R.id.snackbar_text); TextView actionTextView = snackBarContainer.findViewById(android.support.design.R.id.snackbar_action); - mainTextView.setTextColor(CompatUtil.getColorFromAttr(parent.getContext(), R.attr.titleColor)); - actionTextView.setTextColor(CompatUtil.getColorFromAttr(parent.getContext(), R.attr.colorAccent)); + mainTextView.setTextColor(CompatUtil.INSTANCE.getColorFromAttr(parent.getContext(), R.attr.titleColor)); + actionTextView.setTextColor(CompatUtil.INSTANCE.getColorFromAttr(parent.getContext(), R.attr.colorAccent)); actionTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12); return snackbar; } @@ -165,11 +165,11 @@ public static Snackbar make(View parent, String stringRes, int duration) { public static Snackbar make(View parent, @StringRes int stringRes, int duration) { Snackbar snackbar = Snackbar.make(parent, stringRes, duration); View snackBarContainer = snackbar.getView(); - snackBarContainer.setBackgroundColor(CompatUtil.getColorFromAttr(parent.getContext(), R.attr.colorPrimaryDark)); + snackBarContainer.setBackgroundColor(CompatUtil.INSTANCE.getColorFromAttr(parent.getContext(), R.attr.colorPrimaryDark)); TextView mainTextView = snackBarContainer.findViewById(android.support.design.R.id.snackbar_text); TextView actionTextView = snackBarContainer.findViewById(android.support.design.R.id.snackbar_action); - mainTextView.setTextColor(CompatUtil.getColorFromAttr(parent.getContext(), R.attr.titleColor)); - actionTextView.setTextColor(CompatUtil.getColorFromAttr(parent.getContext(), R.attr.colorAccent)); + mainTextView.setTextColor(CompatUtil.INSTANCE.getColorFromAttr(parent.getContext(), R.attr.titleColor)); + actionTextView.setTextColor(CompatUtil.INSTANCE.getColorFromAttr(parent.getContext(), R.attr.colorAccent)); actionTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12); return snackbar; } diff --git a/app/src/main/java/com/mxt/anitrend/util/RegexUtil.kt b/app/src/main/java/com/mxt/anitrend/util/RegexUtil.kt index ec7a8ebd7..e778d0d15 100644 --- a/app/src/main/java/com/mxt/anitrend/util/RegexUtil.kt +++ b/app/src/main/java/com/mxt/anitrend/util/RegexUtil.kt @@ -60,14 +60,20 @@ object RegexUtil { return if (param.isBlank()) null else Pattern.compile(PATTERN_TRAILING_SPACES).matcher(param).replaceAll("") } - internal fun findUserTags(text: String?): String { + fun findUserTags(text: String?): String { var newText = text - if (text.isNullOrBlank()) + if (newText.isNullOrBlank()) return "No content available" - val matcher = Pattern.compile(PATTERN_USER_TAGS).matcher(text) + val matcher = Pattern.compile(PATTERN_USER_TAGS).matcher(newText) while (matcher.find()) { val match = matcher.group() - newText = text.replace(match, String.format(USER_URL_LINK, match, match.replace("@", ""))) + val replacement = String.format( + USER_URL_LINK, match, + match.replace("@", "") + ) + if (newText?.contains(replacement, ignoreCase = false) == true) + continue + newText = newText?.replace(match, replacement) } return newText ?: "No content available" } @@ -75,9 +81,12 @@ object RegexUtil { /** * Returns either an Id of anime listing or user name */ - fun findIntentKeys(path: String): Matcher? { - val deepLinkMatcher = Pattern.compile(PATTERN_DEEP_LINKS).matcher(path) - return if (deepLinkMatcher.find()) deepLinkMatcher else null + fun findIntentKeys(path: String?): Matcher? { + if (path != null) { + val deepLinkMatcher = Pattern.compile(PATTERN_DEEP_LINKS).matcher(path) + return if (deepLinkMatcher.find()) deepLinkMatcher else null + } + return null } /** diff --git a/app/src/main/java/com/mxt/anitrend/util/TapTargetUtil.java b/app/src/main/java/com/mxt/anitrend/util/TapTargetUtil.java index 7dffc615f..495b1d29b 100644 --- a/app/src/main/java/com/mxt/anitrend/util/TapTargetUtil.java +++ b/app/src/main/java/com/mxt/anitrend/util/TapTargetUtil.java @@ -40,9 +40,9 @@ public static MaterialTapTargetPrompt.Builder buildDefault(FragmentActivity cont return new MaterialTapTargetPrompt.Builder(context) .setTarget(context.findViewById(resource)) .setAnimationInterpolator(new FastOutSlowInInterpolator()) - .setPrimaryTextColour(CompatUtil.getColorFromAttr(context, R.attr.titleColor)) - .setSecondaryTextColour(CompatUtil.getColorFromAttr(context, R.attr.subtitleColor)) - .setBackgroundColour(ColorUtils.setAlphaComponent(CompatUtil.getColorFromAttr(context, R.attr.colorPrimaryDark), 0xF2)); + .setPrimaryTextColour(CompatUtil.INSTANCE.getColorFromAttr(context, R.attr.titleColor)) + .setSecondaryTextColour(CompatUtil.INSTANCE.getColorFromAttr(context, R.attr.subtitleColor)) + .setBackgroundColour(ColorUtils.setAlphaComponent(CompatUtil.INSTANCE.getColorFromAttr(context, R.attr.colorPrimaryDark), 0xF2)); } public static MaterialTapTargetPrompt.Builder buildDefault(FragmentActivity context, @StringRes int primary, @StringRes int secondary, @IdRes int resource) { @@ -50,18 +50,18 @@ public static MaterialTapTargetPrompt.Builder buildDefault(FragmentActivity cont .setTarget(context.findViewById(resource)) .setPrimaryText(primary).setSecondaryText(secondary) .setAnimationInterpolator(new FastOutSlowInInterpolator()) - .setPrimaryTextColour(CompatUtil.getColorFromAttr(context, R.attr.titleColor)) - .setSecondaryTextColour(CompatUtil.getColorFromAttr(context, R.attr.subtitleColor)) - .setBackgroundColour(ColorUtils.setAlphaComponent(CompatUtil.getColorFromAttr(context, R.attr.colorPrimaryDark), 0xF2)); + .setPrimaryTextColour(CompatUtil.INSTANCE.getColorFromAttr(context, R.attr.titleColor)) + .setSecondaryTextColour(CompatUtil.INSTANCE.getColorFromAttr(context, R.attr.subtitleColor)) + .setBackgroundColour(ColorUtils.setAlphaComponent(CompatUtil.INSTANCE.getColorFromAttr(context, R.attr.colorPrimaryDark), 0xF2)); } public static MaterialTapTargetPrompt.Builder buildDefault(FragmentActivity context, @StringRes int primary, @StringRes int secondary, View target) { return new MaterialTapTargetPrompt.Builder(context).setTarget(target) .setPrimaryText(primary).setSecondaryText(secondary) .setAnimationInterpolator(new FastOutSlowInInterpolator()) - .setPrimaryTextColour(CompatUtil.getColorFromAttr(context, R.attr.titleColor)) - .setSecondaryTextColour(CompatUtil.getColorFromAttr(context, R.attr.subtitleColor)) - .setBackgroundColour(ColorUtils.setAlphaComponent(CompatUtil.getColorFromAttr(context, R.attr.colorPrimaryDark), 0xF2)); + .setPrimaryTextColour(CompatUtil.INSTANCE.getColorFromAttr(context, R.attr.titleColor)) + .setSecondaryTextColour(CompatUtil.INSTANCE.getColorFromAttr(context, R.attr.subtitleColor)) + .setBackgroundColour(ColorUtils.setAlphaComponent(CompatUtil.INSTANCE.getColorFromAttr(context, R.attr.colorPrimaryDark), 0xF2)); } /** diff --git a/app/src/main/java/com/mxt/anitrend/util/TutorialUtil.java b/app/src/main/java/com/mxt/anitrend/util/TutorialUtil.java index 70401f725..a2380432e 100644 --- a/app/src/main/java/com/mxt/anitrend/util/TutorialUtil.java +++ b/app/src/main/java/com/mxt/anitrend/util/TutorialUtil.java @@ -109,7 +109,7 @@ public TutorialUtil setApplicationPref(ApplicationPref applicationPref) { if (!TapTargetUtil.isActive(tapTarget) && applicationPref.shouldShowTipFor(tapTarget)) return TapTargetUtil.buildDefault(context, resource) .setPromptStateChangeListener(defaultStateChangeListener) - .setFocalColour(CompatUtil.getColor(context, focalColour)); + .setFocalColour(CompatUtil.INSTANCE.getColor(context, focalColour)); return null; } @@ -129,7 +129,7 @@ public TutorialUtil setApplicationPref(ApplicationPref applicationPref) { if (!TapTargetUtil.isActive(tapTarget) && applicationPref.shouldShowTipFor(tapTarget)) return TapTargetUtil.buildDefault(context, primary, secondary, resource) .setPromptStateChangeListener(defaultStateChangeListener) - .setFocalColour(CompatUtil.getColor(context, focalColour)); + .setFocalColour(CompatUtil.INSTANCE.getColor(context, focalColour)); return null; } @@ -149,7 +149,7 @@ public TutorialUtil setApplicationPref(ApplicationPref applicationPref) { if (!TapTargetUtil.isActive(tapTarget) && applicationPref.shouldShowTipFor(tapTarget)) return TapTargetUtil.buildDefault(context, primary, secondary, resource) .setPromptStateChangeListener(defaultStateChangeListener) - .setFocalColour(CompatUtil.getColor(context, focalColour)); + .setFocalColour(CompatUtil.INSTANCE.getColor(context, focalColour)); return null; } @@ -167,7 +167,7 @@ public void showTapTarget(@IdRes int resource) { if (!TapTargetUtil.isActive(tapTarget) && applicationPref.shouldShowTipFor(tapTarget)) TapTargetUtil.buildDefault(context, resource) .setPromptStateChangeListener(defaultStateChangeListener) - .setFocalColour(CompatUtil.getColor(context, focalColour)) + .setFocalColour(CompatUtil.INSTANCE.getColor(context, focalColour)) .show(); } @@ -187,7 +187,7 @@ public void showTapTarget(@StringRes int primary, @StringRes int secondary, @IdR if (!TapTargetUtil.isActive(tapTarget) && applicationPref.shouldShowTipFor(tapTarget)) TapTargetUtil.buildDefault(context, primary, secondary, resource) .setPromptStateChangeListener(defaultStateChangeListener) - .setFocalColour(CompatUtil.getColor(context, focalColour)) + .setFocalColour(CompatUtil.INSTANCE.getColor(context, focalColour)) .show(); } @@ -207,7 +207,7 @@ public void showTapTarget(@StringRes int primary, @StringRes int secondary, View if (!TapTargetUtil.isActive(tapTarget) && applicationPref.shouldShowTipFor(tapTarget)) TapTargetUtil.buildDefault(context, primary, secondary, resource) .setPromptStateChangeListener(defaultStateChangeListener) - .setFocalColour(CompatUtil.getColor(context, focalColour)) + .setFocalColour(CompatUtil.INSTANCE.getColor(context, focalColour)) .show(); } diff --git a/app/src/main/java/com/mxt/anitrend/view/activity/base/AppCompatPreferenceActivity.java b/app/src/main/java/com/mxt/anitrend/view/activity/base/AppCompatPreferenceActivity.java index 2b2efe4e9..a208025ab 100644 --- a/app/src/main/java/com/mxt/anitrend/view/activity/base/AppCompatPreferenceActivity.java +++ b/app/src/main/java/com/mxt/anitrend/view/activity/base/AppCompatPreferenceActivity.java @@ -30,7 +30,7 @@ public abstract class AppCompatPreferenceActivity extends PreferenceActivity { protected void configureActivity() { @StyleRes int style = applicationPref.getTheme(); - if(!CompatUtil.isLightTheme(style) && applicationPref.isBlackThemeEnabled()) + if(!CompatUtil.INSTANCE.isLightTheme(style) && applicationPref.isBlackThemeEnabled()) setTheme(R.style.AppThemeBlack); else setTheme(style); diff --git a/app/src/main/java/com/mxt/anitrend/view/activity/base/GiphyPreviewActivity.java b/app/src/main/java/com/mxt/anitrend/view/activity/base/GiphyPreviewActivity.java index 3755f306d..7c6c3daba 100644 --- a/app/src/main/java/com/mxt/anitrend/view/activity/base/GiphyPreviewActivity.java +++ b/app/src/main/java/com/mxt/anitrend/view/activity/base/GiphyPreviewActivity.java @@ -66,7 +66,7 @@ protected void onPostCreate(@Nullable Bundle savedInstanceState) { */ @Override protected void onActivityReady() { - previewCredits.setImageResource(!CompatUtil.isLightTheme(this) ? R.drawable.powered_by_giphy_light : R.drawable.powered_by_giphy_dark); + previewCredits.setImageResource(!CompatUtil.INSTANCE.isLightTheme(this) ? R.drawable.powered_by_giphy_light : R.drawable.powered_by_giphy_dark); updateUI(); } diff --git a/app/src/main/java/com/mxt/anitrend/view/activity/base/ImagePreviewActivity.java b/app/src/main/java/com/mxt/anitrend/view/activity/base/ImagePreviewActivity.java index ab7c3e30b..5e62b0f2c 100644 --- a/app/src/main/java/com/mxt/anitrend/view/activity/base/ImagePreviewActivity.java +++ b/app/src/main/java/com/mxt/anitrend/view/activity/base/ImagePreviewActivity.java @@ -11,6 +11,7 @@ import android.support.v4.app.ActivityCompat; import android.support.v7.widget.Toolbar; import android.text.TextUtils; +import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.Window; @@ -106,10 +107,15 @@ else if(ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permi startActivity(Intent.createChooser(intent, getResources().getText(R.string.image_preview_share))); return true; case R.id.image_preview_link: - intent = new Intent(); - intent.setAction(Intent.ACTION_VIEW); - intent.setData(Uri.parse(mImageUri)); - startActivity(intent); + try { + intent = new Intent(); + intent.setAction(Intent.ACTION_VIEW); + intent.setData(Uri.parse(mImageUri)); + startActivity(intent); + } catch (Exception e) { + Log.e(toString(), e.getLocalizedMessage()); + NotifyUtil.makeText(this, R.string.text_unknown_error, Toast.LENGTH_SHORT).show(); + } return true; } diff --git a/app/src/main/java/com/mxt/anitrend/view/activity/base/SettingsActivity.java b/app/src/main/java/com/mxt/anitrend/view/activity/base/SettingsActivity.java index 2650e9334..040581d28 100644 --- a/app/src/main/java/com/mxt/anitrend/view/activity/base/SettingsActivity.java +++ b/app/src/main/java/com/mxt/anitrend/view/activity/base/SettingsActivity.java @@ -43,17 +43,17 @@ public class SettingsActivity extends AppCompatPreferenceActivity { private SharedPreferences.OnSharedPreferenceChangeListener onSharedPreferenceChangeListener = (sharedPreferences, key) -> { - if (CompatUtil.equals(key, getString(R.string.pref_key_crash_reports)) || CompatUtil.equals(key, getString(R.string.pref_key_usage_analytics)) || - CompatUtil.equals(key, getString(R.string.pref_key_selected_Language)) || CompatUtil.equals(key, getString(R.string.pref_key_black_theme))) { + if (CompatUtil.INSTANCE.equals(key, getString(R.string.pref_key_crash_reports)) || CompatUtil.INSTANCE.equals(key, getString(R.string.pref_key_usage_analytics)) || + CompatUtil.INSTANCE.equals(key, getString(R.string.pref_key_selected_Language)) || CompatUtil.INSTANCE.equals(key, getString(R.string.pref_key_black_theme))) { // Change the application theme if the current theme is not in dark mode - if (CompatUtil.equals(key, getString(R.string.pref_key_black_theme))) - if(CompatUtil.isLightTheme(getApplicationContext())) + if (CompatUtil.INSTANCE.equals(key, getString(R.string.pref_key_black_theme))) + if(CompatUtil.INSTANCE.isLightTheme(getApplicationContext())) applicationPref.toggleTheme(); Toast.makeText(getApplicationContext(), R.string.text_application_restart_required, Toast.LENGTH_LONG).show(); - } else if (CompatUtil.equals(key, getString(R.string.pref_key_sync_frequency))) { + } else if (CompatUtil.INSTANCE.equals(key, getString(R.string.pref_key_sync_frequency))) { JobSchedulerUtil.INSTANCE.cancelJob(); JobSchedulerUtil.INSTANCE.scheduleJob(getApplicationContext()); - } else if (CompatUtil.equals(key, getString(R.string.pref_key_new_message_notifications))) { + } else if (CompatUtil.INSTANCE.equals(key, getString(R.string.pref_key_new_message_notifications))) { if (applicationPref.isNotificationEnabled()) JobSchedulerUtil.INSTANCE.scheduleJob(getApplicationContext()); else diff --git a/app/src/main/java/com/mxt/anitrend/view/activity/base/SharedContentActivity.java b/app/src/main/java/com/mxt/anitrend/view/activity/base/SharedContentActivity.java index 9ae01d8dc..64cd19803 100644 --- a/app/src/main/java/com/mxt/anitrend/view/activity/base/SharedContentActivity.java +++ b/app/src/main/java/com/mxt/anitrend/view/activity/base/SharedContentActivity.java @@ -116,12 +116,12 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { @Override protected void onPostCreate(@Nullable Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); - bottomSheetBehavior.setPeekHeight(CompatUtil.dipToPx(KeyUtil.PEEK_HEIGHT)); + bottomSheetBehavior.setPeekHeight(CompatUtil.INSTANCE.dipToPx(KeyUtil.PEEK_HEIGHT)); bottomSheetBehavior.setBottomSheetCallback(bottomSheetCallback); bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED); IconArrayAdapter iconArrayAdapter = new IconArrayAdapter(this, R.layout.adapter_spinner_item, R.id.spinner_text, - CompatUtil.getStringList(this, R.array.post_share_types)); + CompatUtil.INSTANCE.getStringList(this, R.array.post_share_types)); iconArrayAdapter.setIndexIconMap(indexIconMap); sharedResourceType.setAdapter(iconArrayAdapter); onActivityReady(); @@ -143,9 +143,9 @@ protected void onActivityReady() { toolbarSearch.setVisibility(View.GONE); toolbarTitle.setText(R.string.menu_title_new_activity_post); if(bottomSheetBehavior.getState() == BottomSheetBehavior.STATE_EXPANDED) - toolbarState.setImageDrawable(CompatUtil.getTintedDrawable(this, R.drawable.ic_keyboard_arrow_down_grey_600_24dp)); + toolbarState.setImageDrawable(CompatUtil.INSTANCE.getTintedDrawable(this, R.drawable.ic_keyboard_arrow_down_grey_600_24dp)); else - toolbarState.setImageDrawable(CompatUtil.getTintedDrawable(this, R.drawable.ic_close_grey_600_24dp)); + toolbarState.setImageDrawable(CompatUtil.INSTANCE.getTintedDrawable(this, R.drawable.ic_close_grey_600_24dp)); toolbarState.setOnClickListener(view -> { switch (bottomSheetBehavior.getState()) { case BottomSheetBehavior.STATE_EXPANDED: @@ -181,12 +181,12 @@ protected void makeRequest() { @Override public void onStateCollapsed() { - toolbarState.setImageDrawable(CompatUtil.getTintedDrawable(this, R.drawable.ic_close_grey_600_24dp)); + toolbarState.setImageDrawable(CompatUtil.INSTANCE.getTintedDrawable(this, R.drawable.ic_close_grey_600_24dp)); } @Override public void onStateExpanded() { - toolbarState.setImageDrawable(CompatUtil.getTintedDrawable(this, R.drawable.ic_keyboard_arrow_down_grey_600_24dp)); + toolbarState.setImageDrawable(CompatUtil.INSTANCE.getTintedDrawable(this, R.drawable.ic_keyboard_arrow_down_grey_600_24dp)); } @Override @Subscribe(threadMode = ThreadMode.MAIN_ORDERED) @@ -239,7 +239,7 @@ public void onItemClick(View target, IntPair data) { mBottomSheet.show(getSupportFragmentManager(), mBottomSheet.getTag()); break; case R.id.widget_flipper: - CompatUtil.hideKeyboard(this); + CompatUtil.INSTANCE.hideKeyboard(this); break; default: DialogUtil.createDialogAttachMedia(target.getId(), binding.composerWidget.getEditor(), this); diff --git a/app/src/main/java/com/mxt/anitrend/view/activity/base/VideoPlayerActivity.java b/app/src/main/java/com/mxt/anitrend/view/activity/base/VideoPlayerActivity.java index a185012a2..8d29ec56d 100644 --- a/app/src/main/java/com/mxt/anitrend/view/activity/base/VideoPlayerActivity.java +++ b/app/src/main/java/com/mxt/anitrend/view/activity/base/VideoPlayerActivity.java @@ -97,7 +97,7 @@ protected void makeRequest() { public void onPause() { super.onPause(); - Jzvd.releaseAllVideos(); + Jzvd.resetAllVideos(); } /** diff --git a/app/src/main/java/com/mxt/anitrend/view/activity/base/WelcomeActivity.java b/app/src/main/java/com/mxt/anitrend/view/activity/base/WelcomeActivity.java index 495100e6a..fc1f790b5 100644 --- a/app/src/main/java/com/mxt/anitrend/view/activity/base/WelcomeActivity.java +++ b/app/src/main/java/com/mxt/anitrend/view/activity/base/WelcomeActivity.java @@ -35,7 +35,7 @@ private AhoyOnboarderCard applyStyle(AhoyOnboarderCard ahoyOnboarderCard) { protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - ahoyPages = new ArrayList<>(CompatUtil.constructListFrom( + ahoyPages = new ArrayList<>(CompatUtil.INSTANCE.constructListFrom( applyStyle(new AhoyOnboarderCard(getString(R.string.app_name), getString(R.string.app_greeting) + " " + getString(R.string.app_provider), R.mipmap.ic_launcher)), @@ -53,7 +53,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { R.drawable.ic_slow_motion_video_white_24dp)) )); } else { - ahoyPages = new ArrayList<>(CompatUtil.constructListFrom( + ahoyPages = new ArrayList<>(CompatUtil.INSTANCE.constructListFrom( applyStyle(new AhoyOnboarderCard(getString(R.string.app_name), getString(R.string.app_greeting) + " " + getString(R.string.app_provider), R.mipmap.ic_launcher)), @@ -87,7 +87,7 @@ protected void onPostCreate(@Nullable Bundle savedInstanceState) { @Override public void onFinishButtonPressed() { View target = findViewById(com.codemybrainsout.onboarder.R.id.btn_skip); - CompatUtil.startRevealAnim(this, target, new Intent(WelcomeActivity.this, MainActivity.class), true); + CompatUtil.INSTANCE.startRevealAnim(this, target, new Intent(WelcomeActivity.this, MainActivity.class), true); } @Override diff --git a/app/src/main/java/com/mxt/anitrend/view/activity/detail/CharacterActivity.java b/app/src/main/java/com/mxt/anitrend/view/activity/detail/CharacterActivity.java index 16c117f94..b1aebfd4e 100644 --- a/app/src/main/java/com/mxt/anitrend/view/activity/detail/CharacterActivity.java +++ b/app/src/main/java/com/mxt/anitrend/view/activity/detail/CharacterActivity.java @@ -126,7 +126,7 @@ protected void updateUI() { @Override protected void makeRequest() { - QueryContainerBuilder queryContainer = GraphUtil.getDefaultQuery(false) + QueryContainerBuilder queryContainer = GraphUtil.INSTANCE.getDefaultQuery(false) .putVariable(KeyUtil.arg_id, id); getViewModel().getParams().putParcelable(KeyUtil.arg_graph_params, queryContainer); getViewModel().requestData(KeyUtil.CHARACTER_BASE_REQ, getApplicationContext()); diff --git a/app/src/main/java/com/mxt/anitrend/view/activity/detail/MediaActivity.java b/app/src/main/java/com/mxt/anitrend/view/activity/detail/MediaActivity.java index e532ff4a0..f0dca6117 100644 --- a/app/src/main/java/com/mxt/anitrend/view/activity/detail/MediaActivity.java +++ b/app/src/main/java/com/mxt/anitrend/view/activity/detail/MediaActivity.java @@ -75,7 +75,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { @Override protected void onPostCreate(@Nullable Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); - mActionBar.setHomeAsUpIndicator(CompatUtil.getDrawable(this, R.drawable.ic_arrow_back_white_24dp)); + mActionBar.setHomeAsUpIndicator(CompatUtil.INSTANCE.getDrawable(this, R.drawable.ic_arrow_back_white_24dp)); onActivityReady(); } @@ -128,7 +128,7 @@ public boolean onOptionsItemSelected(MenuItem item) { protected void onActivityReady() { if(mediaType != null) { BaseStatePageAdapter baseStatePageAdapter = new AnimePageAdapter(getSupportFragmentManager(), getApplicationContext()); - if (!CompatUtil.equals(mediaType, KeyUtil.ANIME)) + if (!CompatUtil.INSTANCE.equals(mediaType, KeyUtil.ANIME)) baseStatePageAdapter = new MangaPageAdapter(getSupportFragmentManager(), getApplicationContext()); baseStatePageAdapter.setParams(getIntent().getExtras()); viewPager.setAdapter(baseStatePageAdapter); @@ -168,7 +168,7 @@ protected void updateUI() { @Override protected void makeRequest() { - QueryContainerBuilder queryContainer = GraphUtil.getDefaultQuery(false) + QueryContainerBuilder queryContainer = GraphUtil.INSTANCE.getDefaultQuery(false) .putVariable(KeyUtil.arg_mediaType, mediaType) .putVariable(KeyUtil.arg_id, id); @@ -192,7 +192,7 @@ public void onChanged(@Nullable MediaBase model) { public void onClick(View view) { switch (view.getId()) { case R.id.series_banner: - CompatUtil.imagePreview(this, view, model.getBannerImage(), R.string.image_preview_error_series_banner); + CompatUtil.INSTANCE.imagePreview(this, view, model.getBannerImage(), R.string.image_preview_error_series_banner); break; } } @@ -206,7 +206,7 @@ protected void onDestroy() { private void setManageMenuItemIcon() { if(model != null && model.getMediaListEntry() != null && manageMenuItem != null) - manageMenuItem.setIcon(CompatUtil.getDrawable(this, R.drawable.ic_mode_edit_white_24dp)); + manageMenuItem.setIcon(CompatUtil.INSTANCE.getDrawable(this, R.drawable.ic_mode_edit_white_24dp)); } private void setFavouriteWidgetMenuItemIcon() { diff --git a/app/src/main/java/com/mxt/anitrend/view/activity/detail/MediaListActivity.java b/app/src/main/java/com/mxt/anitrend/view/activity/detail/MediaListActivity.java index 2b78e971c..e14178fbe 100644 --- a/app/src/main/java/com/mxt/anitrend/view/activity/detail/MediaListActivity.java +++ b/app/src/main/java/com/mxt/anitrend/view/activity/detail/MediaListActivity.java @@ -54,7 +54,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { protected void onPostCreate(@Nullable Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); if(bundle != null) - setTitle(CompatUtil.equals(mediaType, KeyUtil.ANIME) ? R.string.title_anime_list: R.string.title_manga_list); + setTitle(CompatUtil.INSTANCE.equals(mediaType, KeyUtil.ANIME) ? R.string.title_anime_list: R.string.title_manga_list); onActivityReady(); } diff --git a/app/src/main/java/com/mxt/anitrend/view/activity/detail/ProfileActivity.java b/app/src/main/java/com/mxt/anitrend/view/activity/detail/ProfileActivity.java index 283c7621c..3e55a28d9 100644 --- a/app/src/main/java/com/mxt/anitrend/view/activity/detail/ProfileActivity.java +++ b/app/src/main/java/com/mxt/anitrend/view/activity/detail/ProfileActivity.java @@ -64,7 +64,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { @Override protected void onPostCreate(@Nullable Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); - mActionBar.setHomeAsUpIndicator(CompatUtil.getDrawable(this, R.drawable.ic_arrow_back_white_24dp)); + mActionBar.setHomeAsUpIndicator(CompatUtil.INSTANCE.getDrawable(this, R.drawable.ic_arrow_back_white_24dp)); ProfilePageAdapter profilePageAdapter = new ProfilePageAdapter(getSupportFragmentManager(), getApplicationContext()); profilePageAdapter.setParams(getIntent().getExtras()); viewPager.setAdapter(profilePageAdapter); @@ -150,7 +150,7 @@ protected void updateUI() { @Override protected void makeRequest() { - QueryContainerBuilder queryContainer = GraphUtil.getDefaultQuery(false) + QueryContainerBuilder queryContainer = GraphUtil.INSTANCE.getDefaultQuery(false) .putVariable(KeyUtil.arg_userName, userName); if(id > 0) queryContainer.putVariable(KeyUtil.arg_id, id); @@ -179,7 +179,7 @@ public void onChanged(@Nullable UserBase model) { public void onClick(View view) { switch (view.getId()) { case R.id.profile_banner: - CompatUtil.imagePreview(this, view, model.getBannerImage(), R.string.image_preview_error_profile_banner); + CompatUtil.INSTANCE.imagePreview(this, view, model.getBannerImage(), R.string.image_preview_error_profile_banner); break; } } diff --git a/app/src/main/java/com/mxt/anitrend/view/activity/detail/StaffActivity.java b/app/src/main/java/com/mxt/anitrend/view/activity/detail/StaffActivity.java index f1e40c874..f7e494525 100644 --- a/app/src/main/java/com/mxt/anitrend/view/activity/detail/StaffActivity.java +++ b/app/src/main/java/com/mxt/anitrend/view/activity/detail/StaffActivity.java @@ -124,7 +124,7 @@ protected void updateUI() { @Override protected void makeRequest() { - QueryContainerBuilder queryContainer = GraphUtil.getDefaultQuery(false) + QueryContainerBuilder queryContainer = GraphUtil.INSTANCE.getDefaultQuery(false) .putVariable(KeyUtil.arg_id, id); getViewModel().getParams().putParcelable(KeyUtil.arg_graph_params, queryContainer); getViewModel().requestData(KeyUtil.STAFF_BASE_REQ, getApplicationContext()); diff --git a/app/src/main/java/com/mxt/anitrend/view/activity/detail/StudioActivity.java b/app/src/main/java/com/mxt/anitrend/view/activity/detail/StudioActivity.java index 05b1cf989..17a77f3ff 100644 --- a/app/src/main/java/com/mxt/anitrend/view/activity/detail/StudioActivity.java +++ b/app/src/main/java/com/mxt/anitrend/view/activity/detail/StudioActivity.java @@ -122,7 +122,7 @@ protected void updateUI() { @Override protected void makeRequest() { - QueryContainerBuilder queryContainer = GraphUtil.getDefaultQuery(false) + QueryContainerBuilder queryContainer = GraphUtil.INSTANCE.getDefaultQuery(false) .putVariable(KeyUtil.arg_id, id); getViewModel().getParams().putParcelable(KeyUtil.arg_graph_params, queryContainer); getViewModel().requestData(KeyUtil.STUDIO_BASE_REQ, getApplicationContext()); diff --git a/app/src/main/java/com/mxt/anitrend/view/activity/index/LoginActivity.java b/app/src/main/java/com/mxt/anitrend/view/activity/index/LoginActivity.java index e50a36fde..745c4cb3f 100644 --- a/app/src/main/java/com/mxt/anitrend/view/activity/index/LoginActivity.java +++ b/app/src/main/java/com/mxt/anitrend/view/activity/index/LoginActivity.java @@ -221,7 +221,7 @@ public void onChanged(@Nullable WorkInfo workInfo) { if (workInfo != null && workInfo.getState().isFinished()) { Data outputData = workInfo.getOutputData(); if (outputData.getBoolean(KeyUtil.arg_model, false)) { - getViewModel().getParams().putParcelable(KeyUtil.arg_graph_params, GraphUtil.getDefaultQuery(false)); + getViewModel().getParams().putParcelable(KeyUtil.arg_graph_params, GraphUtil.INSTANCE.getDefaultQuery(false)); getViewModel().requestData(KeyUtil.USER_CURRENT_REQ, getApplicationContext()); } else { diff --git a/app/src/main/java/com/mxt/anitrend/view/activity/index/MainActivity.java b/app/src/main/java/com/mxt/anitrend/view/activity/index/MainActivity.java index de19d6f54..9bb4a91fa 100644 --- a/app/src/main/java/com/mxt/anitrend/view/activity/index/MainActivity.java +++ b/app/src/main/java/com/mxt/anitrend/view/activity/index/MainActivity.java @@ -116,10 +116,10 @@ protected void onPostCreate(@Nullable Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) mNavigationView.setItemBackground( - CompatUtil.getDrawable(this, R.drawable.nav_background)); + CompatUtil.INSTANCE.getDrawable(this, R.drawable.nav_background)); mNavigationView.setNavigationItemSelectedListener(this); mViewPager.setOffscreenPageLimit(offScreenLimit); - mPageIndex = DateUtil.getMenuSelect(); + mPageIndex = DateUtil.INSTANCE.getMenuSelect(); menuItems = mNavigationView.getMenu(); onActivityReady(); } @@ -352,7 +352,7 @@ public void onNegativeButton() { public void onPositiveButton() { VersionBase versionBase = getPresenter().getDatabase().getRemoteVersion(); if(versionBase != null && versionBase.isNewerVersion()) - DownloaderService.downloadNewVersion(MainActivity.this, versionBase); + DownloaderService.INSTANCE.downloadNewVersion(MainActivity.this, versionBase); else NotifyUtil.createAlerter(MainActivity.this, getString(R.string.title_update_infodadat), getString(R.string.app_no_date), R.drawable.ic_cloud_done_white_24dp, R.color.colorStateGreen); @@ -495,7 +495,7 @@ public void onClick(View view) { if(user != null) { Intent intent = new Intent(this, ProfileActivity.class); intent.putExtra(KeyUtil.arg_userName, getPresenter().getDatabase().getCurrentUser().getName()); - CompatUtil.startSharedImageTransition(MainActivity.this, mHeaderView, intent, R.string.transition_user_banner); + CompatUtil.INSTANCE.startSharedImageTransition(MainActivity.this, mHeaderView, intent, R.string.transition_user_banner); } else NotifyUtil.makeText(getApplicationContext(), R.string.text_error_login, Toast.LENGTH_SHORT).show(); } diff --git a/app/src/main/java/com/mxt/anitrend/view/activity/index/SplashActivity.java b/app/src/main/java/com/mxt/anitrend/view/activity/index/SplashActivity.java index 4e0470bf4..a091a8bc7 100644 --- a/app/src/main/java/com/mxt/anitrend/view/activity/index/SplashActivity.java +++ b/app/src/main/java/com/mxt/anitrend/view/activity/index/SplashActivity.java @@ -39,7 +39,7 @@ protected void onCreate(Bundle savedInstanceState) { @Override protected void onPostCreate(@Nullable Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); - giphyCitation.setImageResource(!CompatUtil.isLightTheme(this) ? R.drawable.powered_by_giphy_light : R.drawable.powered_by_giphy_dark); + giphyCitation.setImageResource(!CompatUtil.INSTANCE.isLightTheme(this) ? R.drawable.powered_by_giphy_light : R.drawable.powered_by_giphy_dark); onActivityReady(); } @@ -68,7 +68,7 @@ protected void updateUI() { protected void makeRequest() { VersionBase versionBase = getPresenter().getDatabase().getRemoteVersion(); // How frequent the application checks for updates on startup - if(versionBase == null || DateUtil.timeDifferenceSatisfied(KeyUtil.TIME_UNIT_HOURS, versionBase.getLastChecked(), 2)) { + if(versionBase == null || DateUtil.INSTANCE.timeDifferenceSatisfied(KeyUtil.TIME_UNIT_HOURS, versionBase.getLastChecked(), 2)) { getViewModel().getParams().putString(KeyUtil.arg_branch_name, getPresenter().getApplicationPref().getUpdateChannel()); getViewModel().requestData(KeyUtil.UPDATE_CHECKER_REQ, getApplicationContext()); } diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/BrowseReviewFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/BrowseReviewFragment.java index db5485153..ffe3272d9 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/BrowseReviewFragment.java +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/BrowseReviewFragment.java @@ -80,16 +80,16 @@ public boolean onOptionsItemSelected(MenuItem item) { if (getContext() != null) switch (item.getItemId()) { case R.id.action_sort: - DialogUtil.createSelection(getContext(), R.string.app_filter_sort, CompatUtil.getIndexOf(KeyUtil.ReviewSortType, - getPresenter().getApplicationPref().getReviewSort()), CompatUtil.capitalizeWords(KeyUtil.ReviewSortType), + DialogUtil.createSelection(getContext(), R.string.app_filter_sort, CompatUtil.INSTANCE.getIndexOf(KeyUtil.ReviewSortType, + getPresenter().getApplicationPref().getReviewSort()), CompatUtil.INSTANCE.capitalizeWords(KeyUtil.ReviewSortType), (dialog, which) -> { if(which == DialogAction.POSITIVE) getPresenter().getApplicationPref().setReviewSort(KeyUtil.ReviewSortType[dialog.getSelectedIndex()]); }); return true; case R.id.action_order: - DialogUtil.createSelection(getContext(), R.string.app_filter_order, CompatUtil.getIndexOf(KeyUtil.SortOrderType, - getPresenter().getApplicationPref().getSortOrder()), CompatUtil.getStringList(getContext(), R.array.order_by_types), + DialogUtil.createSelection(getContext(), R.string.app_filter_order, CompatUtil.INSTANCE.getIndexOf(KeyUtil.SortOrderType, + getPresenter().getApplicationPref().getSortOrder()), CompatUtil.INSTANCE.getStringList(getContext(), R.array.order_by_types), (dialog, which) -> { if(which == DialogAction.POSITIVE) getPresenter().getApplicationPref().saveSortOrder(KeyUtil.SortOrderType[dialog.getSelectedIndex()]); @@ -113,7 +113,7 @@ protected void updateUI() { @Override public void makeRequest() { ApplicationPref pref = getPresenter().getApplicationPref(); - QueryContainerBuilder queryContainer = GraphUtil.getDefaultQuery(true) + QueryContainerBuilder queryContainer = GraphUtil.INSTANCE.getDefaultQuery(true) .putVariable(KeyUtil.arg_mediaType, mediaType) .putVariable(KeyUtil.arg_page, getPresenter().getCurrentPage()) .putVariable(KeyUtil.arg_sort, pref.getReviewSort() + pref.getSortOrder()); @@ -152,7 +152,7 @@ public void onItemClick(View target, IntPair data) { Intent intent = new Intent(getActivity(), MediaActivity.class); intent.putExtra(KeyUtil.arg_id, mediaBase.getId()); intent.putExtra(KeyUtil.arg_mediaType, mediaBase.getType()); - CompatUtil.startRevealAnim(getActivity(), target, intent); + CompatUtil.INSTANCE.startRevealAnim(getActivity(), target, intent); break; case R.id.review_read_more: mBottomSheet = new BottomReviewReader.Builder() diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/CharacterOverviewFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/CharacterOverviewFragment.java index 684142b5d..914c2b83f 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/CharacterOverviewFragment.java +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/CharacterOverviewFragment.java @@ -63,7 +63,7 @@ protected void updateUI() { binding.setModel(model); binding.stateLayout.showContent(); } else - binding.stateLayout.showError(CompatUtil.getDrawable(getContext(), R.drawable.ic_warning_white_18dp, R.color.colorStateBlue), + binding.stateLayout.showError(CompatUtil.INSTANCE.getDrawable(getContext(), R.drawable.ic_warning_white_18dp, R.color.colorStateBlue), getString(R.string.layout_empty_response), getString(R.string.try_again), (view) -> makeRequest()); } @@ -78,7 +78,7 @@ public void onStart() { @Override public void makeRequest() { - QueryContainerBuilder queryContainer = GraphUtil.getDefaultQuery(false) + QueryContainerBuilder queryContainer = GraphUtil.INSTANCE.getDefaultQuery(false) .putVariable(KeyUtil.arg_id, id); getViewModel().getParams().putParcelable(KeyUtil.arg_graph_params, queryContainer); getViewModel().requestData(KeyUtil.CHARACTER_OVERVIEW_REQ, getContext()); @@ -93,7 +93,7 @@ public void makeRequest() { public void onClick(View view) { switch (view.getId()) { case R.id.character_img: - CompatUtil.imagePreview(getActivity(), view, model.getImage().getLarge(), R.string.image_preview_error_character_image); + CompatUtil.INSTANCE.imagePreview(getActivity(), view, model.getImage().getLarge(), R.string.image_preview_error_character_image); break; default: super.onClick(view); diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/CommentFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/CommentFragment.java index a50083b87..aedf443b6 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/CommentFragment.java +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/CommentFragment.java @@ -125,7 +125,7 @@ public void onItemClick(View target, IntPair data) { showBottomSheet(); break; case R.id.widget_flipper: - CompatUtil.hideKeyboard(getActivity()); + CompatUtil.INSTANCE.hideKeyboard(getActivity()); break; default: DialogUtil.createDialogAttachMedia(target.getId(), composerWidget.getEditor(), getContext()); @@ -159,7 +159,7 @@ public void makeRequest() { initExtraComponents(); } - QueryContainerBuilder queryContainer = GraphUtil.getDefaultQuery(false) + QueryContainerBuilder queryContainer = GraphUtil.INSTANCE.getDefaultQuery(false) .putVariable(KeyUtil.arg_id, userActivityId); getViewModel().getParams().putParcelable(KeyUtil.arg_graph_params, queryContainer); getViewModel().requestData(KeyUtil.FEED_LIST_REPLY_REQ, getContext()); @@ -191,7 +191,7 @@ public void onItemClick(View target, IntPair data) { intent = new Intent(getActivity(), MediaActivity.class); intent.putExtra(KeyUtil.arg_id, data.getSecond().getMedia().getId()); intent.putExtra(KeyUtil.arg_mediaType, data.getSecond().getMedia().getType()); - CompatUtil.startRevealAnim(getActivity(), target, intent); + CompatUtil.INSTANCE.startRevealAnim(getActivity(), target, intent); break; case R.id.widget_users: List likes = data.getSecond().getLikes(); @@ -208,19 +208,19 @@ public void onItemClick(View target, IntPair data) { intent = new Intent(getActivity(), ProfileActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.putExtra(KeyUtil.arg_id, data.getSecond().getUser().getId()); - CompatUtil.startRevealAnim(getActivity(), target, intent); + CompatUtil.INSTANCE.startRevealAnim(getActivity(), target, intent); break; case R.id.recipient_avatar: intent = new Intent(getActivity(), ProfileActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.putExtra(KeyUtil.arg_id, data.getSecond().getRecipient().getId()); - CompatUtil.startRevealAnim(getActivity(), target, intent); + CompatUtil.INSTANCE.startRevealAnim(getActivity(), target, intent); break; case R.id.messenger_avatar: intent = new Intent(getActivity(), ProfileActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.putExtra(KeyUtil.arg_id, data.getSecond().getMessenger().getId()); - CompatUtil.startRevealAnim(getActivity(), target, intent); + CompatUtil.INSTANCE.startRevealAnim(getActivity(), target, intent); break; } } @@ -255,7 +255,7 @@ public void onModelChanged(BaseConsumer consumer) { swipeRefreshLayout.setRefreshing(true); onRefresh(); } else { - pairOptional = CompatUtil.findIndexOf(mAdapter.getData(), consumer.getChangeModel()); + pairOptional = CompatUtil.INSTANCE.findIndexOf(mAdapter.getData(), consumer.getChangeModel()); if(pairOptional.isPresent()) { pairIndex = pairOptional.get().getFirst(); mAdapter.onItemChanged(consumer.getChangeModel(), pairIndex); @@ -263,7 +263,7 @@ public void onModelChanged(BaseConsumer consumer) { } break; case KeyUtil.MUT_DELETE_FEED_REPLY: - pairOptional = CompatUtil.findIndexOf(mAdapter.getData(), consumer.getChangeModel()); + pairOptional = CompatUtil.INSTANCE.findIndexOf(mAdapter.getData(), consumer.getChangeModel()); if(pairOptional.isPresent()) { pairIndex = pairOptional.get().getFirst(); mAdapter.onItemRemoved(pairIndex); @@ -313,7 +313,7 @@ public void onItemClick(View target, IntPair data) { intent = new Intent(getActivity(), MediaActivity.class); intent.putExtra(KeyUtil.arg_id, mediaBase.getId()); intent.putExtra(KeyUtil.arg_mediaType, mediaBase.getType()); - CompatUtil.startRevealAnim(getActivity(), target, intent); + CompatUtil.INSTANCE.startRevealAnim(getActivity(), target, intent); break; case R.id.widget_mention: composerWidget.mentionUserFrom(data.getSecond()); @@ -337,7 +337,7 @@ public void onItemClick(View target, IntPair data) { intent = new Intent(getActivity(), ProfileActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.putExtra(KeyUtil.arg_id, data.getSecond().getUser().getId()); - CompatUtil.startRevealAnim(getActivity(), target, intent); + CompatUtil.INSTANCE.startRevealAnim(getActivity(), target, intent); break; } } diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/MediaOverviewFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/MediaOverviewFragment.java index ced40124f..2176381a3 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/MediaOverviewFragment.java +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/MediaOverviewFragment.java @@ -98,7 +98,7 @@ public void onStart() { */ @Override protected void updateUI() { - if(getActivity() != null && model.getTrailer() != null && CompatUtil.equals(model.getTrailer().getSite(), "youtube")) { + if(getActivity() != null && model.getTrailer() != null && CompatUtil.INSTANCE.equals(model.getTrailer().getSite(), "youtube")) { if(YouTubeIntents.canResolvePlayVideoIntent(getActivity())) { if (youtubePlayerFragment == null) youtubePlayerFragment = YoutubePlayerFragment.newInstance(model.getTrailer()); @@ -115,6 +115,14 @@ protected void updateUI() { binding.setPresenter(getPresenter()); binding.setModel(model); + + if (model.getTags() != null && model.getTagsNoSpoilers() != null) { + if (model.getTagsNoSpoilers().size() == model.getTags().size()) + binding.showSpoilerTags.setVisibility(View.GONE); + else + binding.showSpoilerTags.setVisibility(View.VISIBLE); + } + if(genreAdapter == null) { genreAdapter = new GenreAdapter(getContext()); genreAdapter.onItemsInserted(getPresenter().buildGenres(model)); @@ -125,7 +133,7 @@ public void onItemClick(View target, IntPair data) { case R.id.container: Bundle args = new Bundle(); Intent intent = new Intent(getActivity(), MediaBrowseActivity.class); - args.putParcelable(KeyUtil.arg_graph_params, GraphUtil.getDefaultQuery(true) + args.putParcelable(KeyUtil.arg_graph_params, GraphUtil.INSTANCE.getDefaultQuery(true) .putVariable(KeyUtil.arg_type, mediaType) .putVariable(KeyUtil.arg_genres, data.getSecond().getGenre())); args.putString(KeyUtil.arg_activity_tag, data.getSecond().getGenre()); @@ -161,7 +169,7 @@ public void onItemClick(View target, IntPair data) { case POSITIVE: Bundle args = new Bundle(); Intent intent = new Intent(getActivity(), MediaBrowseActivity.class); - args.putParcelable(KeyUtil.arg_graph_params, GraphUtil.getDefaultQuery(true) + args.putParcelable(KeyUtil.arg_graph_params, GraphUtil.INSTANCE.getDefaultQuery(true) .putVariable(KeyUtil.arg_type, mediaType) .putVariable(KeyUtil.arg_tags, data.getSecond().getName())); args.putString(KeyUtil.arg_activity_tag, data.getSecond().getName()); @@ -194,7 +202,7 @@ public void onItemLongClick(View target, IntPair data) { */ @Override public void makeRequest() { - QueryContainerBuilder queryContainer = GraphUtil.getDefaultQuery(isPager) + QueryContainerBuilder queryContainer = GraphUtil.INSTANCE.getDefaultQuery(isPager) .putVariable(KeyUtil.arg_id, mediaId) .putVariable(KeyUtil.arg_type, mediaType); getViewModel().getParams().putParcelable(KeyUtil.arg_graph_params, queryContainer); @@ -212,7 +220,7 @@ public void onChanged(@Nullable Media model) { this.model = model; updateUI(); } else - binding.stateLayout.showError(CompatUtil.getDrawable(getContext(), R.drawable.ic_emoji_sweat), + binding.stateLayout.showError(CompatUtil.INSTANCE.getDrawable(getContext(), R.drawable.ic_emoji_sweat), getString(R.string.layout_empty_response), getString(R.string.try_again), view -> { binding.stateLayout.showLoading(); makeRequest(); }); } @@ -226,7 +234,7 @@ public void onClick(View v) { Intent intent; switch (v.getId()) { case R.id.series_image: - CompatUtil.imagePreview(getActivity(), v, model.getCoverImage().getLarge(), R.string.image_preview_error_series_cover); + CompatUtil.INSTANCE.imagePreview(getActivity(), v, model.getCoverImage().getLarge(), R.string.image_preview_error_series_cover); break; case R.id.anime_main_studio_container: StudioBase studioBase = getPresenter().getMainStudioObject(model); @@ -239,7 +247,7 @@ public void onClick(View v) { case R.id.show_spoiler_tags: tagAdapter.onItemRangeChanged(model.getTags()); tagAdapter.notifyDataSetChanged(); - v.setVisibility(View.INVISIBLE); + v.setVisibility(View.GONE); break; default: super.onClick(v); diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/MediaStaffFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/MediaStaffFragment.java index 1e02503f5..6d67fab70 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/MediaStaffFragment.java +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/MediaStaffFragment.java @@ -70,7 +70,7 @@ protected void updateUI() { */ @Override public void makeRequest() { - QueryContainerBuilder queryContainer = GraphUtil.getDefaultQuery(isPager) + QueryContainerBuilder queryContainer = GraphUtil.INSTANCE.getDefaultQuery(isPager) .putVariable(KeyUtil.arg_id, mediaId) .putVariable(KeyUtil.arg_type, mediaType) .putVariable(KeyUtil.arg_page, getPresenter().getCurrentPage()); @@ -87,7 +87,7 @@ public void onChanged(@Nullable ConnectionContainer> co if (edgeContainer.hasPageInfo()) getPresenter().setPageInfo(edgeContainer.getPageInfo()); if (!edgeContainer.isEmpty()) - onPostProcessed(GroupingUtil.groupStaffByRole(edgeContainer.getEdges(), mAdapter.getData())); + onPostProcessed(GroupingUtil.INSTANCE.groupStaffByRole(edgeContainer.getEdges(), mAdapter.getData())); else onPostProcessed(Collections.emptyList()); } @@ -110,7 +110,7 @@ public void onItemClick(View target, IntPair data) { case R.id.container: Intent intent = new Intent(getActivity(), StaffActivity.class); intent.putExtra(KeyUtil.arg_id, ((StaffBase)data.getSecond()).getId()); - CompatUtil.startRevealAnim(getActivity(), target, intent); + CompatUtil.INSTANCE.startRevealAnim(getActivity(), target, intent); break; } } diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/MediaStatsFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/MediaStatsFragment.java index f6420af1b..8ca5a5b8a 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/MediaStatsFragment.java +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/MediaStatsFragment.java @@ -111,7 +111,7 @@ protected void updateUI() { public void onItemClick(View target, IntPair data) { Intent intent = new Intent(getActivity(), MediaBrowseActivity.class); Bundle args = new Bundle(); - QueryContainerBuilder queryContainer = GraphUtil.getDefaultQuery(true) + QueryContainerBuilder queryContainer = GraphUtil.INSTANCE.getDefaultQuery(true) .putVariable(KeyUtil.arg_type, mediaType) .putVariable(KeyUtil.arg_format, data.getSecond().getFormat()); @@ -180,7 +180,7 @@ public void onItemLongClick(View target, IntPair data) { */ @Override public void makeRequest() { - QueryContainerBuilder queryContainer = GraphUtil.getDefaultQuery(false) + QueryContainerBuilder queryContainer = GraphUtil.INSTANCE.getDefaultQuery(false) .putVariable(KeyUtil.arg_id, mediaId) .putVariable(KeyUtil.arg_type, mediaType); getViewModel().getParams().putParcelable(KeyUtil.arg_graph_params, queryContainer); @@ -197,9 +197,9 @@ private void showScoreDistribution() { configureScoreDistribution(model.getStats().getScoreDistribution()); if (getContext() != null) - barDataSet.setColor(CompatUtil.getColorFromAttr(getContext(), R.attr.colorAccent), 200); + barDataSet.setColor(CompatUtil.INSTANCE.getColorFromAttr(getContext(), R.attr.colorAccent), 200); - barDataSet.setValueTextColor(CompatUtil.getColorFromAttr(getContext(), R.attr.titleColor)); + barDataSet.setValueTextColor(CompatUtil.INSTANCE.getColorFromAttr(getContext(), R.attr.titleColor)); BarData barData = new BarData(barDataSet); barData.setBarWidth(0.6f); @@ -229,13 +229,13 @@ private void showStatusDistribution() { PieData pieData = new PieData(pieDataSet); if (getContext() != null) - pieData.setValueTextColor(CompatUtil.getColorFromAttr(getContext(), R.attr.titleColor)); + pieData.setValueTextColor(CompatUtil.INSTANCE.getColorFromAttr(getContext(), R.attr.titleColor)); pieData.setValueTextSize(9f); pieData.setValueFormatter(new PercentFormatter()); - binding.seriesStats.getLegend().setTextColor(CompatUtil.getColorFromAttr(getContext(), R.attr.titleColor)); - binding.seriesStats.setHoleColor(CompatUtil.getColorFromAttr(getContext(), R.attr.color)); + binding.seriesStats.getLegend().setTextColor(CompatUtil.INSTANCE.getColorFromAttr(getContext(), R.attr.titleColor)); + binding.seriesStats.setHoleColor(CompatUtil.INSTANCE.getColorFromAttr(getContext(), R.attr.color)); binding.seriesStats.setData(pieData); binding.seriesStats.invalidate(); } @@ -252,7 +252,7 @@ public void onChanged(@Nullable Media model) { this.model = model; updateUI(); } else - binding.stateLayout.showError(CompatUtil.getDrawable(getContext(), R.drawable.ic_emoji_sweat), + binding.stateLayout.showError(CompatUtil.INSTANCE.getDrawable(getContext(), R.drawable.ic_emoji_sweat), getString(R.string.layout_empty_response), getString(R.string.try_again), view -> { binding.stateLayout.showLoading(); makeRequest(); }); } diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/MessageFeedFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/MessageFeedFragment.java index d08982684..540adb539 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/MessageFeedFragment.java +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/MessageFeedFragment.java @@ -52,7 +52,7 @@ protected void updateUI() { @Override public void makeRequest() { - queryContainer = GraphUtil.getDefaultQuery(true); + queryContainer = GraphUtil.INSTANCE.getDefaultQuery(true); queryContainer.putVariable(KeyUtil.arg_page, getPresenter().getCurrentPage()) .putVariable(messageType == KeyUtil.MESSAGE_TYPE_INBOX ? KeyUtil.arg_userId : KeyUtil.arg_messengerId, userId); getViewModel().getParams().putParcelable(KeyUtil.arg_graph_params, queryContainer); @@ -68,7 +68,7 @@ public void onItemClick(View target, IntPair data) { intent = new Intent(getActivity(), ProfileActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.putExtra(KeyUtil.arg_id, data.getSecond().getMessenger().getId()); - CompatUtil.startRevealAnim(getActivity(), target, intent); + CompatUtil.INSTANCE.startRevealAnim(getActivity(), target, intent); } break; case R.id.recipient_avatar: @@ -76,7 +76,7 @@ public void onItemClick(View target, IntPair data) { intent = new Intent(getActivity(), ProfileActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.putExtra(KeyUtil.arg_id, data.getSecond().getRecipient().getId()); - CompatUtil.startRevealAnim(getActivity(), target, intent); + CompatUtil.INSTANCE.startRevealAnim(getActivity(), target, intent); } break; case R.id.widget_edit: diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/NotificationFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/NotificationFragment.java index 89064fd90..7a3cc5f97 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/NotificationFragment.java +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/NotificationFragment.java @@ -113,8 +113,13 @@ public void onChanged(@Nullable PageContainer content) { if(content != null) { if(content.hasPageInfo()) getPresenter().setPageInfo(content.getPageInfo()); - if(!content.isEmpty()) - onPostProcessed(content.getPageData()); + if(!content.isEmpty()) { + List notifications = GraphUtil.INSTANCE.filterNotificationList( + getPresenter(), + content.getPageData() + ); + onPostProcessed(notifications); + } else onPostProcessed(Collections.emptyList()); } else @@ -128,7 +133,7 @@ public void onChanged(@Nullable PageContainer content) { */ @Override public void makeRequest() { - QueryContainerBuilder queryContainer = GraphUtil.getDefaultQuery(isPager) + QueryContainerBuilder queryContainer = GraphUtil.INSTANCE.getDefaultQuery(isPager) .putVariable(KeyUtil.arg_page, getPresenter().getCurrentPage()) .putVariable(KeyUtil.arg_resetNotificationCount, true); getViewModel().getParams().putParcelable(KeyUtil.arg_graph_params, queryContainer); @@ -150,7 +155,7 @@ private void setItemAsRead(final Notification data) { .map(item -> new NotificationHistory(item.getId())) .toList(); - if (!CompatUtil.isEmpty(dismissibleNotifications)) + if (!CompatUtil.INSTANCE.isEmpty(dismissibleNotifications)) getPresenter().getDatabase().getBoxStore(NotificationHistory.class) .put(dismissibleNotifications); else @@ -192,27 +197,27 @@ private void markAllNotificationsAsRead() { public void onItemClick(View target, IntPair data) { Intent intent; setItemAsRead(data.getSecond()); - if(target.getId() == R.id.notification_img && !CompatUtil.equals(data.getSecond().getType(), KeyUtil.AIRING)) { + if(target.getId() == R.id.notification_img && !CompatUtil.INSTANCE.equals(data.getSecond().getType(), KeyUtil.AIRING)) { intent = new Intent(getActivity(), ProfileActivity.class); intent.putExtra(KeyUtil.arg_id, data.getSecond().getUser().getId()); - CompatUtil.startRevealAnim(getActivity(), target, intent); + CompatUtil.INSTANCE.startRevealAnim(getActivity(), target, intent); } else switch (data.getSecond().getType()) { case KeyUtil.ACTIVITY_MESSAGE: intent = new Intent(getActivity(), CommentActivity.class); intent.putExtra(KeyUtil.arg_id, data.getSecond().getActivityId()); - CompatUtil.startRevealAnim(getActivity(), target, intent); + CompatUtil.INSTANCE.startRevealAnim(getActivity(), target, intent); break; case KeyUtil.FOLLOWING: intent = new Intent(getActivity(), ProfileActivity.class); intent.putExtra(KeyUtil.arg_id, data.getSecond().getUser().getId()); - CompatUtil.startRevealAnim(getActivity(), target, intent); + CompatUtil.INSTANCE.startRevealAnim(getActivity(), target, intent); break; case KeyUtil.ACTIVITY_MENTION: intent = new Intent(getActivity(), CommentActivity.class); intent.putExtra(KeyUtil.arg_id, data.getSecond().getActivityId()); - CompatUtil.startRevealAnim(getActivity(), target, intent); + CompatUtil.INSTANCE.startRevealAnim(getActivity(), target, intent); break; case KeyUtil.THREAD_COMMENT_MENTION: DialogUtil.createMessage(getContext(), data.getSecond().getUser().getName(), data.getSecond().getContext()); @@ -228,23 +233,23 @@ public void onItemClick(View target, IntPair data) { intent.putExtra(KeyUtil.arg_id, data.getSecond().getMedia().getId()); intent.putExtra(KeyUtil.arg_mediaType, data.getSecond().getMedia().getType()); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - CompatUtil.startRevealAnim(getActivity(), target, intent); + CompatUtil.INSTANCE.startRevealAnim(getActivity(), target, intent); break; case KeyUtil.ACTIVITY_LIKE: intent = new Intent(getActivity(), CommentActivity.class); intent.putExtra(KeyUtil.arg_id, data.getSecond().getActivityId()); - CompatUtil.startRevealAnim(getActivity(), target, intent); + CompatUtil.INSTANCE.startRevealAnim(getActivity(), target, intent); break; case KeyUtil.ACTIVITY_REPLY: case KeyUtil.ACTIVITY_REPLY_SUBSCRIBED: intent = new Intent(getActivity(), CommentActivity.class); intent.putExtra(KeyUtil.arg_id, data.getSecond().getActivityId()); - CompatUtil.startRevealAnim(getActivity(), target, intent); + CompatUtil.INSTANCE.startRevealAnim(getActivity(), target, intent); break; case KeyUtil.ACTIVITY_REPLY_LIKE: intent = new Intent(getActivity(), CommentActivity.class); intent.putExtra(KeyUtil.arg_id, data.getSecond().getActivityId()); - CompatUtil.startRevealAnim(getActivity(), target, intent); + CompatUtil.INSTANCE.startRevealAnim(getActivity(), target, intent); break; case KeyUtil.THREAD_LIKE: DialogUtil.createMessage(getContext(), data.getSecond().getUser().getName(), data.getSecond().getContext()); @@ -264,7 +269,7 @@ public void onItemClick(View target, IntPair data) { */ @Override public void onItemLongClick(View target, IntPair data) { - if(CompatUtil.equals(data.getSecond().getType(), KeyUtil.AIRING)) { + if(CompatUtil.INSTANCE.equals(data.getSecond().getType(), KeyUtil.AIRING)) { setItemAsRead(data.getSecond()); if(getPresenter().getApplicationPref().isAuthenticated()) { mediaActionUtil = new MediaActionUtil.Builder() diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/ReviewFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/ReviewFragment.java index e90fc7f49..1a82e05e8 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/ReviewFragment.java +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/ReviewFragment.java @@ -75,7 +75,7 @@ protected void updateUI() { public void makeRequest() { if(mediaId == 0) return; - QueryContainerBuilder queryContainer = GraphUtil.getDefaultQuery(isPager) + QueryContainerBuilder queryContainer = GraphUtil.INSTANCE.getDefaultQuery(isPager) .putVariable(KeyUtil.arg_mediaId, mediaId) .putVariable(KeyUtil.arg_mediaType, mediaType) .putVariable(KeyUtil.arg_page, getPresenter().getCurrentPage()); @@ -114,14 +114,14 @@ public void onItemClick(View target, IntPair data) { intent = new Intent(getActivity(), MediaActivity.class); intent.putExtra(KeyUtil.arg_id, mediaBase.getId()); intent.putExtra(KeyUtil.arg_mediaType, mediaBase.getType()); - CompatUtil.startRevealAnim(getActivity(), target, intent); + CompatUtil.INSTANCE.startRevealAnim(getActivity(), target, intent); break; case R.id.user_avatar: if(getPresenter().getApplicationPref().isAuthenticated()) { intent = new Intent(getActivity(), ProfileActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.putExtra(KeyUtil.arg_id, data.getSecond().getUser().getId()); - CompatUtil.startRevealAnim(getActivity(), target, intent); + CompatUtil.INSTANCE.startRevealAnim(getActivity(), target, intent); } else NotifyUtil.makeText(getActivity(), R.string.info_login_req, R.drawable.ic_warning_white_18dp, Toast.LENGTH_SHORT).show(); break; diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/StaffOverviewFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/StaffOverviewFragment.java index 5c23be3b5..237ca6b38 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/StaffOverviewFragment.java +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/StaffOverviewFragment.java @@ -63,7 +63,7 @@ protected void updateUI() { binding.setModel(model); binding.stateLayout.showContent(); } else - binding.stateLayout.showError(CompatUtil.getDrawable(getContext(), R.drawable.ic_emoji_sweat), + binding.stateLayout.showError(CompatUtil.INSTANCE.getDrawable(getContext(), R.drawable.ic_emoji_sweat), getString(R.string.layout_empty_response), getString(R.string.try_again), (view) -> makeRequest()); } @@ -78,7 +78,7 @@ public void onStart() { @Override public void makeRequest() { - QueryContainerBuilder queryContainer = GraphUtil.getDefaultQuery(false) + QueryContainerBuilder queryContainer = GraphUtil.INSTANCE.getDefaultQuery(false) .putVariable(KeyUtil.arg_id, id); getViewModel().getParams().putParcelable(KeyUtil.arg_graph_params, queryContainer); getViewModel().requestData(KeyUtil.STAFF_OVERVIEW_REQ, getContext()); @@ -94,7 +94,7 @@ public void makeRequest() { public void onClick(View view) { switch (view.getId()) { case R.id.staff_img: - CompatUtil.imagePreview(getActivity(), view, model.getImage().getLarge(), R.string.image_preview_error_staff_image); + CompatUtil.INSTANCE.imagePreview(getActivity(), view, model.getImage().getLarge(), R.string.image_preview_error_staff_image); break; default: super.onClick(view); diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/StudioMediaFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/StudioMediaFragment.java index 913e9c629..5eb47e187 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/StudioMediaFragment.java +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/StudioMediaFragment.java @@ -72,16 +72,16 @@ public boolean onOptionsItemSelected(MenuItem item) { if(getContext() != null) switch (item.getItemId()) { case R.id.action_sort: - DialogUtil.createSelection(getContext(), R.string.app_filter_sort, CompatUtil.getIndexOf(KeyUtil.MediaSortType, - getPresenter().getApplicationPref().getMediaSort()), CompatUtil.capitalizeWords(KeyUtil.MediaSortType), + DialogUtil.createSelection(getContext(), R.string.app_filter_sort, CompatUtil.INSTANCE.getIndexOf(KeyUtil.MediaSortType, + getPresenter().getApplicationPref().getMediaSort()), CompatUtil.INSTANCE.capitalizeWords(KeyUtil.MediaSortType), (dialog, which) -> { if(which == DialogAction.POSITIVE) getPresenter().getApplicationPref().setMediaSort(KeyUtil.MediaSortType[dialog.getSelectedIndex()]); }); return true; case R.id.action_order: - DialogUtil.createSelection(getContext(), R.string.app_filter_order, CompatUtil.getIndexOf(KeyUtil.SortOrderType, - getPresenter().getApplicationPref().getSortOrder()), CompatUtil.getStringList(getContext(), R.array.order_by_types), + DialogUtil.createSelection(getContext(), R.string.app_filter_order, CompatUtil.INSTANCE.getIndexOf(KeyUtil.SortOrderType, + getPresenter().getApplicationPref().getSortOrder()), CompatUtil.INSTANCE.getStringList(getContext(), R.array.order_by_types), (dialog, which) -> { if(which == DialogAction.POSITIVE) getPresenter().getApplicationPref().saveSortOrder(KeyUtil.SortOrderType[dialog.getSelectedIndex()]); @@ -100,7 +100,7 @@ protected void updateUI() { @Override public void makeRequest() { ApplicationPref pref = getPresenter().getApplicationPref(); - QueryContainerBuilder queryContainer = GraphUtil.getDefaultQuery(isPager) + QueryContainerBuilder queryContainer = GraphUtil.INSTANCE.getDefaultQuery(isPager) .putVariable(KeyUtil.arg_id, id) .putVariable(KeyUtil.arg_page, getPresenter().getCurrentPage()) .putVariable(KeyUtil.arg_sort, pref.getMediaSort() + pref.getSortOrder()); @@ -140,7 +140,7 @@ public void onItemClick(View target, IntPair data) { Intent intent = new Intent(getActivity(), MediaActivity.class); intent.putExtra(KeyUtil.arg_id, data.getSecond().getId()); intent.putExtra(KeyUtil.arg_mediaType, data.getSecond().getType()); - CompatUtil.startRevealAnim(getActivity(), target, intent); + CompatUtil.INSTANCE.startRevealAnim(getActivity(), target, intent); break; } } diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/UserOverviewFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/UserOverviewFragment.java index ed140eef5..6f2a20817 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/UserOverviewFragment.java +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/UserOverviewFragment.java @@ -112,7 +112,7 @@ protected void updateUI() { */ @Override public void makeRequest() { - QueryContainerBuilder queryContainer = GraphUtil.getDefaultQuery(false) + QueryContainerBuilder queryContainer = GraphUtil.INSTANCE.getDefaultQuery(false) .putVariable(KeyUtil.arg_userName, userName); if(userId > 0) queryContainer.putVariable(KeyUtil.arg_id, userId); @@ -131,7 +131,7 @@ public void onChanged(@Nullable User model) { this.model = model; updateUI(); } else - binding.stateLayout.showError(CompatUtil.getDrawable(getContext(), R.drawable.ic_emoji_sweat), + binding.stateLayout.showError(CompatUtil.INSTANCE.getDrawable(getContext(), R.drawable.ic_emoji_sweat), getString(R.string.layout_empty_response), getString(R.string.try_again), view -> { binding.stateLayout.showLoading(); makeRequest(); }); } @@ -153,7 +153,7 @@ public void onDestroyView() { private List generateStatsData() { List userGenreStats = new ArrayList<>(); - if(model.getStats() != null && !CompatUtil.isEmpty(model.getStats().getFavouredGenres())) { + if(model.getStats() != null && !CompatUtil.INSTANCE.isEmpty(model.getStats().getFavouredGenres())) { int highestValue = Stream.of(model.getStats().getFavouredGenres()) .max((o1, o2) -> o1.getAmount() > o2.getAmount() ? 1 : -1) .get().getAmount(); @@ -171,7 +171,7 @@ private List generateStatsData() { private void showRingStats() { List ringList = generateStatsData(); if(ringList.size() > 1) { - binding.userStats.setDrawBg(CompatUtil.isLightTheme(getContext()), CompatUtil.getColorFromAttr(getContext(), R.attr.subtitleColor)); + binding.userStats.setDrawBg(CompatUtil.INSTANCE.isLightTheme(getContext()), CompatUtil.INSTANCE.getColorFromAttr(getContext(), R.attr.subtitleColor)); binding.userStats.setData(ringList, 500); } } @@ -185,12 +185,12 @@ private void showRingStats() { public void onClick(View view) { switch (view.getId()) { case R.id.user_avatar: - CompatUtil.imagePreview(getActivity(), view, model.getAvatar().getLarge(), R.string.image_preview_error_user_avatar); + CompatUtil.INSTANCE.imagePreview(getActivity(), view, model.getAvatar().getLarge(), R.string.image_preview_error_user_avatar); break; case R.id.user_stats_container: List ringList = generateStatsData(); if(ringList.size() > 1) { - binding.userStats.setDrawBg(CompatUtil.isLightTheme(getContext()), CompatUtil.getColorFromAttr(getContext(), R.attr.subtitleColor)); + binding.userStats.setDrawBg(CompatUtil.INSTANCE.isLightTheme(getContext()), CompatUtil.INSTANCE.getColorFromAttr(getContext(), R.attr.subtitleColor)); binding.userStats.setData(ringList, 500); } else diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/favourite/CharacterFavouriteFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/favourite/CharacterFavouriteFragment.java index 8185971a5..a56fd3155 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/favourite/CharacterFavouriteFragment.java +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/favourite/CharacterFavouriteFragment.java @@ -59,7 +59,7 @@ protected void updateUI() { @Override public void makeRequest() { - QueryContainerBuilder queryContainer = GraphUtil.getDefaultQuery(isPager) + QueryContainerBuilder queryContainer = GraphUtil.INSTANCE.getDefaultQuery(isPager) .putVariable(KeyUtil.arg_id, userId) .putVariable(KeyUtil.arg_page, getPresenter().getCurrentPage()); getViewModel().getParams().putParcelable(KeyUtil.arg_graph_params, queryContainer); @@ -73,7 +73,7 @@ public void onChanged(@Nullable ConnectionContainer content) { PageContainer pageContainer = content.getConnection().getCharacters(); if(pageContainer.hasPageInfo()) getPresenter().setPageInfo(pageContainer.getPageInfo()); - onPostProcessed(GroupingUtil.wrapInGroup(pageContainer.getPageData())); + onPostProcessed(GroupingUtil.INSTANCE.wrapInGroup(pageContainer.getPageData())); } else onPostProcessed(Collections.emptyList()); @@ -96,7 +96,7 @@ public void onItemClick(View target, IntPair data) { case R.id.container: Intent intent = new Intent(getActivity(), CharacterActivity.class); intent.putExtra(KeyUtil.arg_id, ((CharacterBase)data.getSecond()).getId()); - CompatUtil.startRevealAnim(getActivity(), target, intent); + CompatUtil.INSTANCE.startRevealAnim(getActivity(), target, intent); break; } } diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/favourite/MediaFavouriteFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/favourite/MediaFavouriteFragment.java index 54b28764b..04b285ba5 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/favourite/MediaFavouriteFragment.java +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/favourite/MediaFavouriteFragment.java @@ -66,11 +66,11 @@ protected void updateUI() { */ @Override public void makeRequest() { - QueryContainerBuilder queryContainer = GraphUtil.getDefaultQuery(isPager) + QueryContainerBuilder queryContainer = GraphUtil.INSTANCE.getDefaultQuery(isPager) .putVariable(KeyUtil.arg_id, userId) .putVariable(KeyUtil.arg_page, getPresenter().getCurrentPage()); getViewModel().getParams().putParcelable(KeyUtil.arg_graph_params, queryContainer); - getViewModel().requestData(CompatUtil.equals(mediaType, KeyUtil.ANIME) ? + getViewModel().requestData(CompatUtil.INSTANCE.equals(mediaType, KeyUtil.ANIME) ? KeyUtil.USER_ANIME_FAVOURITES_REQ : KeyUtil.USER_MANGA_FAVOURITES_REQ, getContext()); } @@ -78,7 +78,7 @@ public void makeRequest() { public void onChanged(@Nullable ConnectionContainer content) { if(content != null) { if(!content.isEmpty()) { - PageContainer pageContainer = CompatUtil.equals(mediaType, KeyUtil.ANIME) ? + PageContainer pageContainer = CompatUtil.INSTANCE.equals(mediaType, KeyUtil.ANIME) ? content.getConnection().getAnime() : content.getConnection().getManga(); if(pageContainer.hasPageInfo()) getPresenter().setPageInfo(pageContainer.getPageInfo()); @@ -106,7 +106,7 @@ public void onItemClick(View target, IntPair data) { Intent intent = new Intent(getActivity(), MediaActivity.class); intent.putExtra(KeyUtil.arg_id, data.getSecond().getId()); intent.putExtra(KeyUtil.arg_mediaType, data.getSecond().getType()); - CompatUtil.startRevealAnim(getActivity(), target, intent); + CompatUtil.INSTANCE.startRevealAnim(getActivity(), target, intent); break; } } diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/favourite/StaffFavouriteFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/favourite/StaffFavouriteFragment.java index 482fa0ef8..d93242e89 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/favourite/StaffFavouriteFragment.java +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/favourite/StaffFavouriteFragment.java @@ -57,7 +57,7 @@ protected void updateUI() { @Override public void makeRequest() { - QueryContainerBuilder queryContainer = GraphUtil.getDefaultQuery(isPager) + QueryContainerBuilder queryContainer = GraphUtil.INSTANCE.getDefaultQuery(isPager) .putVariable(KeyUtil.arg_id, userId) .putVariable(KeyUtil.arg_page, getPresenter().getCurrentPage()); getViewModel().getParams().putParcelable(KeyUtil.arg_graph_params, queryContainer); @@ -94,7 +94,7 @@ public void onItemClick(View target, IntPair data) { case R.id.container: Intent intent = new Intent(getActivity(), StaffActivity.class); intent.putExtra(KeyUtil.arg_id, data.getSecond().getId()); - CompatUtil.startRevealAnim(getActivity(), target, intent); + CompatUtil.INSTANCE.startRevealAnim(getActivity(), target, intent); break; } } diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/favourite/StudioFavouriteFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/favourite/StudioFavouriteFragment.java index a28538a19..1c5f1acc4 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/favourite/StudioFavouriteFragment.java +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/favourite/StudioFavouriteFragment.java @@ -55,7 +55,7 @@ protected void updateUI() { @Override public void makeRequest() { - QueryContainerBuilder queryContainer = GraphUtil.getDefaultQuery(isPager) + QueryContainerBuilder queryContainer = GraphUtil.INSTANCE.getDefaultQuery(isPager) .putVariable(KeyUtil.arg_id, userId) .putVariable(KeyUtil.arg_page, getPresenter().getCurrentPage()); getViewModel().getParams().putParcelable(KeyUtil.arg_graph_params, queryContainer); diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/group/CharacterActorsFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/group/CharacterActorsFragment.java index e2ac56e92..f077fb4ad 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/group/CharacterActorsFragment.java +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/group/CharacterActorsFragment.java @@ -49,7 +49,7 @@ public static CharacterActorsFragment newInstance(Bundle args) { public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); if(getArguments() != null) { - queryContainer = GraphUtil.getDefaultQuery(true) + queryContainer = GraphUtil.INSTANCE.getDefaultQuery(true) .putVariable(KeyUtil.arg_id, getArguments().getLong(KeyUtil.arg_id)); } mColumnSize = R.integer.grid_giphy_x3; isPager = true; @@ -72,7 +72,7 @@ public void onItemClick(View target, IntPair data) { Intent intent = new Intent(getActivity(), MediaActivity.class); intent.putExtra(KeyUtil.arg_id, ((MediaBase) data.getSecond()).getId()); intent.putExtra(KeyUtil.arg_mediaType, ((MediaBase) data.getSecond()).getType()); - CompatUtil.startRevealAnim(getActivity(), target, intent); + CompatUtil.INSTANCE.startRevealAnim(getActivity(), target, intent); break; } } @@ -121,7 +121,7 @@ public void onChanged(@Nullable ConnectionContainer> co if (edgeContainer.hasPageInfo()) getPresenter().setPageInfo(edgeContainer.getPageInfo()); if (!edgeContainer.isEmpty()) - onPostProcessed(GroupingUtil.groupActorMediaEdge(edgeContainer.getEdges())); + onPostProcessed(GroupingUtil.INSTANCE.groupActorMediaEdge(edgeContainer.getEdges())); else onPostProcessed(Collections.emptyList()); } @@ -144,7 +144,7 @@ public void onItemClick(View target, IntPair data) { case R.id.container: Intent intent = new Intent(getActivity(), StaffActivity.class); intent.putExtra(KeyUtil.arg_id, ((StaffBase)data.getSecond()).getId()); - CompatUtil.startRevealAnim(getActivity(), target, intent); + CompatUtil.INSTANCE.startRevealAnim(getActivity(), target, intent); break; } } diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/group/MediaCharacterFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/group/MediaCharacterFragment.java index 3dbc99e70..ee1cdbc79 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/group/MediaCharacterFragment.java +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/group/MediaCharacterFragment.java @@ -70,7 +70,7 @@ protected void updateUI() { */ @Override public void makeRequest() { - QueryContainerBuilder queryContainer = GraphUtil.getDefaultQuery(isPager) + QueryContainerBuilder queryContainer = GraphUtil.INSTANCE.getDefaultQuery(isPager) .putVariable(KeyUtil.arg_id, mediaId) .putVariable(KeyUtil.arg_type, mediaType) .putVariable(KeyUtil.arg_page, getPresenter().getCurrentPage()); @@ -87,7 +87,7 @@ public void onChanged(@Nullable ConnectionContainer if (edgeContainer.hasPageInfo()) getPresenter().setPageInfo(edgeContainer.getPageInfo()); if (!edgeContainer.isEmpty()) - onPostProcessed(GroupingUtil.groupCharactersByRole(edgeContainer.getEdges(), mAdapter.getData())); + onPostProcessed(GroupingUtil.INSTANCE.groupCharactersByRole(edgeContainer.getEdges(), mAdapter.getData())); else onPostProcessed(Collections.emptyList()); } @@ -110,7 +110,7 @@ public void onItemClick(View target, IntPair data) { case R.id.container: Intent intent = new Intent(getActivity(), CharacterActivity.class); intent.putExtra(KeyUtil.arg_id, ((CharacterBase)data.getSecond()).getId()); - CompatUtil.startRevealAnim(getActivity(), target, intent); + CompatUtil.INSTANCE.startRevealAnim(getActivity(), target, intent); break; } } diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/group/MediaFormatFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/group/MediaFormatFragment.java index 6e4af7e82..f058bddb1 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/group/MediaFormatFragment.java +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/group/MediaFormatFragment.java @@ -80,7 +80,7 @@ protected void updateUI() { */ @Override public void makeRequest() { - QueryContainerBuilder queryContainer = GraphUtil.getDefaultQuery(isPager) + QueryContainerBuilder queryContainer = GraphUtil.INSTANCE.getDefaultQuery(isPager) .putVariable(KeyUtil.arg_id, id) .putVariable(KeyUtil.arg_mediaType, mediaType) .putVariable(KeyUtil.arg_page, getPresenter().getCurrentPage()); @@ -96,7 +96,7 @@ public void onChanged(@Nullable ConnectionContainer> co if (pageContainer.hasPageInfo()) getPresenter().setPageInfo(pageContainer.getPageInfo()); if (!pageContainer.isEmpty()) - onPostProcessed(GroupingUtil.groupMediaByFormat(pageContainer.getPageData(), mAdapter.getData())); + onPostProcessed(GroupingUtil.INSTANCE.groupMediaByFormat(pageContainer.getPageData(), mAdapter.getData())); else onPostProcessed(Collections.emptyList()); } @@ -120,7 +120,7 @@ public void onItemClick(View target, IntPair data) { Intent intent = new Intent(getActivity(), MediaActivity.class); intent.putExtra(KeyUtil.arg_id, ((MediaBase)data.getSecond()).getId()); intent.putExtra(KeyUtil.arg_mediaType, ((MediaBase)data.getSecond()).getType()); - CompatUtil.startRevealAnim(getActivity(), target, intent); + CompatUtil.INSTANCE.startRevealAnim(getActivity(), target, intent); break; } } diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/group/MediaRelationFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/group/MediaRelationFragment.java index cdbc0adab..0c6ec052f 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/group/MediaRelationFragment.java +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/group/MediaRelationFragment.java @@ -74,7 +74,7 @@ protected void updateUI() { */ @Override public void makeRequest() { - QueryContainerBuilder queryContainer = GraphUtil.getDefaultQuery(isPager) + QueryContainerBuilder queryContainer = GraphUtil.INSTANCE.getDefaultQuery(isPager) .putVariable(KeyUtil.arg_id, mediaId) .putVariable(KeyUtil.arg_type, mediaType); getViewModel().getParams().putParcelable(KeyUtil.arg_graph_params, queryContainer); @@ -89,7 +89,7 @@ public void onChanged(@Nullable ConnectionContainer> co if (edgeContainer.hasPageInfo()) getPresenter().setPageInfo(edgeContainer.getPageInfo()); if (!edgeContainer.isEmpty()) - onPostProcessed(GroupingUtil.groupMediaByRelationType(edgeContainer.getEdges())); + onPostProcessed(GroupingUtil.INSTANCE.groupMediaByRelationType(edgeContainer.getEdges())); else onPostProcessed(Collections.emptyList()); } @@ -113,7 +113,7 @@ public void onItemClick(View target, IntPair data) { Intent intent = new Intent(getActivity(), MediaActivity.class); intent.putExtra(KeyUtil.arg_id, ((MediaBase) data.getSecond()).getId()); intent.putExtra(KeyUtil.arg_mediaType, ((MediaBase) data.getSecond()).getType()); - CompatUtil.startRevealAnim(getActivity(), target, intent); + CompatUtil.INSTANCE.startRevealAnim(getActivity(), target, intent); break; } } diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/group/MediaStaffRoleFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/group/MediaStaffRoleFragment.java index 9ac9940a1..43492635b 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/group/MediaStaffRoleFragment.java +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/group/MediaStaffRoleFragment.java @@ -63,7 +63,7 @@ public void onCreate(@Nullable Bundle savedInstanceState) { */ @Override public void makeRequest() { - QueryContainerBuilder queryContainer = GraphUtil.getDefaultQuery(isPager) + QueryContainerBuilder queryContainer = GraphUtil.INSTANCE.getDefaultQuery(isPager) .putVariable(KeyUtil.arg_id, id) .putVariable(KeyUtil.arg_page, getPresenter().getCurrentPage()); getViewModel().getParams().putParcelable(KeyUtil.arg_graph_params, queryContainer); @@ -87,7 +87,7 @@ public void onChanged(@Nullable ConnectionContainer> co if (edgeContainer.hasPageInfo()) getPresenter().setPageInfo(edgeContainer.getPageInfo()); if (!edgeContainer.isEmpty()) - onPostProcessed(GroupingUtil.groupMediaByStaffRole(edgeContainer.getEdges(), mAdapter.getData())); + onPostProcessed(GroupingUtil.INSTANCE.groupMediaByStaffRole(edgeContainer.getEdges(), mAdapter.getData())); else onPostProcessed(Collections.emptyList()); } @@ -111,7 +111,7 @@ public void onItemClick(View target, IntPair data) { Intent intent = new Intent(getActivity(), MediaActivity.class); intent.putExtra(KeyUtil.arg_id, ((MediaBase)data.getSecond()).getId()); intent.putExtra(KeyUtil.arg_mediaType, ((MediaBase)data.getSecond()).getType()); - CompatUtil.startRevealAnim(getActivity(), target, intent); + CompatUtil.INSTANCE.startRevealAnim(getActivity(), target, intent); break; } } diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/list/AiringListFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/list/AiringListFragment.java index 1d61d660f..dfcb779bf 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/list/AiringListFragment.java +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/list/AiringListFragment.java @@ -34,7 +34,7 @@ public void onCreate(@Nullable Bundle savedInstanceState) { UserBase userBase = getPresenter().getDatabase().getCurrentUser(); userId = userBase.getId(); userName = userBase.getName(); mediaType = KeyUtil.ANIME; ((MediaListAdapter)mAdapter).setCurrentUser(userName); - queryContainer = GraphUtil.getDefaultQuery(false) + queryContainer = GraphUtil.INSTANCE.getDefaultQuery(false) .putVariable(KeyUtil.arg_statusIn, KeyUtil.CURRENT); } @@ -57,7 +57,7 @@ public void onChanged(@Nullable PageContainer content) { MediaListCollection mediaListCollection = mediaOptional.get(); List mediaList = Stream.of(mediaListCollection.getEntries()) - .filter(media -> CompatUtil.equals(media.getMedia().getStatus(), KeyUtil.RELEASING)) + .filter(media -> CompatUtil.INSTANCE.equals(media.getMedia().getStatus(), KeyUtil.RELEASING)) .toList(); if(MediaListUtil.isTitleSort(getPresenter().getApplicationPref().getMediaListSort())) diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/list/FeedListFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/list/FeedListFragment.java index 14970d621..8b21c177d 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/list/FeedListFragment.java +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/list/FeedListFragment.java @@ -129,7 +129,7 @@ public void onModelChanged(BaseConsumer consumer) { swipeRefreshLayout.setRefreshing(true); onRefresh(); } else { - pairOptional = CompatUtil.findIndexOf(mAdapter.getData(), consumer.getChangeModel()); + pairOptional = CompatUtil.INSTANCE.findIndexOf(mAdapter.getData(), consumer.getChangeModel()); if(pairOptional.isPresent()) { pairIndex = pairOptional.get().getFirst(); mAdapter.onItemChanged(consumer.getChangeModel(), pairIndex); @@ -141,7 +141,7 @@ public void onModelChanged(BaseConsumer consumer) { swipeRefreshLayout.setRefreshing(true); onRefresh(); } else { - pairOptional = CompatUtil.findIndexOf(mAdapter.getData(), consumer.getChangeModel()); + pairOptional = CompatUtil.INSTANCE.findIndexOf(mAdapter.getData(), consumer.getChangeModel()); if (pairOptional.isPresent()) { pairIndex = pairOptional.get().getFirst(); mAdapter.onItemChanged(consumer.getChangeModel(), pairIndex); @@ -149,7 +149,7 @@ public void onModelChanged(BaseConsumer consumer) { } break; case KeyUtil.MUT_DELETE_FEED: - pairOptional = CompatUtil.findIndexOf(mAdapter.getData(), consumer.getChangeModel()); + pairOptional = CompatUtil.INSTANCE.findIndexOf(mAdapter.getData(), consumer.getChangeModel()); if(pairOptional.isPresent()) { pairIndex = pairOptional.get().getFirst(); mAdapter.onItemRemoved(pairIndex); @@ -169,7 +169,7 @@ public void onChanged(@Nullable PageContainer content) { if(content.hasPageInfo()) getPresenter().setPageInfo(content.getPageInfo()); if(!content.isEmpty()) - onPostProcessed(GraphUtil.filterFeedList(getPresenter(), content.getPageData())); + onPostProcessed(GraphUtil.INSTANCE.filterFeedList(getPresenter(), content.getPageData())); else onPostProcessed(Collections.emptyList()); } else @@ -194,12 +194,12 @@ public void onItemClick(View target, IntPair data) { intent = new Intent(getActivity(), MediaActivity.class); intent.putExtra(KeyUtil.arg_id, series.getId()); intent.putExtra(KeyUtil.arg_mediaType, series.getType()); - CompatUtil.startRevealAnim(getActivity(), target, intent); + CompatUtil.INSTANCE.startRevealAnim(getActivity(), target, intent); break; case R.id.widget_comment: intent = new Intent(getActivity(), CommentActivity.class); intent.putExtra(KeyUtil.arg_model, data.getSecond()); - CompatUtil.startRevealAnim(getActivity(), target, intent); + CompatUtil.INSTANCE.startRevealAnim(getActivity(), target, intent); break; case R.id.widget_edit: mBottomSheet = new BottomSheetComposer.Builder().setUserActivity(data.getSecond()) @@ -224,7 +224,7 @@ public void onItemClick(View target, IntPair data) { intent = new Intent(getActivity(), ProfileActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.putExtra(KeyUtil.arg_id, data.getSecond().getUser().getId()); - CompatUtil.startRevealAnim(getActivity(), target, intent); + CompatUtil.INSTANCE.startRevealAnim(getActivity(), target, intent); } break; } diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/list/MediaBrowseFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/list/MediaBrowseFragment.java index 33c94ce52..234087766 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/list/MediaBrowseFragment.java +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/list/MediaBrowseFragment.java @@ -102,16 +102,16 @@ public boolean onOptionsItemSelected(MenuItem item) { if (getContext() != null) switch (item.getItemId()) { case R.id.action_sort: - DialogUtil.createSelection(getContext(), R.string.app_filter_sort, CompatUtil.getIndexOf(KeyUtil.MediaSortType, - getPresenter().getApplicationPref().getMediaSort()), CompatUtil.capitalizeWords(KeyUtil.MediaSortType), + DialogUtil.createSelection(getContext(), R.string.app_filter_sort, CompatUtil.INSTANCE.getIndexOf(KeyUtil.MediaSortType, + getPresenter().getApplicationPref().getMediaSort()), CompatUtil.INSTANCE.capitalizeWords(KeyUtil.MediaSortType), (dialog, which) -> { if(which == DialogAction.POSITIVE) getPresenter().getApplicationPref().setMediaSort(KeyUtil.MediaSortType[dialog.getSelectedIndex()]); }); return true; case R.id.action_order: - DialogUtil.createSelection(getContext(), R.string.app_filter_order, CompatUtil.getIndexOf(KeyUtil.SortOrderType, - getPresenter().getApplicationPref().getSortOrder()), CompatUtil.getStringList(getContext(), R.array.order_by_types), + DialogUtil.createSelection(getContext(), R.string.app_filter_order, CompatUtil.INSTANCE.getIndexOf(KeyUtil.SortOrderType, + getPresenter().getApplicationPref().getSortOrder()), CompatUtil.INSTANCE.getStringList(getContext(), R.array.order_by_types), (dialog, which) -> { if(which == DialogAction.POSITIVE) getPresenter().getApplicationPref().saveSortOrder(KeyUtil.SortOrderType[dialog.getSelectedIndex()]); @@ -119,7 +119,7 @@ public boolean onOptionsItemSelected(MenuItem item) { return true; case R.id.action_genre: List genres = getPresenter().getDatabase().getGenreCollection(); - if(CompatUtil.isEmpty(genres)) { + if(CompatUtil.INSTANCE.isEmpty(genres)) { NotifyUtil.makeText(getContext(), R.string.app_splash_loading, R.drawable.ic_warning_white_18dp, Toast.LENGTH_SHORT).show(); getPresenter().checkGenresAndTags(getActivity()); } else { @@ -150,7 +150,7 @@ public boolean onOptionsItemSelected(MenuItem item) { return true; case R.id.action_tag: List tagList = getPresenter().getDatabase().getMediaTags(); - if(CompatUtil.isEmpty(tagList)) { + if(CompatUtil.INSTANCE.isEmpty(tagList)) { NotifyUtil.makeText(getContext(), R.string.app_splash_loading, R.drawable.ic_warning_white_18dp, Toast.LENGTH_SHORT).show(); getPresenter().checkGenresAndTags(getActivity()); } else { @@ -180,16 +180,16 @@ public boolean onOptionsItemSelected(MenuItem item) { } return true; case R.id.action_type: - if (CompatUtil.equals(queryContainer.getVariable(KeyUtil.arg_mediaType), KeyUtil.ANIME)) { - DialogUtil.createSelection(getContext(), R.string.app_filter_show_type, CompatUtil.getIndexOf(KeyUtil.AnimeFormat, - getPresenter().getApplicationPref().getAnimeFormat()), CompatUtil.getStringList(getContext(), R.array.anime_formats), + if (CompatUtil.INSTANCE.equals(queryContainer.getVariable(KeyUtil.arg_mediaType), KeyUtil.ANIME)) { + DialogUtil.createSelection(getContext(), R.string.app_filter_show_type, CompatUtil.INSTANCE.getIndexOf(KeyUtil.AnimeFormat, + getPresenter().getApplicationPref().getAnimeFormat()), CompatUtil.INSTANCE.getStringList(getContext(), R.array.anime_formats), (dialog, which) -> { if(which == DialogAction.POSITIVE) getPresenter().getApplicationPref().setAnimeFormat(KeyUtil.AnimeFormat[dialog.getSelectedIndex()]); }); } else { - DialogUtil.createSelection(getContext(), R.string.app_filter_show_type, CompatUtil.getIndexOf(KeyUtil.MangaFormat, - getPresenter().getApplicationPref().getMangaFormat()), CompatUtil.getStringList(getContext(), R.array.manga_formats), + DialogUtil.createSelection(getContext(), R.string.app_filter_show_type, CompatUtil.INSTANCE.getIndexOf(KeyUtil.MangaFormat, + getPresenter().getApplicationPref().getMangaFormat()), CompatUtil.INSTANCE.getStringList(getContext(), R.array.manga_formats), (dialog, which) -> { if(which == DialogAction.POSITIVE) getPresenter().getApplicationPref().setMangaFormat(KeyUtil.MangaFormat[dialog.getSelectedIndex()]); @@ -197,16 +197,16 @@ public boolean onOptionsItemSelected(MenuItem item) { } return true; case R.id.action_year: - final List yearRanges = DateUtil.getYearRanges(1950, 1); - DialogUtil.createSelection(getContext(), R.string.app_filter_year, CompatUtil.getIndexOf(yearRanges, getPresenter().getApplicationPref().getSeasonYear()), + final List yearRanges = DateUtil.INSTANCE.getYearRanges(1950, 1); + DialogUtil.createSelection(getContext(), R.string.app_filter_year, CompatUtil.INSTANCE.getIndexOf(yearRanges, getPresenter().getApplicationPref().getSeasonYear()), yearRanges, (dialog, which) -> { if(which == DialogAction.POSITIVE) getPresenter().getApplicationPref().saveSeasonYear(yearRanges.get(dialog.getSelectedIndex())); }); return true; case R.id.action_status: - DialogUtil.createSelection(getContext(), R.string.anime, CompatUtil.getIndexOf(KeyUtil.MediaStatus, - getPresenter().getApplicationPref().getMediaStatus()), CompatUtil.getStringList(getContext(), R.array.media_status), + DialogUtil.createSelection(getContext(), R.string.anime, CompatUtil.INSTANCE.getIndexOf(KeyUtil.MediaStatus, + getPresenter().getApplicationPref().getMediaStatus()), CompatUtil.INSTANCE.getStringList(getContext(), R.array.media_status), (dialog, which) -> { if(which == DialogAction.POSITIVE) getPresenter().getApplicationPref().setMediaStatus(KeyUtil.MediaStatus[dialog.getSelectedIndex()]); @@ -229,7 +229,7 @@ public void makeRequest() { if(isFilterable) { if(!mediaBrowseUtil.isBasicFilter()) { - if (CompatUtil.equals(queryContainer.getVariable(KeyUtil.arg_mediaType), KeyUtil.MANGA)) { + if (CompatUtil.INSTANCE.equals(queryContainer.getVariable(KeyUtil.arg_mediaType), KeyUtil.MANGA)) { queryContainer.putVariable(KeyUtil.arg_startDateLike, String.format(Locale.getDefault(), "%d%%", getPresenter().getApplicationPref().getSeasonYear())) .putVariable(KeyUtil.arg_format, pref.getMangaFormat()); @@ -277,7 +277,7 @@ public void onItemClick(View target, IntPair data) { Intent intent = new Intent(getActivity(), MediaActivity.class); intent.putExtra(KeyUtil.arg_id, data.getSecond().getId()); intent.putExtra(KeyUtil.arg_mediaType, data.getSecond().getType()); - CompatUtil.startRevealAnim(getActivity(), target, intent); + CompatUtil.INSTANCE.startRevealAnim(getActivity(), target, intent); break; } } diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/list/MediaListFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/list/MediaListFragment.java index e51297cac..4f066a990 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/list/MediaListFragment.java +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/list/MediaListFragment.java @@ -105,16 +105,16 @@ public boolean onOptionsItemSelected(MenuItem item) { if (getContext() != null) switch (item.getItemId()) { case R.id.action_sort: - DialogUtil.createSelection(getContext(), R.string.app_filter_sort, CompatUtil.getIndexOf(KeyUtil.MediaListSortType, - getPresenter().getApplicationPref().getMediaListSort()), CompatUtil.capitalizeWords(KeyUtil.MediaListSortType), + DialogUtil.createSelection(getContext(), R.string.app_filter_sort, CompatUtil.INSTANCE.getIndexOf(KeyUtil.MediaListSortType, + getPresenter().getApplicationPref().getMediaListSort()), CompatUtil.INSTANCE.capitalizeWords(KeyUtil.MediaListSortType), (dialog, which) -> { if(which == DialogAction.POSITIVE) getPresenter().getApplicationPref().setMediaListSort(KeyUtil.MediaListSortType[dialog.getSelectedIndex()]); }); return true; case R.id.action_order: - DialogUtil.createSelection(getContext(), R.string.app_filter_order, CompatUtil.getIndexOf(KeyUtil.SortOrderType, - getPresenter().getApplicationPref().getSortOrder()), CompatUtil.getStringList(getContext(), R.array.order_by_types), + DialogUtil.createSelection(getContext(), R.string.app_filter_order, CompatUtil.INSTANCE.getIndexOf(KeyUtil.SortOrderType, + getPresenter().getApplicationPref().getSortOrder()), CompatUtil.INSTANCE.getStringList(getContext(), R.array.order_by_types), (dialog, which) -> { if(which == DialogAction.POSITIVE) getPresenter().getApplicationPref().saveSortOrder(KeyUtil.SortOrderType[dialog.getSelectedIndex()]); @@ -160,9 +160,9 @@ public void makeRequest() { @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - if(getPresenter() != null && isFilterable && GraphUtil.isKeyFilter(key)) { + if(getPresenter() != null && isFilterable && GraphUtil.INSTANCE.isKeyFilter(key)) { @KeyUtil.MediaListSort String mediaListSort = getPresenter().getApplicationPref().getMediaListSort(); - if(CompatUtil.equals(key, ApplicationPref._mediaListSort) && MediaListUtil.isTitleSort(mediaListSort)) { + if(CompatUtil.INSTANCE.equals(key, ApplicationPref._mediaListSort) && MediaListUtil.isTitleSort(mediaListSort)) { swipeRefreshLayout.setRefreshing(true); sortMediaListByTitle(mAdapter.getData()); } @@ -177,12 +177,12 @@ public void onModelChanged(BaseConsumer consumer) { if(consumer.getRequestMode() == KeyUtil.MUT_SAVE_MEDIA_LIST || consumer.getRequestMode() == KeyUtil.MUT_DELETE_MEDIA_LIST) { int pairIndex; if (getPresenter().isCurrentUser(userId, userName)) { - Optional> pairOptional = CompatUtil.findIndexOf(mAdapter.getData(), consumer.getChangeModel()); + Optional> pairOptional = CompatUtil.INSTANCE.findIndexOf(mAdapter.getData(), consumer.getChangeModel()); if (pairOptional.isPresent()) { switch (consumer.getRequestMode()) { case KeyUtil.MUT_SAVE_MEDIA_LIST: pairIndex = pairOptional.get().getFirst(); - if (mediaListCollectionBase == null || CompatUtil.equals(mediaListCollectionBase.getStatus(), consumer.getChangeModel().getStatus())) + if (mediaListCollectionBase == null || CompatUtil.INSTANCE.equals(mediaListCollectionBase.getStatus(), consumer.getChangeModel().getStatus())) mAdapter.onItemChanged(consumer.getChangeModel(), pairIndex); else mAdapter.onItemRemoved(pairIndex); @@ -192,7 +192,7 @@ public void onModelChanged(BaseConsumer consumer) { mAdapter.onItemRemoved(pairIndex); break; } - } else if (mediaListCollectionBase == null || CompatUtil.equals(mediaListCollectionBase.getStatus(), consumer.getChangeModel().getStatus())) + } else if (mediaListCollectionBase == null || CompatUtil.INSTANCE.equals(mediaListCollectionBase.getStatus(), consumer.getChangeModel().getStatus())) onRefresh(); } } @@ -239,7 +239,7 @@ public void onItemClick(View target, IntPair data) { Intent intent = new Intent(getActivity(), MediaActivity.class); intent.putExtra(KeyUtil.arg_id, data.getSecond().getMediaId()); intent.putExtra(KeyUtil.arg_mediaType, mediaBase.getType()); - CompatUtil.startRevealAnim(getActivity(), target, intent); + CompatUtil.INSTANCE.startRevealAnim(getActivity(), target, intent); break; } } @@ -272,7 +272,7 @@ protected void sortMediaListByTitle(@NonNull List mediaLists) { .sorted((first, second) -> { String firstTitle = MediaUtil.getMediaTitle(first.getMedia()); String secondTitle = MediaUtil.getMediaTitle(second.getMedia()); - return CompatUtil.equals(sortOrder, KeyUtil.ASC) ? + return CompatUtil.INSTANCE.equals(sortOrder, KeyUtil.ASC) ? firstTitle.compareTo(secondTitle) : secondTitle.compareTo(firstTitle); }).toList()); updateUI(); diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/list/SuggestionListFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/list/SuggestionListFragment.java index dea47effb..98712a504 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/list/SuggestionListFragment.java +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/list/SuggestionListFragment.java @@ -21,7 +21,7 @@ public class SuggestionListFragment extends MediaBrowseFragment { public static SuggestionListFragment newInstance(Bundle params) { Bundle args = new Bundle(params); - args.putParcelable(KeyUtil.arg_graph_params, GraphUtil.getDefaultQuery(true) + args.putParcelable(KeyUtil.arg_graph_params, GraphUtil.INSTANCE.getDefaultQuery(true) .putVariable(KeyUtil.arg_mediaType, KeyUtil.ANIME) .putVariable(KeyUtil.arg_onList, false)); SuggestionListFragment fragment = new SuggestionListFragment(); @@ -56,16 +56,16 @@ public boolean onOptionsItemSelected(MenuItem item) { if (getContext() != null) switch (item.getItemId()) { case R.id.action_sort: - DialogUtil.createSelection(getContext(), R.string.app_filter_sort, CompatUtil.getIndexOf(KeyUtil.MediaSortType, - getPresenter().getApplicationPref().getMediaSort()), CompatUtil.capitalizeWords(KeyUtil.MediaSortType), + DialogUtil.createSelection(getContext(), R.string.app_filter_sort, CompatUtil.INSTANCE.getIndexOf(KeyUtil.MediaSortType, + getPresenter().getApplicationPref().getMediaSort()), CompatUtil.INSTANCE.capitalizeWords(KeyUtil.MediaSortType), (dialog, which) -> { if(which == DialogAction.POSITIVE) getPresenter().getApplicationPref().setMediaSort(KeyUtil.MediaSortType[dialog.getSelectedIndex()]); }); return true; case R.id.action_order: - DialogUtil.createSelection(getContext(), R.string.app_filter_order, CompatUtil.getIndexOf(KeyUtil.SortOrderType, - getPresenter().getApplicationPref().getSortOrder()), CompatUtil.getStringList(getContext(), R.array.order_by_types), + DialogUtil.createSelection(getContext(), R.string.app_filter_order, CompatUtil.INSTANCE.getIndexOf(KeyUtil.SortOrderType, + getPresenter().getApplicationPref().getSortOrder()), CompatUtil.INSTANCE.getStringList(getContext(), R.array.order_by_types), (dialog, which) -> { if(which == DialogAction.POSITIVE) getPresenter().getApplicationPref().saveSortOrder(KeyUtil.SortOrderType[dialog.getSelectedIndex()]); diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/list/WatchListFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/list/WatchListFragment.java index 7171dffff..eb5e09df4 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/list/WatchListFragment.java +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/list/WatchListFragment.java @@ -92,7 +92,7 @@ public void makeRequest() { bundle.putBoolean(KeyUtil.arg_feed, feed); getViewModel().requestData(getRequestMode(feed), getContext()); } else { - QueryContainerBuilder queryContainer = GraphUtil.getDefaultQuery(false) + QueryContainerBuilder queryContainer = GraphUtil.INSTANCE.getDefaultQuery(false) .putVariable(KeyUtil.arg_id, mediaId) .putVariable(KeyUtil.arg_type, mediaType); getPresenter().getParams().putParcelable(KeyUtil.arg_graph_params, queryContainer); @@ -114,14 +114,14 @@ public void onResponse(@NonNull Call>> ca if(!connectionContainer.isEmpty()) { externalLinks = connectionContainer.getConnection(); if(mAdapter.getItemCount() < 1 && externalLinks != null) - targetLink = EpisodeUtil.episodeSupport(externalLinks); + targetLink = EpisodeUtil.INSTANCE.episodeSupport(externalLinks); if (targetLink == null) showEmpty(getString(R.string.waring_missing_episode_links)); else makeRequest(); } } else - Log.e(TAG, ErrorUtil.getError(response)); + Log.e(TAG, ErrorUtil.INSTANCE.getError(response)); } } diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/search/CharacterSearchFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/search/CharacterSearchFragment.java index 75d886b07..65095256f 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/search/CharacterSearchFragment.java +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/search/CharacterSearchFragment.java @@ -66,7 +66,7 @@ protected void updateUI() { */ @Override public void makeRequest() { - QueryContainerBuilder queryContainer = GraphUtil.getDefaultQuery(isPager) + QueryContainerBuilder queryContainer = GraphUtil.INSTANCE.getDefaultQuery(isPager) .putVariable(KeyUtil.arg_search, searchQuery) .putVariable(KeyUtil.arg_page, getPresenter().getCurrentPage()) .putVariable(KeyUtil.arg_sort, KeyUtil.SEARCH_MATCH); @@ -85,7 +85,7 @@ public void onChanged(@Nullable PageContainer content) { if(content.hasPageInfo()) getPresenter().setPageInfo(content.getPageInfo()); if(!content.isEmpty()) - onPostProcessed(GroupingUtil.wrapInGroup(content.getPageData())); + onPostProcessed(GroupingUtil.INSTANCE.wrapInGroup(content.getPageData())); else onPostProcessed(Collections.emptyList()); } else @@ -107,7 +107,7 @@ public void onItemClick(View target, IntPair data) { case R.id.container: Intent intent = new Intent(getActivity(), CharacterActivity.class); intent.putExtra(KeyUtil.arg_id, ((CharacterBase)data.getSecond()).getId()); - CompatUtil.startRevealAnim(getActivity(), target, intent); + CompatUtil.INSTANCE.startRevealAnim(getActivity(), target, intent); break; } } diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/search/MediaSearchFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/search/MediaSearchFragment.java index e0db0697c..7a7247ebe 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/search/MediaSearchFragment.java +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/search/MediaSearchFragment.java @@ -72,7 +72,7 @@ protected void updateUI() { */ @Override public void makeRequest() { - QueryContainerBuilder queryContainer = GraphUtil.getDefaultQuery(isPager) + QueryContainerBuilder queryContainer = GraphUtil.INSTANCE.getDefaultQuery(isPager) .putVariable(KeyUtil.arg_search, searchQuery) .putVariable(KeyUtil.arg_mediaType, mediaType) .putVariable(KeyUtil.arg_page, getPresenter().getCurrentPage()) @@ -115,7 +115,7 @@ public void onItemClick(View target, IntPair data) { Intent intent = new Intent(getActivity(), MediaActivity.class); intent.putExtra(KeyUtil.arg_id, data.getSecond().getId()); intent.putExtra(KeyUtil.arg_mediaType, data.getSecond().getType()); - CompatUtil.startRevealAnim(getActivity(), target, intent); + CompatUtil.INSTANCE.startRevealAnim(getActivity(), target, intent); break; } } diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/search/StaffSearchFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/search/StaffSearchFragment.java index a6b93efa9..bf1f54487 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/search/StaffSearchFragment.java +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/search/StaffSearchFragment.java @@ -64,7 +64,7 @@ protected void updateUI() { */ @Override public void makeRequest() { - QueryContainerBuilder queryContainer = GraphUtil.getDefaultQuery(isPager) + QueryContainerBuilder queryContainer = GraphUtil.INSTANCE.getDefaultQuery(isPager) .putVariable(KeyUtil.arg_search, searchQuery) .putVariable(KeyUtil.arg_page, getPresenter().getCurrentPage()) .putVariable(KeyUtil.arg_sort, KeyUtil.SEARCH_MATCH); @@ -105,7 +105,7 @@ public void onItemClick(View target, IntPair data) { case R.id.container: Intent intent = new Intent(getActivity(), StaffActivity.class); intent.putExtra(KeyUtil.arg_id, data.getSecond().getId()); - CompatUtil.startRevealAnim(getActivity(), target, intent); + CompatUtil.INSTANCE.startRevealAnim(getActivity(), target, intent); break; } } diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/search/StudioSearchFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/search/StudioSearchFragment.java index 4830cc9af..f6d9cd42c 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/search/StudioSearchFragment.java +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/search/StudioSearchFragment.java @@ -63,7 +63,7 @@ protected void updateUI() { */ @Override public void makeRequest() { - QueryContainerBuilder queryContainer = GraphUtil.getDefaultQuery(isPager) + QueryContainerBuilder queryContainer = GraphUtil.INSTANCE.getDefaultQuery(isPager) .putVariable(KeyUtil.arg_search, searchQuery) .putVariable(KeyUtil.arg_page, getPresenter().getCurrentPage()) .putVariable(KeyUtil.arg_sort, KeyUtil.SEARCH_MATCH); diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/search/UserSearchFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/search/UserSearchFragment.java index 9ca6cb6ba..a45099049 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/search/UserSearchFragment.java +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/search/UserSearchFragment.java @@ -63,7 +63,7 @@ protected void updateUI() { */ @Override public void makeRequest() { - QueryContainerBuilder queryContainer = GraphUtil.getDefaultQuery(isPager) + QueryContainerBuilder queryContainer = GraphUtil.INSTANCE.getDefaultQuery(isPager) .putVariable(KeyUtil.arg_search, searchQuery) .putVariable(KeyUtil.arg_page, getPresenter().getCurrentPage()) .putVariable(KeyUtil.arg_sort, KeyUtil.SEARCH_MATCH); @@ -105,7 +105,7 @@ public void onItemClick(View target, IntPair data) { Intent intent = new Intent(getActivity(), ProfileActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.putExtra(KeyUtil.arg_id, data.getSecond().getId()); - CompatUtil.startRevealAnim(getActivity(), target, intent); + CompatUtil.INSTANCE.startRevealAnim(getActivity(), target, intent); break; } } diff --git a/app/src/main/java/com/mxt/anitrend/view/sheet/BottomReviewReader.java b/app/src/main/java/com/mxt/anitrend/view/sheet/BottomReviewReader.java index 7f7cbf660..5ff0cb50b 100644 --- a/app/src/main/java/com/mxt/anitrend/view/sheet/BottomReviewReader.java +++ b/app/src/main/java/com/mxt/anitrend/view/sheet/BottomReviewReader.java @@ -57,7 +57,7 @@ public void onCreate(@Nullable Bundle savedInstanceState) { @Override public Dialog onCreateDialog(Bundle savedInstanceState) { Dialog dialog = super.onCreateDialog(savedInstanceState); - binding = BottomSheetReviewBinding.inflate(CompatUtil.getLayoutInflater(getActivity())); + binding = BottomSheetReviewBinding.inflate(CompatUtil.INSTANCE.getLayoutInflater(getActivity())); dialog.setContentView(binding.getRoot()); unbinder = ButterKnife.bind(this, dialog); createBottomSheetBehavior(binding.getRoot()); diff --git a/app/src/main/java/com/mxt/anitrend/view/sheet/BottomSheetComposer.java b/app/src/main/java/com/mxt/anitrend/view/sheet/BottomSheetComposer.java index ba13088b4..765960422 100644 --- a/app/src/main/java/com/mxt/anitrend/view/sheet/BottomSheetComposer.java +++ b/app/src/main/java/com/mxt/anitrend/view/sheet/BottomSheetComposer.java @@ -146,7 +146,7 @@ public void onItemClick(View target, IntPair data) { mBottomSheet.show(getActivity().getSupportFragmentManager(), mBottomSheet.getTag()); break; case R.id.widget_flipper: - CompatUtil.hideKeyboard(getActivity()); + CompatUtil.INSTANCE.hideKeyboard(getActivity()); break; default: DialogUtil.createDialogAttachMedia(target.getId(), composerWidget.getEditor(), getContext()); diff --git a/app/src/main/java/com/mxt/anitrend/view/sheet/BottomSheetGiphy.java b/app/src/main/java/com/mxt/anitrend/view/sheet/BottomSheetGiphy.java index 03ac1102c..06bf1cc6c 100644 --- a/app/src/main/java/com/mxt/anitrend/view/sheet/BottomSheetGiphy.java +++ b/app/src/main/java/com/mxt/anitrend/view/sheet/BottomSheetGiphy.java @@ -63,7 +63,7 @@ public void onCreate(@Nullable Bundle savedInstanceState) { @Override public Dialog onCreateDialog(Bundle savedInstanceState) { Dialog dialog = super.onCreateDialog(savedInstanceState); - binding = BottomSheetListBinding.inflate(CompatUtil.getLayoutInflater(getActivity())); + binding = BottomSheetListBinding.inflate(CompatUtil.INSTANCE.getLayoutInflater(getActivity())); dialog.setContentView(binding.getRoot()); unbinder = ButterKnife.bind(this, dialog); createBottomSheetBehavior(binding.getRoot()); diff --git a/app/src/main/java/com/mxt/anitrend/view/sheet/BottomSheetListUsers.java b/app/src/main/java/com/mxt/anitrend/view/sheet/BottomSheetListUsers.java index 6e1947273..6821278c0 100644 --- a/app/src/main/java/com/mxt/anitrend/view/sheet/BottomSheetListUsers.java +++ b/app/src/main/java/com/mxt/anitrend/view/sheet/BottomSheetListUsers.java @@ -90,7 +90,7 @@ public void onCreate(@Nullable Bundle savedInstanceState) { @Override public Dialog onCreateDialog(Bundle savedInstanceState) { Dialog dialog = super.onCreateDialog(savedInstanceState); - BottomSheetListBinding binding = BottomSheetListBinding.inflate(CompatUtil.getLayoutInflater(getActivity())); + BottomSheetListBinding binding = BottomSheetListBinding.inflate(CompatUtil.INSTANCE.getLayoutInflater(getActivity())); dialog.setContentView(binding.getRoot()); unbinder = ButterKnife.bind(this, dialog); createBottomSheetBehavior(binding.getRoot()); @@ -148,7 +148,7 @@ protected void injectAdapter() { recyclerView.setAdapter(mAdapter); } if (mAdapter.getItemCount() < 1) - stateLayout.showEmpty(CompatUtil.getDrawable(getContext(), R.drawable.ic_new_releases_white_24dp, R.color.colorStateBlue), getString(R.string.layout_empty_response)); + stateLayout.showEmpty(CompatUtil.INSTANCE.getDrawable(getContext(), R.drawable.ic_new_releases_white_24dp, R.color.colorStateBlue), getString(R.string.layout_empty_response)); else stateLayout.showContent(); } @@ -201,7 +201,7 @@ public void onLoadMore() { * All new or updated network requests should be handled in this method */ public void makeRequest() { - QueryContainerBuilder queryContainer = GraphUtil.getDefaultQuery(isPager) + QueryContainerBuilder queryContainer = GraphUtil.INSTANCE.getDefaultQuery(isPager) .putVariable(KeyUtil.arg_id, userId) .putVariable(KeyUtil.arg_page, presenter.getCurrentPage()); @@ -214,7 +214,7 @@ public void makeRequest() { * @param content The main data model for the class */ protected void onPostProcessed(@Nullable List content) { - if(!CompatUtil.isEmpty(content)) { + if(!CompatUtil.INSTANCE.isEmpty(content)) { if(isPager) { if (mAdapter.getItemCount() < 1) mAdapter.onItemsInserted(content); @@ -256,7 +256,7 @@ public void onChanged(@Nullable PageContainer content) { public void showError(String error) { super.showError(error); stateLayout.showLoading(); - stateLayout.showError(CompatUtil.getDrawable(getContext(), R.drawable.ic_emoji_cry), + stateLayout.showError(CompatUtil.INSTANCE.getDrawable(getContext(), R.drawable.ic_emoji_cry), error, getString(R.string.try_again), stateLayoutOnClick); } @@ -264,7 +264,7 @@ public void showError(String error) { public void showEmpty(String message) { super.showEmpty(message); stateLayout.showLoading(); - stateLayout.showError(CompatUtil.getDrawable(getContext(), R.drawable.ic_emoji_sweat), + stateLayout.showError(CompatUtil.INSTANCE.getDrawable(getContext(), R.drawable.ic_emoji_sweat), message, getString(R.string.try_again) , stateLayoutOnClick); } @@ -282,7 +282,7 @@ public void onItemClick(View target, IntPair data) { Intent intent = new Intent(getActivity(), ProfileActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.putExtra(KeyUtil.arg_id, data.getSecond().getId()); - CompatUtil.startRevealAnim(getActivity(), target, intent); + CompatUtil.INSTANCE.startRevealAnim(getActivity(), target, intent); break; } } diff --git a/app/src/main/java/com/mxt/anitrend/view/sheet/BottomSheetUsers.java b/app/src/main/java/com/mxt/anitrend/view/sheet/BottomSheetUsers.java index 8a512ff04..7ddea294b 100644 --- a/app/src/main/java/com/mxt/anitrend/view/sheet/BottomSheetUsers.java +++ b/app/src/main/java/com/mxt/anitrend/view/sheet/BottomSheetUsers.java @@ -47,7 +47,7 @@ public void onCreate(@Nullable Bundle savedInstanceState) { mAdapter = new UserAdapter(getActivity()); if(getArguments() != null) { List baseList = getArguments().getParcelableArrayList(KeyUtil.arg_list_model); - if(!CompatUtil.isEmpty(baseList)) + if(!CompatUtil.INSTANCE.isEmpty(baseList)) mAdapter.onItemsInserted(baseList); } } @@ -62,7 +62,7 @@ public void onCreate(@Nullable Bundle savedInstanceState) { @Override public Dialog onCreateDialog(Bundle savedInstanceState) { Dialog dialog = super.onCreateDialog(savedInstanceState); - binding = BottomSheetListBinding.inflate(CompatUtil.getLayoutInflater(getActivity())); + binding = BottomSheetListBinding.inflate(CompatUtil.INSTANCE.getLayoutInflater(getActivity())); dialog.setContentView(binding.getRoot()); unbinder = ButterKnife.bind(this, dialog); createBottomSheetBehavior(binding.getRoot()); diff --git a/app/src/main/res/layout/adapter_comment.xml b/app/src/main/res/layout/adapter_comment.xml index 3efa41a0a..1c1a1f384 100644 --- a/app/src/main/res/layout/adapter_comment.xml +++ b/app/src/main/res/layout/adapter_comment.xml @@ -51,7 +51,7 @@ android:layout_height="wrap_content" android:layout_gravity="center|end" android:textAlignment="viewEnd" - android:text="@{DateUtil.getPrettyDateUnix(model.createdAt)}" + android:text="@{DateUtil.INSTANCE.getPrettyDateUnix(model.createdAt)}" tools:text="20 mintus ago" /> diff --git a/app/src/main/res/layout/adapter_feed_message.xml b/app/src/main/res/layout/adapter_feed_message.xml index f482be5f6..570184a67 100644 --- a/app/src/main/res/layout/adapter_feed_message.xml +++ b/app/src/main/res/layout/adapter_feed_message.xml @@ -86,7 +86,7 @@ android:layout_height="wrap_content" android:layout_gravity="center|end" android:textAlignment="viewEnd" - android:text="@{DateUtil.getPrettyDateUnix(model.createdAt)}" + android:text="@{DateUtil.INSTANCE.getPrettyDateUnix(model.createdAt)}" tools:text="5 days ago" /> diff --git a/app/src/main/res/layout/adapter_feed_progress.xml b/app/src/main/res/layout/adapter_feed_progress.xml index 01650b153..2dd6304bf 100644 --- a/app/src/main/res/layout/adapter_feed_progress.xml +++ b/app/src/main/res/layout/adapter_feed_progress.xml @@ -51,7 +51,7 @@ android:layout_height="wrap_content" android:layout_gravity="center|end" android:textAlignment="viewEnd" - android:text="@{DateUtil.getPrettyDateUnix(model.createdAt)}" + android:text="@{DateUtil.INSTANCE.getPrettyDateUnix(model.createdAt)}" tools:text="25 minutes ago" /> diff --git a/app/src/main/res/layout/adapter_feed_status.xml b/app/src/main/res/layout/adapter_feed_status.xml index 06b078986..2f188590d 100644 --- a/app/src/main/res/layout/adapter_feed_status.xml +++ b/app/src/main/res/layout/adapter_feed_status.xml @@ -51,7 +51,7 @@ android:layout_height="wrap_content" android:layout_gravity="center|end" android:textAlignment="viewEnd" - android:text="@{DateUtil.getPrettyDateUnix(model.createdAt)}" + android:text="@{DateUtil.INSTANCE.getPrettyDateUnix(model.createdAt)}" tools:text="5 days ago" /> diff --git a/app/src/main/res/layout/adapter_media_header.xml b/app/src/main/res/layout/adapter_media_header.xml index f2e5fbe05..2cbfb5e33 100644 --- a/app/src/main/res/layout/adapter_media_header.xml +++ b/app/src/main/res/layout/adapter_media_header.xml @@ -68,7 +68,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="@style/TextAppearance.AppCompat.Caption" - android:text="@{CompatUtil.capitalizeWords(model.subGroupTitle)}" + android:text="@{CompatUtil.INSTANCE.capitalizeWords(model.subGroupTitle)}" tools:text="Supporting" /> diff --git a/app/src/main/res/layout/adapter_series_review.xml b/app/src/main/res/layout/adapter_series_review.xml index b014ed610..76f38f3f0 100644 --- a/app/src/main/res/layout/adapter_series_review.xml +++ b/app/src/main/res/layout/adapter_series_review.xml @@ -51,7 +51,7 @@ android:layout_height="wrap_content" android:layout_gravity="center|end" android:textAlignment="viewEnd" - android:text="@{DateUtil.convertDate(model.createdAt)}" + android:text="@{DateUtil.INSTANCE.convertDate(model.createdAt)}" tools:text="Oct 28 2017" /> diff --git a/app/src/main/res/layout/adapter_staff.xml b/app/src/main/res/layout/adapter_staff.xml index 8928fb758..2fa0e04dd 100644 --- a/app/src/main/res/layout/adapter_staff.xml +++ b/app/src/main/res/layout/adapter_staff.xml @@ -55,7 +55,7 @@ android:layout_height="wrap_content" android:textAppearance="@style/TextAppearance.AppCompat.Caption" android:visibility="@{model.language != null? View.VISIBLE : View.GONE}" - android:text="@{CompatUtil.capitalizeWords(model.language)}" + android:text="@{CompatUtil.INSTANCE.capitalizeWords(model.language)}" tools:text="Japanese" /> diff --git a/app/src/main/res/layout/custom_review_template.xml b/app/src/main/res/layout/custom_review_template.xml index 5ba15c650..10e2d2a4f 100644 --- a/app/src/main/res/layout/custom_review_template.xml +++ b/app/src/main/res/layout/custom_review_template.xml @@ -39,7 +39,7 @@ android:layout_height="wrap_content" android:layout_gravity="center|end" android:textAlignment="viewEnd" - android:text="@{DateUtil.convertDate(model.createdAt)}" + android:text="@{DateUtil.INSTANCE.convertDate(model.createdAt)}" tools:text="Oct 28 2017" /> diff --git a/app/src/main/res/layout/fragment_series_overview.xml b/app/src/main/res/layout/fragment_series_overview.xml index bfe43936d..6ca0ef996 100644 --- a/app/src/main/res/layout/fragment_series_overview.xml +++ b/app/src/main/res/layout/fragment_series_overview.xml @@ -41,7 +41,7 @@ @@ -51,19 +51,28 @@ - + android:focusable="true" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:foreground="?selectableItemBackground" + android:layout_gravity="center_horizontal" + android:layout_margin="@dimen/lg_margin"> + + + + diff --git a/app/src/main/res/layout/fragment_series_stats.xml b/app/src/main/res/layout/fragment_series_stats.xml index 80e0b1f0a..0451e10a9 100644 --- a/app/src/main/res/layout/fragment_series_stats.xml +++ b/app/src/main/res/layout/fragment_series_stats.xml @@ -26,7 +26,7 @@ @@ -35,7 +35,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="@dimen/lg_margin" - android:visibility="@{model.stats != null & !CompatUtil.isEmpty(model.stats.scoreDistribution) ? View.VISIBLE : View.GONE}"> + android:visibility="@{model.stats != null & !CompatUtil.INSTANCE.isEmpty(model.stats.scoreDistribution) ? View.VISIBLE : View.GONE}"> + android:visibility="@{model.stats != null & !CompatUtil.INSTANCE.isEmpty(model.stats.statusDistribution) ? View.VISIBLE : View.GONE}"> diff --git a/app/src/main/res/layout/fragment_staff_overview.xml b/app/src/main/res/layout/fragment_staff_overview.xml index ff4178fc6..a25cc0e6c 100644 --- a/app/src/main/res/layout/fragment_staff_overview.xml +++ b/app/src/main/res/layout/fragment_staff_overview.xml @@ -88,7 +88,7 @@ Download Share Original Link + + + The character image doesn\'t exist! + The user has not set a banner image! + The series cover image doesn\'t exist! + The series banner image doesn\'t exist! + The staff image doesn\'t exist! + The user\'s avatar image doesn\'t exist + + + App Logs + Save Bug Report + Bug Report saved to Downloads Folder (AniTrend Logcat.txt) + + Show Spoiler Tags + New Related Media Added diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 638ca1671..0256f7cb6 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -936,4 +936,20 @@ Download Share Original Link + + + The character image doesn\'t exist! + The user has not set a banner image! + The series cover image doesn\'t exist! + The series banner image doesn\'t exist! + The staff image doesn\'t exist! + The user\'s avatar image doesn\'t exist + + + App Logs + Save Bug Report + Bug Report saved to Downloads Folder (AniTrend Logcat.txt) + + Show Spoiler Tags + New Related Media Added \ No newline at end of file diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index b636f6480..1d503a619 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -954,4 +954,20 @@ elementos de tus favoritos al presionar en el icono del corazón . Download Share Original Link + + + The character image doesn\'t exist! + The user has not set a banner image! + The series cover image doesn\'t exist! + The series banner image doesn\'t exist! + The staff image doesn\'t exist! + The user\'s avatar image doesn\'t exist + + + App Logs + Save Bug Report + Bug Report saved to Downloads Folder (AniTrend Logcat.txt) + + Show Spoiler Tags + New Related Media Added diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index a3fa070b1..ce93149dd 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -940,4 +940,20 @@ Download Share Original Link + + + The character image doesn\'t exist! + The user has not set a banner image! + The series cover image doesn\'t exist! + The series banner image doesn\'t exist! + The staff image doesn\'t exist! + The user\'s avatar image doesn\'t exist + + + App Logs + Save Bug Report + Bug Report saved to Downloads Folder (AniTrend Logcat.txt) + + Show Spoiler Tags + New Related Media Added \ No newline at end of file diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index ac8f8eb95..cee339c38 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -945,4 +945,20 @@ Download Share Original Link + + + The character image doesn\'t exist! + The user has not set a banner image! + The series cover image doesn\'t exist! + The series banner image doesn\'t exist! + The staff image doesn\'t exist! + The user\'s avatar image doesn\'t exist + + + App Logs + Save Bug Report + Bug Report saved to Downloads Folder (AniTrend Logcat.txt) + + Show Spoiler Tags + New Related Media Added diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 5d33daeb1..3d774901b 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -938,4 +938,20 @@ Download Delen Originele Link + + + The character image doesn\'t exist! + The user has not set a banner image! + The series cover image doesn\'t exist! + The series banner image doesn\'t exist! + The staff image doesn\'t exist! + The user\'s avatar image doesn\'t exist + + + App Logs + Save Bug Report + Bug Report saved to Downloads Folder (AniTrend Logcat.txt) + + Show Spoiler Tags + New Related Media Added diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 111ba364d..4696c9f42 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -958,4 +958,20 @@ Download Share Original Link + + + The character image doesn\'t exist! + The user has not set a banner image! + The series cover image doesn\'t exist! + The series banner image doesn\'t exist! + The staff image doesn\'t exist! + The user\'s avatar image doesn\'t exist + + + App Logs + Save Bug Report + Bug Report saved to Downloads Folder (AniTrend Logcat.txt) + + Show Spoiler Tags + New Related Media Added diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index dbcd1723e..ea7128b1c 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -958,4 +958,20 @@ Download Share Original Link + + + The character image doesn\'t exist! + The user has not set a banner image! + The series cover image doesn\'t exist! + The series banner image doesn\'t exist! + The staff image doesn\'t exist! + The user\'s avatar image doesn\'t exist + + + App Logs + Save Bug Report + Bug Report saved to Downloads Folder (AniTrend Logcat.txt) + + Show Spoiler Tags + New Related Media Added \ No newline at end of file diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index f3228a4f4..432c60db6 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -954,4 +954,20 @@ Download Share Original Link + + + The character image doesn\'t exist! + The user has not set a banner image! + The series cover image doesn\'t exist! + The series banner image doesn\'t exist! + The staff image doesn\'t exist! + The user\'s avatar image doesn\'t exist + + + App Logs + Save Bug Report + Bug Report saved to Downloads Folder (AniTrend Logcat.txt) + + Show Spoiler Tags + New Related Media Added diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d68b5fe4f..237981899 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1032,4 +1032,5 @@ Bug Report saved to Downloads Folder (AniTrend Logcat.txt) Show Spoiler Tags + New Related Media Added From 1da97504a1ed90385e065b5c0089dc2db1b873b5 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Sun, 12 May 2019 20:48:18 +0200 Subject: [PATCH 12/17] IDE Configuration Changes --- .idea/codeStyles/Project.xml | 29 ----------------------------- 1 file changed, 29 deletions(-) delete mode 100644 .idea/codeStyles/Project.xml diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml deleted file mode 100644 index 30aa626c2..000000000 --- a/.idea/codeStyles/Project.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file From e4b600bd57077b07bc473859360cfbaae4cac5fe Mon Sep 17 00:00:00 2001 From: Maxwell Date: Mon, 13 May 2019 21:22:39 +0200 Subject: [PATCH 13/17] Fixed Score Not Matching Sort Order --- .../base/custom/view/text/RatingTextView.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/text/RatingTextView.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/text/RatingTextView.java index bc4342c5f..34d3e4355 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/text/RatingTextView.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/text/RatingTextView.java @@ -147,18 +147,18 @@ private void setRating(MediaList mediaList) { } private void setRating(MediaBase mediaBase) { - float mediaScoreDefault = (float) mediaBase.getMeanScore() * 5 / 100f; + float mediaScoreDefault = (float) mediaBase.getAverageScore() * 5 / 100f; if(mediaListOptions != null) switch (mediaListOptions.getScoreFormat()) { case KeyUtil.POINT_10_DECIMAL: - mediaScoreDefault = (mediaBase.getMeanScore() / 10f); + mediaScoreDefault = (mediaBase.getAverageScore() / 10f); binding.ratingValue.setText(String.format(Locale.getDefault(),"%.1f", mediaScoreDefault)); break; case KeyUtil.POINT_100: - binding.ratingValue.setText(String.format(Locale.getDefault(),"%d", mediaBase.getMeanScore())); + binding.ratingValue.setText(String.format(Locale.getDefault(),"%d", mediaBase.getAverageScore())); break; case KeyUtil.POINT_10: - mediaScoreDefault = (mediaBase.getMeanScore() / 10); + mediaScoreDefault = (mediaBase.getAverageScore() / 10f); binding.ratingValue.setText(String.format(Locale.getDefault(),"%d", (int) mediaScoreDefault)); break; case KeyUtil.POINT_5: @@ -166,22 +166,22 @@ private void setRating(MediaBase mediaBase) { break; case KeyUtil.POINT_3: binding.ratingValue.setText(""); - if(mediaBase.getMeanScore() == 0) + if(mediaBase.getAverageScore() == 0) binding.ratingValue.setCompoundDrawablesWithIntrinsicBounds(CompatUtil.INSTANCE.getDrawable(getContext(), R.drawable.ic_face_white_18dp), null, null, null); - if(mediaBase.getMeanScore() > 0 && mediaBase.getMeanScore() <= 33) + if(mediaBase.getAverageScore() > 0 && mediaBase.getAverageScore() <= 33) binding.ratingValue.setCompoundDrawablesWithIntrinsicBounds(CompatUtil.INSTANCE.getDrawable(getContext(), R.drawable.ic_sentiment_dissatisfied_white_18dp), null, null, null); - else if (mediaBase.getMeanScore() >= 34 && mediaBase.getMeanScore() <= 66) + else if (mediaBase.getAverageScore() >= 34 && mediaBase.getAverageScore() <= 66) binding.ratingValue.setCompoundDrawablesWithIntrinsicBounds(CompatUtil.INSTANCE.getDrawable(getContext(), R.drawable.ic_sentiment_neutral_white_18dp), null, null, null); - else if (mediaBase.getMeanScore() >= 67 && mediaBase.getMeanScore() <= 100) + else if (mediaBase.getAverageScore() >= 67 && mediaBase.getAverageScore() <= 100) binding.ratingValue.setCompoundDrawablesWithIntrinsicBounds(CompatUtil.INSTANCE.getDrawable(getContext(), R.drawable.ic_sentiment_satisfied_white_18dp), null, null, null); break; } else - binding.ratingValue.setText(String.format(Locale.getDefault(),"%d", mediaBase.getMeanScore())); + binding.ratingValue.setText(String.format(Locale.getDefault(),"%d", mediaBase.getAverageScore())); } @BindingAdapter("rating") From 5e18538dbc6a74025b0feac4cf2004bcbab925d5 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Mon, 13 May 2019 21:24:18 +0200 Subject: [PATCH 14/17] Fixed Potential Null Illegal Exception - Capitalize helper function asserts non-null while the data source may present nullable values --- .../java/com/mxt/anitrend/util/CompatUtil.kt | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/com/mxt/anitrend/util/CompatUtil.kt b/app/src/main/java/com/mxt/anitrend/util/CompatUtil.kt index f725a2be0..ee11bee16 100644 --- a/app/src/main/java/com/mxt/anitrend/util/CompatUtil.kt +++ b/app/src/main/java/com/mxt/anitrend/util/CompatUtil.kt @@ -467,14 +467,16 @@ object CompatUtil { /** * Capitalize words for text view consumption */ - fun capitalizeWords(input: String): String { - if (!TextUtils.isEmpty(input)) { + fun capitalizeWords(input: String?): String { + if (!input.isNullOrBlank()) { val exceptions = constructListFrom(KeyUtil.TV, KeyUtil.ONA, KeyUtil.OVA) val result = StringBuilder(input.length) - val words = input.split("_|\\s".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() - var index = 0 - for (word in words) { - if (!TextUtils.isEmpty(word)) { + val words = input.split("_|\\s".toRegex()) + .dropLastWhile { + it.isEmpty() + }.toTypedArray() + for ((index, word) in words.withIndex()) { + if (word.isNotEmpty()) { if (exceptions.contains(word)) result.append(word) else { @@ -484,7 +486,6 @@ object CompatUtil { } if (index != word.length - 1) result.append(" ") - index++ } return result.toString() } @@ -495,10 +496,8 @@ object CompatUtil { * Get a list from a given array of strings * @return list of capitalized strings */ - fun capitalizeWords(vararg strings: String): List { - return Stream.of(*strings) - .map { capitalizeWords(it) } - .toList() + fun capitalizeWords(strings: Array): List { + return strings.map { capitalizeWords(it) } } fun > isEmpty(collection: T?): Boolean { From 552646099d4fc2ed222960c9a4a3bed50aeb795b Mon Sep 17 00:00:00 2001 From: Maxwell Date: Mon, 13 May 2019 21:24:35 +0200 Subject: [PATCH 15/17] Minor Code Refactored --- app/src/main/java/com/mxt/anitrend/App.kt | 19 ++++++++++--------- .../anitrend/receiver/SchedulerDelegate.kt | 8 +++++--- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/com/mxt/anitrend/App.kt b/app/src/main/java/com/mxt/anitrend/App.kt index cb86a6231..72e56b67f 100644 --- a/app/src/main/java/com/mxt/anitrend/App.kt +++ b/app/src/main/java/com/mxt/anitrend/App.kt @@ -24,8 +24,14 @@ import org.greenrobot.eventbus.EventBus class App : MultiDexApplication() { - val applicationPref by lazy { - ApplicationPref(this) + val applicationPref = ApplicationPref(this) + + init { + EventBus.builder().logNoSubscriberMessages(BuildConfig.DEBUG) + .sendNoSubscriberEvent(BuildConfig.DEBUG) + .sendSubscriberExceptionEvent(BuildConfig.DEBUG) + .throwSubscriberException(BuildConfig.DEBUG) + .installDefaultEventBus() } /** @@ -42,6 +48,7 @@ class App : MultiDexApplication() { */ lateinit var boxStore: BoxStore private set + /** * Get application global registered fabric instance, depending on * the current application preferences the application may have @@ -60,7 +67,7 @@ class App : MultiDexApplication() { private fun setCrashAnalytics() { if (!BuildConfig.DEBUG) - if (applicationPref.isCrashReportsEnabled!!) { + if (applicationPref.isCrashReportsEnabled == true) { val crashlyticsCore = CrashlyticsCore.Builder() .build() @@ -72,17 +79,11 @@ class App : MultiDexApplication() { } private fun initApp() { - EventBus.builder().logNoSubscriberMessages(BuildConfig.DEBUG) - .sendNoSubscriberEvent(BuildConfig.DEBUG) - .sendSubscriberExceptionEvent(BuildConfig.DEBUG) - .throwSubscriberException(BuildConfig.DEBUG) - .installDefaultEventBus() if (applicationPref.isUsageAnalyticsEnabled == true) { analytics = FirebaseAnalytics.getInstance(this).apply { setAnalyticsCollectionEnabled(applicationPref.isUsageAnalyticsEnabled!!) } } - JobSchedulerUtil.scheduleJob(applicationContext) if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) ProviderInstaller.installIfNeededAsync(applicationContext, object : ProviderInstaller.ProviderInstallListener { diff --git a/app/src/main/java/com/mxt/anitrend/receiver/SchedulerDelegate.kt b/app/src/main/java/com/mxt/anitrend/receiver/SchedulerDelegate.kt index 69eb9e406..27664fe66 100644 --- a/app/src/main/java/com/mxt/anitrend/receiver/SchedulerDelegate.kt +++ b/app/src/main/java/com/mxt/anitrend/receiver/SchedulerDelegate.kt @@ -13,8 +13,10 @@ import com.mxt.anitrend.util.JobSchedulerUtil class SchedulerDelegate : BroadcastReceiver() { - override fun onReceive(context: Context, intent: Intent) { - if (intent.action != null && intent.action == Intent.ACTION_BOOT_COMPLETED) - JobSchedulerUtil.scheduleJob(context) + override fun onReceive(context: Context, intent: Intent?) { + when (intent?.action) { + Intent.ACTION_BOOT_COMPLETED -> + JobSchedulerUtil.scheduleJob(context) + } } } \ No newline at end of file From eca5a59559a7516d1a8aa4ff17099e72f8ca3645 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Mon, 13 May 2019 21:25:47 +0200 Subject: [PATCH 16/17] Updated Application Version --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index c2822a808..6c29e11f1 100644 --- a/build.gradle +++ b/build.gradle @@ -5,8 +5,8 @@ buildscript { compileSdk = 28 targetSdk = 28 minSdk = 17 - versionCode = 104 - versionName = '1.4.1' + versionCode = 105 + versionName = '1.4.2' butterKnife = '8.8.1' glide = '4.9.0' retrofit = '2.5.0' From 98b8cb7117999cf4263facb59c0e2d82779ee883 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Mon, 13 May 2019 21:25:57 +0200 Subject: [PATCH 17/17] Release Information Changed --- app/.meta/version.json | 4 ++-- app/release/output.json | 2 +- app/src/main/assets/changelog.md | 4 +++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/app/.meta/version.json b/app/.meta/version.json index 26845eb12..ebe437fd4 100644 --- a/app/.meta/version.json +++ b/app/.meta/version.json @@ -1,7 +1,7 @@ { - "code": 104, + "code": 105, "migration": false, "releaseNotes": "", - "version": "1.4.1", + "version": "1.4.2", "appId": "com.mxt.anitrend" } diff --git a/app/release/output.json b/app/release/output.json index c0d2acd50..95c8b7aca 100644 --- a/app/release/output.json +++ b/app/release/output.json @@ -1 +1 @@ -[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":104,"versionName":"1.4.1","enabled":true,"outputFile":"anitrend_v1.4.1_rc_104.apk","fullName":"release","baseName":"release"},"path":"anitrend_v1.4.1_rc_104.apk","properties":{}}] \ No newline at end of file +[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":105,"versionName":"1.4.2","enabled":true,"outputFile":"anitrend_v1.4.2_rc_105.apk","fullName":"release","baseName":"release"},"path":"anitrend_v1.4.2_rc_105.apk","properties":{}}] \ No newline at end of file diff --git a/app/src/main/assets/changelog.md b/app/src/main/assets/changelog.md index 575e15f32..b44457967 100644 --- a/app/src/main/assets/changelog.md +++ b/app/src/main/assets/changelog.md @@ -5,10 +5,12 @@ which can result in authentication errors [read more](https://github.com/square/ #### Enhancements - Reintroduced emoji support -- Spoiler tags support (Mittens) +- Spoiler tags in media pages (Mittens) +- New notification type for media the user may be interested in #### Bug Fixes - Multiple translations fixed +- Scores not matching sorted order - Crashes on some device related to crunchyroll feeds #### Current Issues