From 879715dce8c8324d1d61879ffb464f516fd4bced Mon Sep 17 00:00:00 2001 From: Maxwell Date: Sun, 30 Jun 2019 11:42:39 +0200 Subject: [PATCH 01/81] Update Travis Configuration --- .travis.yml | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/.travis.yml b/.travis.yml index dd7b89473..9b937647f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,7 @@ language: android jdk: oraclejdk8 +dist: trusty +sudo: false env: global: @@ -9,20 +11,29 @@ env: android: components: - - tools - - platform-tools + # Uncomment the lines below if you want to + # use the latest revision of Android SDK Tools + # - tools + # - platform-tools + - build-tools-$ANDROID_BUILD_TOOLS_VERSION - # system images - - sys-img-armeabi-v7a-android-$ANDROID_API_LEVEL - - sys-img-x86-android-$ANDROID_API_LEVEL - - sys-img-armeabi-v7a-android-17 + # The BuildTools version used by your project + - build-tools-$ANDROID_BUILD_TOOLS_VERSION - # extras + # The SDK version used to compile your project + - android-ANDROID_API_LEVEL + + # Additional components - extra-google-google_play_services - extra-google-m2repository - extra-android-m2repository - - extra-android-support + + # Specify at least one system image, + # if you need to run emulator(s) during your tests + - sys-img-armeabi-v7a-android-$ANDROID_API_LEVEL + - sys-img-x86-android-$ANDROID_API_LEVEL + - sys-img-armeabi-v7a-android-17 # addons - addon-google_apis-google-$ANDROID_API_LEVEL @@ -37,17 +48,17 @@ before_cache: - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock - rm -fr $HOME/.gradle/caches/*/plugin-resolution/ -# Move our test play-services configuration to the appropreiate config location -before_script: - - mv app/.travic-ci/google-services.json app/google-services.json - - mv app/.travic-ci/secrets ./secrets.properties - cache: directories: - - $HOME/.m2 - $HOME/.gradle/caches/ - $HOME/.gradle/wrapper/ + - $HOME/.android/build-cache +# Move our test play-services configuration to the appropreiate config location +before_script: + - mv app/.travic-ci/google-services.json app/google-services.json + - mv app/.travic-ci/secrets ./secrets.properties + script: - ./gradlew test @@ -55,3 +66,5 @@ script: before_install: - chmod +x gradlew - yes | sdkmanager "platforms;android-28" + - yes | sdkmanager "build-tools;28.0.3" + From 77458a5b1859631f2c2e3a86b81528292dc3f337 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Sun, 7 Jul 2019 19:22:12 +0200 Subject: [PATCH 02/81] Update Translations Adds non-streaming disclaimer for lazy users --- app/src/main/res/values-es/strings.xml | 2 +- app/src/main/res/values-it/strings.xml | 2 +- app/src/main/res/values-pl/strings.xml | 2 +- app/src/main/res/values-pt/strings.xml | 2 +- app/src/main/res/values-sv/strings.xml | 2 +- app/src/main/res/values/strings.xml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 31b603bc3..8fc363d42 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -150,7 +150,7 @@ Encuentra ¡Anime y Manga gracias a su motor de búsqueda eficiente y lleno de características! ¡Facilita la visualización de vídeos de Youtube a través del reproductor integrado! - ¡Bienvenido/a a AniTrend! + ¡Bienvenido/a a AniTrend, this is not a streaming app! Ordenar Por: diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 982fd3f12..8c8c66d41 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -146,7 +146,7 @@ Cerca Anime, manga & ed altre funzioni di ricerca! Usa il Player Video di Youtube integrato! - Benvenuto su AniTrend! + Benvenuto su AniTrend, this is not a streaming app! Organizza diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 2504138ec..343d0c002 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -151,7 +151,7 @@ Anime, Manga i Więcej funkcji wyszukiwania! Wideo Używa wbudowanego odtwarzacza wideo Youtube! - Witaj w AniTrend! + Witaj w AniTrend, this is not a streaming app! Sortuj według diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index fefa787ed..d1e1022ad 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -149,7 +149,7 @@ Pesquisando Anime, Mangá & Mais Opções de Pesquisa! Usando um Player Embutido do Youtube! - Bem-vindo ao AniTrend! + Bem-vindo ao AniTrend, this is not a streaming app! Classificar por? diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index c2c7fb376..a486c4897 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -150,7 +150,7 @@ Anime, Manga & Mer sökfunktionalitet! Videoklipp Använda Inbyggd Youtube Video Player! - Välkommen till AniTrend! + Välkommen till AniTrend, this is not a streaming app! Sortera efter? diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ac3982de3..bfdf3f301 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -161,7 +161,7 @@ Anime, Manga & More Search Functionality! Videos Using Builtin Youtube Video Player! - Welcome to AniTrend! + Welcome to AniTrend, this is not a streaming app! Sort By? From 3555bd80eba5194ceddb809f98bddc678657d17e Mon Sep 17 00:00:00 2001 From: Maxwell Date: Sun, 7 Jul 2019 19:44:29 +0200 Subject: [PATCH 03/81] Bump Kotlin Version from 1.3.31 to 1.3.41 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index bb43a67aa..1a40b8d97 100644 --- a/build.gradle +++ b/build.gradle @@ -16,7 +16,7 @@ buildscript { architecture = '1.1.1' workManager = '1.0.1' emojify = '1.4' - kotlin = '1.3.31' + kotlin = '1.3.41' // testing libraries mockito = '2.18.3' hemcrest = '1.3' From 80ada7f5c4bbcee69112cd270afc54e29af9947a Mon Sep 17 00:00:00 2001 From: Maxwell Date: Sun, 7 Jul 2019 19:45:06 +0200 Subject: [PATCH 04/81] Bump Google Service Version from 4.2.0 to 4.3.0 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 1a40b8d97..03669d845 100644 --- a/build.gradle +++ b/build.gradle @@ -34,7 +34,7 @@ buildscript { classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${rootProject.kotlin}" // Google Play Services - classpath 'com.google.gms:google-services:4.2.0' + classpath 'com.google.gms:google-services:4.3.0' // Crash Analytics classpath 'io.fabric.tools:gradle:1.28.1' // Object Box From cfdc0b5c808f9d53d06b394cd8bd0019fd38fa50 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Sun, 7 Jul 2019 19:46:10 +0200 Subject: [PATCH 05/81] Bump Fabric Tools Version from 1.28.1 to 1.29.0 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 03669d845..329745c7c 100644 --- a/build.gradle +++ b/build.gradle @@ -36,7 +36,7 @@ buildscript { // Google Play Services classpath 'com.google.gms:google-services:4.3.0' // Crash Analytics - classpath 'io.fabric.tools:gradle:1.28.1' + classpath 'io.fabric.tools:gradle:1.29.0' // Object Box classpath "io.objectbox:objectbox-gradle-plugin:${rootProject.objectBox}" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${rootProject.kotlin}" From 4b08e8aaa958174f49b5a7db2de053ab75b025e2 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Sun, 7 Jul 2019 19:48:38 +0200 Subject: [PATCH 06/81] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 350215dfe..cc3460476 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# [ :biohazard: W.I.P v2.0 :biohazard: ] AniTrend v1.4.7   [![license](https://img.shields.io/github/license/mashape/apistatus.svg?style=flat-square)](https://github.com/AniTrend/anitrend-app/blob/master/LICENSE.md) +# [ :biohazard: W.I.P v2.0 :biohazard: ] AniTrend v1.4.8   [![license](https://img.shields.io/github/license/mashape/apistatus.svg?style=flat-square)](https://github.com/AniTrend/anitrend-app/blob/master/LICENSE.md) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/30a8f983c55541cbb504671ecc32786c)](https://www.codacy.com/app/wax911/anitrend-app?utm_source=github.com&utm_medium=referral&utm_content=wax911/anitrend-app&utm_campaign=Badge_Grade)   [![Build Status](https://travis-ci.org/AniTrend/anitrend-app.svg?branch=master)](https://travis-ci.org/AniTrend/anitrend-app)   [![Discord](https://img.shields.io/discord/314442908478472203.svg?color=%237289da&label=Join%20Anitrend%21&logo=discord&logoColor=%23fff)](https://discordapp.com/invite/2wzTqnF) Discover anime or manga with AniTrend which is a free [AniList](https://anilist.co) android client written in java.(AniTrend does not offer streaming capabilities, but official website links such as Hulu, Chrunchyroll, Netflix will be provided if available) From 910a959d0d212d89d02e23255d9203ce592ce0fd Mon Sep 17 00:00:00 2001 From: Maxwell Date: Sun, 7 Jul 2019 19:48:57 +0200 Subject: [PATCH 07/81] Bump Application Version from 1.4.7 to 1.4.8 --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 329745c7c..bb6c004e7 100644 --- a/build.gradle +++ b/build.gradle @@ -5,8 +5,8 @@ buildscript { compileSdk = 28 targetSdk = 28 minSdk = 17 - versionCode = 111 - versionName = '1.4.7' + versionCode = 112 + versionName = '1.4.8' butterKnife = '8.8.1' glide = '4.9.0' retrofit = '2.5.0' From ea6347dd29e355c7e92db9c4bf26fb164c42741e Mon Sep 17 00:00:00 2001 From: Maxwell Date: Wed, 31 Jul 2019 19:14:07 +0200 Subject: [PATCH 08/81] Improve Invalid Token Error Message --- app/src/main/assets/changelog.md | 6 +- .../pager/detail/AnimePageAdapter.java | 2 +- .../pager/detail/MangaPageAdapter.java | 2 +- .../base/custom/viewmodel/ViewModelBase.kt | 12 +- .../detail/MediaOverviewFragment.java | 257 ------------------ .../fragment/detail/MediaOverviewFragment.kt | 249 +++++++++++++++++ .../fragment/youtube/YoutubePlayerFragment.kt | 26 +- app/src/main/res/values-ar/strings.xml | 1 + app/src/main/res/values-de/strings.xml | 1 + app/src/main/res/values-es/strings.xml | 1 + app/src/main/res/values-fr/strings.xml | 1 + app/src/main/res/values-it/strings.xml | 1 + app/src/main/res/values-nl/strings.xml | 1 + app/src/main/res/values-pl/strings.xml | 1 + app/src/main/res/values-pt/strings.xml | 1 + app/src/main/res/values-sv/strings.xml | 1 + app/src/main/res/values/strings.xml | 3 + build.gradle | 6 +- 18 files changed, 298 insertions(+), 274 deletions(-) delete mode 100644 app/src/main/java/com/mxt/anitrend/view/fragment/detail/MediaOverviewFragment.java create mode 100644 app/src/main/java/com/mxt/anitrend/view/fragment/detail/MediaOverviewFragment.kt diff --git a/app/src/main/assets/changelog.md b/app/src/main/assets/changelog.md index 83a7a7099..e76fbd9f7 100644 --- a/app/src/main/assets/changelog.md +++ b/app/src/main/assets/changelog.md @@ -7,9 +7,7 @@ which can result in authentication errors [read more](https://github.com/square/ - Minor UI tweaks, specifically view radius #### Bug Fixes -- About page crashes -- Episode duration always displaying TBA (Swap) -- Missing notification type for subscribed activities (Mittens, Taichi) +- Improved error message for invalid token errors #### Current Issues - Clicking on @username shows mixed feed @@ -22,5 +20,5 @@ __Admins, Devs & Cutie Pies:__ _Mittens, Switchums, Kuji, Moka, Flare, Silver, Mrspits4ever_ __Awesome Donators:__ -_Bas, Golumpa, artemisthemp, Trivernis, PeakZer0, KorenTeam, keiggard_ +_Bas, Golumpa, artemisthemp, trivernis, keiggard, barbas_ 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 2a9f0f687..446094be4 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 @@ -46,7 +46,7 @@ public int getCount() { public Fragment getItem(int position) { switch (position) { case 0: - return MediaOverviewFragment.newInstance(getParams()); + return MediaOverviewFragment.Companion.newInstance(getParams()); case 1: return MediaRelationFragment.newInstance(getParams()); case 2: 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 32984bd54..7f9863cde 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 @@ -45,7 +45,7 @@ public int getCount() { public Fragment getItem(int position) { switch (position) { case 0: - return MediaOverviewFragment.newInstance(getParams()); + return MediaOverviewFragment.Companion.newInstance(getParams()); case 1: return MediaRelationFragment.newInstance(getParams()); case 2: 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 index da8a084ed..c5ae0da9a 100644 --- 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 @@ -35,6 +35,7 @@ class ViewModelBase: ViewModel(), RetroCallback { private var emptyMessage: String? = null private var errorMessage: String? = null + private var tokenMessage: String? = null val params by lazy { Bundle() @@ -44,6 +45,7 @@ class ViewModelBase: ViewModel(), RetroCallback { context?.apply { emptyMessage = getString(R.string.layout_empty_response) errorMessage = getString(R.string.text_error_request) + tokenMessage = getString(R.string.text_error_auth_token) } } @@ -86,8 +88,14 @@ class ViewModelBase: ViewModel(), RetroCallback { val container: T? = response.body() if (response.isSuccessful && container != null) model.setValue(container) - else - state?.showError(ErrorUtil.getError(response)) + else { + val error = ErrorUtil.getError(response) + // Hacky fix that I'm ashamed of + if (response.code() == 400 && error.contains("Invalid token")) + state?.showError(tokenMessage) + else + state?.showError(error) + } } /** 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 deleted file mode 100644 index 44f3fa208..000000000 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/MediaOverviewFragment.java +++ /dev/null @@ -1,257 +0,0 @@ -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; -import android.support.v7.widget.StaggeredGridLayoutManager; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import com.annimon.stream.IntPair; -import com.google.android.youtube.player.YouTubeIntents; -import com.mxt.anitrend.R; -import com.mxt.anitrend.adapter.recycler.detail.GenreAdapter; -import com.mxt.anitrend.adapter.recycler.detail.TagAdapter; -import com.mxt.anitrend.base.custom.fragment.FragmentBase; -import com.mxt.anitrend.base.interfaces.event.ItemClickListener; -import com.mxt.anitrend.databinding.FragmentSeriesOverviewBinding; -import com.mxt.anitrend.model.entity.anilist.Genre; -import com.mxt.anitrend.model.entity.anilist.Media; -import com.mxt.anitrend.model.entity.anilist.MediaTag; -import com.mxt.anitrend.model.entity.base.StudioBase; -import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder; -import com.mxt.anitrend.presenter.fragment.MediaPresenter; -import com.mxt.anitrend.util.CompatUtil; -import com.mxt.anitrend.util.DialogUtil; -import com.mxt.anitrend.util.GraphUtil; -import com.mxt.anitrend.util.KeyUtil; -import com.mxt.anitrend.util.MediaBrowseUtil; -import com.mxt.anitrend.view.activity.detail.MediaBrowseActivity; -import com.mxt.anitrend.view.activity.detail.StudioActivity; -import com.mxt.anitrend.view.fragment.youtube.YouTubeEmbedFragment; -import com.mxt.anitrend.view.fragment.youtube.YoutubePlayerFragment; - -import butterknife.ButterKnife; -import butterknife.OnClick; - -/** - * Created by max on 2017/12/31. - */ - -public class MediaOverviewFragment extends FragmentBase { - - private FragmentSeriesOverviewBinding binding; - private YoutubePlayerFragment youtubePlayerFragment; - private Media model; - - private GenreAdapter genreAdapter; - private TagAdapter tagAdapter; - - private long mediaId; - private @KeyUtil.MediaType String mediaType; - - public static MediaOverviewFragment newInstance(Bundle args) { - MediaOverviewFragment fragment = new MediaOverviewFragment(); - fragment.setArguments(args); - return fragment; - } - - @Override - public void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - if (getArguments() != null) { - mediaId = getArguments().getLong(KeyUtil.arg_id); - mediaType = getArguments().getString(KeyUtil.arg_mediaType); - } - isMenuDisabled = true; mColumnSize = R.integer.grid_list_x2; - setPresenter(new MediaPresenter(getContext())); - setViewModel(true); - } - - @Nullable @Override - public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - binding = FragmentSeriesOverviewBinding.inflate(inflater, container, false); - unbinder = ButterKnife.bind(this, binding.getRoot()); - binding.stateLayout.showLoading(); - - binding.genreRecycler.setLayoutManager(new StaggeredGridLayoutManager(getResources().getInteger(mColumnSize), StaggeredGridLayoutManager.VERTICAL)); - binding.genreRecycler.setNestedScrollingEnabled(false); - binding.genreRecycler.setHasFixedSize(true); - - binding.tagsRecycler.setLayoutManager(new StaggeredGridLayoutManager(getResources().getInteger(mColumnSize), StaggeredGridLayoutManager.VERTICAL)); - binding.tagsRecycler.setNestedScrollingEnabled(false); - binding.tagsRecycler.setHasFixedSize(true); - - return binding.getRoot(); - } - - @Override - public void onStart() { - super.onStart(); - makeRequest(); - } - - /** - * Is automatically called in the @onStart Method if overridden in list implementation - */ - @Override - protected void updateUI() { - if(getActivity() != null && model.getTrailer() != null && CompatUtil.INSTANCE.equals(model.getTrailer().getSite(), "youtube")) { - if(YouTubeIntents.canResolvePlayVideoIntent(getActivity())) { - if (youtubePlayerFragment == null) - youtubePlayerFragment = YoutubePlayerFragment.Companion.newInstance(model.getTrailer()); - getChildFragmentManager().beginTransaction() - .replace(R.id.youtube_view, youtubePlayerFragment) - .commit(); - } else { - getChildFragmentManager().beginTransaction() - .replace(R.id.youtube_view, YouTubeEmbedFragment.newInstance(model.getTrailer())) - .commit(); - } - } else - binding.youtubeView.setVisibility(View.GONE); - 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)); - genreAdapter.setClickListener(new ItemClickListener() { - @Override - public void onItemClick(View target, IntPair data) { - switch (target.getId()) { - case R.id.container: - Bundle args = new Bundle(); - Intent intent = new Intent(getActivity(), MediaBrowseActivity.class); - 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()); - args.putParcelable(KeyUtil.arg_media_util, new MediaBrowseUtil() - .setCompactType(true) - .setBasicFilter(true) - .setFilterEnabled(true)); - intent.putExtras(args); - startActivity(intent); - break; - } - } - - @Override - public void onItemLongClick(View target, IntPair data) { - - } - }); - } - binding.genreRecycler.setAdapter(genreAdapter); - - if(tagAdapter == null) { - tagAdapter = new TagAdapter(getContext()); - tagAdapter.onItemsInserted(model.getTagsNoSpoilers()); - tagAdapter.setClickListener(new ItemClickListener() { - @Override - public void onItemClick(View target, IntPair data) { - switch (target.getId()) { - case R.id.container: - DialogUtil.createTagMessage(getActivity(), data.getSecond().getName(), data.getSecond().getDescription(), data.getSecond().isMediaSpoiler(), - R.string.More, R.string.Close, (dialog, which) -> { - switch (which) { - case POSITIVE: - Bundle args = new Bundle(); - Intent intent = new Intent(getActivity(), MediaBrowseActivity.class); - 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()); - args.putParcelable(KeyUtil.arg_media_util, new MediaBrowseUtil() - .setCompactType(true) - .setBasicFilter(true) - .setFilterEnabled(true)); - intent.putExtras(args); - startActivity(intent); - break; - } - }); - break; - } - } - - @Override - public void onItemLongClick(View target, IntPair data) { - - } - }); - } - binding.tagsRecycler.setAdapter(tagAdapter); - - binding.stateLayout.showContent(); - } - - /** - * All new or updated network requests should be handled in this method - */ - @Override - public void makeRequest() { - QueryContainerBuilder queryContainer = GraphUtil.INSTANCE.getDefaultQuery(isPager) - .putVariable(KeyUtil.arg_id, mediaId) - .putVariable(KeyUtil.arg_type, mediaType); - getViewModel().getParams().putParcelable(KeyUtil.arg_graph_params, queryContainer); - getViewModel().requestData(KeyUtil.MEDIA_OVERVIEW_REQ, getContext()); - } - - /** - * Called when the model state is changed. - * - * @param model The new data - */ - @Override - public void onChanged(@Nullable Media model) { - if(model != null) { - this.model = model; - updateUI(); - } else - 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(); }); - } - - /** - * Called when a view has been clicked. - * - * @param v The view that was clicked. - */ - @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: - 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); - if(studioBase != null) { - intent = new Intent(getActivity(), StudioActivity.class); - intent.putExtra(KeyUtil.arg_id, studioBase.getId()); - startActivity(intent); - } - break; - case R.id.show_spoiler_tags: - tagAdapter.onItemRangeChanged(model.getTags()); - tagAdapter.notifyDataSetChanged(); - v.setVisibility(View.GONE); - break; - default: - super.onClick(v); - break; - } - } -} diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/MediaOverviewFragment.kt b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/MediaOverviewFragment.kt new file mode 100644 index 000000000..076e7f74a --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/MediaOverviewFragment.kt @@ -0,0 +1,249 @@ +package com.mxt.anitrend.view.fragment.detail + +import android.content.Intent +import android.os.Bundle +import android.support.v7.widget.StaggeredGridLayoutManager +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup + +import com.annimon.stream.IntPair +import com.google.android.youtube.player.YouTubeIntents +import com.mxt.anitrend.R +import com.mxt.anitrend.adapter.recycler.detail.GenreAdapter +import com.mxt.anitrend.adapter.recycler.detail.TagAdapter +import com.mxt.anitrend.base.custom.fragment.FragmentBase +import com.mxt.anitrend.base.interfaces.event.ItemClickListener +import com.mxt.anitrend.databinding.FragmentSeriesOverviewBinding +import com.mxt.anitrend.model.entity.anilist.Genre +import com.mxt.anitrend.model.entity.anilist.Media +import com.mxt.anitrend.model.entity.anilist.MediaTag +import com.mxt.anitrend.model.entity.base.StudioBase +import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder +import com.mxt.anitrend.presenter.fragment.MediaPresenter +import com.mxt.anitrend.util.CompatUtil +import com.mxt.anitrend.util.DialogUtil +import com.mxt.anitrend.util.GraphUtil +import com.mxt.anitrend.util.KeyUtil +import com.mxt.anitrend.util.MediaBrowseUtil +import com.mxt.anitrend.view.activity.detail.MediaBrowseActivity +import com.mxt.anitrend.view.activity.detail.StudioActivity +import com.mxt.anitrend.view.fragment.youtube.YouTubeEmbedFragment +import com.mxt.anitrend.view.fragment.youtube.YoutubePlayerFragment + +import butterknife.ButterKnife +import butterknife.OnClick +import com.afollestad.materialdialogs.DialogAction + +/** + * Created by max on 2017/12/31. + */ + +class MediaOverviewFragment : FragmentBase() { + + private var binding: FragmentSeriesOverviewBinding? = null + private var youtubePlayerFragment: YoutubePlayerFragment? = null + private var model: Media? = null + + private var genreAdapter: GenreAdapter? = null + private var tagAdapter: TagAdapter? = null + + private var mediaId: Long = 0 + @KeyUtil.MediaType + private var mediaType: String? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + if (arguments != null) { + mediaId = arguments!!.getLong(KeyUtil.arg_id) + mediaType = arguments!!.getString(KeyUtil.arg_mediaType) + } + isMenuDisabled = true + mColumnSize = R.integer.grid_list_x2 + setPresenter(MediaPresenter(context)) + setViewModel(true) + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + binding = FragmentSeriesOverviewBinding.inflate(inflater, container, false).apply { + unbinder = ButterKnife.bind(this, root) + stateLayout.showLoading() + + genreRecycler.layoutManager = StaggeredGridLayoutManager(resources.getInteger(mColumnSize), StaggeredGridLayoutManager.VERTICAL) + genreRecycler.isNestedScrollingEnabled = false + genreRecycler.setHasFixedSize(true) + + tagsRecycler.layoutManager = StaggeredGridLayoutManager(resources.getInteger(mColumnSize), StaggeredGridLayoutManager.VERTICAL) + tagsRecycler.isNestedScrollingEnabled = false + tagsRecycler.setHasFixedSize(true) + } + + return binding?.root + } + + override fun onStart() { + super.onStart() + makeRequest() + } + + /** + * Is automatically called in the @onStart Method if overridden in list implementation + */ + override fun updateUI() { + if (activity != null && model!!.trailer != null && CompatUtil.equals(model!!.trailer.site, "youtube")) { + if (YouTubeIntents.canResolvePlayVideoIntent(activity!!)) { + if (youtubePlayerFragment == null) + youtubePlayerFragment = YoutubePlayerFragment.newInstance(model!!.trailer) + childFragmentManager.beginTransaction() + .replace(R.id.youtube_view, youtubePlayerFragment!!) + .commit() + } else { + childFragmentManager.beginTransaction() + .replace(R.id.youtube_view, YouTubeEmbedFragment.newInstance(model!!.trailer)) + .commit() + } + } else + binding!!.youtubeView.visibility = View.GONE + binding!!.presenter = presenter + binding!!.model = model + + + if (model!!.tags != null && model!!.tagsNoSpoilers != null) { + if (model!!.tagsNoSpoilers.size == model!!.tags.size) + binding!!.showSpoilerTags.visibility = View.GONE + else + binding!!.showSpoilerTags.visibility = View.VISIBLE + } + + if (genreAdapter == null) { + genreAdapter = GenreAdapter(context) + genreAdapter!!.onItemsInserted(presenter.buildGenres(model)) + genreAdapter!!.setClickListener(object : ItemClickListener { + override fun onItemClick(target: View, data: IntPair) { + when (target.id) { + R.id.container -> { + val args = Bundle() + val intent = Intent(activity, MediaBrowseActivity::class.java) + args.putParcelable(KeyUtil.arg_graph_params, GraphUtil.getDefaultQuery(true) + .putVariable(KeyUtil.arg_type, mediaType) + .putVariable(KeyUtil.arg_genres, data.second.genre)) + args.putString(KeyUtil.arg_activity_tag, data.second.genre) + args.putParcelable(KeyUtil.arg_media_util, MediaBrowseUtil() + .setCompactType(true) + .setBasicFilter(true) + .setFilterEnabled(true)) + intent.putExtras(args) + startActivity(intent) + } + } + } + + override fun onItemLongClick(target: View, data: IntPair) { + + } + }) + } + binding!!.genreRecycler.adapter = genreAdapter + + if (tagAdapter == null) { + tagAdapter = TagAdapter(context) + tagAdapter!!.onItemsInserted(model!!.tagsNoSpoilers) + tagAdapter!!.setClickListener(object : ItemClickListener { + override fun onItemClick(target: View, data: IntPair) { + when (target.id) { + R.id.container -> DialogUtil.createTagMessage(activity, data.second.name, data.second.description, data.second.isMediaSpoiler, + R.string.More, R.string.Close) { dialog, which -> + when (which) { + DialogAction.POSITIVE -> { + val args = Bundle() + val intent = Intent(activity, MediaBrowseActivity::class.java) + args.putParcelable(KeyUtil.arg_graph_params, GraphUtil.getDefaultQuery(true) + .putVariable(KeyUtil.arg_type, mediaType) + .putVariable(KeyUtil.arg_tags, data.second.name)) + args.putString(KeyUtil.arg_activity_tag, data.second.name) + args.putParcelable(KeyUtil.arg_media_util, MediaBrowseUtil() + .setCompactType(true) + .setBasicFilter(true) + .setFilterEnabled(true)) + intent.putExtras(args) + startActivity(intent) + } + } + } + } + } + + override fun onItemLongClick(target: View, data: IntPair) { + + } + }) + } + binding!!.tagsRecycler.adapter = tagAdapter + + binding!!.stateLayout.showContent() + } + + /** + * All new or updated network requests should be handled in this method + */ + override fun makeRequest() { + val queryContainer = GraphUtil.getDefaultQuery(isPager) + .putVariable(KeyUtil.arg_id, mediaId) + .putVariable(KeyUtil.arg_type, mediaType) + getViewModel().params.putParcelable(KeyUtil.arg_graph_params, queryContainer) + getViewModel().requestData(KeyUtil.MEDIA_OVERVIEW_REQ, context!!) + } + + /** + * Called when the model state is changed. + * + * @param model The new data + */ + override fun onChanged(model: Media?) { + if (model != null) { + this.model = model + updateUI() + } else + binding!!.stateLayout.showError(CompatUtil.getDrawable(context!!, R.drawable.ic_emoji_sweat), + getString(R.string.layout_empty_response), getString(R.string.try_again)) { view -> + binding!!.stateLayout.showLoading() + makeRequest() + } + } + + /** + * Called when a view has been clicked. + * + * @param v The view that was clicked. + */ + @OnClick(R.id.series_image, R.id.anime_main_studio_container, R.id.show_spoiler_tags) + override fun onClick(v: View) { + val intent: Intent + when (v.id) { + R.id.series_image -> CompatUtil.imagePreview(activity, v, model!!.coverImage.large, R.string.image_preview_error_series_cover) + R.id.anime_main_studio_container -> { + val studioBase = presenter.getMainStudioObject(model) + if (studioBase != null) { + intent = Intent(activity, StudioActivity::class.java) + intent.putExtra(KeyUtil.arg_id, studioBase.id) + startActivity(intent) + } + } + R.id.show_spoiler_tags -> { + tagAdapter!!.onItemRangeChanged(model!!.tags) + tagAdapter!!.notifyDataSetChanged() + v.visibility = View.GONE + } + else -> super.onClick(v) + } + } + + companion object { + + fun newInstance(args: Bundle): MediaOverviewFragment { + val fragment = MediaOverviewFragment() + fragment.arguments = args + return fragment + } + } +} diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/youtube/YoutubePlayerFragment.kt b/app/src/main/java/com/mxt/anitrend/view/fragment/youtube/YoutubePlayerFragment.kt index 2164e83a1..0802216f1 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/youtube/YoutubePlayerFragment.kt +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/youtube/YoutubePlayerFragment.kt @@ -21,6 +21,11 @@ class YoutubePlayerFragment : YouTubePlayerSupportFragment(), YouTubePlayer.OnIn private var mediaTrailer: MediaTrailer? = null private var youTubePlayer: YouTubePlayer? = null + private var isFullScreen: Boolean = false + + private val youTubePlayerFullscreenListener = YouTubePlayer.OnFullscreenListener { + fullScreen -> isFullScreen = fullScreen + } override fun onCreate(bundle: Bundle?) { super.onCreate(bundle) @@ -37,9 +42,16 @@ class YoutubePlayerFragment : YouTubePlayerSupportFragment(), YouTubePlayer.OnIn } } - override fun onDestroyView() { - youTubePlayer?.release() - super.onDestroyView() + /** + * Informs parent activity if on back can continue to super method or not + */ + fun onBackPress(): Boolean { + if (isFullScreen) { + youTubePlayer?.setFullscreen(false) + youTubePlayer?.release() + return false + } + return true } override fun onInitializationSuccess( @@ -49,9 +61,11 @@ class YoutubePlayerFragment : YouTubePlayerSupportFragment(), YouTubePlayer.OnIn ) { try { if (lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)) { - this@YoutubePlayerFragment.youTubePlayer = youTubePlayer - if (!wasRestored) - this@YoutubePlayerFragment.youTubePlayer?.cueVideo(mediaTrailer?.id) + this@YoutubePlayerFragment.youTubePlayer = youTubePlayer.apply { + setOnFullscreenListener(youTubePlayerFullscreenListener) + if (!wasRestored) + cueVideo(mediaTrailer?.id) + } } } catch (e: Exception) { e.printStackTrace() diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 31bf2f874..b8cf2cf07 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -970,4 +970,5 @@ Show Spoiler Tags New Related Media Added Use black theme for devices that have OLED displays to save power + Invalid session, please log out and back in diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index f44bf649e..7938d84aa 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -967,4 +967,5 @@ Extras Get Started Videos + Invalid session, please log out and back in \ 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 8fc363d42..4fabb84ef 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -970,4 +970,5 @@ elementos de tus favoritos al presionar en el icono del corazón . Extras Videos General + Invalid session, please log out and back in diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 8b32f3d36..dfc10363d 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -971,4 +971,5 @@ Contact About Configuration + Invalid session, please log out and back in \ 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 8c8c66d41..6eaa73b49 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -968,4 +968,5 @@ Status Feeds Account Videos + Invalid session, please log out and back in diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index e38c22023..3f754d2ba 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -973,4 +973,5 @@ Videos Searching Welcome to AniTrend! + Invalid session, please log out and back in diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 343d0c002..14a973067 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -972,4 +972,5 @@ New Related Media Added Studio Use black theme for devices that have OLED displays to save power + Invalid session, please log out and back in diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index d1e1022ad..dcff9da9f 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -974,4 +974,5 @@ Home Extras Videos + Invalid session, please log out and back in \ 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 a486c4897..292a4270b 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -971,4 +971,5 @@ Use black theme for devices that have OLED displays to save power Support AniTrend Hub + Invalid session, please log out and back in diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index bfdf3f301..2ca96659a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1029,4 +1029,7 @@ Show Spoiler Tags New Related Media Added + + + Invalid session, please log out and back in diff --git a/build.gradle b/build.gradle index bb6c004e7..9915f266a 100644 --- a/build.gradle +++ b/build.gradle @@ -5,8 +5,8 @@ buildscript { compileSdk = 28 targetSdk = 28 minSdk = 17 - versionCode = 112 - versionName = '1.4.8' + versionCode = 113 + versionName = '1.4.9' butterKnife = '8.8.1' glide = '4.9.0' retrofit = '2.5.0' @@ -30,7 +30,7 @@ buildscript { maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' } } dependencies { - classpath 'com.android.tools.build:gradle:3.4.1' + classpath 'com.android.tools.build:gradle:3.4.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${rootProject.kotlin}" // Google Play Services From ef8dfd99add8be86c2c8829530a917ec2a3558e2 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Sun, 4 Aug 2019 14:38:21 +0200 Subject: [PATCH 09/81] Bump Fabric Tools from 1.29.0 to 1.31.0 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 9915f266a..7b2fc16d6 100644 --- a/build.gradle +++ b/build.gradle @@ -36,7 +36,7 @@ buildscript { // Google Play Services classpath 'com.google.gms:google-services:4.3.0' // Crash Analytics - classpath 'io.fabric.tools:gradle:1.29.0' + classpath 'io.fabric.tools:gradle:1.31.0' // Object Box classpath "io.objectbox:objectbox-gradle-plugin:${rootProject.objectBox}" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${rootProject.kotlin}" From ba46fff6a9f0ad4a8f17987d92f671c0364de807 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Sun, 4 Aug 2019 16:04:58 +0200 Subject: [PATCH 10/81] Migrate to AndroidX Components --- app/build.gradle | 180 +++++++++++------- app/src/main/java/com/mxt/anitrend/App.kt | 4 +- .../pager/detail/AnimePageAdapter.java | 4 +- .../pager/detail/CharacterPageAdapter.java | 4 +- .../pager/detail/FavouritePageAdapter.java | 4 +- .../pager/detail/MangaPageAdapter.java | 4 +- .../pager/detail/MessagePageAdapter.java | 4 +- .../pager/detail/ProfilePageAdapter.java | 4 +- .../pager/detail/StaffPageAdapter.java | 4 +- .../pager/index/AiringPageAdapter.java | 4 +- .../adapter/pager/index/FeedPageAdapter.java | 4 +- .../adapter/pager/index/HubPageAdapter.java | 4 +- .../adapter/pager/index/MangaPageAdapter.java | 4 +- .../pager/index/MediaListPageAdapter.java | 4 +- .../pager/index/ReviewPageAdapter.java | 4 +- .../pager/index/SearchPageAdapter.java | 4 +- .../pager/index/SeasonPageAdapter.java | 4 +- .../pager/index/TrendingPageAdapter.java | 4 +- .../recycler/detail/CommentAdapter.java | 2 +- .../adapter/recycler/detail/GenreAdapter.java | 2 +- .../adapter/recycler/detail/GiphyAdapter.java | 2 +- .../recycler/detail/ImagePreviewAdapter.java | 5 +- .../adapter/recycler/detail/LinkAdapter.java | 2 +- .../adapter/recycler/detail/RankAdapter.java | 2 +- .../adapter/recycler/detail/TagAdapter.java | 2 +- .../recycler/group/GroupActorAdapter.java | 2 +- .../recycler/group/GroupCharacterAdapter.java | 4 +- .../recycler/group/GroupSeriesAdapter.java | 2 +- .../recycler/group/GroupStaffRoleAdapter.java | 2 +- .../recycler/index/EpisodeAdapter.java | 2 +- .../adapter/recycler/index/FeedAdapter.java | 2 +- .../adapter/recycler/index/MediaAdapter.java | 2 +- .../recycler/index/MediaListAdapter.java | 2 +- .../adapter/recycler/index/ReviewAdapter.java | 2 +- .../adapter/recycler/index/StaffAdapter.java | 2 +- .../adapter/recycler/index/StudioAdapter.java | 2 +- .../adapter/recycler/index/UserAdapter.java | 2 +- .../adapter/spinner/IconArrayAdapter.java | 4 +- .../base/custom/activity/ActivityBase.java | 20 +- .../base/custom/async/WebTokenRequest.java | 2 +- .../base/custom/fragment/FragmentBase.java | 16 +- .../custom/fragment/FragmentBaseComment.java | 10 +- .../custom/fragment/FragmentBaseList.java | 8 +- .../custom/fragment/FragmentChannelBase.java | 8 +- .../custom/pager/BaseStatePageAdapter.java | 8 +- .../recycler/RecyclerScrollListener.java | 8 +- .../custom/recycler/RecyclerViewAdapter.java | 10 +- .../custom/recycler/RecyclerViewHolder.java | 4 +- .../custom/recycler/StatefulRecyclerView.java | 4 +- .../base/custom/sheet/BottomSheetBase.java | 14 +- .../custom/sheet/BottomSheetGiphyList.java | 10 +- .../base/custom/sheet/BottomSheetList.java | 8 +- .../custom/view/container/CardViewBase.java | 6 +- .../container/CustomSwipeRefreshLayout.java | 24 +-- .../custom/view/container/LoginCardView.java | 9 +- .../view/container/NotificationCardView.java | 4 +- .../drawable/MaterialProgressDrawable.java | 6 +- .../base/custom/view/editor/ComposerWidget.kt | 6 +- .../custom/view/editor/MarkdownInputEditor.kt | 12 +- .../view/image/AppCompatTintImageView.java | 10 +- .../custom/view/image/AspectImageView.java | 4 +- .../custom/view/image/AvatarImageView.java | 4 +- .../custom/view/image/BrandImageView.java | 4 +- .../custom/view/image/CircleImageView.java | 4 +- .../custom/view/image/HeaderImageView.java | 4 +- .../base/custom/view/image/WideImageView.java | 4 +- .../base/custom/view/text/AiringTextView.java | 2 +- .../view/text/FeedHeadlineTextView.java | 4 +- .../base/custom/view/text/PageIndicator.java | 4 +- .../custom/view/text/RangeDateTextView.java | 2 +- .../base/custom/view/text/RatingTextView.java | 8 +- .../custom/view/text/RichMarkdownTextView.kt | 72 +++---- .../base/custom/view/text/SeriesTypeView.java | 2 +- .../view/text/SeriesYearTypeTextView.java | 2 +- .../view/text/SingleLineFontTextView.java | 2 +- .../custom/view/text/SingleLineTextView.java | 2 +- .../custom/view/text/SpoilerTagTextView.java | 4 +- .../custom/view/widget/AboutPanelWidget.java | 10 +- .../view/widget/AutoIncrementWidget.java | 4 +- .../custom/view/widget/CustomProgress.java | 2 +- .../custom/view/widget/CustomRatingBar.java | 4 +- .../view/widget/CustomSeriesAnimeManage.java | 2 +- .../view/widget/CustomSeriesManageBase.java | 4 +- .../view/widget/CustomSeriesMangaManage.java | 2 +- .../view/widget/FavouriteToolbarWidget.java | 4 +- .../custom/view/widget/FavouriteWidget.java | 4 +- .../custom/view/widget/FollowStateWidget.java | 2 +- .../custom/view/widget/FuzzyDateWidget.java | 2 +- .../custom/view/widget/MentionWidget.java | 2 +- .../view/widget/ProfileStatsWidget.java | 10 +- .../custom/view/widget/ProgressWidget.java | 2 +- .../base/custom/view/widget/RingProgress.java | 4 +- .../base/custom/view/widget/ScoreWidget.java | 2 +- .../view/widget/SeriesStatusWidget.java | 6 +- .../view/widget/StatusContentWidget.java | 10 +- .../view/widget/StatusDeleteWidget.java | 2 +- .../base/custom/view/widget/VoteWidget.java | 10 +- .../base/custom/viewmodel/ViewModelBase.kt | 4 +- .../interfaces/base/PreferenceConverter.java | 4 +- .../event/RecyclerChangeListener.java | 2 +- .../base/interfaces/event/RetroCallback.java | 2 +- .../binding/RichMarkdownExtensions.kt | 4 +- .../model/api/converter/GraphQLConverter.java | 2 +- .../anitrend/model/api/retro/WebFactory.java | 4 +- .../model/entity/anilist/MediaRank.java | 2 +- .../anitrend/model/entity/base/MediaBase.java | 2 +- .../model/entity/base/NotificationBase.java | 2 +- .../request/QueryContainerBuilder.java | 2 +- .../presenter/base/BasePresenter.java | 2 +- .../com/mxt/anitrend/util/ActionModeUtil.java | 6 +- .../com/mxt/anitrend/util/AnalyticsUtil.java | 4 +- .../com/mxt/anitrend/util/ApplicationPref.kt | 4 +- .../com/mxt/anitrend/util/CenterSnapUtil.kt | 4 +- .../java/com/mxt/anitrend/util/ChartUtil.kt | 5 +- .../java/com/mxt/anitrend/util/CompatUtil.kt | 16 +- .../java/com/mxt/anitrend/util/DateUtil.kt | 2 +- .../com/mxt/anitrend/util/DialogUtil.java | 8 +- .../com/mxt/anitrend/util/GenreTagUtil.java | 4 +- .../com/mxt/anitrend/util/IntentBundleUtil.kt | 6 +- .../java/com/mxt/anitrend/util/KeyUtil.java | 6 +- .../com/mxt/anitrend/util/MarkDownUtil.kt | 2 +- .../mxt/anitrend/util/MediaActionUtil.java | 6 +- .../mxt/anitrend/util/MediaDialogUtil.java | 2 +- .../com/mxt/anitrend/util/MediaListUtil.java | 2 +- .../com/mxt/anitrend/util/NotificationUtil.kt | 6 +- .../com/mxt/anitrend/util/NotifyUtil.java | 18 +- .../com/mxt/anitrend/util/ShortcutUtil.java | 4 +- .../com/mxt/anitrend/util/TapTargetUtil.java | 12 +- .../com/mxt/anitrend/util/TutorialUtil.java | 12 +- .../view/activity/base/AboutActivity.kt | 2 +- .../base/AppCompatPreferenceActivity.java | 13 +- .../activity/base/GiphyPreviewActivity.java | 2 +- .../activity/base/ImagePreviewActivity.java | 8 +- .../view/activity/base/ReportActivity.java | 5 +- .../view/activity/base/SettingsActivity.java | 4 +- .../activity/base/SharedContentActivity.java | 14 +- .../activity/base/VideoPlayerActivity.java | 6 +- .../view/activity/base/WelcomeActivity.java | 4 +- .../activity/detail/CharacterActivity.java | 8 +- .../view/activity/detail/CommentActivity.java | 8 +- .../activity/detail/FavouriteActivity.java | 8 +- .../view/activity/detail/MediaActivity.java | 9 +- .../activity/detail/MediaBrowseActivity.java | 8 +- .../activity/detail/MediaListActivity.java | 8 +- .../view/activity/detail/MessageActivity.java | 8 +- .../activity/detail/NotificationActivity.java | 8 +- .../view/activity/detail/ProfileActivity.java | 9 +- .../view/activity/detail/StaffActivity.java | 8 +- .../view/activity/detail/StudioActivity.java | 8 +- .../view/activity/index/LoginActivity.java | 10 +- .../view/activity/index/MainActivity.java | 29 ++- .../view/activity/index/SearchActivity.java | 8 +- .../view/activity/index/SplashActivity.java | 2 +- .../view/fragment/detail/AboutFragment.kt | 2 +- .../fragment/detail/BrowseReviewFragment.java | 2 +- .../detail/CharacterOverviewFragment.java | 6 +- .../view/fragment/detail/CommentFragment.java | 2 +- .../fragment/detail/MediaFeedFragment.java | 2 +- .../fragment/detail/MediaOverviewFragment.kt | 21 +- .../fragment/detail/MediaStaffFragment.java | 2 +- .../fragment/detail/MediaStatsFragment.java | 6 +- .../fragment/detail/MessageFeedFragment.java | 2 +- .../fragment/detail/NotificationFragment.kt | 8 +- .../view/fragment/detail/ReviewFragment.java | 2 +- .../detail/StaffOverviewFragment.java | 6 +- .../fragment/detail/StudioMediaFragment.java | 2 +- .../fragment/detail/UserFeedFragment.java | 2 +- .../fragment/detail/UserOverviewFragment.java | 4 +- .../favourite/CharacterFavouriteFragment.java | 2 +- .../favourite/MediaFavouriteFragment.java | 2 +- .../favourite/StaffFavouriteFragment.java | 2 +- .../favourite/StudioFavouriteFragment.java | 2 +- .../group/CharacterActorsFragment.java | 2 +- .../group/MediaCharacterFragment.java | 2 +- .../fragment/group/MediaFormatFragment.java | 2 +- .../fragment/group/MediaRelationFragment.java | 2 +- .../group/MediaStaffRoleFragment.java | 2 +- .../fragment/list/AiringListFragment.java | 2 +- .../view/fragment/list/FeedListFragment.java | 2 +- .../fragment/list/MediaBrowseFragment.java | 2 +- .../view/fragment/list/MediaLatestList.java | 2 +- .../view/fragment/list/MediaListFragment.java | 4 +- .../view/fragment/list/WatchListFragment.java | 6 +- .../search/CharacterSearchFragment.java | 2 +- .../fragment/search/MediaSearchFragment.java | 2 +- .../fragment/search/StaffSearchFragment.java | 2 +- .../fragment/search/StudioSearchFragment.java | 2 +- .../fragment/search/UserSearchFragment.java | 2 +- .../youtube/YouTubeEmbedFragment.java | 4 +- .../fragment/youtube/YoutubePlayerFragment.kt | 89 --------- .../view/sheet/BottomReviewReader.java | 4 +- .../view/sheet/BottomSheetComposer.java | 4 +- .../anitrend/view/sheet/BottomSheetGiphy.java | 8 +- .../view/sheet/BottomSheetListUsers.java | 10 +- .../view/sheet/BottomSheetMessage.java | 6 +- .../anitrend/view/sheet/BottomSheetUsers.java | 8 +- .../res/layout/activity_frame_generic.xml | 8 +- .../res/layout/activity_image_preview.xml | 8 +- app/src/main/res/layout/activity_login.xml | 8 +- app/src/main/res/layout/activity_main.xml | 6 +- .../res/layout/activity_pager_generic.xml | 8 +- app/src/main/res/layout/activity_profile.xml | 12 +- app/src/main/res/layout/activity_series.xml | 12 +- .../res/layout/activity_share_content.xml | 8 +- app/src/main/res/layout/activity_splash.xml | 10 +- app/src/main/res/layout/adapter_anime.xml | 8 +- app/src/main/res/layout/adapter_character.xml | 4 +- app/src/main/res/layout/adapter_comment.xml | 4 +- app/src/main/res/layout/adapter_episode.xml | 6 +- .../main/res/layout/adapter_feed_message.xml | 4 +- .../main/res/layout/adapter_feed_progress.xml | 6 +- .../main/res/layout/adapter_feed_slide.xml | 2 +- .../main/res/layout/adapter_feed_status.xml | 4 +- app/src/main/res/layout/adapter_genre.xml | 2 +- app/src/main/res/layout/adapter_link.xml | 2 +- app/src/main/res/layout/adapter_manga.xml | 6 +- .../main/res/layout/adapter_media_header.xml | 12 +- .../main/res/layout/adapter_notification.xml | 4 +- app/src/main/res/layout/adapter_ranking.xml | 2 +- app/src/main/res/layout/adapter_review.xml | 4 +- app/src/main/res/layout/adapter_series.xml | 6 +- .../main/res/layout/adapter_series_airing.xml | 8 +- .../main/res/layout/adapter_series_review.xml | 6 +- app/src/main/res/layout/adapter_staff.xml | 4 +- app/src/main/res/layout/adapter_tag.xml | 4 +- app/src/main/res/layout/adapter_user.xml | 4 +- app/src/main/res/layout/app_bar_main.xml | 8 +- .../main/res/layout/bottom_sheet_composer.xml | 4 +- .../main/res/layout/bottom_sheet_message.xml | 4 +- .../main/res/layout/bottom_sheet_review.xml | 4 +- app/src/main/res/layout/content_main.xml | 2 +- .../main/res/layout/content_view_pager.xml | 2 +- .../main/res/layout/custom_action_anime.xml | 20 +- .../main/res/layout/custom_action_manga.xml | 22 +-- app/src/main/res/layout/custom_nav_header.xml | 5 +- .../main/res/layout/custom_rating_widget.xml | 2 +- .../res/layout/custom_recycler_loading.xml | 2 +- .../res/layout/custom_recycler_unresolved.xml | 2 +- .../res/layout/custom_review_template.xml | 4 +- .../main/res/layout/custom_sheet_toolbar.xml | 4 +- app/src/main/res/layout/custom_toast.xml | 4 +- app/src/main/res/layout/custom_toolbar.xml | 2 +- .../res/layout/custom_toolbar_transparent.xml | 2 +- app/src/main/res/layout/dialog_changelog.xml | 2 +- .../layout/fragment_character_overview.xml | 20 +- app/src/main/res/layout/fragment_comment.xml | 6 +- .../res/layout/fragment_series_overview.xml | 8 +- .../main/res/layout/fragment_series_stats.xml | 8 +- .../res/layout/fragment_staff_overview.xml | 16 +- .../main/res/layout/fragment_user_about.xml | 12 +- .../res/layout/section_series_description.xml | 12 +- .../res/layout/section_series_details.xml | 10 +- .../main/res/layout/section_series_info.xml | 16 +- .../res/layout/widget_avatar_indicator.xml | 4 +- .../main/res/layout/widget_button_state.xml | 4 +- app/src/main/res/layout/widget_composer.xml | 14 +- app/src/main/res/layout/widget_fuzzy_date.xml | 2 +- app/src/main/res/layout/widget_status.xml | 2 +- app/src/main/res/layout/widget_vote.xml | 2 +- build.gradle | 64 +++++-- gradle.properties | 4 +- 261 files changed, 887 insertions(+), 918 deletions(-) delete mode 100644 app/src/main/java/com/mxt/anitrend/view/fragment/youtube/YoutubePlayerFragment.kt diff --git a/app/build.gradle b/app/build.gradle index 63d3dc9a5..f70ab6a0f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -2,17 +2,16 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'io.objectbox' apply plugin: 'kotlin-kapt' -apply plugin: 'io.fabric' android { - compileSdkVersion rootProject.compileSdk + compileSdkVersion compileSdk defaultConfig { applicationId "com.mxt.anitrend" - minSdkVersion rootProject.minSdk - targetSdkVersion rootProject.targetSdk + minSdkVersion minSdk + targetSdkVersion targetSdk versionCode rootProject.versionCode versionName rootProject.versionName - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables.useSupportLibrary = true multiDexEnabled true } @@ -58,12 +57,18 @@ android { it.buildConfigField "String", "GIPHY_LINK", GIPHY_LINK } } - dataBinding { - enabled = true + testOptions { + unitTests.returnDefaultValues = true } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility = 1.8 + targetCompatibility = 1.8 + } + kotlinOptions { + jvmTarget = "1.8" + } + dataBinding { + enabled = true } dexOptions { jumboMode true @@ -77,109 +82,146 @@ configurations.all { dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - /** Testing Libraries */ - testImplementation 'junit:junit:4.12' - testImplementation "org.hamcrest:hamcrest-library:${rootProject.hemcrest}" - testImplementation "org.mockito:mockito-core:${rootProject.mockito}" - androidTestImplementation "org.mockito:mockito-android:${rootProject.mockito}" - androidTestImplementation 'com.android.support.test:runner:1.0.2' - androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' + /** Koin AndroidX Dependency Injection */ + implementation "org.koin:koin-core:$koin" + implementation "org.koin:koin-core-ext:$koin" + implementation "org.koin:koin-androidx-scope:$koin" + implementation "org.koin:koin-androidx-viewmodel:$koin" - /** Architecture Components */ - implementation "android.arch.lifecycle:extensions:${rootProject.architecture}" - implementation "android.arch.work:work-runtime-ktx:${rootProject.workManager}" + /** Kotlin Libraries */ + implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion" + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesCore" + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutinesAndroid" - /** 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:design:${rootProject.supportLibrary}" - implementation "com.android.support:cardview-v7:${rootProject.supportLibrary}" - implementation "com.android.support:support-vector-drawable:${rootProject.supportLibrary}" + /** Material Design */ + implementation "com.google.android.material:material:$material" + + implementation "androidx.constraintlayout:constraintlayout:$constraint" + implementation 'androidx.appcompat:appcompat:1.0.2' + implementation 'com.google.android.material:material:1.0.0' + implementation 'androidx.cardview:cardview:1.0.0' + implementation 'androidx.vectordrawable:vectordrawable:1.0.1' + + /** Architecture Components */ + implementation "androidx.core:core-ktx:$ktx" + implementation "androidx.fragment:fragment-ktx:$fragmentKtx" + implementation "androidx.work:work-runtime-ktx:$workerKtx" + implementation "androidx.lifecycle:lifecycle-extensions:$androidx" /** Fire-base Libraries */ - implementation "com.google.firebase:firebase-core:${rootProject.firebase}" + implementation "com.google.firebase:firebase-core:$firebase" /** Crash Analytics */ - implementation('com.crashlytics.sdk.android:crashlytics:2.9.9@aar') { + implementation("com.crashlytics.sdk.android:crashlytics:$crashlytics") { transitive = true } + /** Glide Libraries */ + implementation "com.github.bumptech.glide:glide:$glide" + kapt "com.github.bumptech.glide:compiler:$glide" + + /** Material Dialogs */ + implementation "com.afollestad.material-dialogs:core:$materialDialogs" + /** Retrofit Libraries */ - implementation "com.squareup.retrofit2:retrofit:${rootProject.retrofit}" - implementation "com.squareup.retrofit2:converter-gson:${rootProject.retrofit}" - implementation("com.squareup.retrofit2:converter-simplexml:${rootProject.retrofit}") { + implementation "com.squareup.retrofit2:retrofit:$retrofit" + implementation "com.squareup.retrofit2:converter-gson:$retrofit" + implementation("com.squareup.retrofit2:converter-simplexml:$retrofit") { exclude group: 'xpp3', module: 'xpp3' 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:$okHttpLogger" /** Glide Libraries */ - implementation "com.github.bumptech.glide:glide:${rootProject.glide}" - kapt "com.github.bumptech.glide:compiler:${rootProject.glide}" + implementation "com.github.bumptech.glide:glide:$glide" + kapt "com.github.bumptech.glide:compiler:$glide" /** Butter Knife Libraries */ - implementation "com.jakewharton:butterknife:${rootProject.butterKnife}" - kapt "com.jakewharton:butterknife-compiler:${rootProject.butterKnife}" + implementation "com.jakewharton:butterknife:$butterKnife" + kapt "com.jakewharton:butterknife-compiler:$butterKnife" - /** State Layout Library */ - implementation 'com.github.nguyenhoanglam:ProgressLayout:1.0.1' - - /** Event Bus Library */ - implementation 'org.greenrobot:eventbus:3.1.1' - - /** Material Dialogs Library*/ - implementation 'com.afollestad.material-dialogs:core:0.9.6.0' + /** Rich Text Markdown Parser */ + implementation "io.noties.markwon:core:$markwon" + implementation "io.noties.markwon:html:$markwon" + implementation "io.noties.markwon:image-glide:$markwon" + implementation "io.noties.markwon:linkify:$markwon" /** Object Box */ - implementation "io.objectbox:objectbox-android:${rootProject.objectBox}" - kapt "io.objectbox:objectbox-processor:${rootProject.objectBox}" + implementation "io.objectbox:objectbox-android:$objectBox" + kapt "io.objectbox:objectbox-processor:$objectBox" - /** Pretty Time */ - implementation 'org.ocpsoft.prettytime:prettytime:4.0.2.Final' + /** Material Dialogs */ + implementation "com.afollestad.material-dialogs:core:$materialDialogs" + + /** Flex Box */ + implementation "com.google.android:flexbox:$flexBox" /** Smart Tab Layout */ - implementation 'com.ogaclejapan.smarttablayout:library:1.7.0' + implementation "com.ogaclejapan.smarttablayout:library:$smartTab" - /** Java Streams Port */ - implementation 'com.annimon:stream:1.2.1' + /** Tap Target Prompt */ + implementation "uk.co.samuelwall:material-tap-target-prompt:$tapTarget" - /** Highly Customizable Video Player */ - implementation 'cn.jzvd:jiaozivideoplayer:7.0_preview' + /** Emojify */ + implementation "com.github.wax911:android-emojify:$emojify" - /** Photo View */ - implementation 'com.github.chrisbanes:PhotoView:2.1.3' + /** GraphQL */ + //implementation "com.github.anitrend:retrofit-graphql:$graphql" - /** Alerter */ - implementation 'com.tapadoo.android:alerter:2.0.4' + /** Timber */ + //implementation "com.jakewharton.timber:timber:$timber" - /** Rich Text Markdown Parser */ - implementation "ru.noties.markwon:core:$rootProject.markwon" - implementation "ru.noties.markwon:html:$rootProject.markwon" - implementation "ru.noties.markwon:image-okhttp:$rootProject.markwon" + /** Pretty Time */ + implementation 'org.ocpsoft.prettytime:prettytime:4.0.2.Final' - /** Tap Target Prompt */ - implementation 'uk.co.samuelwall:material-tap-target-prompt:2.14.0' + /** Highly Customizable Video Player */ + implementation 'cn.jzvd:jiaozivideoplayer:7.0.5' - /** Circular Progress View */ - implementation 'com.github.rahatarmanahmed:circularprogressview:2.5.0' + /** Photo View */ + implementation 'com.github.chrisbanes:PhotoView:2.3.0' /** On-boarding Experience */ implementation 'com.codemybrainsout.onboarding:onboarder:1.0.4' /** Charts */ - implementation'com.github.PhilJay:MPAndroidChart:v3.0.3' + implementation'com.github.PhilJay:MPAndroidChart:v3.1.0' /** About Library */ implementation 'com.github.medyo:android-about-page:1.2.5' /** Multi Dex */ - implementation 'com.android.support:multidex:1.0.3' + implementation 'androidx.multidex:multidex:2.0.1' /** Material Search View */ - implementation 'com.miguelcatalan:materialsearchview:1.4.0' + implementation 'com.github.ma-myair:MaterialSearchView:1.4.15' + + /** State Layout Library */ + implementation 'com.github.nguyenhoanglam:ProgressLayout:1.0.1' + + /** Event Bus Library */ + implementation 'org.greenrobot:eventbus:3.1.1' + + /** Alerter */ + implementation "com.tapadoo.android:alerter:4.0.3" - implementation "com.github.wax911:android-emojify:$rootProject.emojify" + /** Stream */ + implementation "com.annimon:stream:1.2.1" + + /** Circular Progress View */ + implementation 'com.github.rahatarmanahmed:circularprogressview:2.5.0' + + /** Testing-only dependencies */ + testImplementation "junit:junit:$junit" + testImplementation "org.mockito:mockito-core:$mockito" + testImplementation "org.hamcrest:hamcrest-library:$hemcrest" + + androidTestImplementation "androidx.test:runner:$runner" + androidTestImplementation "org.mockito:mockito-android:$mockito" + androidTestImplementation "androidx.test.espresso:espresso-core:$espresso" } -apply plugin: 'com.google.gms.google-services' +if (file("google-services.json").exists()) { + apply plugin: 'com.google.gms.google-services' + apply plugin: 'io.fabric' +} diff --git a/app/src/main/java/com/mxt/anitrend/App.kt b/app/src/main/java/com/mxt/anitrend/App.kt index a8b743b1f..b32f3202f 100644 --- a/app/src/main/java/com/mxt/anitrend/App.kt +++ b/app/src/main/java/com/mxt/anitrend/App.kt @@ -3,8 +3,8 @@ 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 androidx.multidex.MultiDex +import androidx.multidex.MultiDexApplication import com.crashlytics.android.core.CrashlyticsCore import com.google.android.gms.security.ProviderInstaller import com.google.firebase.analytics.FirebaseAnalytics 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 446094be4..7e77ac007 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 @@ -1,8 +1,8 @@ package com.mxt.anitrend.adapter.pager.detail; import android.content.Context; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.pager.BaseStatePageAdapter; diff --git a/app/src/main/java/com/mxt/anitrend/adapter/pager/detail/CharacterPageAdapter.java b/app/src/main/java/com/mxt/anitrend/adapter/pager/detail/CharacterPageAdapter.java index 05575ca6c..7190ac813 100644 --- a/app/src/main/java/com/mxt/anitrend/adapter/pager/detail/CharacterPageAdapter.java +++ b/app/src/main/java/com/mxt/anitrend/adapter/pager/detail/CharacterPageAdapter.java @@ -1,8 +1,8 @@ package com.mxt.anitrend.adapter.pager.detail; import android.content.Context; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.pager.BaseStatePageAdapter; diff --git a/app/src/main/java/com/mxt/anitrend/adapter/pager/detail/FavouritePageAdapter.java b/app/src/main/java/com/mxt/anitrend/adapter/pager/detail/FavouritePageAdapter.java index c62e0c262..52f801e62 100644 --- a/app/src/main/java/com/mxt/anitrend/adapter/pager/detail/FavouritePageAdapter.java +++ b/app/src/main/java/com/mxt/anitrend/adapter/pager/detail/FavouritePageAdapter.java @@ -1,8 +1,8 @@ package com.mxt.anitrend.adapter.pager.detail; import android.content.Context; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.pager.BaseStatePageAdapter; 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 7f9863cde..d1a16f981 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 @@ -1,8 +1,8 @@ package com.mxt.anitrend.adapter.pager.detail; import android.content.Context; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.pager.BaseStatePageAdapter; diff --git a/app/src/main/java/com/mxt/anitrend/adapter/pager/detail/MessagePageAdapter.java b/app/src/main/java/com/mxt/anitrend/adapter/pager/detail/MessagePageAdapter.java index f7580c42f..d32d4d26c 100644 --- a/app/src/main/java/com/mxt/anitrend/adapter/pager/detail/MessagePageAdapter.java +++ b/app/src/main/java/com/mxt/anitrend/adapter/pager/detail/MessagePageAdapter.java @@ -1,8 +1,8 @@ package com.mxt.anitrend.adapter.pager.detail; import android.content.Context; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.pager.BaseStatePageAdapter; 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 45042b73b..ed1f9677b 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 @@ -1,8 +1,8 @@ package com.mxt.anitrend.adapter.pager.detail; import android.content.Context; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.pager.BaseStatePageAdapter; diff --git a/app/src/main/java/com/mxt/anitrend/adapter/pager/detail/StaffPageAdapter.java b/app/src/main/java/com/mxt/anitrend/adapter/pager/detail/StaffPageAdapter.java index 5d9489aba..1ad134745 100644 --- a/app/src/main/java/com/mxt/anitrend/adapter/pager/detail/StaffPageAdapter.java +++ b/app/src/main/java/com/mxt/anitrend/adapter/pager/detail/StaffPageAdapter.java @@ -1,8 +1,8 @@ package com.mxt.anitrend.adapter.pager.detail; import android.content.Context; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.pager.BaseStatePageAdapter; diff --git a/app/src/main/java/com/mxt/anitrend/adapter/pager/index/AiringPageAdapter.java b/app/src/main/java/com/mxt/anitrend/adapter/pager/index/AiringPageAdapter.java index 2af61ad59..48af55bfc 100644 --- a/app/src/main/java/com/mxt/anitrend/adapter/pager/index/AiringPageAdapter.java +++ b/app/src/main/java/com/mxt/anitrend/adapter/pager/index/AiringPageAdapter.java @@ -1,8 +1,8 @@ package com.mxt.anitrend.adapter.pager.index; import android.content.Context; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; import com.mxt.anitrend.BuildConfig; import com.mxt.anitrend.R; 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 65635e88f..c1789a7e6 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 @@ -1,8 +1,8 @@ package com.mxt.anitrend.adapter.pager.index; import android.content.Context; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.pager.BaseStatePageAdapter; diff --git a/app/src/main/java/com/mxt/anitrend/adapter/pager/index/HubPageAdapter.java b/app/src/main/java/com/mxt/anitrend/adapter/pager/index/HubPageAdapter.java index 77fc7e6d9..37a2f6f06 100644 --- a/app/src/main/java/com/mxt/anitrend/adapter/pager/index/HubPageAdapter.java +++ b/app/src/main/java/com/mxt/anitrend/adapter/pager/index/HubPageAdapter.java @@ -1,8 +1,8 @@ package com.mxt.anitrend.adapter.pager.index; import android.content.Context; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; import com.mxt.anitrend.BuildConfig; import com.mxt.anitrend.R; 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 8573a2c8b..50387a77d 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 @@ -1,8 +1,8 @@ package com.mxt.anitrend.adapter.pager.index; import android.content.Context; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.pager.BaseStatePageAdapter; 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 1d1390fef..fc21aad3b 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 @@ -1,8 +1,8 @@ package com.mxt.anitrend.adapter.pager.index; import android.content.Context; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.pager.BaseStatePageAdapter; diff --git a/app/src/main/java/com/mxt/anitrend/adapter/pager/index/ReviewPageAdapter.java b/app/src/main/java/com/mxt/anitrend/adapter/pager/index/ReviewPageAdapter.java index 53d3345ad..e530ea41b 100644 --- a/app/src/main/java/com/mxt/anitrend/adapter/pager/index/ReviewPageAdapter.java +++ b/app/src/main/java/com/mxt/anitrend/adapter/pager/index/ReviewPageAdapter.java @@ -1,8 +1,8 @@ package com.mxt.anitrend.adapter.pager.index; import android.content.Context; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.pager.BaseStatePageAdapter; diff --git a/app/src/main/java/com/mxt/anitrend/adapter/pager/index/SearchPageAdapter.java b/app/src/main/java/com/mxt/anitrend/adapter/pager/index/SearchPageAdapter.java index 5a9aad75f..933498e46 100644 --- a/app/src/main/java/com/mxt/anitrend/adapter/pager/index/SearchPageAdapter.java +++ b/app/src/main/java/com/mxt/anitrend/adapter/pager/index/SearchPageAdapter.java @@ -1,8 +1,8 @@ package com.mxt.anitrend.adapter.pager.index; import android.content.Context; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.pager.BaseStatePageAdapter; 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 864f4d966..4ce15cfa8 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 @@ -1,8 +1,8 @@ package com.mxt.anitrend.adapter.pager.index; import android.content.Context; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.pager.BaseStatePageAdapter; 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 37243f0b4..505675b33 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 @@ -1,8 +1,8 @@ package com.mxt.anitrend.adapter.pager.index; import android.content.Context; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.pager.BaseStatePageAdapter; 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 b53b134b1..d7ec6118c 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 @@ -1,7 +1,7 @@ package com.mxt.anitrend.adapter.recycler.detail; import android.content.Context; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import android.view.View; import android.view.ViewGroup; import android.widget.Filter; 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 83d00fa0e..912c0246e 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 @@ -1,7 +1,7 @@ package com.mxt.anitrend.adapter.recycler.detail; import android.content.Context; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import android.view.View; import android.view.ViewGroup; import android.widget.Filter; 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 a5ec02025..90094e322 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 @@ -1,7 +1,7 @@ package com.mxt.anitrend.adapter.recycler.detail; import android.content.Context; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import android.view.View; import android.view.ViewGroup; import android.widget.Filter; 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 0216c8bd5..7b5b2eea5 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 @@ -1,8 +1,8 @@ package com.mxt.anitrend.adapter.recycler.detail; import android.content.Context; -import android.support.annotation.NonNull; -import android.support.v4.view.ViewCompat; +import androidx.annotation.NonNull; +import androidx.core.view.ViewCompat; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -13,7 +13,6 @@ import com.bumptech.glide.load.resource.bitmap.CenterInside; import com.bumptech.glide.load.resource.bitmap.RoundedCorners; import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions; -import com.bumptech.glide.request.RequestOptions; import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.recycler.RecyclerViewAdapter; import com.mxt.anitrend.base.custom.recycler.RecyclerViewHolder; 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 a6b91a15a..f60b6006c 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 @@ -1,7 +1,7 @@ package com.mxt.anitrend.adapter.recycler.detail; import android.content.Context; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import android.view.View; import android.view.ViewGroup; import android.widget.Filter; 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 6c52f93e3..daffdf21b 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 @@ -1,7 +1,7 @@ package com.mxt.anitrend.adapter.recycler.detail; import android.content.Context; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import android.view.View; import android.view.ViewGroup; import android.widget.Filter; 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 3d286fb81..bbf1c6848 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 @@ -1,7 +1,7 @@ package com.mxt.anitrend.adapter.recycler.detail; import android.content.Context; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import android.view.View; import android.view.ViewGroup; import android.widget.Filter; 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 af51464a0..ef1bd3274 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 @@ -1,7 +1,7 @@ package com.mxt.anitrend.adapter.recycler.group; import android.content.Context; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import android.view.View; import android.view.ViewGroup; import android.widget.Filter; 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 1f5fc7cef..b104cef4c 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 @@ -1,8 +1,8 @@ package com.mxt.anitrend.adapter.recycler.group; import android.content.Context; -import android.support.annotation.NonNull; -import android.support.v7.widget.StaggeredGridLayoutManager; +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.StaggeredGridLayoutManager; import android.view.View; import android.view.ViewGroup; import android.widget.Filter; 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 2afa63e3d..fca95c2ea 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 @@ -1,7 +1,7 @@ package com.mxt.anitrend.adapter.recycler.group; import android.content.Context; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import android.view.View; import android.view.ViewGroup; import android.widget.Filter; 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 cd488201f..6fe00e3eb 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 @@ -1,7 +1,7 @@ package com.mxt.anitrend.adapter.recycler.group; import android.content.Context; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import android.view.View; import android.view.ViewGroup; import android.widget.Filter; diff --git a/app/src/main/java/com/mxt/anitrend/adapter/recycler/index/EpisodeAdapter.java b/app/src/main/java/com/mxt/anitrend/adapter/recycler/index/EpisodeAdapter.java index 1838fda53..0b3bb1c70 100644 --- a/app/src/main/java/com/mxt/anitrend/adapter/recycler/index/EpisodeAdapter.java +++ b/app/src/main/java/com/mxt/anitrend/adapter/recycler/index/EpisodeAdapter.java @@ -1,7 +1,7 @@ package com.mxt.anitrend.adapter.recycler.index; import android.content.Context; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; 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 87db5e689..51bed3823 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 @@ -1,7 +1,7 @@ package com.mxt.anitrend.adapter.recycler.index; import android.content.Context; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; 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 4a7e88cc7..fc48eec15 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 @@ -1,7 +1,7 @@ package com.mxt.anitrend.adapter.recycler.index; import android.content.Context; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; 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 4785c09c3..7d03f7a64 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 @@ -1,7 +1,7 @@ package com.mxt.anitrend.adapter.recycler.index; import android.content.Context; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; diff --git a/app/src/main/java/com/mxt/anitrend/adapter/recycler/index/ReviewAdapter.java b/app/src/main/java/com/mxt/anitrend/adapter/recycler/index/ReviewAdapter.java index 37c816a93..dae9b5738 100644 --- a/app/src/main/java/com/mxt/anitrend/adapter/recycler/index/ReviewAdapter.java +++ b/app/src/main/java/com/mxt/anitrend/adapter/recycler/index/ReviewAdapter.java @@ -1,7 +1,7 @@ package com.mxt.anitrend.adapter.recycler.index; import android.content.Context; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; 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 d0828f4a4..be833ac1d 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 @@ -1,7 +1,7 @@ package com.mxt.anitrend.adapter.recycler.index; import android.content.Context; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import android.view.View; import android.view.ViewGroup; import android.widget.Filter; 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 38f4bfa6c..661dff4f1 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 @@ -1,7 +1,7 @@ package com.mxt.anitrend.adapter.recycler.index; import android.content.Context; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import android.view.View; import android.view.ViewGroup; import android.widget.Filter; 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 6f8dd1a48..7aad5c1cf 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 @@ -1,7 +1,7 @@ package com.mxt.anitrend.adapter.recycler.index; import android.content.Context; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; diff --git a/app/src/main/java/com/mxt/anitrend/adapter/spinner/IconArrayAdapter.java b/app/src/main/java/com/mxt/anitrend/adapter/spinner/IconArrayAdapter.java index 269d5a177..c0dc885cf 100644 --- a/app/src/main/java/com/mxt/anitrend/adapter/spinner/IconArrayAdapter.java +++ b/app/src/main/java/com/mxt/anitrend/adapter/spinner/IconArrayAdapter.java @@ -1,8 +1,8 @@ package com.mxt.anitrend.adapter.spinner; import android.content.Context; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; 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 05c3e0634..54f63a371 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 @@ -1,20 +1,20 @@ package com.mxt.anitrend.base.custom.activity; -import android.arch.lifecycle.Observer; -import android.arch.lifecycle.ViewModelProviders; +import androidx.lifecycle.Observer; +import androidx.lifecycle.ViewModelProviders; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.os.Build; import android.os.Bundle; import android.speech.RecognizerIntent; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.StyleRes; -import android.support.v4.app.ActivityCompat; -import android.support.v4.content.ContextCompat; -import android.support.v7.app.ActionBar; -import android.support.v7.app.AppCompatActivity; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.StyleRes; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatActivity; import android.text.TextUtils; import android.util.Log; import android.view.Menu; @@ -143,7 +143,7 @@ protected void onPostCreate(@Nullable Bundle savedInstanceState) { * @param toolbar Toolbar to set as the Activity's action bar, or {@code null} to clear it */ @Override - public void setSupportActionBar(@Nullable android.support.v7.widget.Toolbar toolbar) { + public void setSupportActionBar(@Nullable androidx.appcompat.widget.Toolbar toolbar) { super.setSupportActionBar(toolbar); setHomeUp(); } 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 2bf277dd7..53c7fb7a0 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 @@ -3,7 +3,7 @@ import android.content.Context; import android.os.AsyncTask; import android.os.Build; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import android.util.Log; import com.mxt.anitrend.base.custom.presenter.CommonPresenter; diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/fragment/FragmentBase.java b/app/src/main/java/com/mxt/anitrend/base/custom/fragment/FragmentBase.java index 06d45da33..77764aa39 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/fragment/FragmentBase.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/fragment/FragmentBase.java @@ -1,16 +1,16 @@ package com.mxt.anitrend.base.custom.fragment; import android.app.Activity; -import android.arch.lifecycle.Observer; -import android.arch.lifecycle.ViewModelProviders; +import androidx.lifecycle.Observer; +import androidx.lifecycle.ViewModelProviders; import android.content.SharedPreferences; import android.os.Bundle; -import android.support.annotation.IntegerRes; -import android.support.annotation.MenuRes; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.design.widget.Snackbar; -import android.support.v4.app.Fragment; +import androidx.annotation.IntegerRes; +import androidx.annotation.MenuRes; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import com.google.android.material.snackbar.Snackbar; +import androidx.fragment.app.Fragment; import android.text.TextUtils; import android.util.Log; import android.view.ActionMode; 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 22dfd6a31..ff09ba822 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 @@ -3,11 +3,11 @@ import android.app.Activity; import android.content.SharedPreferences; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.design.widget.Snackbar; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.StaggeredGridLayoutManager; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import com.google.android.material.snackbar.Snackbar; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.StaggeredGridLayoutManager; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; 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 f37d4bf35..f00d5fd82 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 @@ -3,10 +3,10 @@ import android.app.Activity; import android.content.SharedPreferences; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.design.widget.Snackbar; -import android.support.v7.widget.StaggeredGridLayoutManager; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import com.google.android.material.snackbar.Snackbar; +import androidx.recyclerview.widget.StaggeredGridLayoutManager; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; 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 0e37d1b36..069f4b5b9 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 @@ -5,10 +5,10 @@ import android.content.SharedPreferences; import android.net.Uri; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.design.widget.Snackbar; -import android.support.v7.widget.StaggeredGridLayoutManager; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import com.google.android.material.snackbar.Snackbar; +import androidx.recyclerview.widget.StaggeredGridLayoutManager; import android.text.TextUtils; import android.util.Log; import android.view.LayoutInflater; diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/pager/BaseStatePageAdapter.java b/app/src/main/java/com/mxt/anitrend/base/custom/pager/BaseStatePageAdapter.java index b957d5e3e..f6e720b4f 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/pager/BaseStatePageAdapter.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/pager/BaseStatePageAdapter.java @@ -2,10 +2,10 @@ import android.content.Context; import android.os.Bundle; -import android.support.annotation.ArrayRes; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; -import android.support.v4.app.FragmentStatePagerAdapter; +import androidx.annotation.ArrayRes; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentStatePagerAdapter; import java.util.Locale; diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/recycler/RecyclerScrollListener.java b/app/src/main/java/com/mxt/anitrend/base/custom/recycler/RecyclerScrollListener.java index 035342b0b..a96bc311b 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/recycler/RecyclerScrollListener.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/recycler/RecyclerScrollListener.java @@ -1,9 +1,9 @@ package com.mxt.anitrend.base.custom.recycler; -import android.support.annotation.Nullable; -import android.support.v7.widget.GridLayoutManager; -import android.support.v7.widget.RecyclerView; -import android.support.v7.widget.StaggeredGridLayoutManager; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.recyclerview.widget.StaggeredGridLayoutManager; import com.mxt.anitrend.base.interfaces.event.RecyclerLoadListener; import com.mxt.anitrend.model.entity.container.attribute.PageInfo; 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 8b883f0a5..0a54959e0 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 @@ -2,11 +2,11 @@ import android.animation.Animator; import android.content.Context; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.v7.widget.GridLayoutManager; -import android.support.v7.widget.RecyclerView; -import android.support.v7.widget.StaggeredGridLayoutManager; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.recyclerview.widget.StaggeredGridLayoutManager; import android.view.ViewGroup; import android.widget.Filterable; diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/recycler/RecyclerViewHolder.java b/app/src/main/java/com/mxt/anitrend/base/custom/recycler/RecyclerViewHolder.java index 2985b26ee..b63763fd5 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/recycler/RecyclerViewHolder.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/recycler/RecyclerViewHolder.java @@ -1,8 +1,8 @@ package com.mxt.anitrend.base.custom.recycler; import android.content.Context; -import android.support.annotation.NonNull; -import android.support.v7.widget.RecyclerView; +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; import android.view.View; import com.annimon.stream.IntPair; diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/recycler/StatefulRecyclerView.java b/app/src/main/java/com/mxt/anitrend/base/custom/recycler/StatefulRecyclerView.java index 31494523d..61a188a27 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/recycler/StatefulRecyclerView.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/recycler/StatefulRecyclerView.java @@ -1,8 +1,8 @@ package com.mxt.anitrend.base.custom.recycler; import android.content.Context; -import android.support.annotation.Nullable; -import android.support.v7.widget.RecyclerView; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.RecyclerView; import android.util.AttributeSet; import com.mxt.anitrend.base.interfaces.view.CustomView; 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 6435518aa..112c0fa8d 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 @@ -2,13 +2,13 @@ import android.app.Dialog; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.StringRes; -import android.support.design.widget.BottomSheetBehavior; -import android.support.design.widget.BottomSheetDialogFragment; -import android.support.design.widget.CoordinatorLayout; -import android.support.v7.widget.AppCompatImageView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.StringRes; +import com.google.android.material.bottomsheet.BottomSheetBehavior; +import com.google.android.material.bottomsheet.BottomSheetDialogFragment; +import androidx.coordinatorlayout.widget.CoordinatorLayout; +import androidx.appcompat.widget.AppCompatImageView; import android.util.Log; import android.view.View; 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 0b993f1b5..0617ec717 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 @@ -1,12 +1,12 @@ package com.mxt.anitrend.base.custom.sheet; import android.app.Activity; -import android.arch.lifecycle.Observer; -import android.arch.lifecycle.ViewModelProviders; +import androidx.lifecycle.Observer; +import androidx.lifecycle.ViewModelProviders; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.v7.widget.StaggeredGridLayoutManager; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.StaggeredGridLayoutManager; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; 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 8d2c62e52..42525bdcf 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 @@ -1,11 +1,11 @@ package com.mxt.anitrend.base.custom.sheet; -import android.arch.lifecycle.Observer; -import android.arch.lifecycle.ViewModelProviders; +import androidx.lifecycle.Observer; +import androidx.lifecycle.ViewModelProviders; import android.os.Bundle; import android.os.Parcelable; -import android.support.annotation.Nullable; -import android.support.v7.widget.StaggeredGridLayoutManager; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.StaggeredGridLayoutManager; import android.util.Log; import android.view.View; 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 e340f92d4..dd10ad2e0 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 @@ -1,9 +1,9 @@ package com.mxt.anitrend.base.custom.view.container; import android.content.Context; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.v7.widget.CardView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.cardview.widget.CardView; import android.util.AttributeSet; import com.mxt.anitrend.R; diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/container/CustomSwipeRefreshLayout.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/container/CustomSwipeRefreshLayout.java index 6d83e8729..05353ca63 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/container/CustomSwipeRefreshLayout.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/container/CustomSwipeRefreshLayout.java @@ -3,16 +3,16 @@ import android.annotation.SuppressLint; import android.content.Context; import android.content.res.TypedArray; -import android.support.annotation.ColorInt; -import android.support.annotation.ColorRes; -import android.support.annotation.NonNull; -import android.support.v4.content.ContextCompat; -import android.support.v4.view.MotionEventCompat; -import android.support.v4.view.NestedScrollingChild; -import android.support.v4.view.NestedScrollingChildHelper; -import android.support.v4.view.NestedScrollingParent; -import android.support.v4.view.NestedScrollingParentHelper; -import android.support.v4.view.ViewCompat; +import androidx.annotation.ColorInt; +import androidx.annotation.ColorRes; +import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; +import androidx.core.view.MotionEventCompat; +import androidx.core.view.NestedScrollingChild; +import androidx.core.view.NestedScrollingChildHelper; +import androidx.core.view.NestedScrollingParent; +import androidx.core.view.NestedScrollingParentHelper; +import androidx.core.view.ViewCompat; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.view.MotionEvent; @@ -24,6 +24,8 @@ import android.view.animation.Transformation; import android.widget.AbsListView; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; + import com.mxt.anitrend.base.custom.view.drawable.MaterialProgressDrawable; import com.mxt.anitrend.base.custom.view.image.CircleImageView; @@ -31,7 +33,7 @@ * Created by max on 2017/12/05. * Both way swipe refresh layout. * - * This is a more powerful {@link android.support.v4.widget.SwipeRefreshLayout}, it can swipe + * This is a more powerful {@link SwipeRefreshLayout}, it can swipe * to refresh and load. * * @author wangdaye MySplash diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/container/LoginCardView.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/container/LoginCardView.java index 7bf8a2309..2fe230fd7 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/container/LoginCardView.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/container/LoginCardView.java @@ -1,14 +1,13 @@ package com.mxt.anitrend.base.custom.view.container; import android.content.Context; -import android.os.Build; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.v7.widget.LinearLayoutCompat; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.widget.LinearLayoutCompat; import android.util.AttributeSet; import com.mxt.anitrend.R; -import com.mxt.anitrend.util.CompatUtil; public class LoginCardView extends CardViewBase { diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/container/NotificationCardView.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/container/NotificationCardView.java index de05ec630..db935d1cb 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/container/NotificationCardView.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/container/NotificationCardView.java @@ -1,8 +1,8 @@ package com.mxt.anitrend.base.custom.view.container; import android.content.Context; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import android.util.AttributeSet; public class NotificationCardView extends CardViewBase { diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/drawable/MaterialProgressDrawable.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/drawable/MaterialProgressDrawable.java index 8997b0185..4b416736b 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/drawable/MaterialProgressDrawable.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/drawable/MaterialProgressDrawable.java @@ -12,9 +12,9 @@ import android.graphics.RectF; import android.graphics.drawable.Animatable; import android.graphics.drawable.Drawable; -import android.support.annotation.IntDef; -import android.support.annotation.NonNull; -import android.support.v4.view.animation.FastOutSlowInInterpolator; +import androidx.annotation.IntDef; +import androidx.annotation.NonNull; +import androidx.interpolator.view.animation.FastOutSlowInInterpolator; import android.util.DisplayMetrics; import android.view.View; import android.view.animation.Animation; diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/editor/ComposerWidget.kt b/app/src/main/java/com/mxt/anitrend/base/custom/view/editor/ComposerWidget.kt index 8cd05af34..9ff68fce7 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/editor/ComposerWidget.kt +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/editor/ComposerWidget.kt @@ -1,10 +1,10 @@ package com.mxt.anitrend.base.custom.view.editor import android.annotation.SuppressLint -import android.arch.lifecycle.Lifecycle +import androidx.lifecycle.Lifecycle import android.content.Context import android.os.Build -import android.support.annotation.RequiresApi +import androidx.annotation.RequiresApi import android.text.Editable import android.text.TextUtils import android.util.AttributeSet @@ -223,7 +223,7 @@ class ComposerWidget : FrameLayout, CustomView, View.OnClickListener, RetroCallb if (lifecycle?.currentState?.isAtLeast(Lifecycle.State.RESUMED) == true) { resetFlipperState() if (response.isSuccessful) { - binding.comment.text.clear() + binding.comment.text?.clear() when (requestType) { KeyUtil.MUT_SAVE_TEXT_FEED -> if (feedList != null) presenter.notifyAllListeners(BaseConsumer(requestType, feedList), false) 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 1cb067736..db9b26b02 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 @@ -4,12 +4,12 @@ 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 androidx.annotation.IdRes +import com.google.android.material.textfield.TextInputEditText +import androidx.core.view.inputmethod.EditorInfoCompat +import androidx.core.view.inputmethod.InputConnectionCompat +import androidx.core.view.inputmethod.InputContentInfoCompat +import androidx.core.content.ContextCompat import android.text.InputFilter import android.text.Spanned import android.text.TextUtils diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/image/AppCompatTintImageView.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/image/AppCompatTintImageView.java index b0d2e92d3..ab3e49ab2 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/image/AppCompatTintImageView.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/image/AppCompatTintImageView.java @@ -1,11 +1,11 @@ package com.mxt.anitrend.base.custom.view.image; import android.content.Context; -import android.databinding.BindingAdapter; -import android.support.annotation.AttrRes; -import android.support.annotation.ColorRes; -import android.support.annotation.DrawableRes; -import android.support.v7.widget.AppCompatImageView; +import androidx.databinding.BindingAdapter; +import androidx.annotation.AttrRes; +import androidx.annotation.ColorRes; +import androidx.annotation.DrawableRes; +import androidx.appcompat.widget.AppCompatImageView; import android.util.AttributeSet; import com.mxt.anitrend.R; diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/image/AspectImageView.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/image/AspectImageView.java index f9ac4aabf..fb270cf09 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/image/AspectImageView.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/image/AspectImageView.java @@ -1,7 +1,7 @@ package com.mxt.anitrend.base.custom.view.image; import android.content.Context; -import android.databinding.BindingAdapter; +import androidx.databinding.BindingAdapter; import android.graphics.Point; import android.util.AttributeSet; @@ -21,7 +21,7 @@ * or set to wrap content to automatically get the view width at runtime */ -public class AspectImageView extends android.support.v7.widget.AppCompatImageView implements CustomView { +public class AspectImageView extends androidx.appcompat.widget.AppCompatImageView implements CustomView { private int spanSize; private int defaultMargin; diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/image/AvatarImageView.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/image/AvatarImageView.java index a1050e0b2..40847362c 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/image/AvatarImageView.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/image/AvatarImageView.java @@ -1,8 +1,8 @@ package com.mxt.anitrend.base.custom.view.image; import android.content.Context; -import android.databinding.BindingAdapter; -import android.support.v7.widget.AppCompatImageView; +import androidx.databinding.BindingAdapter; +import androidx.appcompat.widget.AppCompatImageView; import android.util.AttributeSet; import com.bumptech.glide.Glide; 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 8d76c2cf1..15d1b8e51 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 @@ -14,8 +14,8 @@ import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.os.Build; -import android.support.annotation.NonNull; -import android.support.v7.widget.AppCompatImageView; +import androidx.annotation.NonNull; +import androidx.appcompat.widget.AppCompatImageView; import android.text.TextPaint; import android.util.AttributeSet; import android.util.DisplayMetrics; diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/image/CircleImageView.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/image/CircleImageView.java index d67b75743..79302217c 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/image/CircleImageView.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/image/CircleImageView.java @@ -8,8 +8,8 @@ import android.graphics.Shader; import android.graphics.drawable.ShapeDrawable; import android.graphics.drawable.shapes.OvalShape; -import android.support.v4.view.ViewCompat; -import android.support.v7.widget.AppCompatImageView; +import androidx.core.view.ViewCompat; +import androidx.appcompat.widget.AppCompatImageView; import android.util.AttributeSet; import android.view.animation.Animation; diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/image/HeaderImageView.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/image/HeaderImageView.java index 7adca64e1..7de26de33 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/image/HeaderImageView.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/image/HeaderImageView.java @@ -1,8 +1,8 @@ package com.mxt.anitrend.base.custom.view.image; import android.content.Context; -import android.databinding.BindingAdapter; -import android.support.v7.widget.AppCompatImageView; +import androidx.databinding.BindingAdapter; +import androidx.appcompat.widget.AppCompatImageView; import android.util.AttributeSet; import com.bumptech.glide.Glide; diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/image/WideImageView.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/image/WideImageView.java index 3462c8193..d380a23f2 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/image/WideImageView.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/image/WideImageView.java @@ -1,8 +1,8 @@ package com.mxt.anitrend.base.custom.view.image; import android.content.Context; -import android.databinding.BindingAdapter; -import android.support.v7.widget.AppCompatImageView; +import androidx.databinding.BindingAdapter; +import androidx.appcompat.widget.AppCompatImageView; import android.util.AttributeSet; import com.bumptech.glide.Glide; 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 f18810e31..50d742a3b 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 @@ -1,7 +1,7 @@ package com.mxt.anitrend.base.custom.view.text; import android.content.Context; -import android.databinding.BindingAdapter; +import androidx.databinding.BindingAdapter; import android.util.AttributeSet; import com.mxt.anitrend.model.entity.base.MediaBase; diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/text/FeedHeadlineTextView.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/text/FeedHeadlineTextView.java index d6ad97efb..f7ab0080e 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/text/FeedHeadlineTextView.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/text/FeedHeadlineTextView.java @@ -1,8 +1,8 @@ package com.mxt.anitrend.base.custom.view.text; import android.content.Context; -import android.databinding.BindingAdapter; -import android.support.v7.widget.AppCompatTextView; +import androidx.databinding.BindingAdapter; +import androidx.appcompat.widget.AppCompatTextView; import android.text.TextUtils; import android.util.AttributeSet; import android.util.TypedValue; 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 311af41fd..6b14c81ff 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 @@ -2,8 +2,8 @@ import android.content.Context; import android.graphics.Typeface; -import android.support.annotation.Nullable; -import android.support.v7.widget.AppCompatTextView; +import androidx.annotation.Nullable; +import androidx.appcompat.widget.AppCompatTextView; import android.util.AttributeSet; import android.util.TypedValue; 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 8590bd05d..1afa99594 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 @@ -1,7 +1,7 @@ package com.mxt.anitrend.base.custom.view.text; import android.content.Context; -import android.databinding.BindingAdapter; +import androidx.databinding.BindingAdapter; import android.util.AttributeSet; import com.mxt.anitrend.model.entity.anilist.meta.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 34d3e4355..a5c2ceeba 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 @@ -1,12 +1,12 @@ package com.mxt.anitrend.base.custom.view.text; import android.content.Context; -import android.databinding.BindingAdapter; +import androidx.databinding.BindingAdapter; import android.graphics.drawable.Drawable; import android.os.Build; -import android.support.annotation.ColorRes; -import android.support.annotation.Nullable; -import android.support.annotation.RequiresApi; +import androidx.annotation.ColorRes; +import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; import android.util.AttributeSet; import android.widget.LinearLayout; 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 2104005f8..2212b2380 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,26 +1,35 @@ package com.mxt.anitrend.base.custom.view.text import android.content.Context -import android.support.v4.text.util.LinkifyCompat -import android.support.v7.widget.AppCompatTextView +import android.graphics.drawable.Drawable +import androidx.core.text.util.LinkifyCompat +import androidx.appcompat.widget.AppCompatTextView import android.text.Spanned import android.text.method.LinkMovementMethod import android.text.util.Linkify import android.util.AttributeSet import android.widget.TextView +import com.bumptech.glide.Glide +import com.bumptech.glide.RequestBuilder +import com.bumptech.glide.load.resource.bitmap.CenterCrop +import com.bumptech.glide.load.resource.bitmap.RoundedCorners +import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions +import com.bumptech.glide.request.target.Target +import com.mxt.anitrend.R import com.mxt.anitrend.base.interfaces.view.CustomView import com.mxt.anitrend.util.MarkDownUtil import com.mxt.anitrend.util.RegexUtil 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.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.okhttp.OkHttpImagesPlugin +import io.noties.markwon.AbstractMarkwonPlugin +import io.noties.markwon.Markwon +import io.noties.markwon.MarkwonConfiguration +import io.noties.markwon.core.CorePlugin +import io.noties.markwon.html.HtmlPlugin +import io.noties.markwon.html.MarkwonHtmlParserImpl +import io.noties.markwon.image.AsyncDrawable +import io.noties.markwon.image.AsyncDrawableScheduler +import io.noties.markwon.image.glide.GlideImagesPlugin +import io.noties.markwon.linkify.LinkifyPlugin import java.util.Arrays.asList class RichMarkdownTextView : AppCompatTextView, CustomView { @@ -36,31 +45,24 @@ class RichMarkdownTextView : AppCompatTextView, CustomView { val markwon by lazy { Markwon.builder(context) - .usePlugins(asList( - CorePlugin.create(), - ImagesPlugin.create(context), - OkHttpImagesPlugin.create(), - HtmlPlugin.create(), - object: AbstractMarkwonPlugin() { - @Override - override fun configureParser(builder: Parser.Builder) { + .usePlugin(HtmlPlugin.create()) + .usePlugin(LinkifyPlugin.create()) + .usePlugin(GlideImagesPlugin.create(context)) + .usePlugin(GlideImagesPlugin.create(Glide.with(context))) + .usePlugin(GlideImagesPlugin.create(object : GlideImagesPlugin.GlideStore { + override fun cancel(target: Target<*>) { + Glide.with(context).clear(target) + } - } - - 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() + override fun load(drawable: AsyncDrawable): RequestBuilder { + return Glide.with(context).load(drawable.destination) + .transition(DrawableTransitionOptions.withCrossFade(250)) + .transform( + CenterCrop(), + RoundedCorners(context.resources.getDimensionPixelSize(R.dimen.md_margin)) + ) + } + })).build() } /** diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/text/SeriesTypeView.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/text/SeriesTypeView.java index 0d35a4c85..1c178c8b4 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/text/SeriesTypeView.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/text/SeriesTypeView.java @@ -1,7 +1,7 @@ package com.mxt.anitrend.base.custom.view.text; import android.content.Context; -import android.databinding.BindingAdapter; +import androidx.databinding.BindingAdapter; import android.util.AttributeSet; import com.mxt.anitrend.R; 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 f4622ee18..b5136860a 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 @@ -1,7 +1,7 @@ package com.mxt.anitrend.base.custom.view.text; import android.content.Context; -import android.databinding.BindingAdapter; +import androidx.databinding.BindingAdapter; import android.util.AttributeSet; import com.mxt.anitrend.R; diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/text/SingleLineFontTextView.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/text/SingleLineFontTextView.java index 96c6dda0e..e77545da1 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/text/SingleLineFontTextView.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/text/SingleLineFontTextView.java @@ -2,7 +2,7 @@ import android.content.Context; import android.content.res.AssetManager; -import android.databinding.BindingAdapter; +import androidx.databinding.BindingAdapter; import android.graphics.Typeface; import android.util.AttributeSet; diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/text/SingleLineTextView.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/text/SingleLineTextView.java index 8ceeafb78..da0813df4 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/text/SingleLineTextView.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/text/SingleLineTextView.java @@ -1,7 +1,7 @@ package com.mxt.anitrend.base.custom.view.text; import android.content.Context; -import android.support.v7.widget.AppCompatTextView; +import androidx.appcompat.widget.AppCompatTextView; import android.text.TextUtils; import android.util.AttributeSet; 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 2b49712b1..e72a11d59 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 @@ -1,8 +1,8 @@ package com.mxt.anitrend.base.custom.view.text; import android.content.Context; -import android.databinding.BindingAdapter; -import android.text.TextUtils; +import androidx.databinding.BindingAdapter; + import android.util.AttributeSet; import com.mxt.anitrend.util.CompatUtil; import com.mxt.anitrend.R; 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 bb4e7e8f0..0fb3e9feb 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 @@ -1,12 +1,12 @@ package com.mxt.anitrend.base.custom.view.widget; -import android.arch.lifecycle.Lifecycle; +import androidx.lifecycle.Lifecycle; import android.content.Context; import android.content.Intent; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.v4.app.FragmentActivity; -import android.support.v4.app.FragmentManager; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.FragmentActivity; +import androidx.fragment.app.FragmentManager; import android.util.AttributeSet; import android.util.Log; import android.view.LayoutInflater; 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 91a0c0a74..d61181e82 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 @@ -3,8 +3,8 @@ import android.annotation.TargetApi; import android.content.Context; import android.os.Build; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import android.util.AttributeSet; import android.util.Log; import android.view.View; 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 8b0b7897d..9a9e5e225 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 @@ -6,7 +6,7 @@ import android.graphics.PorterDuffColorFilter; import android.graphics.drawable.Drawable; import android.os.Build; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import android.util.AttributeSet; import android.widget.ProgressBar; diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/CustomRatingBar.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/CustomRatingBar.java index f355a799b..c1c2d4294 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/CustomRatingBar.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/CustomRatingBar.java @@ -1,8 +1,8 @@ package com.mxt.anitrend.base.custom.view.widget; import android.content.Context; -import android.databinding.BindingAdapter; -import android.support.v7.widget.AppCompatRatingBar; +import androidx.databinding.BindingAdapter; +import androidx.appcompat.widget.AppCompatRatingBar; import android.util.AttributeSet; import com.mxt.anitrend.base.interfaces.view.CustomView; 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 db2aa3e98..9794ae094 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 @@ -3,7 +3,7 @@ import android.content.Context; import android.os.Build; import android.os.Bundle; -import android.support.annotation.RequiresApi; +import androidx.annotation.RequiresApi; import android.text.TextUtils; import android.util.AttributeSet; import android.view.View; 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 585f38c2c..48f4ced6f 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 @@ -3,8 +3,8 @@ import android.content.Context; import android.os.Build; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.RequiresApi; +import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; import android.util.AttributeSet; import android.widget.AdapterView; import android.widget.RelativeLayout; 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 b076f7ff8..e10361ce1 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 @@ -3,7 +3,7 @@ import android.content.Context; import android.os.Build; import android.os.Bundle; -import android.support.annotation.RequiresApi; +import androidx.annotation.RequiresApi; import android.text.TextUtils; import android.util.AttributeSet; import android.view.View; 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 f31967d97..11f86bd38 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 @@ -3,8 +3,8 @@ import android.annotation.TargetApi; import android.content.Context; import android.os.Build; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import android.util.AttributeSet; import android.util.Log; import android.view.View; 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 f3d3943e5..538dfb367 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 @@ -1,8 +1,8 @@ package com.mxt.anitrend.base.custom.view.widget; import android.content.Context; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import android.util.AttributeSet; import android.util.Log; import android.view.View; 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 d41f1d632..3f382abc7 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 @@ -1,7 +1,7 @@ package com.mxt.anitrend.base.custom.view.widget; import android.content.Context; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import android.util.AttributeSet; import android.util.Log; import android.view.View; 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 f37c91e1a..c44a943e9 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 @@ -5,7 +5,7 @@ import android.content.Context; import android.content.DialogInterface; import android.os.Build; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import android.util.AttributeSet; import android.view.View; import android.widget.DatePicker; 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 6e9be10f9..314684b62 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 @@ -1,7 +1,7 @@ package com.mxt.anitrend.base.custom.view.widget; import android.content.Context; -import android.support.v7.widget.AppCompatImageView; +import androidx.appcompat.widget.AppCompatImageView; import android.util.AttributeSet; import com.mxt.anitrend.R; 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 c7550c813..a08604e8e 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 @@ -4,11 +4,11 @@ import android.content.Intent; import android.os.Build; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.RequiresApi; -import android.support.design.widget.Snackbar; -import android.support.v4.content.ContextCompat; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; +import com.google.android.material.snackbar.Snackbar; +import androidx.core.content.ContextCompat; import android.util.AttributeSet; import android.util.Log; import android.view.LayoutInflater; 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 dad6ef8ea..2edfbb2f5 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 @@ -3,7 +3,7 @@ import android.annotation.TargetApi; import android.content.Context; import android.os.Build; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/RingProgress.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/RingProgress.java index 047821ea9..bad6fec69 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/RingProgress.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/RingProgress.java @@ -14,8 +14,8 @@ import android.graphics.RectF; import android.graphics.Shader; import android.os.Build; -import android.support.annotation.Nullable; -import android.support.annotation.RequiresApi; +import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; import android.util.AttributeSet; import android.view.View; import android.view.animation.LinearInterpolator; 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 4a8a952a2..21ab72266 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 @@ -1,7 +1,7 @@ package com.mxt.anitrend.base.custom.view.widget; import android.content.Context; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import android.text.Editable; import android.text.TextUtils; import android.text.method.DigitsKeyListener; 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 8349e3b46..1233b7619 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 @@ -2,10 +2,10 @@ import android.annotation.TargetApi; import android.content.Context; -import android.databinding.BindingAdapter; +import androidx.databinding.BindingAdapter; import android.os.Build; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import android.text.TextUtils; import android.util.AttributeSet; import android.widget.FrameLayout; 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 8ee5a3a2f..811b967a0 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 @@ -5,11 +5,11 @@ import android.content.Intent; import android.net.Uri; import android.os.Build; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.RequiresApi; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.SnapHelper; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.SnapHelper; import android.text.TextUtils; import android.util.AttributeSet; import android.view.LayoutInflater; 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 6d0d239bb..bf762c530 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 @@ -1,7 +1,7 @@ package com.mxt.anitrend.base.custom.view.widget; import android.content.Context; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import android.util.AttributeSet; import android.util.Log; import android.view.View; 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 69d8a4f72..9d316863f 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 @@ -2,11 +2,11 @@ import android.content.Context; import android.os.Build; -import android.support.annotation.ColorRes; -import android.support.annotation.DrawableRes; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.RequiresApi; +import androidx.annotation.ColorRes; +import androidx.annotation.DrawableRes; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; import android.util.AttributeSet; import android.util.Log; import android.view.LayoutInflater; 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 index c5ae0da9a..a942f1790 100644 --- 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 @@ -1,7 +1,7 @@ package com.mxt.anitrend.base.custom.viewmodel -import android.arch.lifecycle.MutableLiveData -import android.arch.lifecycle.ViewModel +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel import android.content.Context import android.os.AsyncTask import android.os.Bundle diff --git a/app/src/main/java/com/mxt/anitrend/base/interfaces/base/PreferenceConverter.java b/app/src/main/java/com/mxt/anitrend/base/interfaces/base/PreferenceConverter.java index 65f5340b0..866515471 100644 --- a/app/src/main/java/com/mxt/anitrend/base/interfaces/base/PreferenceConverter.java +++ b/app/src/main/java/com/mxt/anitrend/base/interfaces/base/PreferenceConverter.java @@ -1,7 +1,7 @@ package com.mxt.anitrend.base.interfaces.base; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; /** * Created by max on 2018/09/01. diff --git a/app/src/main/java/com/mxt/anitrend/base/interfaces/event/RecyclerChangeListener.java b/app/src/main/java/com/mxt/anitrend/base/interfaces/event/RecyclerChangeListener.java index d7d5c4a0f..ba7f5132f 100644 --- a/app/src/main/java/com/mxt/anitrend/base/interfaces/event/RecyclerChangeListener.java +++ b/app/src/main/java/com/mxt/anitrend/base/interfaces/event/RecyclerChangeListener.java @@ -1,6 +1,6 @@ package com.mxt.anitrend.base.interfaces.event; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import java.util.List; diff --git a/app/src/main/java/com/mxt/anitrend/base/interfaces/event/RetroCallback.java b/app/src/main/java/com/mxt/anitrend/base/interfaces/event/RetroCallback.java index c7617dcea..d70185229 100644 --- a/app/src/main/java/com/mxt/anitrend/base/interfaces/event/RetroCallback.java +++ b/app/src/main/java/com/mxt/anitrend/base/interfaces/event/RetroCallback.java @@ -1,6 +1,6 @@ package com.mxt.anitrend.base.interfaces.event; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import retrofit2.Call; import retrofit2.Callback; 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 fcefeec39..37744b923 100644 --- a/app/src/main/java/com/mxt/anitrend/binding/RichMarkdownExtensions.kt +++ b/app/src/main/java/com/mxt/anitrend/binding/RichMarkdownExtensions.kt @@ -1,7 +1,7 @@ package com.mxt.anitrend.binding -import android.databinding.BindingAdapter -import android.support.annotation.StringRes +import androidx.databinding.BindingAdapter +import androidx.annotation.StringRes import android.text.Html import android.widget.TextView import com.mxt.anitrend.base.custom.view.text.RichMarkdownTextView diff --git a/app/src/main/java/com/mxt/anitrend/model/api/converter/GraphQLConverter.java b/app/src/main/java/com/mxt/anitrend/model/api/converter/GraphQLConverter.java index 9cd776fb8..3b3223a3f 100644 --- a/app/src/main/java/com/mxt/anitrend/model/api/converter/GraphQLConverter.java +++ b/app/src/main/java/com/mxt/anitrend/model/api/converter/GraphQLConverter.java @@ -1,7 +1,7 @@ package com.mxt.anitrend.model.api.converter; import android.content.Context; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import android.util.Log; import com.google.gson.Gson; 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 dc4f566e3..cff6bc580 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 @@ -1,8 +1,8 @@ package com.mxt.anitrend.model.api.retro; import android.content.Context; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import android.util.Log; import com.google.gson.Gson; 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 116eb8bb2..a5ecb049c 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 @@ -2,7 +2,7 @@ import android.os.Parcel; import android.os.Parcelable; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import com.mxt.anitrend.util.CompatUtil; import com.mxt.anitrend.util.KeyUtil; diff --git a/app/src/main/java/com/mxt/anitrend/model/entity/base/MediaBase.java b/app/src/main/java/com/mxt/anitrend/model/entity/base/MediaBase.java index d97a6ac4a..484b28680 100644 --- a/app/src/main/java/com/mxt/anitrend/model/entity/base/MediaBase.java +++ b/app/src/main/java/com/mxt/anitrend/model/entity/base/MediaBase.java @@ -2,7 +2,7 @@ import android.os.Parcel; import android.os.Parcelable; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import com.mxt.anitrend.model.entity.anilist.MediaList; import com.mxt.anitrend.model.entity.anilist.meta.AiringSchedule; diff --git a/app/src/main/java/com/mxt/anitrend/model/entity/base/NotificationBase.java b/app/src/main/java/com/mxt/anitrend/model/entity/base/NotificationBase.java index 727d7c90b..2c0f2532b 100644 --- a/app/src/main/java/com/mxt/anitrend/model/entity/base/NotificationBase.java +++ b/app/src/main/java/com/mxt/anitrend/model/entity/base/NotificationBase.java @@ -2,7 +2,7 @@ import android.os.Parcel; import android.os.Parcelable; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import com.mxt.anitrend.model.entity.group.RecyclerItem; import com.mxt.anitrend.util.KeyUtil; diff --git a/app/src/main/java/com/mxt/anitrend/model/entity/container/request/QueryContainerBuilder.java b/app/src/main/java/com/mxt/anitrend/model/entity/container/request/QueryContainerBuilder.java index 6b6b09f6b..2da37f40b 100644 --- a/app/src/main/java/com/mxt/anitrend/model/entity/container/request/QueryContainerBuilder.java +++ b/app/src/main/java/com/mxt/anitrend/model/entity/container/request/QueryContainerBuilder.java @@ -2,7 +2,7 @@ import android.os.Parcel; import android.os.Parcelable; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import com.annimon.stream.Collectors; import com.annimon.stream.Stream; 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 1a29716cf..b0d98e938 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 @@ -2,7 +2,7 @@ import android.content.Context; import android.content.Intent; -import android.support.v4.app.FragmentActivity; +import androidx.fragment.app.FragmentActivity; import android.util.Log; import com.annimon.stream.Stream; 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 03a000336..4801fd7fa 100644 --- a/app/src/main/java/com/mxt/anitrend/util/ActionModeUtil.java +++ b/app/src/main/java/com/mxt/anitrend/util/ActionModeUtil.java @@ -1,8 +1,8 @@ package com.mxt.anitrend.util; -import android.support.v4.content.ContextCompat; -import android.support.v7.widget.CardView; -import android.support.v7.widget.RecyclerView; +import androidx.core.content.ContextCompat; +import androidx.cardview.widget.CardView; +import androidx.recyclerview.widget.RecyclerView; import android.view.ActionMode; import android.widget.CheckBox; diff --git a/app/src/main/java/com/mxt/anitrend/util/AnalyticsUtil.java b/app/src/main/java/com/mxt/anitrend/util/AnalyticsUtil.java index 370635114..ac222eaaa 100644 --- a/app/src/main/java/com/mxt/anitrend/util/AnalyticsUtil.java +++ b/app/src/main/java/com/mxt/anitrend/util/AnalyticsUtil.java @@ -1,7 +1,7 @@ package com.mxt.anitrend.util; -import android.support.annotation.NonNull; -import android.support.v4.app.FragmentActivity; +import androidx.annotation.NonNull; +import androidx.fragment.app.FragmentActivity; import com.crashlytics.android.Crashlytics; import com.mxt.anitrend.App; diff --git a/app/src/main/java/com/mxt/anitrend/util/ApplicationPref.kt b/app/src/main/java/com/mxt/anitrend/util/ApplicationPref.kt index 6c89988b9..dd0d79d6d 100644 --- a/app/src/main/java/com/mxt/anitrend/util/ApplicationPref.kt +++ b/app/src/main/java/com/mxt/anitrend/util/ApplicationPref.kt @@ -3,8 +3,8 @@ 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 androidx.annotation.IdRes +import androidx.annotation.StyleRes import com.mxt.anitrend.BuildConfig import com.mxt.anitrend.R diff --git a/app/src/main/java/com/mxt/anitrend/util/CenterSnapUtil.kt b/app/src/main/java/com/mxt/anitrend/util/CenterSnapUtil.kt index 7f93b74d1..58371f313 100644 --- a/app/src/main/java/com/mxt/anitrend/util/CenterSnapUtil.kt +++ b/app/src/main/java/com/mxt/anitrend/util/CenterSnapUtil.kt @@ -1,7 +1,7 @@ package com.mxt.anitrend.util -import android.support.v7.widget.PagerSnapHelper -import android.support.v7.widget.RecyclerView +import androidx.recyclerview.widget.PagerSnapHelper +import androidx.recyclerview.widget.RecyclerView import android.view.View import com.mxt.anitrend.base.interfaces.view.CustomView diff --git a/app/src/main/java/com/mxt/anitrend/util/ChartUtil.kt b/app/src/main/java/com/mxt/anitrend/util/ChartUtil.kt index 484b25995..eb1ae4a3c 100644 --- a/app/src/main/java/com/mxt/anitrend/util/ChartUtil.kt +++ b/app/src/main/java/com/mxt/anitrend/util/ChartUtil.kt @@ -7,6 +7,7 @@ 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.github.mikephil.charting.formatter.ValueFormatter import com.mxt.anitrend.R /** @@ -15,7 +16,7 @@ import com.mxt.anitrend.R class ChartUtil { - class StepXAxisFormatter : IAxisValueFormatter { + class StepXAxisFormatter : ValueFormatter() { private lateinit var dataModel: List private lateinit var chartBase: BarLineChartBase<*> @@ -57,7 +58,7 @@ class ChartUtil { } } - class StepYAxisFormatter : IAxisValueFormatter { + class StepYAxisFormatter : ValueFormatter() { private lateinit var chartBase: BarLineChartBase<*> 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 ee11bee16..c8c1e2df1 100644 --- a/app/src/main/java/com/mxt/anitrend/util/CompatUtil.kt +++ b/app/src/main/java/com/mxt/anitrend/util/CompatUtil.kt @@ -9,14 +9,14 @@ 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 androidx.annotation.* +import androidx.core.app.ActivityManagerCompat +import androidx.core.app.ActivityOptionsCompat +import androidx.fragment.app.FragmentActivity +import androidx.core.content.ContextCompat +import androidx.core.graphics.drawable.DrawableCompat +import androidx.core.view.ViewCompat +import androidx.appcompat.content.res.AppCompatResources import android.text.TextUtils import android.view.LayoutInflater import android.view.View diff --git a/app/src/main/java/com/mxt/anitrend/util/DateUtil.kt b/app/src/main/java/com/mxt/anitrend/util/DateUtil.kt index ec926bf89..f2b0d8310 100644 --- a/app/src/main/java/com/mxt/anitrend/util/DateUtil.kt +++ b/app/src/main/java/com/mxt/anitrend/util/DateUtil.kt @@ -1,6 +1,6 @@ package com.mxt.anitrend.util -import android.support.annotation.IntRange +import androidx.annotation.IntRange import com.annimon.stream.Collectors import com.annimon.stream.IntStream import com.mxt.anitrend.model.entity.anilist.meta.AiringSchedule 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 ff5e0d7c8..17eceead1 100644 --- a/app/src/main/java/com/mxt/anitrend/util/DialogUtil.java +++ b/app/src/main/java/com/mxt/anitrend/util/DialogUtil.java @@ -3,14 +3,16 @@ import android.content.Context; import android.content.res.AssetManager; import android.graphics.Typeface; -import android.support.annotation.IdRes; -import android.support.annotation.StringRes; +import androidx.annotation.IdRes; +import androidx.annotation.StringRes; import android.text.InputType; import android.text.SpannedString; import android.text.TextUtils; import android.widget.EditText; import android.widget.Toast; +import androidx.fragment.app.FragmentActivity; + import com.afollestad.materialdialogs.MaterialDialog; import com.afollestad.materialdialogs.Theme; import com.mxt.anitrend.BuildConfig; @@ -243,7 +245,7 @@ public static void createChangeLog(Context context) { *
* * @param context from a fragment activity derived class - * @see android.support.v4.app.FragmentActivity + * @see FragmentActivity */ static MaterialDialog.Builder createDefaultDialog(Context context) { return new MaterialDialog.Builder(context) diff --git a/app/src/main/java/com/mxt/anitrend/util/GenreTagUtil.java b/app/src/main/java/com/mxt/anitrend/util/GenreTagUtil.java index 2e410b71b..b32fdaf87 100644 --- a/app/src/main/java/com/mxt/anitrend/util/GenreTagUtil.java +++ b/app/src/main/java/com/mxt/anitrend/util/GenreTagUtil.java @@ -1,8 +1,8 @@ package com.mxt.anitrend.util; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.annimon.stream.Stream; import com.google.gson.reflect.TypeToken; diff --git a/app/src/main/java/com/mxt/anitrend/util/IntentBundleUtil.kt b/app/src/main/java/com/mxt/anitrend/util/IntentBundleUtil.kt index 98c41d853..1ee102730 100644 --- a/app/src/main/java/com/mxt/anitrend/util/IntentBundleUtil.kt +++ b/app/src/main/java/com/mxt/anitrend/util/IntentBundleUtil.kt @@ -3,9 +3,9 @@ package com.mxt.anitrend.util import android.content.Intent import android.net.Uri import android.os.Build -import android.support.annotation.VisibleForTesting -import android.support.v4.app.FragmentActivity -import android.support.v4.app.ShareCompat +import androidx.annotation.VisibleForTesting +import androidx.fragment.app.FragmentActivity +import androidx.core.app.ShareCompat import android.text.TextUtils import java.util.regex.Matcher 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 c9c25451a..1406a778d 100644 --- a/app/src/main/java/com/mxt/anitrend/util/KeyUtil.java +++ b/app/src/main/java/com/mxt/anitrend/util/KeyUtil.java @@ -1,8 +1,8 @@ package com.mxt.anitrend.util; -import android.support.annotation.IntDef; -import android.support.annotation.LongDef; -import android.support.annotation.StringDef; +import androidx.annotation.IntDef; +import androidx.annotation.LongDef; +import androidx.annotation.StringDef; /** * Created by max on 2017/09/16. 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 5fcf27e96..06600e898 100644 --- a/app/src/main/java/com/mxt/anitrend/util/MarkDownUtil.kt +++ b/app/src/main/java/com/mxt/anitrend/util/MarkDownUtil.kt @@ -2,7 +2,7 @@ package com.mxt.anitrend.util import android.content.Context import android.os.Build -import android.support.v7.widget.AppCompatTextView +import androidx.appcompat.widget.AppCompatTextView import android.text.Html import android.text.SpannableStringBuilder import android.text.Spanned 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 e6c571442..80e56c1e7 100644 --- a/app/src/main/java/com/mxt/anitrend/util/MediaActionUtil.java +++ b/app/src/main/java/com/mxt/anitrend/util/MediaActionUtil.java @@ -1,10 +1,10 @@ package com.mxt.anitrend.util; import android.app.ProgressDialog; -import android.arch.lifecycle.Lifecycle; +import androidx.lifecycle.Lifecycle; import android.content.SharedPreferences; -import android.support.annotation.NonNull; -import android.support.v4.app.FragmentActivity; +import androidx.annotation.NonNull; +import androidx.fragment.app.FragmentActivity; import android.util.Log; import android.widget.Toast; 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 8dc850ba9..82172bb4b 100644 --- a/app/src/main/java/com/mxt/anitrend/util/MediaDialogUtil.java +++ b/app/src/main/java/com/mxt/anitrend/util/MediaDialogUtil.java @@ -3,7 +3,7 @@ import android.app.ProgressDialog; import android.content.Context; import android.os.Bundle; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import android.text.Html; import android.util.Log; import android.widget.Toast; 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 77b976ee2..aa52788bb 100644 --- a/app/src/main/java/com/mxt/anitrend/util/MediaListUtil.java +++ b/app/src/main/java/com/mxt/anitrend/util/MediaListUtil.java @@ -1,7 +1,7 @@ package com.mxt.anitrend.util; import android.os.Bundle; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import com.annimon.stream.Stream; import com.mxt.anitrend.base.custom.view.widget.AutoIncrementWidget; diff --git a/app/src/main/java/com/mxt/anitrend/util/NotificationUtil.kt b/app/src/main/java/com/mxt/anitrend/util/NotificationUtil.kt index fd2c692a1..ee7b77dbb 100644 --- a/app/src/main/java/com/mxt/anitrend/util/NotificationUtil.kt +++ b/app/src/main/java/com/mxt/anitrend/util/NotificationUtil.kt @@ -8,9 +8,9 @@ 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 androidx.core.app.NotificationCompat +import androidx.core.app.NotificationCompat.PRIORITY_DEFAULT +import androidx.core.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 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 92e6a4868..26f41f086 100644 --- a/app/src/main/java/com/mxt/anitrend/util/NotifyUtil.java +++ b/app/src/main/java/com/mxt/anitrend/util/NotifyUtil.java @@ -2,11 +2,11 @@ import android.app.ProgressDialog; import android.content.Context; -import android.support.annotation.ColorRes; -import android.support.annotation.DrawableRes; -import android.support.annotation.StringRes; -import android.support.design.widget.Snackbar; -import android.support.v4.app.FragmentActivity; +import androidx.annotation.ColorRes; +import androidx.annotation.DrawableRes; +import androidx.annotation.StringRes; +import com.google.android.material.snackbar.Snackbar; +import androidx.fragment.app.FragmentActivity; import android.util.TypedValue; import android.view.Gravity; import android.view.View; @@ -154,8 +154,8 @@ public static Snackbar make(View parent, String stringRes, int duration) { Snackbar snackbar = Snackbar.make(parent, stringRes, duration); View snackBarContainer = snackbar.getView(); 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); + TextView mainTextView = snackBarContainer.findViewById(R.id.snackbar_text); + TextView actionTextView = snackBarContainer.findViewById(R.id.snackbar_action); 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); @@ -166,8 +166,8 @@ 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.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); + TextView mainTextView = snackBarContainer.findViewById(R.id.snackbar_text); + TextView actionTextView = snackBarContainer.findViewById(R.id.snackbar_action); 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); diff --git a/app/src/main/java/com/mxt/anitrend/util/ShortcutUtil.java b/app/src/main/java/com/mxt/anitrend/util/ShortcutUtil.java index f1bcd187d..6e8e0d9ba 100644 --- a/app/src/main/java/com/mxt/anitrend/util/ShortcutUtil.java +++ b/app/src/main/java/com/mxt/anitrend/util/ShortcutUtil.java @@ -8,8 +8,8 @@ import android.graphics.drawable.Icon; import android.os.Build; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.RequiresApi; +import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; import com.mxt.anitrend.R; import com.mxt.anitrend.view.activity.detail.MediaListActivity; 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 495b1d29b..6286e303e 100644 --- a/app/src/main/java/com/mxt/anitrend/util/TapTargetUtil.java +++ b/app/src/main/java/com/mxt/anitrend/util/TapTargetUtil.java @@ -1,11 +1,11 @@ package com.mxt.anitrend.util; -import android.support.annotation.IdRes; -import android.support.annotation.Nullable; -import android.support.annotation.StringRes; -import android.support.v4.app.FragmentActivity; -import android.support.v4.graphics.ColorUtils; -import android.support.v4.view.animation.FastOutSlowInInterpolator; +import androidx.annotation.IdRes; +import androidx.annotation.Nullable; +import androidx.annotation.StringRes; +import androidx.fragment.app.FragmentActivity; +import androidx.core.graphics.ColorUtils; +import androidx.interpolator.view.animation.FastOutSlowInInterpolator; import android.view.View; import com.annimon.stream.Stream; 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 a2380432e..5a127feca 100644 --- a/app/src/main/java/com/mxt/anitrend/util/TutorialUtil.java +++ b/app/src/main/java/com/mxt/anitrend/util/TutorialUtil.java @@ -1,11 +1,11 @@ package com.mxt.anitrend.util; -import android.support.annotation.ColorRes; -import android.support.annotation.IdRes; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.StringRes; -import android.support.v4.app.FragmentActivity; +import androidx.annotation.ColorRes; +import androidx.annotation.IdRes; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.StringRes; +import androidx.fragment.app.FragmentActivity; import android.util.Log; import android.view.View; diff --git a/app/src/main/java/com/mxt/anitrend/view/activity/base/AboutActivity.kt b/app/src/main/java/com/mxt/anitrend/view/activity/base/AboutActivity.kt index 0e2ae9e8f..7a1226af0 100644 --- a/app/src/main/java/com/mxt/anitrend/view/activity/base/AboutActivity.kt +++ b/app/src/main/java/com/mxt/anitrend/view/activity/base/AboutActivity.kt @@ -1,7 +1,7 @@ package com.mxt.anitrend.view.activity.base import android.os.Bundle -import android.support.v7.widget.Toolbar +import androidx.appcompat.widget.Toolbar import butterknife.ButterKnife import com.mxt.anitrend.R import com.mxt.anitrend.base.custom.activity.ActivityBase 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 a208025ab..89f34694b 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 @@ -1,15 +1,14 @@ package com.mxt.anitrend.view.activity.base; import android.content.res.Configuration; -import android.os.Build; import android.os.Bundle; import android.preference.PreferenceActivity; -import android.support.annotation.LayoutRes; -import android.support.annotation.Nullable; -import android.support.annotation.StyleRes; -import android.support.v7.app.ActionBar; -import android.support.v7.app.AppCompatDelegate; -import android.support.v7.widget.Toolbar; +import androidx.annotation.LayoutRes; +import androidx.annotation.Nullable; +import androidx.annotation.StyleRes; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatDelegate; +import androidx.appcompat.widget.Toolbar; import android.view.MenuInflater; import android.view.View; import android.view.ViewGroup; 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 7c6c3daba..64947ac1c 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 @@ -2,7 +2,7 @@ import android.graphics.drawable.Drawable; import android.os.Bundle; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import android.text.TextUtils; import android.view.View; import android.view.Window; 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 5e62b0f2c..e4e8ea61e 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 @@ -6,10 +6,10 @@ import android.net.Uri; import android.os.Bundle; import android.os.Environment; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.v4.app.ActivityCompat; -import android.support.v7.widget.Toolbar; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.app.ActivityCompat; +import androidx.appcompat.widget.Toolbar; import android.text.TextUtils; import android.util.Log; import android.view.Menu; diff --git a/app/src/main/java/com/mxt/anitrend/view/activity/base/ReportActivity.java b/app/src/main/java/com/mxt/anitrend/view/activity/base/ReportActivity.java index b2d0992d8..1f901599e 100644 --- a/app/src/main/java/com/mxt/anitrend/view/activity/base/ReportActivity.java +++ b/app/src/main/java/com/mxt/anitrend/view/activity/base/ReportActivity.java @@ -1,7 +1,6 @@ package com.mxt.anitrend.view.activity.base; import android.Manifest; -import android.content.Context; import android.os.Bundle; import com.mxt.anitrend.R; @@ -9,8 +8,8 @@ import com.mxt.anitrend.presenter.base.BasePresenter; import android.os.Environment; -import android.support.annotation.Nullable; -import android.widget.Button; +import androidx.annotation.Nullable; + import android.widget.TextView; import android.widget.Toast; 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 040581d28..a9272f12f 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 @@ -17,8 +17,8 @@ import android.preference.PreferenceFragment; import android.preference.PreferenceManager; import android.preference.RingtonePreference; -import android.support.v4.app.NavUtils; -import android.support.v7.app.ActionBar; +import androidx.core.app.NavUtils; +import androidx.appcompat.app.ActionBar; import android.text.TextUtils; import android.view.MenuItem; import android.widget.Toast; 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 64cd19803..96fc95464 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 @@ -1,13 +1,13 @@ package com.mxt.anitrend.view.activity.base; -import android.databinding.DataBindingUtil; +import androidx.databinding.DataBindingUtil; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.design.widget.BottomSheetBehavior; -import android.support.design.widget.TextInputEditText; -import android.support.v4.app.ShareCompat; -import android.support.v7.widget.AppCompatImageView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import com.google.android.material.bottomsheet.BottomSheetBehavior; +import com.google.android.material.textfield.TextInputEditText; +import androidx.core.app.ShareCompat; +import androidx.appcompat.widget.AppCompatImageView; import android.view.View; import android.widget.Spinner; import android.widget.Toast; 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 8d29ec56d..a11be6a64 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 @@ -3,7 +3,7 @@ import android.os.Build; import android.os.Bundle; import android.os.PersistableBundle; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import android.view.View; import android.view.Window; import android.view.WindowManager; @@ -75,7 +75,7 @@ public void onBackPressed() { @Override protected void onActivityReady() { JZDataSource dataSource = new JZDataSource(contentLink); - player.setUp(dataSource, Jzvd.SCREEN_WINDOW_FULLSCREEN); + player.setUp(dataSource, Jzvd.SCREEN_FULLSCREEN); // player.backButton.setOnClickListener(this); // player.tinyBackImageView.setVisibility(View.INVISIBLE); player.fullscreenButton.setImageResource(R.drawable.jz_shrink); @@ -97,7 +97,7 @@ protected void makeRequest() { public void onPause() { super.onPause(); - Jzvd.resetAllVideos(); + Jzvd.releaseAllVideos(); } /** 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 fc1f790b5..ba9f361a1 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 @@ -3,8 +3,8 @@ import android.content.Intent; import android.os.Build; import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v4.content.ContextCompat; +import androidx.annotation.Nullable; +import androidx.core.content.ContextCompat; import android.view.View; import com.codemybrainsout.onboarder.AhoyOnboarderActivity; 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 b1aebfd4e..4cbe291a5 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 @@ -2,10 +2,10 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.design.widget.CoordinatorLayout; -import android.support.v4.view.ViewPager; -import android.support.v7.widget.Toolbar; +import androidx.annotation.Nullable; +import androidx.coordinatorlayout.widget.CoordinatorLayout; +import androidx.viewpager.widget.ViewPager; +import androidx.appcompat.widget.Toolbar; import android.view.Menu; import android.view.MenuItem; import android.widget.Toast; diff --git a/app/src/main/java/com/mxt/anitrend/view/activity/detail/CommentActivity.java b/app/src/main/java/com/mxt/anitrend/view/activity/detail/CommentActivity.java index e01e65ffd..fdc499a1e 100644 --- a/app/src/main/java/com/mxt/anitrend/view/activity/detail/CommentActivity.java +++ b/app/src/main/java/com/mxt/anitrend/view/activity/detail/CommentActivity.java @@ -1,10 +1,10 @@ package com.mxt.anitrend.view.activity.detail; import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v4.app.FragmentManager; -import android.support.v4.app.FragmentTransaction; -import android.support.v7.widget.Toolbar; +import androidx.annotation.Nullable; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentTransaction; +import androidx.appcompat.widget.Toolbar; import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.activity.ActivityBase; diff --git a/app/src/main/java/com/mxt/anitrend/view/activity/detail/FavouriteActivity.java b/app/src/main/java/com/mxt/anitrend/view/activity/detail/FavouriteActivity.java index 719b24cc8..2def97d14 100644 --- a/app/src/main/java/com/mxt/anitrend/view/activity/detail/FavouriteActivity.java +++ b/app/src/main/java/com/mxt/anitrend/view/activity/detail/FavouriteActivity.java @@ -1,10 +1,10 @@ package com.mxt.anitrend.view.activity.detail; import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.design.widget.CoordinatorLayout; -import android.support.v4.view.ViewPager; -import android.support.v7.widget.Toolbar; +import androidx.annotation.Nullable; +import androidx.coordinatorlayout.widget.CoordinatorLayout; +import androidx.viewpager.widget.ViewPager; +import androidx.appcompat.widget.Toolbar; import com.mxt.anitrend.R; import com.mxt.anitrend.adapter.pager.detail.FavouritePageAdapter; 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 f0dca6117..ce0e2950b 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 @@ -1,11 +1,11 @@ package com.mxt.anitrend.view.activity.detail; import android.content.Intent; -import android.databinding.DataBindingUtil; +import androidx.databinding.DataBindingUtil; import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v4.view.ViewPager; -import android.support.v7.widget.Toolbar; +import androidx.annotation.Nullable; +import androidx.viewpager.widget.ViewPager; +import androidx.appcompat.widget.Toolbar; import android.view.Menu; import android.view.MenuItem; import android.view.View; @@ -29,7 +29,6 @@ import com.mxt.anitrend.util.NotifyUtil; import com.mxt.anitrend.util.TapTargetUtil; import com.mxt.anitrend.util.TutorialUtil; -import com.mxt.anitrend.view.activity.base.ImagePreviewActivity; import com.ogaclejapan.smarttablayout.SmartTabLayout; import java.util.Locale; 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 6bb78a9d0..65531f9ed 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 @@ -1,10 +1,10 @@ package com.mxt.anitrend.view.activity.detail; import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v4.app.FragmentManager; -import android.support.v4.app.FragmentTransaction; -import android.support.v7.widget.Toolbar; +import androidx.annotation.Nullable; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentTransaction; +import androidx.appcompat.widget.Toolbar; import android.text.Spanned; import com.mxt.anitrend.R; 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 e14178fbe..357a3cee3 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 @@ -1,10 +1,10 @@ package com.mxt.anitrend.view.activity.detail; import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.design.widget.CoordinatorLayout; -import android.support.v4.view.ViewPager; -import android.support.v7.widget.Toolbar; +import androidx.annotation.Nullable; +import androidx.coordinatorlayout.widget.CoordinatorLayout; +import androidx.viewpager.widget.ViewPager; +import androidx.appcompat.widget.Toolbar; import android.view.Menu; import android.view.MenuItem; diff --git a/app/src/main/java/com/mxt/anitrend/view/activity/detail/MessageActivity.java b/app/src/main/java/com/mxt/anitrend/view/activity/detail/MessageActivity.java index a5434aec5..2d16d288f 100644 --- a/app/src/main/java/com/mxt/anitrend/view/activity/detail/MessageActivity.java +++ b/app/src/main/java/com/mxt/anitrend/view/activity/detail/MessageActivity.java @@ -1,10 +1,10 @@ package com.mxt.anitrend.view.activity.detail; import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.design.widget.CoordinatorLayout; -import android.support.v4.view.ViewPager; -import android.support.v7.widget.Toolbar; +import androidx.annotation.Nullable; +import androidx.coordinatorlayout.widget.CoordinatorLayout; +import androidx.viewpager.widget.ViewPager; +import androidx.appcompat.widget.Toolbar; import com.mxt.anitrend.R; import com.mxt.anitrend.adapter.pager.detail.MessagePageAdapter; diff --git a/app/src/main/java/com/mxt/anitrend/view/activity/detail/NotificationActivity.java b/app/src/main/java/com/mxt/anitrend/view/activity/detail/NotificationActivity.java index 17c7786a9..f66575000 100644 --- a/app/src/main/java/com/mxt/anitrend/view/activity/detail/NotificationActivity.java +++ b/app/src/main/java/com/mxt/anitrend/view/activity/detail/NotificationActivity.java @@ -1,10 +1,10 @@ package com.mxt.anitrend.view.activity.detail; import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v4.app.FragmentManager; -import android.support.v4.app.FragmentTransaction; -import android.support.v7.widget.Toolbar; +import androidx.annotation.Nullable; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentTransaction; +import androidx.appcompat.widget.Toolbar; import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.activity.ActivityBase; 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 3e55a28d9..9e637a719 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 @@ -1,11 +1,11 @@ package com.mxt.anitrend.view.activity.detail; import android.content.Intent; -import android.databinding.DataBindingUtil; +import androidx.databinding.DataBindingUtil; import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v4.view.ViewPager; -import android.support.v7.widget.Toolbar; +import androidx.annotation.Nullable; +import androidx.viewpager.widget.ViewPager; +import androidx.appcompat.widget.Toolbar; import android.view.Menu; import android.view.MenuItem; import android.view.View; @@ -24,7 +24,6 @@ import com.mxt.anitrend.util.KeyUtil; import com.mxt.anitrend.util.NotifyUtil; import com.mxt.anitrend.util.TutorialUtil; -import com.mxt.anitrend.view.activity.base.ImagePreviewActivity; import com.mxt.anitrend.view.sheet.BottomSheetComposer; import com.ogaclejapan.smarttablayout.SmartTabLayout; 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 f7e494525..19becccf7 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 @@ -2,10 +2,10 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.design.widget.CoordinatorLayout; -import android.support.v4.view.ViewPager; -import android.support.v7.widget.Toolbar; +import androidx.annotation.Nullable; +import androidx.coordinatorlayout.widget.CoordinatorLayout; +import androidx.viewpager.widget.ViewPager; +import androidx.appcompat.widget.Toolbar; import android.view.Menu; import android.view.MenuItem; import android.widget.Toast; 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 17a77f3ff..69533f6fb 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 @@ -2,10 +2,10 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v4.app.FragmentManager; -import android.support.v4.app.FragmentTransaction; -import android.support.v7.widget.Toolbar; +import androidx.annotation.Nullable; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentTransaction; +import androidx.appcompat.widget.Toolbar; import android.view.Menu; import android.view.MenuItem; import android.widget.Toast; 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 d84aa1fc1..07f5efe50 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 @@ -1,12 +1,12 @@ package com.mxt.anitrend.view.activity.index; -import android.arch.lifecycle.Observer; +import androidx.lifecycle.Observer; import android.content.Intent; -import android.databinding.DataBindingUtil; +import androidx.databinding.DataBindingUtil; import android.net.Uri; import android.os.Build; import android.os.Bundle; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import android.text.TextUtils; import android.util.Log; import android.view.View; @@ -209,8 +209,8 @@ private void checkNewIntent(Intent intent) { .addTag(KeyUtil.WorkAuthenticatorTag) .setInputData(workerInputData) .build(); - WorkManager.getInstance().enqueue(authenticatorWorker); - WorkManager.getInstance().getWorkInfoByIdLiveData(authenticatorWorker.getId()) + WorkManager.getInstance(getApplicationContext()).enqueue(authenticatorWorker); + WorkManager.getInstance(getApplicationContext()).getWorkInfoByIdLiveData(authenticatorWorker.getId()) .observe(this, workInfoObserver); } } 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 3e999d692..33bc96e1b 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 @@ -5,20 +5,20 @@ import android.net.Uri; import android.os.Build; import android.os.Bundle; -import android.support.annotation.IdRes; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.StringRes; -import android.support.design.widget.CoordinatorLayout; -import android.support.design.widget.NavigationView; -import android.support.v4.app.ActivityCompat; -import android.support.v4.content.ContextCompat; -import android.support.v4.view.GravityCompat; -import android.support.v4.view.ViewPager; -import android.support.v4.widget.DrawerLayout; -import android.support.v7.app.ActionBarDrawerToggle; -import android.support.v7.widget.Toolbar; -import android.text.Spannable; +import androidx.annotation.IdRes; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.StringRes; +import androidx.coordinatorlayout.widget.CoordinatorLayout; +import com.google.android.material.navigation.NavigationView; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; +import androidx.core.view.GravityCompat; +import androidx.viewpager.widget.ViewPager; +import androidx.drawerlayout.widget.DrawerLayout; +import androidx.appcompat.app.ActionBarDrawerToggle; +import androidx.appcompat.widget.Toolbar; + import android.view.Menu; import android.view.MenuItem; import android.view.View; @@ -49,7 +49,6 @@ import com.mxt.anitrend.util.DateUtil; import com.mxt.anitrend.util.DialogUtil; import com.mxt.anitrend.util.KeyUtil; -import com.mxt.anitrend.util.MarkDownUtil; import com.mxt.anitrend.util.NotifyUtil; import com.mxt.anitrend.view.activity.base.AboutActivity; import com.mxt.anitrend.view.activity.base.ReportActivity; diff --git a/app/src/main/java/com/mxt/anitrend/view/activity/index/SearchActivity.java b/app/src/main/java/com/mxt/anitrend/view/activity/index/SearchActivity.java index f962ca26f..d2cc37334 100644 --- a/app/src/main/java/com/mxt/anitrend/view/activity/index/SearchActivity.java +++ b/app/src/main/java/com/mxt/anitrend/view/activity/index/SearchActivity.java @@ -1,10 +1,10 @@ package com.mxt.anitrend.view.activity.index; import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.design.widget.CoordinatorLayout; -import android.support.v4.view.ViewPager; -import android.support.v7.widget.Toolbar; +import androidx.annotation.Nullable; +import androidx.coordinatorlayout.widget.CoordinatorLayout; +import androidx.viewpager.widget.ViewPager; +import androidx.appcompat.widget.Toolbar; import com.mxt.anitrend.R; import com.mxt.anitrend.adapter.pager.index.SearchPageAdapter; 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 a091a8bc7..c219fb53a 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 @@ -2,7 +2,7 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.activity.ActivityBase; diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/AboutFragment.kt b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/AboutFragment.kt index 8220cf054..285951e41 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/AboutFragment.kt +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/AboutFragment.kt @@ -3,7 +3,7 @@ package com.mxt.anitrend.view.fragment.detail import android.content.Intent import android.net.Uri import android.os.Bundle -import android.support.v7.app.AppCompatDelegate +import androidx.appcompat.app.AppCompatDelegate import android.view.LayoutInflater import android.view.View import android.view.ViewGroup 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 ffe3272d9..d1a9a53b2 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 @@ -2,7 +2,7 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; 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 914c2b83f..1d46723e0 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 @@ -1,9 +1,8 @@ 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; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -17,7 +16,6 @@ import com.mxt.anitrend.util.CompatUtil; import com.mxt.anitrend.util.GraphUtil; import com.mxt.anitrend.util.KeyUtil; -import com.mxt.anitrend.view.activity.base.ImagePreviewActivity; import butterknife.ButterKnife; import butterknife.OnClick; 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 aedf443b6..06bd3dda7 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 @@ -2,7 +2,7 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/MediaFeedFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/MediaFeedFragment.java index 7eb2a4afe..6e7385669 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/MediaFeedFragment.java +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/MediaFeedFragment.java @@ -1,7 +1,7 @@ package com.mxt.anitrend.view.fragment.detail; import android.os.Bundle; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder; import com.mxt.anitrend.util.KeyUtil; diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/MediaOverviewFragment.kt b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/MediaOverviewFragment.kt index 076e7f74a..2a8fe1bad 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/MediaOverviewFragment.kt +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/MediaOverviewFragment.kt @@ -2,13 +2,12 @@ package com.mxt.anitrend.view.fragment.detail import android.content.Intent import android.os.Bundle -import android.support.v7.widget.StaggeredGridLayoutManager +import androidx.recyclerview.widget.StaggeredGridLayoutManager import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import com.annimon.stream.IntPair -import com.google.android.youtube.player.YouTubeIntents import com.mxt.anitrend.R import com.mxt.anitrend.adapter.recycler.detail.GenreAdapter import com.mxt.anitrend.adapter.recycler.detail.TagAdapter @@ -18,8 +17,6 @@ import com.mxt.anitrend.databinding.FragmentSeriesOverviewBinding import com.mxt.anitrend.model.entity.anilist.Genre import com.mxt.anitrend.model.entity.anilist.Media import com.mxt.anitrend.model.entity.anilist.MediaTag -import com.mxt.anitrend.model.entity.base.StudioBase -import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder import com.mxt.anitrend.presenter.fragment.MediaPresenter import com.mxt.anitrend.util.CompatUtil import com.mxt.anitrend.util.DialogUtil @@ -29,7 +26,6 @@ import com.mxt.anitrend.util.MediaBrowseUtil import com.mxt.anitrend.view.activity.detail.MediaBrowseActivity import com.mxt.anitrend.view.activity.detail.StudioActivity import com.mxt.anitrend.view.fragment.youtube.YouTubeEmbedFragment -import com.mxt.anitrend.view.fragment.youtube.YoutubePlayerFragment import butterknife.ButterKnife import butterknife.OnClick @@ -42,7 +38,6 @@ import com.afollestad.materialdialogs.DialogAction class MediaOverviewFragment : FragmentBase() { private var binding: FragmentSeriesOverviewBinding? = null - private var youtubePlayerFragment: YoutubePlayerFragment? = null private var model: Media? = null private var genreAdapter: GenreAdapter? = null @@ -91,17 +86,9 @@ class MediaOverviewFragment : FragmentBase() { */ override fun updateUI() { if (activity != null && model!!.trailer != null && CompatUtil.equals(model!!.trailer.site, "youtube")) { - if (YouTubeIntents.canResolvePlayVideoIntent(activity!!)) { - if (youtubePlayerFragment == null) - youtubePlayerFragment = YoutubePlayerFragment.newInstance(model!!.trailer) - childFragmentManager.beginTransaction() - .replace(R.id.youtube_view, youtubePlayerFragment!!) - .commit() - } else { - childFragmentManager.beginTransaction() - .replace(R.id.youtube_view, YouTubeEmbedFragment.newInstance(model!!.trailer)) - .commit() - } + childFragmentManager.beginTransaction() + .replace(R.id.youtube_view, YouTubeEmbedFragment.newInstance(model!!.trailer)) + .commit() } else binding!!.youtubeView.visibility = View.GONE binding!!.presenter = presenter 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 6d67fab70..5f885f559 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 @@ -2,7 +2,7 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import android.view.View; import com.annimon.stream.IntPair; 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 8ca5a5b8a..d10438c8d 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 @@ -4,9 +4,9 @@ import android.graphics.Color; import android.net.Uri; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.v7.widget.StaggeredGridLayoutManager; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.StaggeredGridLayoutManager; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; 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 540adb539..2b1c1e201 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 @@ -2,7 +2,7 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import android.view.View; import com.annimon.stream.IntPair; diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/NotificationFragment.kt b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/NotificationFragment.kt index d8b659b9c..7ea15a76d 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/NotificationFragment.kt +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/NotificationFragment.kt @@ -74,13 +74,13 @@ class NotificationFragment : FragmentBaseList(model.subList(5, 6))); } - override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) { + override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { super.onCreateOptionsMenu(menu, inflater) - menu!!.findItem(R.id.action_mark_all).isVisible = true + menu.findItem(R.id.action_mark_all).isVisible = true } - override fun onOptionsItemSelected(item: MenuItem?): Boolean { - when (item!!.itemId) { + override fun onOptionsItemSelected(item: MenuItem): Boolean { + when (item.itemId) { R.id.action_mark_all -> { if (mAdapter.itemCount > 0) { ThreadPool.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 1a82e05e8..f7024e75d 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 @@ -2,7 +2,7 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import android.view.View; import android.widget.Toast; 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 237ca6b38..a1d843466 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 @@ -1,9 +1,8 @@ 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; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -17,7 +16,6 @@ import com.mxt.anitrend.util.CompatUtil; import com.mxt.anitrend.util.GraphUtil; import com.mxt.anitrend.util.KeyUtil; -import com.mxt.anitrend.view.activity.base.ImagePreviewActivity; import butterknife.ButterKnife; import butterknife.OnClick; 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 5eb47e187..b7ab534fe 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 @@ -2,7 +2,7 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/UserFeedFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/UserFeedFragment.java index f13574cf5..780e9db54 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/UserFeedFragment.java +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/UserFeedFragment.java @@ -1,7 +1,7 @@ package com.mxt.anitrend.view.fragment.detail; import android.os.Bundle; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder; import com.mxt.anitrend.util.KeyUtil; 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 6f2a20817..b27474457 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,8 +1,8 @@ package com.mxt.anitrend.view.fragment.detail; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; 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 a56fd3155..4ecfe31e8 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 @@ -2,7 +2,7 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import android.view.View; import com.annimon.stream.IntPair; 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 04b285ba5..b01acb8d7 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 @@ -2,7 +2,7 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import android.view.View; import android.widget.Toast; 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 d93242e89..7085e82c1 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 @@ -2,7 +2,7 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import android.view.View; import com.annimon.stream.IntPair; 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 1c5f1acc4..05317317c 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 @@ -2,7 +2,7 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import android.view.View; import com.annimon.stream.IntPair; 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 f077fb4ad..25e3930e6 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 @@ -2,7 +2,7 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import android.view.View; import android.widget.Toast; 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 ee1cdbc79..9ec2a7c67 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 @@ -2,7 +2,7 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import android.view.View; import com.annimon.stream.IntPair; 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 f058bddb1..8a8b75981 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 @@ -2,7 +2,7 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import android.view.View; import android.widget.Toast; 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 0c6ec052f..365b2d653 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 @@ -2,7 +2,7 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import android.view.View; import android.widget.Toast; 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 43492635b..4e9e712d3 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 @@ -2,7 +2,7 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import android.view.View; import android.widget.Toast; 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 dfcb779bf..8c46db0e3 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 @@ -1,7 +1,7 @@ package com.mxt.anitrend.view.fragment.list; import android.os.Bundle; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import com.annimon.stream.Optional; import com.annimon.stream.Stream; 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 8b21c177d..0b1b21a24 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 @@ -2,7 +2,7 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import android.view.ActionMode; import android.view.Menu; import android.view.MenuItem; 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 234087766..672f32169 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 @@ -2,7 +2,7 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/list/MediaLatestList.java b/app/src/main/java/com/mxt/anitrend/view/fragment/list/MediaLatestList.java index dc59a0b8c..91a0615ce 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/list/MediaLatestList.java +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/list/MediaLatestList.java @@ -1,7 +1,7 @@ package com.mxt.anitrend.view.fragment.list; import android.os.Bundle; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder; import com.mxt.anitrend.util.KeyUtil; 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 03287208a..b61907fac 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 @@ -4,8 +4,8 @@ import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; 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 eb5e09df4..204f18e3c 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 @@ -1,10 +1,10 @@ package com.mxt.anitrend.view.fragment.list; -import android.arch.lifecycle.Lifecycle; +import androidx.lifecycle.Lifecycle; import android.os.Bundle; import android.os.Parcelable; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import android.util.Log; import com.mxt.anitrend.BuildConfig; 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 65095256f..bf9a6dc2e 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 @@ -2,7 +2,7 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import android.view.View; import com.annimon.stream.IntPair; 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 7a7247ebe..31a1d0eb0 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 @@ -2,7 +2,7 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import android.view.View; import android.widget.Toast; 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 bf1f54487..2c5633f14 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 @@ -2,7 +2,7 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import android.view.View; import com.annimon.stream.IntPair; 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 f6d9cd42c..43d10c091 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 @@ -2,7 +2,7 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import android.view.View; import com.annimon.stream.IntPair; 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 a45099049..6962970ce 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 @@ -2,7 +2,7 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import android.view.View; import com.annimon.stream.IntPair; 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 58a7d1943..952489a04 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 @@ -4,8 +4,8 @@ import android.content.Intent; import android.net.Uri; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/youtube/YoutubePlayerFragment.kt b/app/src/main/java/com/mxt/anitrend/view/fragment/youtube/YoutubePlayerFragment.kt deleted file mode 100644 index 0802216f1..000000000 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/youtube/YoutubePlayerFragment.kt +++ /dev/null @@ -1,89 +0,0 @@ -package com.mxt.anitrend.view.fragment.youtube - -import android.arch.lifecycle.Lifecycle -import android.os.Bundle -import android.util.Log - -import com.google.android.youtube.player.YouTubeInitializationResult -import com.google.android.youtube.player.YouTubePlayer -import com.google.android.youtube.player.YouTubePlayerSupportFragment -import com.mxt.anitrend.BuildConfig -import com.mxt.anitrend.model.entity.anilist.meta.MediaTrailer -import com.mxt.anitrend.util.KeyUtil - -/** - * Created by max on 2017/12/29. - * Youtube support player fragment - */ - -class YoutubePlayerFragment : YouTubePlayerSupportFragment(), YouTubePlayer.OnInitializedListener { - - private var mediaTrailer: MediaTrailer? = null - - private var youTubePlayer: YouTubePlayer? = null - private var isFullScreen: Boolean = false - - private val youTubePlayerFullscreenListener = YouTubePlayer.OnFullscreenListener { - fullScreen -> isFullScreen = fullScreen - } - - override fun onCreate(bundle: Bundle?) { - super.onCreate(bundle) - mediaTrailer = arguments?.getParcelable(KeyUtil.arg_media_trailer) - } - - override fun onResume() { - super.onResume() - try { - initialize(BuildConfig.API_KEY, this) - } catch (e: Exception) { - e.printStackTrace() - Log.e(YoutubePlayerFragment::class.java.simpleName, e.localizedMessage) - } - } - - /** - * Informs parent activity if on back can continue to super method or not - */ - fun onBackPress(): Boolean { - if (isFullScreen) { - youTubePlayer?.setFullscreen(false) - youTubePlayer?.release() - return false - } - return true - } - - override fun onInitializationSuccess( - provider: YouTubePlayer.Provider, - youTubePlayer: YouTubePlayer, - wasRestored: Boolean - ) { - try { - if (lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)) { - this@YoutubePlayerFragment.youTubePlayer = youTubePlayer.apply { - setOnFullscreenListener(youTubePlayerFullscreenListener) - if (!wasRestored) - cueVideo(mediaTrailer?.id) - } - } - } catch (e: Exception) { - e.printStackTrace() - } - } - - override fun onInitializationFailure(provider: YouTubePlayer.Provider, youTubeInitializationResult: YouTubeInitializationResult) { - - } - - companion object { - - fun newInstance(mediaTrailer: MediaTrailer): YoutubePlayerFragment { - return YoutubePlayerFragment().apply { - arguments = Bundle().apply { - putParcelable(KeyUtil.arg_media_trailer, mediaTrailer) - } - } - } - } -} 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 5ff0cb50b..0847c8cd9 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 @@ -2,8 +2,8 @@ import android.app.Dialog; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.sheet.BottomSheetBase; 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 765960422..37d48ca51 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 @@ -3,8 +3,8 @@ import android.annotation.SuppressLint; import android.app.Dialog; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import android.view.View; import com.annimon.stream.IntPair; 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 06bf1cc6c..9ff86185b 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 @@ -3,10 +3,10 @@ import android.app.Dialog; import android.content.Intent; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.design.widget.BottomSheetBehavior; -import android.support.v7.widget.StaggeredGridLayoutManager; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import com.google.android.material.bottomsheet.BottomSheetBehavior; +import androidx.recyclerview.widget.StaggeredGridLayoutManager; import android.text.TextUtils; import android.view.View; 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 6821278c0..188d48cdb 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 @@ -1,13 +1,13 @@ package com.mxt.anitrend.view.sheet; import android.app.Dialog; -import android.arch.lifecycle.Observer; -import android.arch.lifecycle.ViewModelProviders; +import androidx.lifecycle.Observer; +import androidx.lifecycle.ViewModelProviders; import android.content.Intent; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.v7.widget.StaggeredGridLayoutManager; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.StaggeredGridLayoutManager; import android.view.View; import com.annimon.stream.IntPair; 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 cbeaceb2b..ed2e87b42 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 @@ -2,9 +2,9 @@ import android.app.Dialog; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.StringRes; -import android.support.v7.widget.AppCompatButton; +import androidx.annotation.NonNull; +import androidx.annotation.StringRes; +import androidx.appcompat.widget.AppCompatButton; import android.view.View; import com.mxt.anitrend.R; 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 7ddea294b..216527fc4 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 @@ -4,10 +4,10 @@ import android.content.Intent; import android.os.Bundle; import android.os.Parcelable; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.design.widget.BottomSheetBehavior; -import android.support.v7.widget.StaggeredGridLayoutManager; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import com.google.android.material.bottomsheet.BottomSheetBehavior; +import androidx.recyclerview.widget.StaggeredGridLayoutManager; import android.text.TextUtils; import android.view.View; diff --git a/app/src/main/res/layout/activity_frame_generic.xml b/app/src/main/res/layout/activity_frame_generic.xml index 9d6eb0e7d..870c5495f 100644 --- a/app/src/main/res/layout/activity_frame_generic.xml +++ b/app/src/main/res/layout/activity_frame_generic.xml @@ -1,18 +1,18 @@ - - - + - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_image_preview.xml b/app/src/main/res/layout/activity_image_preview.xml index 9f0424e6b..bafa25a0b 100644 --- a/app/src/main/res/layout/activity_image_preview.xml +++ b/app/src/main/res/layout/activity_image_preview.xml @@ -1,5 +1,5 @@ - - - + - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml index 163d63082..9eba9b911 100644 --- a/app/src/main/res/layout/activity_login.xml +++ b/app/src/main/res/layout/activity_login.xml @@ -44,7 +44,7 @@ android:textColor="?colorAccent" android:text="@string/anitrend_sign_in_browser"/> - @@ -57,7 +57,7 @@ android:inAnimation="@android:anim/fade_in" android:outAnimation="@android:anim/fade_out"> - - + - diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 0c8ad330b..e7f4e19be 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,5 +1,5 @@ - - - + diff --git a/app/src/main/res/layout/activity_pager_generic.xml b/app/src/main/res/layout/activity_pager_generic.xml index c6733747e..44f1a6585 100644 --- a/app/src/main/res/layout/activity_pager_generic.xml +++ b/app/src/main/res/layout/activity_pager_generic.xml @@ -1,5 +1,5 @@ - - @@ -16,8 +16,8 @@ - + - + diff --git a/app/src/main/res/layout/activity_profile.xml b/app/src/main/res/layout/activity_profile.xml index a19a11b31..286b9a828 100644 --- a/app/src/main/res/layout/activity_profile.xml +++ b/app/src/main/res/layout/activity_profile.xml @@ -7,17 +7,17 @@ - - - - + - + - + diff --git a/app/src/main/res/layout/activity_series.xml b/app/src/main/res/layout/activity_series.xml index 587239516..cc7c673a1 100644 --- a/app/src/main/res/layout/activity_series.xml +++ b/app/src/main/res/layout/activity_series.xml @@ -8,17 +8,17 @@ - - - - + - + - + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_share_content.xml b/app/src/main/res/layout/activity_share_content.xml index cd823e575..2c8c71fca 100644 --- a/app/src/main/res/layout/activity_share_content.xml +++ b/app/src/main/res/layout/activity_share_content.xml @@ -4,7 +4,7 @@ xmlns:tools="http://schemas.android.com/tools" tools:context=".view.activity.base.SharedContentActivity"> - @@ -18,7 +18,7 @@ android:orientation="vertical" app:behavior_hideable="true" android:background="?attr/cardColor" - app:layout_behavior="android.support.design.widget.BottomSheetBehavior"> + app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"> @@ -43,7 +43,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content"> - - + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_splash.xml b/app/src/main/res/layout/activity_splash.xml index 89122a4ca..015540782 100644 --- a/app/src/main/res/layout/activity_splash.xml +++ b/app/src/main/res/layout/activity_splash.xml @@ -3,7 +3,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools"> - - @@ -35,7 +35,7 @@ android:layout_height="@dimen/md_margin" android:background="@color/colorStateBlue" /> - @@ -44,7 +44,7 @@ android:layout_height="@dimen/md_margin" android:background="@color/colorStateOrange" /> - @@ -127,5 +127,5 @@ app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="1.0" /> - + \ No newline at end of file diff --git a/app/src/main/res/layout/adapter_anime.xml b/app/src/main/res/layout/adapter_anime.xml index 4f6ee43da..c829ae5a6 100644 --- a/app/src/main/res/layout/adapter_anime.xml +++ b/app/src/main/res/layout/adapter_anime.xml @@ -7,7 +7,7 @@ - - @@ -66,7 +66,7 @@ android:textAppearance="@style/TextAppearance.AppCompat.Caption" tools:text="Gintama."/> - @@ -89,6 +89,6 @@ android:layout_margin="@dimen/md_margin" app:rating="@{model}"/> - + \ No newline at end of file diff --git a/app/src/main/res/layout/adapter_character.xml b/app/src/main/res/layout/adapter_character.xml index 68922ac48..6769ca620 100644 --- a/app/src/main/res/layout/adapter_character.xml +++ b/app/src/main/res/layout/adapter_character.xml @@ -9,7 +9,7 @@ - - + \ No newline at end of file diff --git a/app/src/main/res/layout/adapter_comment.xml b/app/src/main/res/layout/adapter_comment.xml index 1c1a1f384..e378b66be 100644 --- a/app/src/main/res/layout/adapter_comment.xml +++ b/app/src/main/res/layout/adapter_comment.xml @@ -56,7 +56,7 @@ - @@ -65,7 +65,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content"/> - diff --git a/app/src/main/res/layout/adapter_episode.xml b/app/src/main/res/layout/adapter_episode.xml index 5bb69bc6f..13cfe7f6d 100644 --- a/app/src/main/res/layout/adapter_episode.xml +++ b/app/src/main/res/layout/adapter_episode.xml @@ -8,7 +8,7 @@ - - @@ -74,6 +74,6 @@ android:text="@{model.title}" tools:text="Boku no Hero Accademia"/> - + diff --git a/app/src/main/res/layout/adapter_feed_message.xml b/app/src/main/res/layout/adapter_feed_message.xml index 570184a67..913b7acd0 100644 --- a/app/src/main/res/layout/adapter_feed_message.xml +++ b/app/src/main/res/layout/adapter_feed_message.xml @@ -91,7 +91,7 @@ - @@ -100,7 +100,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content"/> - diff --git a/app/src/main/res/layout/adapter_feed_progress.xml b/app/src/main/res/layout/adapter_feed_progress.xml index 6e0d1c090..a2af3e535 100644 --- a/app/src/main/res/layout/adapter_feed_progress.xml +++ b/app/src/main/res/layout/adapter_feed_progress.xml @@ -56,7 +56,7 @@ - @@ -84,7 +84,7 @@ app:feedHeadline="@{model}" tools:text="plans to read: Aggressive Restuko" /> - @@ -94,7 +94,7 @@ android:text="@{model.media.title.english}" tools:text="Aggressive Restuko" /> - diff --git a/app/src/main/res/layout/adapter_feed_slide.xml b/app/src/main/res/layout/adapter_feed_slide.xml index 382a1f95b..b5e079c51 100644 --- a/app/src/main/res/layout/adapter_feed_slide.xml +++ b/app/src/main/res/layout/adapter_feed_slide.xml @@ -24,7 +24,7 @@ tools:scaleType="centerCrop" tools:src="@drawable/sample_banner"/> - - @@ -70,7 +70,7 @@ android:layout_height="wrap_content" app:richMarkDown="@{model.text}"/>--> - diff --git a/app/src/main/res/layout/adapter_genre.xml b/app/src/main/res/layout/adapter_genre.xml index 98e3e5942..8aca5cb78 100644 --- a/app/src/main/res/layout/adapter_genre.xml +++ b/app/src/main/res/layout/adapter_genre.xml @@ -28,7 +28,7 @@ app:srcCompat="@drawable/ic_label_outline_white_24dp" app:tint="?colorAccent"/> - diff --git a/app/src/main/res/layout/adapter_link.xml b/app/src/main/res/layout/adapter_link.xml index d3a96faf1..007d5029b 100644 --- a/app/src/main/res/layout/adapter_link.xml +++ b/app/src/main/res/layout/adapter_link.xml @@ -28,7 +28,7 @@ app:srcCompat="@drawable/ic_link_white_24dp" app:tint="?colorAccent"/> - diff --git a/app/src/main/res/layout/adapter_manga.xml b/app/src/main/res/layout/adapter_manga.xml index f86866527..dc03110fe 100644 --- a/app/src/main/res/layout/adapter_manga.xml +++ b/app/src/main/res/layout/adapter_manga.xml @@ -7,7 +7,7 @@ - - @@ -77,6 +77,6 @@ android:layout_margin="@dimen/lg_margin" app:rating="@{model}"/> - + \ No newline at end of file diff --git a/app/src/main/res/layout/adapter_media_header.xml b/app/src/main/res/layout/adapter_media_header.xml index 2cbfb5e33..9442fb0fa 100644 --- a/app/src/main/res/layout/adapter_media_header.xml +++ b/app/src/main/res/layout/adapter_media_header.xml @@ -8,7 +8,7 @@ - - @@ -50,7 +50,7 @@ app:seriesStatus="@{model}" tools:background="@color/colorStateBlue"/> - @@ -60,7 +60,7 @@ android:layout_height="wrap_content" tools:text="Gintama."/> - @@ -71,7 +71,7 @@ android:text="@{CompatUtil.INSTANCE.capitalizeWords(model.subGroupTitle)}" tools:text="Supporting" /> - @@ -86,6 +86,6 @@ - + diff --git a/app/src/main/res/layout/adapter_notification.xml b/app/src/main/res/layout/adapter_notification.xml index 5b016ab46..d8f63747e 100644 --- a/app/src/main/res/layout/adapter_notification.xml +++ b/app/src/main/res/layout/adapter_notification.xml @@ -51,7 +51,7 @@ - @@ -61,7 +61,7 @@ android:layout_height="wrap_content" tools:text="AnukWolf" /> - diff --git a/app/src/main/res/layout/adapter_ranking.xml b/app/src/main/res/layout/adapter_ranking.xml index 4bf5e08a4..de48cd3c7 100644 --- a/app/src/main/res/layout/adapter_ranking.xml +++ b/app/src/main/res/layout/adapter_ranking.xml @@ -28,7 +28,7 @@ android:layout_height="@dimen/menu_item_icon_size" tools:src="@drawable/ic_star_yellow_700_24dp"/> - diff --git a/app/src/main/res/layout/adapter_review.xml b/app/src/main/res/layout/adapter_review.xml index 939508681..05fc79898 100644 --- a/app/src/main/res/layout/adapter_review.xml +++ b/app/src/main/res/layout/adapter_review.xml @@ -7,7 +7,7 @@ - - + diff --git a/app/src/main/res/layout/adapter_series.xml b/app/src/main/res/layout/adapter_series.xml index 6f6e1ae3f..0a80a776b 100644 --- a/app/src/main/res/layout/adapter_series.xml +++ b/app/src/main/res/layout/adapter_series.xml @@ -7,7 +7,7 @@ - - @@ -77,6 +77,6 @@ android:layout_margin="@dimen/lg_margin" app:rating="@{model}"/> - + \ No newline at end of file diff --git a/app/src/main/res/layout/adapter_series_airing.xml b/app/src/main/res/layout/adapter_series_airing.xml index 77d21ebb2..1f0273364 100644 --- a/app/src/main/res/layout/adapter_series_airing.xml +++ b/app/src/main/res/layout/adapter_series_airing.xml @@ -7,7 +7,7 @@ - - @@ -79,7 +79,7 @@ android:textAppearance="@style/TextAppearance.AppCompat.Caption" tools:text="Gintama."/> - @@ -102,6 +102,6 @@ android:layout_margin="@dimen/lg_margin" app:rating="@{model}"/> - + \ No newline at end of file diff --git a/app/src/main/res/layout/adapter_series_review.xml b/app/src/main/res/layout/adapter_series_review.xml index 5e5f209e6..58e7ce5bb 100644 --- a/app/src/main/res/layout/adapter_series_review.xml +++ b/app/src/main/res/layout/adapter_series_review.xml @@ -56,7 +56,7 @@ - @@ -85,7 +85,7 @@ android:ellipsize="end" tools:text="Gintama." /> - @@ -97,7 +97,7 @@ app:markDown="@{model.summary}" tools:text="Amazing show with a well thought out plot" /> - diff --git a/app/src/main/res/layout/adapter_staff.xml b/app/src/main/res/layout/adapter_staff.xml index a20a7bd8d..eb39a5da0 100644 --- a/app/src/main/res/layout/adapter_staff.xml +++ b/app/src/main/res/layout/adapter_staff.xml @@ -10,7 +10,7 @@ - - + \ No newline at end of file diff --git a/app/src/main/res/layout/adapter_tag.xml b/app/src/main/res/layout/adapter_tag.xml index 470478d6a..c2e89a68d 100644 --- a/app/src/main/res/layout/adapter_tag.xml +++ b/app/src/main/res/layout/adapter_tag.xml @@ -28,7 +28,7 @@ app:srcCompat="@drawable/ic_loyalty_white_24dp" app:tint="?colorAccent"/> - @@ -47,7 +47,7 @@ app:isSpoiler="@{model.mediaSpoiler}" tools:text="High School"/> - diff --git a/app/src/main/res/layout/adapter_user.xml b/app/src/main/res/layout/adapter_user.xml index 7e2fc9624..f345aa081 100644 --- a/app/src/main/res/layout/adapter_user.xml +++ b/app/src/main/res/layout/adapter_user.xml @@ -27,7 +27,7 @@ app:avatarUrl="@{model.avatar}" tools:src="@drawable/avatar_placeholder"/> - @@ -40,7 +40,7 @@ android:text="@{model.name}" tools:text="Loath57"/> - diff --git a/app/src/main/res/layout/app_bar_main.xml b/app/src/main/res/layout/app_bar_main.xml index 31674ca0d..b62d0efa2 100644 --- a/app/src/main/res/layout/app_bar_main.xml +++ b/app/src/main/res/layout/app_bar_main.xml @@ -1,5 +1,5 @@ - - @@ -17,8 +17,8 @@ - + - + diff --git a/app/src/main/res/layout/bottom_sheet_composer.xml b/app/src/main/res/layout/bottom_sheet_composer.xml index 60a2701d3..3e5b9abfc 100644 --- a/app/src/main/res/layout/bottom_sheet_composer.xml +++ b/app/src/main/res/layout/bottom_sheet_composer.xml @@ -9,7 +9,7 @@ - @@ -19,6 +19,6 @@ android:layout_width="match_parent" android:layout_height="wrap_content" /> - + \ No newline at end of file diff --git a/app/src/main/res/layout/bottom_sheet_message.xml b/app/src/main/res/layout/bottom_sheet_message.xml index 77ef9f9d5..a6f5a7379 100644 --- a/app/src/main/res/layout/bottom_sheet_message.xml +++ b/app/src/main/res/layout/bottom_sheet_message.xml @@ -42,7 +42,7 @@ android:gravity="end" android:orientation="horizontal"> - - - @@ -43,7 +43,7 @@ - + diff --git a/app/src/main/res/layout/content_main.xml b/app/src/main/res/layout/content_main.xml index 6631318fc..928efada7 100644 --- a/app/src/main/res/layout/content_main.xml +++ b/app/src/main/res/layout/content_main.xml @@ -1,5 +1,5 @@ - - - @@ -55,7 +55,7 @@ - @@ -77,7 +77,7 @@ - @@ -99,7 +99,7 @@ - @@ -120,7 +120,7 @@ android:layout_gravity="center_vertical|end" /> - @@ -141,7 +141,7 @@ android:layout_gravity="center_vertical|end" /> - @@ -155,7 +155,7 @@ android:layout_gravity="center_vertical|start" android:text="@string/dialog_title_private" /> - - - @@ -180,7 +180,7 @@ android:text="@{model.notes}" android:textSize="@dimen/subtitle_text_size" /> - + - @@ -55,7 +55,7 @@ - @@ -77,7 +77,7 @@ - @@ -99,7 +99,7 @@ - @@ -120,7 +120,7 @@ android:layout_gravity="center_vertical|end" /> - @@ -141,7 +141,7 @@ android:layout_gravity="center_vertical|end" /> - @@ -164,7 +164,7 @@ - @@ -178,7 +178,7 @@ android:layout_gravity="center_vertical|start" android:text="@string/dialog_title_private" /> - - - @@ -203,7 +203,7 @@ android:text="@{model.notes}" android:textSize="@dimen/subtitle_text_size" /> - + - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/custom_rating_widget.xml b/app/src/main/res/layout/custom_rating_widget.xml index 2cc2c54a2..05f30e5bc 100644 --- a/app/src/main/res/layout/custom_rating_widget.xml +++ b/app/src/main/res/layout/custom_rating_widget.xml @@ -18,7 +18,7 @@ android:textColor="@color/white" tools:text="4.35"/> - diff --git a/app/src/main/res/layout/custom_recycler_loading.xml b/app/src/main/res/layout/custom_recycler_loading.xml index 192fb57b1..33d61d873 100644 --- a/app/src/main/res/layout/custom_recycler_loading.xml +++ b/app/src/main/res/layout/custom_recycler_loading.xml @@ -8,7 +8,7 @@ android:orientation="vertical" android:id="@+id/container"> - - - @@ -73,7 +73,7 @@ android:ellipsize="end" tools:text="Gintama." /> - diff --git a/app/src/main/res/layout/custom_sheet_toolbar.xml b/app/src/main/res/layout/custom_sheet_toolbar.xml index 37596a916..6536d4079 100644 --- a/app/src/main/res/layout/custom_sheet_toolbar.xml +++ b/app/src/main/res/layout/custom_sheet_toolbar.xml @@ -23,7 +23,7 @@ android:textStyle="bold" tools:text="Toolbar Title" /> - - - - diff --git a/app/src/main/res/layout/custom_toolbar.xml b/app/src/main/res/layout/custom_toolbar.xml index 8a71de382..2c39ff0b8 100644 --- a/app/src/main/res/layout/custom_toolbar.xml +++ b/app/src/main/res/layout/custom_toolbar.xml @@ -5,7 +5,7 @@ android:layout_width="match_parent" android:layout_height="?attr/actionBarSize"> - - - diff --git a/app/src/main/res/layout/fragment_character_overview.xml b/app/src/main/res/layout/fragment_character_overview.xml index 8bd744da4..03d07ce48 100644 --- a/app/src/main/res/layout/fragment_character_overview.xml +++ b/app/src/main/res/layout/fragment_character_overview.xml @@ -12,7 +12,7 @@ android:layout_height="match_parent" android:layout_width="match_parent"> - @@ -21,7 +21,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content"> - - @@ -74,7 +74,7 @@ android:layout_height="@dimen/md_margin" android:background="@drawable/dashed_background" /> - @@ -83,7 +83,7 @@ android:layout_height="wrap_content" android:text="@string/title_native_name"/> - - + - @@ -128,7 +128,7 @@ app:textHtml="@{model.name.alternativeFormatted}" tools:text="Yorozuya, Mr. Odd Jobs, Shiroyasha, Gin, Gin-chan, Kintoki, Paako, Ginpachi-sensei" /> - @@ -138,7 +138,7 @@ android:text="@string/title_summary" /> - @@ -155,7 +155,7 @@ - + diff --git a/app/src/main/res/layout/fragment_comment.xml b/app/src/main/res/layout/fragment_comment.xml index f3ae36077..4f6999071 100644 --- a/app/src/main/res/layout/fragment_comment.xml +++ b/app/src/main/res/layout/fragment_comment.xml @@ -14,7 +14,7 @@ android:layout_weight="1" android:descendantFocusability="blocksDescendants"> - @@ -28,7 +28,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" /> - @@ -48,7 +48,7 @@ - + diff --git a/app/src/main/res/layout/fragment_series_overview.xml b/app/src/main/res/layout/fragment_series_overview.xml index 6ca0ef996..f084d8359 100644 --- a/app/src/main/res/layout/fragment_series_overview.xml +++ b/app/src/main/res/layout/fragment_series_overview.xml @@ -16,7 +16,7 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - @@ -39,7 +39,7 @@ tools:visibility="gone" tools:layout_height="@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 0451e10a9..d170ae75b 100644 --- a/app/src/main/res/layout/fragment_series_stats.xml +++ b/app/src/main/res/layout/fragment_series_stats.xml @@ -15,7 +15,7 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - @@ -24,7 +24,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content"> - - - + diff --git a/app/src/main/res/layout/fragment_staff_overview.xml b/app/src/main/res/layout/fragment_staff_overview.xml index 61ca51faf..6d31a5954 100644 --- a/app/src/main/res/layout/fragment_staff_overview.xml +++ b/app/src/main/res/layout/fragment_staff_overview.xml @@ -14,7 +14,7 @@ android:layout_height="match_parent" android:layout_width="match_parent"> - @@ -23,7 +23,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content"> - - @@ -76,7 +76,7 @@ android:layout_height="@dimen/md_margin" android:background="@drawable/dashed_background" /> - @@ -85,7 +85,7 @@ android:layout_height="wrap_content" android:text="@string/title_language"/> - - + - @@ -136,7 +136,7 @@ - + diff --git a/app/src/main/res/layout/fragment_user_about.xml b/app/src/main/res/layout/fragment_user_about.xml index b14beeb09..3ba743c0f 100644 --- a/app/src/main/res/layout/fragment_user_about.xml +++ b/app/src/main/res/layout/fragment_user_about.xml @@ -13,7 +13,7 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - @@ -78,7 +78,7 @@ - @@ -93,7 +93,7 @@ android:layout_height="wrap_content" app:richMarkDown="@{model.about}"/>--> - @@ -102,7 +102,7 @@ - @@ -120,7 +120,7 @@ android:textAppearance="@style/TextAppearance.AppCompat.Caption" android:text="@string/text_tap_on_item_below_to_view_stats" /> - @@ -148,7 +148,7 @@ - + diff --git a/app/src/main/res/layout/section_series_description.xml b/app/src/main/res/layout/section_series_description.xml index 4607721bf..3af3d1499 100644 --- a/app/src/main/res/layout/section_series_description.xml +++ b/app/src/main/res/layout/section_series_description.xml @@ -36,7 +36,7 @@ app:startDate="@{model.startDate}" tools:text="Started: 2017/09/30"/> - @@ -50,7 +50,7 @@ tools:text="Ended: 2017/10/30"/> - @@ -60,11 +60,11 @@ android:text="@string/title_series_japanese_name" /> - - - @@ -82,7 +82,7 @@ android:text="@string/title_series_description" /> - diff --git a/app/src/main/res/layout/section_series_details.xml b/app/src/main/res/layout/section_series_details.xml index 5355474a4..a0e9aa59d 100644 --- a/app/src/main/res/layout/section_series_details.xml +++ b/app/src/main/res/layout/section_series_details.xml @@ -69,7 +69,7 @@ - @@ -123,7 +123,7 @@ - @@ -177,7 +177,7 @@ - @@ -229,7 +229,7 @@ - @@ -289,7 +289,7 @@ - diff --git a/app/src/main/res/layout/section_series_info.xml b/app/src/main/res/layout/section_series_info.xml index 7212cc1a2..6fe9f1a61 100644 --- a/app/src/main/res/layout/section_series_info.xml +++ b/app/src/main/res/layout/section_series_info.xml @@ -8,7 +8,7 @@ - - - @@ -60,7 +60,7 @@ tools:background="@color/colorStateBlue" app:seriesStatus="@{model}"/> - @@ -69,7 +69,7 @@ android:layout_height="wrap_content" android:text="@string/title_series_english_name"/> - - @@ -89,7 +89,7 @@ android:textIsSelectable="true" tools:text="Series Type: TV"/> - @@ -97,6 +97,6 @@ - + \ No newline at end of file diff --git a/app/src/main/res/layout/widget_avatar_indicator.xml b/app/src/main/res/layout/widget_avatar_indicator.xml index c66ea650d..fa0679cf9 100644 --- a/app/src/main/res/layout/widget_avatar_indicator.xml +++ b/app/src/main/res/layout/widget_avatar_indicator.xml @@ -29,14 +29,14 @@ android:visibility="gone" tools:visibility="visible"> - - - - + - @@ -30,7 +30,7 @@ android:scrollbarStyle="insideInset" android:scrollbars="vertical"/> - + - @@ -78,7 +78,7 @@ app:tint="?colorAccent" app:srcCompat="@drawable/ic_slow_motion_video_white_24dp" /> - @@ -95,7 +95,7 @@ app:tint="?colorAccent" app:srcCompat="@drawable/ic_link_white_24dp" /> - @@ -133,7 +133,7 @@ app:tint="?colorAccent" app:srcCompat="@drawable/ic_gif_white_24dp" /> - @@ -151,7 +151,7 @@ app:tint="?colorAccent" app:srcCompat="@drawable/ic_insert_emoticon_white_24dp" /> - diff --git a/app/src/main/res/layout/widget_fuzzy_date.xml b/app/src/main/res/layout/widget_fuzzy_date.xml index 468a58c43..2469f7bd1 100644 --- a/app/src/main/res/layout/widget_fuzzy_date.xml +++ b/app/src/main/res/layout/widget_fuzzy_date.xml @@ -35,7 +35,7 @@ android:layout_height="wrap_content" android:layout_width="@dimen/lg_margin"/> - diff --git a/app/src/main/res/layout/widget_status.xml b/app/src/main/res/layout/widget_status.xml index b9203f035..309b9b690 100644 --- a/app/src/main/res/layout/widget_status.xml +++ b/app/src/main/res/layout/widget_status.xml @@ -33,7 +33,7 @@ - diff --git a/app/src/main/res/layout/widget_vote.xml b/app/src/main/res/layout/widget_vote.xml index 8ecd631a3..356ae097b 100644 --- a/app/src/main/res/layout/widget_vote.xml +++ b/app/src/main/res/layout/widget_vote.xml @@ -44,7 +44,7 @@ - diff --git a/build.gradle b/build.gradle index 7b2fc16d6..27815c1cc 100644 --- a/build.gradle +++ b/build.gradle @@ -5,22 +5,54 @@ buildscript { compileSdk = 28 targetSdk = 28 minSdk = 17 - versionCode = 113 - versionName = '1.4.9' - butterKnife = '8.8.1' + + versionCode = 130 + versionName = '1.5.1' + + butterKnife = '10.1.0' + + constraint = '1.1.3' + glide = '4.9.0' - retrofit = '2.5.0' - supportLibrary = '27.1.1' - firebase = '16.0.8' + retrofit = '2.6.0' + + supportLibrary = '28.0.0' + material = '1.0.0' + androidx = '2.0.0' objectBox = '2.3.3' - architecture = '1.1.1' - workManager = '1.0.1' - emojify = '1.4' - kotlin = '1.3.41' - // testing libraries - mockito = '2.18.3' + paging = '2.1.0' + pagingKtx = '2.1.0' + ktx = '1.2.0-alpha02' + fragmentKtx = '1.2.0-alpha01' + workerKtx = '2.1.0' + navigation = '2.1.0-beta02' + firebase = '17.0.1' + + koin = '2.0.1' + kotlinVersion = '1.3.41' + + // mockito = '2.18.3' hemcrest = '1.3' - markwon = '3.0.0' + mockito = '3.0.0' + junit = '4.12' + runner = '1.2.0' + espresso = '3.2.0' + + flexBox = '1.1.0' + crashlytics = '2.6.8@aar' + coroutinesCore = '1.2.2' + coroutinesAndroid = '1.2.2' + materialDialogs = '0.9.6.0' + + gson = '2.8.5' + timber = '4.7.1' + + graphql = '0.10.1' + emojify = '1.4' + markwon = '4.0.2' + smartTab = '2.0.0' + tapTarget = '2.15.0' + okHttpLogger = '3.12.1' } repositories { google() @@ -32,14 +64,14 @@ buildscript { dependencies { classpath 'com.android.tools.build:gradle:3.4.2' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${rootProject.kotlin}" + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" // Google Play Services classpath 'com.google.gms:google-services:4.3.0' // Crash Analytics classpath 'io.fabric.tools:gradle:1.31.0' // Object Box - classpath "io.objectbox:objectbox-gradle-plugin:${rootProject.objectBox}" - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${rootProject.kotlin}" + classpath "io.objectbox:objectbox-gradle-plugin:$objectBox" + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" } } diff --git a/gradle.properties b/gradle.properties index d08ab663f..239505509 100644 --- a/gradle.properties +++ b/gradle.properties @@ -15,8 +15,8 @@ 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.useAndroidX=true +android.enableJetifier=true android.databinding.enableV2=true # Kotlin code style for this project: "official" or "obsolete": From 92ec4ce718fc3fb029aa84684f6dbc94802801b6 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Sun, 4 Aug 2019 16:05:59 +0200 Subject: [PATCH 11/81] Bump Target and Build SDK from API 28 to 29 --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 27815c1cc..b71f2263b 100644 --- a/build.gradle +++ b/build.gradle @@ -2,8 +2,8 @@ buildscript { ext { - compileSdk = 28 - targetSdk = 28 + compileSdk = 29 + targetSdk = 29 minSdk = 17 versionCode = 130 From dc570c80afb35007e24f382335238b3476454607 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Sun, 4 Aug 2019 16:06:09 +0200 Subject: [PATCH 12/81] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cc3460476..34a6937c5 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# [ :biohazard: W.I.P v2.0 :biohazard: ] AniTrend v1.4.8   [![license](https://img.shields.io/github/license/mashape/apistatus.svg?style=flat-square)](https://github.com/AniTrend/anitrend-app/blob/master/LICENSE.md) +# [ :biohazard: W.I.P v2.0 :biohazard: ] AniTrend v1.5.1   [![license](https://img.shields.io/github/license/mashape/apistatus.svg?style=flat-square)](https://github.com/AniTrend/anitrend-app/blob/master/LICENSE.md) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/30a8f983c55541cbb504671ecc32786c)](https://www.codacy.com/app/wax911/anitrend-app?utm_source=github.com&utm_medium=referral&utm_content=wax911/anitrend-app&utm_campaign=Badge_Grade)   [![Build Status](https://travis-ci.org/AniTrend/anitrend-app.svg?branch=master)](https://travis-ci.org/AniTrend/anitrend-app)   [![Discord](https://img.shields.io/discord/314442908478472203.svg?color=%237289da&label=Join%20Anitrend%21&logo=discord&logoColor=%23fff)](https://discordapp.com/invite/2wzTqnF) Discover anime or manga with AniTrend which is a free [AniList](https://anilist.co) android client written in java.(AniTrend does not offer streaming capabilities, but official website links such as Hulu, Chrunchyroll, Netflix will be provided if available) From eb2436748317fbd22bd2b04994c21ddda74b7410 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Mon, 5 Aug 2019 14:35:35 +0200 Subject: [PATCH 13/81] Add New Statistics Object Type --- app/objectbox-models/default.json | 6 +- app/objectbox-models/default.json.bak | 0 .../anitrend/model/entity/anilist/User.java | 13 ++++ .../model/entity/anilist/UserStats.java | 2 +- .../entity/anilist/meta/FormatStats.java | 1 + .../model/entity/anilist/meta/GenreStats.java | 2 +- .../entity/anilist/meta/MediaTagStats.java | 2 +- .../anilist/meta/StatusDistribution.java | 2 +- .../model/entity/anilist/meta/YearStats.java | 1 + .../entity/anilist/user/UserStatisticTypes.kt | 29 +++++++++ .../entity/anilist/user/UserStatistics.kt | 64 +++++++++++++++++++ .../user/statistics/UserCountryStatistic.kt | 33 ++++++++++ .../user/statistics/UserFormatStatistic.kt | 35 ++++++++++ .../user/statistics/UserGenreStatistic.kt | 33 ++++++++++ .../user/statistics/UserLengthStatistic.kt | 33 ++++++++++ .../statistics/UserReleaseYearStatistic.kt | 33 ++++++++++ .../user/statistics/UserScoreStatistic.kt | 33 ++++++++++ .../user/statistics/UserStaffStatistic.kt | 34 ++++++++++ .../user/statistics/UserStartYearStatistic.kt | 33 ++++++++++ .../user/statistics/UserStatusStatistic.kt | 35 ++++++++++ .../user/statistics/UserStudioStatistic.kt | 34 ++++++++++ .../user/statistics/UserTagStatistic.kt | 34 ++++++++++ .../statistics/UserVoiceActorStatistic.kt | 35 ++++++++++ .../statistics/contract/IUserStatistic.kt | 35 ++++++++++ .../container/body/ConnectionContainer.java | 2 +- 25 files changed, 558 insertions(+), 6 deletions(-) mode change 100755 => 100644 app/objectbox-models/default.json.bak create mode 100644 app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/UserStatisticTypes.kt create mode 100644 app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/UserStatistics.kt create mode 100644 app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserCountryStatistic.kt create mode 100644 app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserFormatStatistic.kt create mode 100644 app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserGenreStatistic.kt create mode 100644 app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserLengthStatistic.kt create mode 100644 app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserReleaseYearStatistic.kt create mode 100644 app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserScoreStatistic.kt create mode 100644 app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserStaffStatistic.kt create mode 100644 app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserStartYearStatistic.kt create mode 100644 app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserStatusStatistic.kt create mode 100644 app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserStudioStatistic.kt create mode 100644 app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserTagStatistic.kt create mode 100644 app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserVoiceActorStatistic.kt create mode 100644 app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/contract/IUserStatistic.kt diff --git a/app/objectbox-models/default.json b/app/objectbox-models/default.json index 2d5365950..2b2df8d6d 100755 --- a/app/objectbox-models/default.json +++ b/app/objectbox-models/default.json @@ -58,7 +58,7 @@ }, { "id": "4:2500178567314633405", - "lastPropertyId": "27:684903496913852672", + "lastPropertyId": "28:6177613386273186625", "name": "User", "properties": [ { @@ -101,6 +101,10 @@ { "id": "27:684903496913852672", "name": "unreadNotificationCount" + }, + { + "id": "28:6177613386273186625", + "name": "statistics" } ], "relations": [] diff --git a/app/objectbox-models/default.json.bak b/app/objectbox-models/default.json.bak old mode 100755 new mode 100644 diff --git a/app/src/main/java/com/mxt/anitrend/model/entity/anilist/User.java b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/User.java index 9a0ab06b7..6427189a4 100644 --- a/app/src/main/java/com/mxt/anitrend/model/entity/anilist/User.java +++ b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/User.java @@ -2,11 +2,15 @@ import android.os.Parcel; +import androidx.annotation.Nullable; + import com.mxt.anitrend.data.converter.MediaListOptionsConverter; import com.mxt.anitrend.data.converter.UserOptionsConverter; +import com.mxt.anitrend.data.converter.UserStatisticTypesConverter; import com.mxt.anitrend.data.converter.UserStatsConverter; import com.mxt.anitrend.model.entity.anilist.meta.MediaListOptions; import com.mxt.anitrend.model.entity.anilist.meta.UserOptions; +import com.mxt.anitrend.model.entity.anilist.user.UserStatisticTypes; import com.mxt.anitrend.model.entity.base.UserBase; import io.objectbox.annotation.Convert; @@ -25,7 +29,11 @@ public class User extends UserBase { @Convert(converter = MediaListOptionsConverter.class, dbType = String.class) private MediaListOptions mediaListOptions; @Convert(converter = UserStatsConverter.class, dbType = String.class) + @Deprecated private UserStats stats; + @Nullable + @Convert(converter = UserStatisticTypesConverter.class, dbType = String.class) + private UserStatisticTypes statistics; private int unreadNotificationCount; public User() { @@ -106,6 +114,11 @@ public void setAbout(String about) { this.about = about; } + @Nullable + public UserStatisticTypes getStatistics() { + return statistics; + } + public void setStats(UserStats stats) { this.stats = stats; } diff --git a/app/src/main/java/com/mxt/anitrend/model/entity/anilist/UserStats.java b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/UserStats.java index 73624651e..5552aef21 100644 --- a/app/src/main/java/com/mxt/anitrend/model/entity/anilist/UserStats.java +++ b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/UserStats.java @@ -16,7 +16,7 @@ * UserStats for user * @see User */ - +@Deprecated public class UserStats implements Parcelable { private int watchedTime; diff --git a/app/src/main/java/com/mxt/anitrend/model/entity/anilist/meta/FormatStats.java b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/meta/FormatStats.java index 1cbafb3c5..48f2f708c 100644 --- a/app/src/main/java/com/mxt/anitrend/model/entity/anilist/meta/FormatStats.java +++ b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/meta/FormatStats.java @@ -3,6 +3,7 @@ import android.os.Parcel; import android.os.Parcelable; +@Deprecated public class FormatStats implements Parcelable { private String format; diff --git a/app/src/main/java/com/mxt/anitrend/model/entity/anilist/meta/GenreStats.java b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/meta/GenreStats.java index d1230299e..c50b88fd9 100644 --- a/app/src/main/java/com/mxt/anitrend/model/entity/anilist/meta/GenreStats.java +++ b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/meta/GenreStats.java @@ -10,7 +10,7 @@ * GenreStats for userStats * @see UserStats */ - +@Deprecated public class GenreStats implements Parcelable { private String genre; diff --git a/app/src/main/java/com/mxt/anitrend/model/entity/anilist/meta/MediaTagStats.java b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/meta/MediaTagStats.java index 747d3cfc8..2898d396c 100644 --- a/app/src/main/java/com/mxt/anitrend/model/entity/anilist/meta/MediaTagStats.java +++ b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/meta/MediaTagStats.java @@ -4,7 +4,7 @@ import android.os.Parcelable; import com.mxt.anitrend.model.entity.anilist.MediaTag; - +@Deprecated public class MediaTagStats implements Parcelable { private MediaTag tag; diff --git a/app/src/main/java/com/mxt/anitrend/model/entity/anilist/meta/StatusDistribution.java b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/meta/StatusDistribution.java index bcc2b007b..a9154fea7 100644 --- a/app/src/main/java/com/mxt/anitrend/model/entity/anilist/meta/StatusDistribution.java +++ b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/meta/StatusDistribution.java @@ -11,7 +11,7 @@ * StatusDistribution for media and userStats * @see UserStats */ - +@Deprecated public class StatusDistribution implements Parcelable { private @KeyUtil.MediaListStatus String status; diff --git a/app/src/main/java/com/mxt/anitrend/model/entity/anilist/meta/YearStats.java b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/meta/YearStats.java index a173fa2aa..b8722394e 100644 --- a/app/src/main/java/com/mxt/anitrend/model/entity/anilist/meta/YearStats.java +++ b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/meta/YearStats.java @@ -3,6 +3,7 @@ import android.os.Parcel; import android.os.Parcelable; +@Deprecated public class YearStats implements Parcelable { private int year; diff --git a/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/UserStatisticTypes.kt b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/UserStatisticTypes.kt new file mode 100644 index 000000000..351aabc52 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/UserStatisticTypes.kt @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2019 AniTrend + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.mxt.anitrend.model.entity.anilist.user + +/** [UserStatisticTypes](https://anilist.github.io/ApiV2-GraphQL-Docs/UserStatisticTypes.doc.html) + * A user's statistics + * + * @param anime TBA + * @param manga TBA + */ +data class UserStatisticTypes( + val anime: UserStatistics, + val manga: UserStatistics +) \ No newline at end of file diff --git a/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/UserStatistics.kt b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/UserStatistics.kt new file mode 100644 index 000000000..58f0966e9 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/UserStatistics.kt @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2019 AniTrend + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.mxt.anitrend.model.entity.anilist.user + +import com.mxt.anitrend.model.entity.anilist.user.statistics.* + +/** [UserStatistics](https://anilist.github.io/ApiV2-GraphQL-Docs/UserStatistics.doc.html) + * + * @param chaptersRead TBA + * @param count TBA + * @param countries TBA + * @param episodesWatched TBA + * @param formats TBA + * @param genres TBA + * @param lengths TBA + * @param meanScore TBA + * @param minutesWatched TBA + * @param releaseYears TBA + * @param scores TBA + * @param staff TBA + * @param standardDeviation TBA + * @param startYears TBA + * @param statuses TBA + * @param studios TBA + * @param tags TBA + * @param voiceActors TBA + * @param volumesRead TBA + */ +data class UserStatistics( + val chaptersRead: Int, + val count: Int, + val countries: List?, + val episodesWatched: Int, + val formats: List?, + val genres: List?, + val lengths: List?, + val meanScore: Float, + val minutesWatched: Int, + val releaseYears: List?, + val scores: List?, + val staff: List?, + val standardDeviation: Float, + val startYears: List?, + val statuses: List?, + val studios: List?, + val tags: List?, + val voiceActors: List?, + val volumesRead: Int +) \ No newline at end of file diff --git a/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserCountryStatistic.kt b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserCountryStatistic.kt new file mode 100644 index 000000000..2608f6433 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserCountryStatistic.kt @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2019 AniTrend + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.mxt.anitrend.model.entity.anilist.user.statistics + +import com.mxt.anitrend.model.entity.anilist.user.statistics.contract.IUserStatistic + +/** (UserCountryStatistic)[https://anilist.github.io/ApiV2-GraphQL-Docs/usercountrystatistic.doc.html] + * + * @param country country code + */ +data class UserCountryStatistic( + val country: String?, + override val chaptersRead: Int, + override val count: Int, + override val meanScore: Float, + override val mediaIds: List, + override val minutesWatched: Int +) : IUserStatistic diff --git a/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserFormatStatistic.kt b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserFormatStatistic.kt new file mode 100644 index 000000000..a725cdf84 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserFormatStatistic.kt @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2019 AniTrend + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.mxt.anitrend.model.entity.anilist.user.statistics + +import com.mxt.anitrend.model.entity.anilist.user.statistics.contract.IUserStatistic +import com.mxt.anitrend.util.KeyUtil + +/** [UserFormatStatistic](https://anilist.github.io/ApiV2-GraphQL-Docs/userformatstatistic.doc.html) + * + * @param format media format + */ +data class UserFormatStatistic( + @get:KeyUtil.MediaFormat + val format: String?, + override val chaptersRead: Int, + override val count: Int, + override val meanScore: Float, + override val mediaIds: List, + override val minutesWatched: Int +) : IUserStatistic diff --git a/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserGenreStatistic.kt b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserGenreStatistic.kt new file mode 100644 index 000000000..5114699b9 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserGenreStatistic.kt @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2019 AniTrend + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.mxt.anitrend.model.entity.anilist.user.statistics + +import com.mxt.anitrend.model.entity.anilist.user.statistics.contract.IUserStatistic + +/** [UserGenreStatistic](https://anilist.github.io/ApiV2-GraphQL-Docs/usergenrestatistic.doc.html) + * + * @param genre media genre + */ +data class UserGenreStatistic( + val genre: String?, + override val chaptersRead: Int, + override val count: Int, + override val meanScore: Float, + override val mediaIds: List, + override val minutesWatched: Int +) : IUserStatistic diff --git a/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserLengthStatistic.kt b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserLengthStatistic.kt new file mode 100644 index 000000000..079579c99 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserLengthStatistic.kt @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2019 AniTrend + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.mxt.anitrend.model.entity.anilist.user.statistics + +import com.mxt.anitrend.model.entity.anilist.user.statistics.contract.IUserStatistic + +/** [UserLengthStatistic](https://anilist.github.io/ApiV2-GraphQL-Docs/userlengthstatistic.doc.html) + * + * @param length length of something + */ +data class UserLengthStatistic( + val length: String?, + override val chaptersRead: Int, + override val count: Int, + override val meanScore: Float, + override val mediaIds: List, + override val minutesWatched: Int +) : IUserStatistic diff --git a/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserReleaseYearStatistic.kt b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserReleaseYearStatistic.kt new file mode 100644 index 000000000..182fabe4f --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserReleaseYearStatistic.kt @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2019 AniTrend + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.mxt.anitrend.model.entity.anilist.user.statistics + +import com.mxt.anitrend.model.entity.anilist.user.statistics.contract.IUserStatistic + +/** [UserReleaseYearStatistic](https://anilist.github.io/ApiV2-GraphQL-Docs/userreleaseyearstatistic.doc.html) + * + * @param releaseYear release year + */ +data class UserReleaseYearStatistic( + val releaseYear: Int?, + override val chaptersRead: Int, + override val count: Int, + override val meanScore: Float, + override val mediaIds: List, + override val minutesWatched: Int +) : IUserStatistic diff --git a/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserScoreStatistic.kt b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserScoreStatistic.kt new file mode 100644 index 000000000..c86caf50c --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserScoreStatistic.kt @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2019 AniTrend + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.mxt.anitrend.model.entity.anilist.user.statistics + +import com.mxt.anitrend.model.entity.anilist.user.statistics.contract.IUserStatistic + +/** [UserScoreStatistic](https://anilist.github.io/ApiV2-GraphQL-Docs/userscorestatistic.doc.html) + * + * @param score score + */ +data class UserScoreStatistic( + val score: Int?, + override val chaptersRead: Int, + override val count: Int, + override val meanScore: Float, + override val mediaIds: List, + override val minutesWatched: Int +) : IUserStatistic diff --git a/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserStaffStatistic.kt b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserStaffStatistic.kt new file mode 100644 index 000000000..048dfce3d --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserStaffStatistic.kt @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2019 AniTrend + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.mxt.anitrend.model.entity.anilist.user.statistics + +import com.mxt.anitrend.model.entity.anilist.user.statistics.contract.IUserStatistic +import com.mxt.anitrend.model.entity.base.StaffBase + +/** [UserStaffStatistic](https://anilist.github.io/ApiV2-GraphQL-Docs/userstaffstatistic.doc.html) + * + * @param staff staff/actor + */ +data class UserStaffStatistic( + val staff: StaffBase?, + override val chaptersRead: Int, + override val count: Int, + override val meanScore: Float, + override val mediaIds: List, + override val minutesWatched: Int +) : IUserStatistic diff --git a/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserStartYearStatistic.kt b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserStartYearStatistic.kt new file mode 100644 index 000000000..c7c146199 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserStartYearStatistic.kt @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2019 AniTrend + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.mxt.anitrend.model.entity.anilist.user.statistics + +import com.mxt.anitrend.model.entity.anilist.user.statistics.contract.IUserStatistic + +/** [UserStartYearStatistic](https://anilist.github.io/ApiV2-GraphQL-Docs/userstartyearstatistic.doc.html) + * + * @param startYear start year + */ +data class UserStartYearStatistic( + val startYear: Int?, + override val chaptersRead: Int, + override val count: Int, + override val meanScore: Float, + override val mediaIds: List, + override val minutesWatched: Int +) : IUserStatistic diff --git a/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserStatusStatistic.kt b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserStatusStatistic.kt new file mode 100644 index 000000000..73d7e6068 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserStatusStatistic.kt @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2019 AniTrend + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.mxt.anitrend.model.entity.anilist.user.statistics + +import com.mxt.anitrend.model.entity.anilist.user.statistics.contract.IUserStatistic +import com.mxt.anitrend.util.KeyUtil + +/** [UserStatusStatistic](https://anilist.github.io/ApiV2-GraphQL-Docs/userstatusstatistic.doc.html) + * + * @param status media list status + */ +data class UserStatusStatistic( + @get:KeyUtil.MediaListStatus + val status: String, + override val chaptersRead: Int, + override val count: Int, + override val meanScore: Float, + override val mediaIds: List, + override val minutesWatched: Int +) : IUserStatistic diff --git a/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserStudioStatistic.kt b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserStudioStatistic.kt new file mode 100644 index 000000000..d245c1323 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserStudioStatistic.kt @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2019 AniTrend + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.mxt.anitrend.model.entity.anilist.user.statistics + +import com.mxt.anitrend.model.entity.anilist.user.statistics.contract.IUserStatistic +import com.mxt.anitrend.model.entity.base.StudioBase + +/** [UserStudioStatistic](https://anilist.github.io/ApiV2-GraphQL-Docs/userstudiostatistic.doc.html) + * + * @param studio studio + */ +data class UserStudioStatistic( + val studio: StudioBase?, + override val chaptersRead: Int, + override val count: Int, + override val meanScore: Float, + override val mediaIds: List, + override val minutesWatched: Int +) : IUserStatistic diff --git a/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserTagStatistic.kt b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserTagStatistic.kt new file mode 100644 index 000000000..fad6adcc3 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserTagStatistic.kt @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2019 AniTrend + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.mxt.anitrend.model.entity.anilist.user.statistics + +import com.mxt.anitrend.model.entity.anilist.user.statistics.contract.IUserStatistic +import com.mxt.anitrend.model.entity.anilist.MediaTag + +/** [UserTagStatistic](https://anilist.github.io/ApiV2-GraphQL-Docs/usertagstatistic.doc.html) + * + * @param tag media tag + */ +data class UserTagStatistic( + val tag: MediaTag?, + override val chaptersRead: Int, + override val count: Int, + override val meanScore: Float, + override val mediaIds: List, + override val minutesWatched: Int +) : IUserStatistic diff --git a/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserVoiceActorStatistic.kt b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserVoiceActorStatistic.kt new file mode 100644 index 000000000..25a6a876e --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/UserVoiceActorStatistic.kt @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2019 AniTrend + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.mxt.anitrend.model.entity.anilist.user.statistics + +import com.mxt.anitrend.model.entity.anilist.user.statistics.contract.IUserStatistic +import com.mxt.anitrend.model.entity.base.StaffBase + +/** [UserVoiceActorStatistic](https://anilist.github.io/ApiV2-GraphQL-Docs/uservoiceactorstatistic.doc.html) + * + * @param voiceActor actor + */ + +data class UserVoiceActorStatistic( + val voiceActor: StaffBase?, + override val chaptersRead: Int, + override val count: Int, + override val meanScore: Float, + override val mediaIds: List, + override val minutesWatched: Int +) : IUserStatistic diff --git a/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/contract/IUserStatistic.kt b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/contract/IUserStatistic.kt new file mode 100644 index 000000000..18213e5bb --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/statistics/contract/IUserStatistic.kt @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2019 AniTrend + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.mxt.anitrend.model.entity.anilist.user.statistics.contract + +/** + * Contract for user statistics, applied on various items such as countries, formats, genres, years, staff e.t.c + * + * @property chaptersRead Chapters read for the statistic + * @property count Count for the statistic + * @property meanScore Mean score for the the statistic + * @property mediaIds List of media ids for the statistic + * @property minutesWatched Minutes for watched for teh statistic + */ +interface IUserStatistic { + val chaptersRead: Int + val count: Int + val meanScore: Float + val mediaIds: List + val minutesWatched: Int +} \ No newline at end of file diff --git a/app/src/main/java/com/mxt/anitrend/model/entity/container/body/ConnectionContainer.java b/app/src/main/java/com/mxt/anitrend/model/entity/container/body/ConnectionContainer.java index 96b172c1a..3c4c93688 100644 --- a/app/src/main/java/com/mxt/anitrend/model/entity/container/body/ConnectionContainer.java +++ b/app/src/main/java/com/mxt/anitrend/model/entity/container/body/ConnectionContainer.java @@ -6,7 +6,7 @@ public class ConnectionContainer { @SerializedName(value = "relations", alternate = {"anime", "manga", "media", "characters", "staff", "staffMedia", - "stats", "favourites", "nodes", + "stats", "statistics", "favourites", "nodes", "externalLinks" }) private T connection; From 1f585a4ed107c2ff2d5443d98da014b83c820e2d Mon Sep 17 00:00:00 2001 From: Maxwell Date: Mon, 5 Aug 2019 14:35:56 +0200 Subject: [PATCH 14/81] Add New Type Convert for Statistics --- .../converter/UserStatisticTypesConverter.kt | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 app/src/main/java/com/mxt/anitrend/data/converter/UserStatisticTypesConverter.kt diff --git a/app/src/main/java/com/mxt/anitrend/data/converter/UserStatisticTypesConverter.kt b/app/src/main/java/com/mxt/anitrend/data/converter/UserStatisticTypesConverter.kt new file mode 100644 index 000000000..eb6177ae9 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/data/converter/UserStatisticTypesConverter.kt @@ -0,0 +1,16 @@ +package com.mxt.anitrend.data.converter + +import com.mxt.anitrend.model.api.retro.WebFactory +import com.mxt.anitrend.model.entity.anilist.user.UserStatisticTypes +import io.objectbox.converter.PropertyConverter + +class UserStatisticTypesConverter: PropertyConverter { + + override fun convertToEntityProperty(databaseValue: String?): UserStatisticTypes? { + return if (databaseValue == null) null else WebFactory.gson.fromJson(databaseValue, UserStatisticTypes::class.java) + } + + override fun convertToDatabaseValue(entityProperty: UserStatisticTypes?): String? { + return if (entityProperty == null) null else WebFactory.gson.toJson(entityProperty) + } +} \ No newline at end of file From e256cde465d2c3786e5159f208a429e4d7de66e1 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Mon, 5 Aug 2019 14:38:05 +0200 Subject: [PATCH 15/81] Refactor Application build.gradle - Adds experimental extensions and enables kotlin extensions plugin - Removes api key for embedded YouTube player --- app/build.gradle | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index f70ab6a0f..09c5ab690 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,7 +1,10 @@ -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply plugin: 'io.objectbox' -apply plugin: 'kotlin-kapt' +plugins { + id("com.android.application") + id("kotlin-kapt") + id("kotlin-android") + id("kotlin-android-extensions") + id("io.objectbox") +} android { compileSdkVersion compileSdk @@ -30,12 +33,10 @@ android { if (rootProject.file("secrets.properties").exists()) { def props = new Properties() props.load(new FileInputStream(rootProject.file("secrets.properties"))) - it.buildConfigField "String", "API_KEY", props['API_KEY'] it.buildConfigField "String", "CLIENT_ID", props['CLIENT_ID'] it.buildConfigField "String", "CLIENT_SECRET", props['CLIENT_SECRET'] it.buildConfigField "String", "GIPHY_KEY", props['GIPHY_KEY'] } else { - it.buildConfigField "String", "API_KEY", "API_KEY" it.buildConfigField "String", "CLIENT_ID", "CLIENT_ID" it.buildConfigField "String", "CLIENT_SECRET", "CLIENT_SECRET" it.buildConfigField "String", "GIPHY_KEY", "GIPHY_KEY" @@ -79,6 +80,10 @@ configurations.all { resolutionStrategy.force 'com.google.code.findbugs:jsr305:3.0.2' } +androidExtensions { + experimental = true +} + dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) From 2914e2c06504059195cb34c79d8702451666f736 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Mon, 5 Aug 2019 14:58:46 +0200 Subject: [PATCH 16/81] Update Schema for GraphQL --- app/schema.graphql | 251 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 248 insertions(+), 3 deletions(-) diff --git a/app/schema.graphql b/app/schema.graphql index a93faaefd..51249e3ce 100644 --- a/app/schema.graphql +++ b/app/schema.graphql @@ -283,6 +283,8 @@ type CharacterName { alternative: [String] "The character's given name" first: String + "The character's full name" + full: String "The character's surname" last: String "The character's full name in their native language" @@ -1224,9 +1226,9 @@ type MediaListOptions { "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") + sharedTheme: Json @deprecated(reason : "No longer used") "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") + sharedThemeEnabled: Boolean @deprecated(reason : "No longer used") "(Site only) If the user should be using legacy css-supporting list versions" useLegacyLists: Boolean } @@ -2641,6 +2643,8 @@ type Query { #Filter by media id userId: Int ): Review + "Site statistics query" + SiteStatistics: SiteStatistics "Staff query" Staff( #Filter by the staff id @@ -2823,6 +2827,79 @@ type ScoreDistribution { score: Int } +type SiteStatistics { + anime( + #The page + page: Int, + #The amount of entries per page, max 25 + perPage: Int, + sort: [SiteTrendSort] + ): SiteTrendConnection + characters( + #The page + page: Int, + #The amount of entries per page, max 25 + perPage: Int, + sort: [SiteTrendSort] + ): SiteTrendConnection + manga( + #The page + page: Int, + #The amount of entries per page, max 25 + perPage: Int, + sort: [SiteTrendSort] + ): SiteTrendConnection + reviews( + #The page + page: Int, + #The amount of entries per page, max 25 + perPage: Int, + sort: [SiteTrendSort] + ): SiteTrendConnection + staff( + #The page + page: Int, + #The amount of entries per page, max 25 + perPage: Int, + sort: [SiteTrendSort] + ): SiteTrendConnection + studios( + #The page + page: Int, + #The amount of entries per page, max 25 + perPage: Int, + sort: [SiteTrendSort] + ): SiteTrendConnection + users( + #The page + page: Int, + #The amount of entries per page, max 25 + perPage: Int, + sort: [SiteTrendSort] + ): SiteTrendConnection +} + +"Daily site statistics" +type SiteTrend { + "The change from yesterday" + change: Int! + count: Int! + "The day the data was recorded (timestamp)" + date: Int! +} + +type SiteTrendConnection { + edges: [SiteTrendEdge] + nodes: [SiteTrend] + "The pagination information" + pageInfo: PageInfo +} + +"Site trend connection edge" +type SiteTrendEdge { + node: SiteTrend +} + "Voice actors or production staff" type Staff { "Characters voiced by the actor" @@ -2900,8 +2977,12 @@ type StaffImage { "The names of the staff member" type StaffName { + "Other names the staff member might be referred to as (pen names)" + alternative: [String] "The person's given name" first: String + "The person's full name" + full: String "The person's surname" last: String "The person's full name in their native language" @@ -2948,6 +3029,8 @@ type Studio { favourites: Int "The id of the studio" id: Int! + "If the studio is an animation studio or a different kind of company" + isAnimationStudio: Boolean! "If the studio is marked as favourite by the currently authenticated user" isFavourite: Boolean! "The media the studio has worked on" @@ -3261,8 +3344,10 @@ type User { options: UserOptions "The url for the user page on the AniList website" siteUrl: String + "The users anime & manga list statistics" + statistics: UserStatisticTypes "The user's statistics" - stats: UserStats + stats: UserStats @deprecated(reason : "Deprecated. Replaced with statistics field.") "The number of unread notifications the user has" unreadNotificationCount: Int "When the user's data was last updated" @@ -3287,6 +3372,42 @@ type UserAvatar { medium: String } +type UserCountryStatistic { + chaptersRead: Int! + count: Int! + country: CountryCode + meanScore: Float! + mediaIds: [Int]! + minutesWatched: Int! +} + +type UserFormatStatistic { + chaptersRead: Int! + count: Int! + format: MediaFormat + meanScore: Float! + mediaIds: [Int]! + minutesWatched: Int! +} + +type UserGenreStatistic { + chaptersRead: Int! + count: Int! + genre: String + meanScore: Float! + mediaIds: [Int]! + minutesWatched: Int! +} + +type UserLengthStatistic { + chaptersRead: Int! + count: Int! + length: String + meanScore: Float! + mediaIds: [Int]! + minutesWatched: Int! +} + "A user's general options" type UserOptions { "Whether the user receives notifications when a show they are watching aires" @@ -3301,6 +3422,69 @@ type UserOptions { titleLanguage: UserTitleLanguage } +type UserReleaseYearStatistic { + chaptersRead: Int! + count: Int! + meanScore: Float! + mediaIds: [Int]! + minutesWatched: Int! + releaseYear: Int +} + +type UserScoreStatistic { + chaptersRead: Int! + count: Int! + meanScore: Float! + mediaIds: [Int]! + minutesWatched: Int! + score: Int +} + +type UserStaffStatistic { + chaptersRead: Int! + count: Int! + meanScore: Float! + mediaIds: [Int]! + minutesWatched: Int! + staff: Staff +} + +type UserStartYearStatistic { + chaptersRead: Int! + count: Int! + meanScore: Float! + mediaIds: [Int]! + minutesWatched: Int! + startYear: Int +} + +type UserStatisticTypes { + anime: UserStatistics + manga: UserStatistics +} + +type UserStatistics { + chaptersRead: Int! + count: Int! + countries(limit: Int, sort: [UserStatisticsSort]): [UserCountryStatistic] + episodesWatched: Int! + formats(limit: Int, sort: [UserStatisticsSort]): [UserFormatStatistic] + genres(limit: Int, sort: [UserStatisticsSort]): [UserGenreStatistic] + lengths(limit: Int, sort: [UserStatisticsSort]): [UserLengthStatistic] + meanScore: Float! + minutesWatched: Int! + releaseYears(limit: Int, sort: [UserStatisticsSort]): [UserReleaseYearStatistic] + scores(limit: Int, sort: [UserStatisticsSort]): [UserScoreStatistic] + staff(limit: Int, sort: [UserStatisticsSort]): [UserStaffStatistic] + standardDeviation: Float! + startYears(limit: Int, sort: [UserStatisticsSort]): [UserStartYearStatistic] + statuses(limit: Int, sort: [UserStatisticsSort]): [UserStatusStatistic] + studios(limit: Int, sort: [UserStatisticsSort]): [UserStudioStatistic] + tags(limit: Int, sort: [UserStatisticsSort]): [UserTagStatistic] + voiceActors(limit: Int, sort: [UserStatisticsSort]): [UserVoiceActorStatistic] + volumesRead: Int! +} + "A user's statistics" type UserStats { activityHistory: [UserActivityHistory] @@ -3324,6 +3508,43 @@ type UserStats { watchedTime: Int } +type UserStatusStatistic { + chaptersRead: Int! + count: Int! + meanScore: Float! + mediaIds: [Int]! + minutesWatched: Int! + status: MediaListStatus +} + +type UserStudioStatistic { + chaptersRead: Int! + count: Int! + meanScore: Float! + mediaIds: [Int]! + minutesWatched: Int! + studio: Studio +} + +type UserTagStatistic { + chaptersRead: Int! + count: Int! + meanScore: Float! + mediaIds: [Int]! + minutesWatched: Int! + tag: MediaTag +} + +type UserVoiceActorStatistic { + chaptersRead: Int! + characterIds: [Int]! + count: Int! + meanScore: Float! + mediaIds: [Int]! + minutesWatched: Int! + voiceActor: Staff +} + "User's year statistics" type YearStats { amount: Int @@ -3689,6 +3910,16 @@ enum ScoreFormat { POINT_5 } +"Site trend sort enums" +enum SiteTrendSort { + CHANGE + CHANGE_DESC + COUNT + COUNT_DESC + DATE + DATE_DESC +} + "The primary language of the voice actor" enum StaffLanguage { #English @@ -3784,6 +4015,18 @@ enum UserSort { WATCHED_TIME_DESC } +"User statistics sort enum" +enum UserStatisticsSort { + COUNT + COUNT_DESC + ID + ID_DESC + MEAN_SCORE + MEAN_SCORE_DESC + PROGRESS + PROGRESS_DESC +} + "The language the user wants to see media titles in" enum UserTitleLanguage { #The official english title @@ -3879,6 +4122,8 @@ input NotificationOptionInput { "The names of the staff member" input StaffNameInput { + "Other names the character might be referred by" + alternative: [String] "The person's given name" first: String "The person's surname" From 7c1ebd0cb6296b15e9bd92552d3e885fa83b55d2 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Mon, 5 Aug 2019 15:00:01 +0200 Subject: [PATCH 17/81] Update User Stats GraphQL Query Added objects for new statistics --- .../graphql/User/Query/UserStats.graphql | 175 ++++++++++++++++-- 1 file changed, 161 insertions(+), 14 deletions(-) diff --git a/app/src/main/assets/graphql/User/Query/UserStats.graphql b/app/src/main/assets/graphql/User/Query/UserStats.graphql index 29a968f98..2599989ff 100644 --- a/app/src/main/assets/graphql/User/Query/UserStats.graphql +++ b/app/src/main/assets/graphql/User/Query/UserStats.graphql @@ -1,24 +1,171 @@ query UserStats($id: Int, $userName: String) { User(id: $id, name: $userName) { ... on User { - stats { - ... on UserStats { - watchedTime - chaptersRead - animeStatusDistribution { - ... on StatusDistribution { - status - amount - } + statistics { + ... on UserStatisticTypes { + anime { + ... userStatistics } - mangaStatusDistribution { - ... on StatusDistribution { - status - amount - } + manga { + ... userStatistics } } } } } } + +fragment userStatistics on UserStatistics { + chaptersRead + count + countries { + chaptersRead + count + country + meanScore + mediaIds + minutesWatched + } + episodesWatched + formats { + chaptersRead + count + format + meanScore + mediaIds + minutesWatched + } + genres { + chaptersRead + count + genre + meanScore + mediaIds + minutesWatched + } + lengths { + chaptersRead + count + length + meanScore + mediaIds + minutesWatched + } + meanScore + minutesWatched + releaseYears { + chaptersRead + count + releaseYear + meanScore + mediaIds + minutesWatched + } + scores { + chaptersRead + count + score + meanScore + mediaIds + minutesWatched + } + staff { + chaptersRead + count + staff { + ... on Staff { + id + name { + ... on StaffName { + first + last + native + } + } + isFavourite + language + image { + ... on StaffImage { + large + medium + } + } + } + } + meanScore + mediaIds + minutesWatched + } + standardDeviation + startYears { + chaptersRead + count + startYear + meanScore + mediaIds + minutesWatched + } + statuses { + chaptersRead + count + status + meanScore + mediaIds + minutesWatched + } + studios { + chaptersRead + count + studio { + ... on Studio { + id + name + siteUrl + isFavourite + } + } + meanScore + mediaIds + minutesWatched + } + tags { + chaptersRead + count + tag { + ... on MediaTag { + id + name + description + category + rank + isGeneralSpoiler + isAdult + } + } + meanScore + mediaIds + minutesWatched + } + voiceActors { + chaptersRead + count + voiceActor { + ... on Staff { + id + siteUrl + name { + ... on StaffName { + first + last + native + } + } + isFavourite + } + } + meanScore + mediaIds + minutesWatched + } + volumesRead +} From 351e939296ece7fde69953f9db485da159792965 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Mon, 5 Aug 2019 15:01:01 +0200 Subject: [PATCH 18/81] Refactor User Overview Fragment, Replacing UserStats with UserStatistics --- .../fragment/detail/UserOverviewFragment.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) 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 b27474457..3e90d4b75 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 @@ -153,15 +153,15 @@ public void onDestroyView() { private List generateStatsData() { List userGenreStats = new ArrayList<>(); - 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(); - - userGenreStats = Stream.of(model.getStats().getFavouredGenres()) - .sortBy(s -> - s.getAmount()).map(genreStats -> { - float percentage = (((float)genreStats.getAmount()) / ((float)highestValue)) * 100f; - return new StatsRing((int)percentage, genreStats.getGenre(), String.valueOf(genreStats.getAmount())); + if(model.getStatistics() != null && model.getStatistics().getAnime().getGenres() != null && !CompatUtil.INSTANCE.isEmpty(model.getStatistics().getAnime().getGenres())) { + int highestValue = Stream.of(model.getStatistics().getAnime().getGenres()) + .max((o1, o2) -> o1.getCount() > o2.getCount() ? 1 : -1) + .get().getCount(); + + userGenreStats = Stream.of(model.getStatistics().getAnime().getGenres()) + .sortBy(s -> - s.getCount()).map(genreStats -> { + float percentage = (((float)genreStats.getCount()) / ((float)highestValue)) * 100f; + return new StatsRing((int)percentage, genreStats.getGenre(), String.valueOf(genreStats.getCount())); }).limit(5).toList(); } From 9afd18f1ccefcfa35ec1a78dfa5847890c9d76c5 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Mon, 5 Aug 2019 15:01:29 +0200 Subject: [PATCH 19/81] Refactor Profiles Widget, Replacing UserStats with UserStatistics --- .../view/widget/ProfileStatsWidget.java | 66 +++++++++++-------- 1 file changed, 37 insertions(+), 29 deletions(-) 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 a08604e8e..3ef06c7c3 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 @@ -22,6 +22,8 @@ import com.mxt.anitrend.databinding.WidgetProfileStatsBinding; import com.mxt.anitrend.model.entity.anilist.UserStats; import com.mxt.anitrend.model.entity.anilist.meta.StatusDistribution; +import com.mxt.anitrend.model.entity.anilist.user.UserStatisticTypes; +import com.mxt.anitrend.model.entity.anilist.user.UserStatistics; import com.mxt.anitrend.model.entity.container.body.ConnectionContainer; import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder; import com.mxt.anitrend.presenter.widget.WidgetPresenter; @@ -42,12 +44,13 @@ * status widget */ -public class ProfileStatsWidget extends FrameLayout implements CustomView, View.OnClickListener, RetroCallback> { +public class ProfileStatsWidget extends FrameLayout implements CustomView, View.OnClickListener, RetroCallback> { private WidgetProfileStatsBinding binding; - private WidgetPresenter> presenter; + private WidgetPresenter> presenter; - private UserStats model; + @Nullable + private UserStatisticTypes model; private QueryContainerBuilder queryContainer; private Bundle bundle; @@ -98,14 +101,12 @@ public void onInit() { public void updateUI() { binding.setClickListener(this); - binding.userAnimeTime.setText(getAnimeTime(model.getWatchedTime())); - binding.userMangaChaps.setText(getMangaChaptersCount(model.getChaptersRead())); - - if(model.getAnimeStatusDistribution() != null && !model.getAnimeStatusDistribution().isEmpty()) - binding.userAnimeTotal.setText(getCount(model.getAnimeStatusDistribution())); - - if(model.getMangaStatusDistribution() != null && !model.getMangaStatusDistribution().isEmpty()) - binding.userMangaTotal.setText(getCount(model.getMangaStatusDistribution())); + if (model != null) { + binding.userAnimeTime.setText(getAnimeTime(model.getAnime().getMinutesWatched())); + binding.userMangaChaps.setText(getMangaChaptersCount(model.getManga().getChaptersRead())); + binding.userAnimeTotal.setText(getCount(model.getAnime().getEpisodesWatched())); + binding.userMangaTotal.setText(getCount(model.getManga().getChaptersRead())); + } } public void setParams(Bundle bundle) { @@ -133,10 +134,22 @@ public void onClick(View view) { Intent intent; switch (view.getId()) { case R.id.user_anime_time_container: - Snackbar.make(this, getContext().getString(R.string.text_user_anime_time, getAnimeTime(model.getWatchedTime())), Snackbar.LENGTH_LONG).show(); + if (model != null) + Snackbar.make(this, + getContext().getString( + R.string.text_user_anime_time, + getAnimeTime(model.getAnime().getMinutesWatched()) + ), Snackbar.LENGTH_LONG + ).show(); break; case R.id.user_manga_chaps_container: - Snackbar.make(this, getContext().getString(R.string.text_user_manga_chapters, getMangaChaptersCount(model.getChaptersRead())), Snackbar.LENGTH_LONG).show(); + if (model != null) + Snackbar.make(this, + getContext().getString( + R.string.text_user_manga_chapters, + getMangaChaptersCount(model.getManga().getChaptersRead()) + ), Snackbar.LENGTH_LONG + ).show(); break; case R.id.user_anime_total_container: intent = new Intent(getContext(), MediaListActivity.class); @@ -156,9 +169,9 @@ public void onClick(View view) { } @Override - public void onResponse(@NonNull Call> call, @NonNull Response> response) { + public void onResponse(@NonNull Call> call, @NonNull Response> response) { try { - ConnectionContainer connectionContainer; + ConnectionContainer connectionContainer; if(response.isSuccessful() && (connectionContainer = response.body()) != null) { if(!connectionContainer.isEmpty()) { model = connectionContainer.getConnection(); @@ -172,19 +185,20 @@ public void onResponse(@NonNull Call> call, @NonN } @Override - public void onFailure(@NonNull Call> call, @NonNull Throwable throwable) { + public void onFailure(@NonNull Call> call, @NonNull Throwable throwable) { try { - Log.e(toString(), throwable.getLocalizedMessage()); + if (throwable.getLocalizedMessage() != null) + Log.e(toString(), throwable.getLocalizedMessage()); throwable.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } - public String getAnimeTime(int animeTime) { - if(animeTime < 1) + public String getAnimeTime(@Nullable Integer animeTime) { + if(animeTime == null || animeTime < 1) return placeHolder; - float item_time = animeTime / 60; + float item_time = animeTime / 60f; if(item_time > 60) { item_time /= 24; if(item_time > 365) @@ -194,21 +208,15 @@ public String getAnimeTime(int animeTime) { return getContext().getString(R.string.anime_time_hours, item_time); } - public String getMangaChaptersCount(long manga_chap) { - if(manga_chap < 1) + public String getMangaChaptersCount(@Nullable Integer manga_chap) { + if(manga_chap == null || manga_chap < 1) return placeHolder; if(manga_chap > 1000) return String.format(Locale.getDefault(), "%.1f K", (float)manga_chap/1000); return String.format(Locale.getDefault(), "%d", manga_chap); } - public String getCount(List statusDistributions) { - int totalCount = 0; - if(!CompatUtil.INSTANCE.isEmpty(statusDistributions)) - totalCount = Stream.of(statusDistributions) - .mapToInt(StatusDistribution::getAmount) - .sum(); - + public String getCount(int totalCount) { if(totalCount >= 1000) return String.format(Locale.getDefault(), "%.1f K", (float)totalCount/1000); return String.format(Locale.getDefault(),"%d", totalCount); From b0a85330730d15cfc49133a6b926e0ffa4f6e067 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Mon, 5 Aug 2019 15:01:58 +0200 Subject: [PATCH 20/81] Convert Base Presenter to Kotlin --- .../presenter/base/BasePresenter.java | 152 ----------------- .../anitrend/presenter/base/BasePresenter.kt | 158 ++++++++++++++++++ 2 files changed, 158 insertions(+), 152 deletions(-) delete mode 100644 app/src/main/java/com/mxt/anitrend/presenter/base/BasePresenter.java create mode 100644 app/src/main/java/com/mxt/anitrend/presenter/base/BasePresenter.kt 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 deleted file mode 100644 index b0d98e938..000000000 --- a/app/src/main/java/com/mxt/anitrend/presenter/base/BasePresenter.java +++ /dev/null @@ -1,152 +0,0 @@ -package com.mxt.anitrend.presenter.base; - -import android.content.Context; -import android.content.Intent; -import androidx.fragment.app.FragmentActivity; -import android.util.Log; - -import com.annimon.stream.Stream; -import com.mxt.anitrend.base.custom.async.WebTokenRequest; -import com.mxt.anitrend.base.custom.presenter.CommonPresenter; -import com.mxt.anitrend.base.interfaces.dao.BoxQuery; -import com.mxt.anitrend.model.entity.anilist.UserStats; -import com.mxt.anitrend.model.entity.anilist.meta.FormatStats; -import com.mxt.anitrend.model.entity.anilist.meta.GenreStats; -import com.mxt.anitrend.model.entity.base.UserBase; -import com.mxt.anitrend.model.entity.crunchy.MediaContent; -import com.mxt.anitrend.model.entity.crunchy.Thumbnail; -import com.mxt.anitrend.service.TagGenreService; -import com.mxt.anitrend.util.CompatUtil; - -import java.util.List; -import java.util.Locale; -import java.util.concurrent.TimeUnit; - -/** - * Created by max on 2017/09/16. - * General presenter for most objects - */ - -public class BasePresenter extends CommonPresenter { - - private List favouriteGenres, favouriteTags, favouriteYears, favouriteFormats; - - public BasePresenter(Context context) { - super(context); - } - - public final void checkGenresAndTags(FragmentActivity fragmentActivity) { - Intent intent = new Intent(fragmentActivity, TagGenreService.class); - fragmentActivity.startService(intent); - } - - public String getThumbnail(List thumbnails) { - if(CompatUtil.INSTANCE.isEmpty(thumbnails)) - return null; - return thumbnails.get(0).getUrl(); - } - - public String getDuration(MediaContent mediaContent) { - if(mediaContent.getDuration() != null) { - long timeSpan = Integer.valueOf(mediaContent.getDuration()); - long minutes = TimeUnit.SECONDS.toMinutes(timeSpan); - long seconds = timeSpan - TimeUnit.MINUTES.toSeconds(minutes); - return (String.format(Locale.getDefault(), seconds < 10 ? "%d:0%d":"%d:%d", minutes, seconds)); - } - return "00:00"; - } - - public List getTopFavouriteGenres(int limit) { - if(CompatUtil.INSTANCE.isEmpty(favouriteGenres)) { - UserStats userStats; - if (getDatabase().getCurrentUser() != null && (userStats = getDatabase().getCurrentUser().getStats()) != null) { - if (!CompatUtil.INSTANCE.isEmpty(userStats.getFavouredGenres())) { - favouriteGenres = Stream.of(userStats.getFavouredGenres()) - .sortBy(genreStat -> - genreStat.getAmount()) - .map(GenreStats::getGenre) - .limit(limit).toList(); - - } - } - } - return favouriteGenres; - } - - public List getTopFavouriteTags(int limit) { - if(CompatUtil.INSTANCE.isEmpty(favouriteTags)) { - UserStats userStats; - if (getDatabase().getCurrentUser() != null && (userStats = getDatabase().getCurrentUser().getStats()) != null) { - if (!CompatUtil.INSTANCE.isEmpty(userStats.getFavouredTags())) { - favouriteTags = Stream.of(userStats.getFavouredTags()) - .sortBy(mediaTagStats -> - mediaTagStats.getAmount()) - .map(s -> s.getTag().getName()) - .limit(limit).toList(); - - } - } - } - return favouriteTags; - } - - public List getTopFavouriteYears(int limit) { - if(CompatUtil.INSTANCE.isEmpty(favouriteYears)) { - UserStats userStats; - if (getDatabase().getCurrentUser() != null && (userStats = getDatabase().getCurrentUser().getStats()) != null) { - if (!CompatUtil.INSTANCE.isEmpty(userStats.getFavouredTags())) { - favouriteYears = Stream.of(userStats.getFavouredYears()) - .sortBy(yearStats -> - yearStats.getAmount()) - .map(y -> String.valueOf(y.getYear())) - .limit(limit).toList(); - - } - } - } - return favouriteTags; - } - - public List getTopFormats(int limit) { - if(CompatUtil.INSTANCE.isEmpty(favouriteFormats)) { - UserStats userStats; - if (getDatabase().getCurrentUser() != null && (userStats = getDatabase().getCurrentUser().getStats()) != null) { - if (!CompatUtil.INSTANCE.isEmpty(userStats.getFavouredFormats())) { - favouriteFormats = Stream.of(userStats.getFavouredFormats()) - .sortBy(formatStats -> - formatStats.getAmount()) - .map(FormatStats::getFormat) - .limit(limit).toList(); - - } - } - } - return favouriteFormats; - } - - public boolean isCurrentUser(long userId) { - return getApplicationPref().isAuthenticated() && getDatabase().getCurrentUser() != null && - userId != 0 && getDatabase().getCurrentUser().getId() == userId; - } - - public boolean isCurrentUser(String userName) { - return getApplicationPref().isAuthenticated() && getDatabase().getCurrentUser() != null && - userName != null && getDatabase().getCurrentUser().getName().equals(userName); - } - - public boolean isCurrentUser(long userId, String userName) { - if (userName != null) - return isCurrentUser(userName); - return isCurrentUser(userId); - } - - public boolean isCurrentUser(UserBase userBase) { - return userBase != null && isCurrentUser(userBase.getId()); - } - - public void checkValidAuth() { - if(getApplicationPref().isAuthenticated()) { - BoxQuery boxQuery = getDatabase(); - if(boxQuery.getCurrentUser() == null) { - Log.e("checkValidAuth", "Last attempt to authenticate failed, refreshing session!"); - WebTokenRequest.invalidateInstance(getContext()); - } - } - } -} diff --git a/app/src/main/java/com/mxt/anitrend/presenter/base/BasePresenter.kt b/app/src/main/java/com/mxt/anitrend/presenter/base/BasePresenter.kt new file mode 100644 index 000000000..2e6174852 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/presenter/base/BasePresenter.kt @@ -0,0 +1,158 @@ +package com.mxt.anitrend.presenter.base + +import android.content.Context +import android.content.Intent +import android.util.Log +import androidx.fragment.app.FragmentActivity +import com.annimon.stream.Stream +import com.mxt.anitrend.base.custom.async.WebTokenRequest +import com.mxt.anitrend.base.custom.presenter.CommonPresenter +import com.mxt.anitrend.model.entity.anilist.user.UserStatisticTypes +import com.mxt.anitrend.model.entity.anilist.user.statistics.UserGenreStatistic +import com.mxt.anitrend.model.entity.base.UserBase +import com.mxt.anitrend.model.entity.crunchy.MediaContent +import com.mxt.anitrend.model.entity.crunchy.Thumbnail +import com.mxt.anitrend.service.TagGenreService +import com.mxt.anitrend.util.CompatUtil +import java.util.* +import java.util.concurrent.TimeUnit + +/** + * Created by max on 2017/09/16. + * General presenter for most objects + */ + +open class BasePresenter(context: Context?) : CommonPresenter(context) { + + private var favouriteGenres: List? = null + private var favouriteTags: List? = null + private var favouriteYears: List? = null + private var favouriteFormats: List? = null + + fun checkGenresAndTags(fragmentActivity: FragmentActivity) { + val intent = Intent(fragmentActivity, TagGenreService::class.java) + fragmentActivity.startService(intent) + } + + fun getThumbnail(thumbnails: List): String? { + return if (CompatUtil.isEmpty(thumbnails)) null else thumbnails[0].url + } + + fun getDuration(mediaContent: MediaContent): String { + if (mediaContent.duration != null) { + val timeSpan = Integer.valueOf(mediaContent.duration).toLong() + val minutes = TimeUnit.SECONDS.toMinutes(timeSpan) + val seconds = timeSpan - TimeUnit.MINUTES.toSeconds(minutes) + return String.format(Locale.getDefault(), if (seconds < 10) "%d:0%d" else "%d:%d", minutes, seconds) + } + return "00:00" + } + + fun getTopFavouriteGenres(limit: Int): List? { + if (CompatUtil.isEmpty(favouriteGenres)) { + val userStats: UserStatisticTypes? = database.currentUser.statistics + if (database.currentUser != null && userStats != null) { + if (!userStats.anime.genres.isNullOrEmpty()) { + favouriteGenres = userStats.anime.genres + .sortedByDescending { + it.count + }.filter { + it.genre != null + }.map { + it.genre!! + }.take(limit) + } + } + } + return favouriteGenres + } + + fun getTopFavouriteTags(limit: Int): List? { + if (CompatUtil.isEmpty(favouriteTags)) { + val userStats: UserStatisticTypes? = database.currentUser.statistics + if (database.currentUser != null && userStats != null) { + if (!userStats.anime.tags.isNullOrEmpty()) { + favouriteTags = Stream.of(userStats.anime.tags!!) + .sortBy { (_, _, count) -> -count } + .filter { (tag) -> tag != null } + .map { (tag) -> tag!!.name } + .limit(limit.toLong()).toList() + favouriteTags = userStats.anime.tags.sortedByDescending { + it.count + }.filter { + it.tag != null + }.map { + it.tag!!.name + }.take(limit) + } + } + } + return favouriteTags + } + + fun getTopFavouriteYears(limit: Int): List? { + if (CompatUtil.isEmpty(favouriteYears)) { + val userStats: UserStatisticTypes? = database.currentUser.statistics + if (database.currentUser != null && userStats != null) { + if (!userStats.anime.releaseYears.isNullOrEmpty()) { + favouriteYears = userStats.anime.releaseYears + .sortedByDescending { + it.count + }.filter { + it.releaseYear != null + }.map { + it.releaseYear?.toString()!! + }.take(limit) + } + } + } + return favouriteTags + } + + fun getTopFormats(limit: Int): List? { + if (CompatUtil.isEmpty(favouriteFormats)) { + val userStats: UserStatisticTypes? = database.currentUser.statistics + if (database.currentUser != null && userStats != null) { + if (!userStats.anime.formats.isNullOrEmpty()) { + favouriteFormats = userStats.anime.formats + .sortedByDescending { + it.count + }.filter { + it.format != null + }.map { + it.format!! + }.take(limit) + } + } + } + return favouriteFormats + } + + fun isCurrentUser(userId: Long): Boolean { + return applicationPref.isAuthenticated && database.currentUser != null && + userId != 0L && database.currentUser.id == userId + } + + fun isCurrentUser(userName: String?): Boolean { + return applicationPref.isAuthenticated && database.currentUser != null && + userName != null && database.currentUser.name == userName + } + + fun isCurrentUser(userId: Long, userName: String?): Boolean { + return userName?.let { isCurrentUser(it) } ?: isCurrentUser(userId) + } + + fun isCurrentUser(userBase: UserBase?): Boolean { + return userBase != null && isCurrentUser(userBase.id) + } + + fun checkValidAuth() { + if (applicationPref.isAuthenticated) { + val boxQuery = database + if (boxQuery.currentUser == null) { + Log.e("checkValidAuth", "Last attempt to authenticate failed, refreshing session!") + WebTokenRequest.invalidateInstance(context) + } + } + } +} From 210a672bf7aa12ec5a988c35bb74b14ae5c56158 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Mon, 5 Aug 2019 15:03:08 +0200 Subject: [PATCH 21/81] Refactor User Model Endpoint Changes return type for the `getUserStats` abstraction --- .../com/mxt/anitrend/model/api/retro/anilist/UserModel.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/UserModel.java b/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/UserModel.java index 82e4f134c..35edf8aff 100644 --- a/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/UserModel.java +++ b/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/UserModel.java @@ -5,6 +5,7 @@ import com.mxt.anitrend.model.entity.anilist.Notification; import com.mxt.anitrend.model.entity.anilist.User; import com.mxt.anitrend.model.entity.anilist.UserStats; +import com.mxt.anitrend.model.entity.anilist.user.UserStatistics; import com.mxt.anitrend.model.entity.base.UserBase; import com.mxt.anitrend.model.entity.container.body.ConnectionContainer; import com.mxt.anitrend.model.entity.container.body.GraphContainer; @@ -46,7 +47,7 @@ public interface UserModel { @POST("/") @GraphQuery("UserStats") @Headers("Content-Type: application/json") - Call>> getUserStats(@Body QueryContainerBuilder request); + Call>> getUserStats(@Body QueryContainerBuilder request); @POST("/") @GraphQuery("UserFollowers") From 143f82ad58c2674d426d78195547f408bfdac27b Mon Sep 17 00:00:00 2001 From: Maxwell Date: Mon, 5 Aug 2019 15:03:44 +0200 Subject: [PATCH 22/81] Add Default Object States for User Statistics --- .../model/entity/anilist/user/UserStatistics.kt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/UserStatistics.kt b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/UserStatistics.kt index 58f0966e9..afc9aec69 100644 --- a/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/UserStatistics.kt +++ b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/user/UserStatistics.kt @@ -42,23 +42,23 @@ import com.mxt.anitrend.model.entity.anilist.user.statistics.* * @param volumesRead TBA */ data class UserStatistics( - val chaptersRead: Int, - val count: Int, + val chaptersRead: Int = 0, + val count: Int = 0, val countries: List?, - val episodesWatched: Int, + val episodesWatched: Int = 0, val formats: List?, val genres: List?, val lengths: List?, - val meanScore: Float, - val minutesWatched: Int, + val meanScore: Float = 0f, + val minutesWatched: Int = 0, val releaseYears: List?, val scores: List?, val staff: List?, - val standardDeviation: Float, + val standardDeviation: Float = 0f, val startYears: List?, val statuses: List?, val studios: List?, val tags: List?, val voiceActors: List?, - val volumesRead: Int + val volumesRead: Int = 0 ) \ No newline at end of file From bffbc59161c479fc19f0b5e455498a1a85d4d525 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Mon, 5 Aug 2019 15:19:47 +0200 Subject: [PATCH 23/81] Update Changelog --- app/src/main/assets/changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/assets/changelog.md b/app/src/main/assets/changelog.md index e76fbd9f7..238c86331 100644 --- a/app/src/main/assets/changelog.md +++ b/app/src/main/assets/changelog.md @@ -8,6 +8,7 @@ which can result in authentication errors [read more](https://github.com/square/ #### Bug Fixes - Improved error message for invalid token errors +- User stats no updating (due to deprecated stats) #### Current Issues - Clicking on @username shows mixed feed From fdee73afacab7c51e9278a220e06d3da9fe58f31 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Tue, 6 Aug 2019 13:24:06 +0200 Subject: [PATCH 24/81] Correct Response Type for Stats --- .../com/mxt/anitrend/model/api/retro/anilist/UserModel.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/UserModel.java b/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/UserModel.java index 35edf8aff..d7c1fabb5 100644 --- a/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/UserModel.java +++ b/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/UserModel.java @@ -5,6 +5,7 @@ import com.mxt.anitrend.model.entity.anilist.Notification; import com.mxt.anitrend.model.entity.anilist.User; import com.mxt.anitrend.model.entity.anilist.UserStats; +import com.mxt.anitrend.model.entity.anilist.user.UserStatisticTypes; import com.mxt.anitrend.model.entity.anilist.user.UserStatistics; import com.mxt.anitrend.model.entity.base.UserBase; import com.mxt.anitrend.model.entity.container.body.ConnectionContainer; @@ -47,7 +48,7 @@ public interface UserModel { @POST("/") @GraphQuery("UserStats") @Headers("Content-Type: application/json") - Call>> getUserStats(@Body QueryContainerBuilder request); + Call>> getUserStats(@Body QueryContainerBuilder request); @POST("/") @GraphQuery("UserFollowers") From 1b9e79b3dbbc096d6719c569442ec69bdda57379 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Tue, 6 Aug 2019 13:34:27 +0200 Subject: [PATCH 25/81] Remove Redundant Glide Plugin Initialization --- .../mxt/anitrend/base/custom/view/text/RichMarkdownTextView.kt | 1 - 1 file changed, 1 deletion(-) 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 2212b2380..f38a7f1f9 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 @@ -47,7 +47,6 @@ class RichMarkdownTextView : AppCompatTextView, CustomView { Markwon.builder(context) .usePlugin(HtmlPlugin.create()) .usePlugin(LinkifyPlugin.create()) - .usePlugin(GlideImagesPlugin.create(context)) .usePlugin(GlideImagesPlugin.create(Glide.with(context))) .usePlugin(GlideImagesPlugin.create(object : GlideImagesPlugin.GlideStore { override fun cancel(target: Target<*>) { From d9073612048a10bd7d3ff5aea12368a9d36fa0e1 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Tue, 6 Aug 2019 13:34:51 +0200 Subject: [PATCH 26/81] Fix Incorrect Stats being Displayed --- .../anitrend/base/custom/view/widget/ProfileStatsWidget.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 3ef06c7c3..c2e828f31 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 @@ -104,8 +104,8 @@ public void updateUI() { if (model != null) { binding.userAnimeTime.setText(getAnimeTime(model.getAnime().getMinutesWatched())); binding.userMangaChaps.setText(getMangaChaptersCount(model.getManga().getChaptersRead())); - binding.userAnimeTotal.setText(getCount(model.getAnime().getEpisodesWatched())); - binding.userMangaTotal.setText(getCount(model.getManga().getChaptersRead())); + binding.userAnimeTotal.setText(getCount(model.getAnime().getCount())); + binding.userMangaTotal.setText(getCount(model.getManga().getCount())); } } From c3d727a9ee2bf0bac7f68dab865fc0cfe90c2844 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Tue, 6 Aug 2019 13:35:12 +0200 Subject: [PATCH 27/81] Update App Changelog --- app/src/main/assets/changelog.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/assets/changelog.md b/app/src/main/assets/changelog.md index 238c86331..542642d7d 100644 --- a/app/src/main/assets/changelog.md +++ b/app/src/main/assets/changelog.md @@ -4,11 +4,12 @@ __N.B__ v2.0 will be dropping support for Jellybean - Kitkat, due to missing or which can result in authentication errors [read more](https://github.com/square/okhttp/issues/2372) #### Enhancements -- Minor UI tweaks, specifically view radius +- Support for Android Q #### Bug Fixes +- Remove embedded YoutubePlayer - Improved error message for invalid token errors -- User stats no updating (due to deprecated stats) +- User stats not updating (due to deprecated stats) #### Current Issues - Clicking on @username shows mixed feed From ff88dd84ab8d55cc601e6cc2257bb9aa6d853960 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Tue, 6 Aug 2019 13:49:30 +0200 Subject: [PATCH 28/81] Release Minor 1.5.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### Enhancements & Bug Fixes ☆ Added support for upcoming Android Q ✓ User stats not updating (due to deprecated stats) ✓ Improved error message for invalid token errors ✓ Remove embedded YoutubePlayer --- 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 845ed8a72..58c3ba695 100644 --- a/app/.meta/version.json +++ b/app/.meta/version.json @@ -1,7 +1,7 @@ { - "code": 111, + "code": 130, "migration": false, "releaseNotes": "", - "version": "1.4.7", + "version": "1.5.1", "appId": "com.mxt.anitrend" } diff --git a/app/release/output.json b/app/release/output.json index 8b04596b1..9335c7709 100644 --- a/app/release/output.json +++ b/app/release/output.json @@ -1 +1 @@ -[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":111,"versionName":"1.4.7","enabled":true,"outputFile":"anitrend_v1.4.7_rc_111.apk","fullName":"release","baseName":"release"},"path":"anitrend_v1.4.7_rc_111.apk","properties":{}}] \ No newline at end of file +[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":130,"versionName":"1.5.1","enabled":true,"outputFile":"anitrend_v1.5.1_rc_130.apk","fullName":"release","baseName":"release"},"path":"anitrend_v1.5.1_rc_130.apk","properties":{}}] \ No newline at end of file From 15e724a4b10f85582c4cbf1ca8148d75936ec51c Mon Sep 17 00:00:00 2001 From: Maxwell Date: Tue, 6 Aug 2019 13:53:33 +0200 Subject: [PATCH 29/81] Remove YouTube Player Library --- app/libs/YouTubeAndroidPlayerApi.jar | Bin 106430 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 app/libs/YouTubeAndroidPlayerApi.jar diff --git a/app/libs/YouTubeAndroidPlayerApi.jar b/app/libs/YouTubeAndroidPlayerApi.jar deleted file mode 100644 index 0acbebde9d65136b7a4f43461eacf190725a0333..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 106430 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 From 1edca7858f604f1ad1e06c337aa78d9200e2a710 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Wed, 7 Aug 2019 00:07:37 +0200 Subject: [PATCH 30/81] Add Missing Statistics to User Profile Requests --- .../assets/graphql/User/Query/User.graphql | 167 ++++++++++++++++++ .../graphql/User/Query/UserOverview.graphql | 166 +++++++++++++++++ 2 files changed, 333 insertions(+) diff --git a/app/src/main/assets/graphql/User/Query/User.graphql b/app/src/main/assets/graphql/User/Query/User.graphql index 2155cceda..2279b7cc9 100644 --- a/app/src/main/assets/graphql/User/Query/User.graphql +++ b/app/src/main/assets/graphql/User/Query/User.graphql @@ -45,6 +45,16 @@ query User($userId: Int, $username: String, $asHtml: Boolean = false) { } } } + statistics { + ... on UserStatisticTypes { + anime { + ... userStatistics + } + manga { + ... userStatistics + } + } + } stats { ... on UserStats { watchedTime @@ -76,3 +86,160 @@ query User($userId: Int, $username: String, $asHtml: Boolean = false) { } } } + + +fragment userStatistics on UserStatistics { + chaptersRead + count + countries { + chaptersRead + count + country + meanScore + mediaIds + minutesWatched + } + episodesWatched + formats { + chaptersRead + count + format + meanScore + mediaIds + minutesWatched + } + genres { + chaptersRead + count + genre + meanScore + mediaIds + minutesWatched + } + lengths { + chaptersRead + count + length + meanScore + mediaIds + minutesWatched + } + meanScore + minutesWatched + releaseYears { + chaptersRead + count + releaseYear + meanScore + mediaIds + minutesWatched + } + scores { + chaptersRead + count + score + meanScore + mediaIds + minutesWatched + } + staff { + chaptersRead + count + staff { + ... on Staff { + id + name { + ... on StaffName { + first + last + native + } + } + isFavourite + language + image { + ... on StaffImage { + large + medium + } + } + } + } + meanScore + mediaIds + minutesWatched + } + standardDeviation + startYears { + chaptersRead + count + startYear + meanScore + mediaIds + minutesWatched + } + statuses { + chaptersRead + count + status + meanScore + mediaIds + minutesWatched + } + studios { + chaptersRead + count + studio { + ... on Studio { + id + name + siteUrl + isFavourite + } + } + meanScore + mediaIds + minutesWatched + } + tags { + chaptersRead + count + tag { + ... on MediaTag { + id + name + description + category + rank + isGeneralSpoiler + isAdult + } + } + meanScore + mediaIds + minutesWatched + } + voiceActors { + chaptersRead + count + voiceActor { + ... on Staff { + id + siteUrl + name { + ... on StaffName { + first + last + native + } + } + isFavourite + } + } + meanScore + mediaIds + minutesWatched + } + volumesRead +} + diff --git a/app/src/main/assets/graphql/User/Query/UserOverview.graphql b/app/src/main/assets/graphql/User/Query/UserOverview.graphql index 2c9c5d923..06f3e628e 100644 --- a/app/src/main/assets/graphql/User/Query/UserOverview.graphql +++ b/app/src/main/assets/graphql/User/Query/UserOverview.graphql @@ -12,6 +12,16 @@ query UserOverview($id: Int, $userName: String, $asHtml: Boolean = false) { bannerImage about(asHtml: $asHtml) isFollowing + statistics { + ... on UserStatisticTypes { + anime { + ... userStatistics + } + manga { + ... userStatistics + } + } + } stats { ... on UserStats { favouredGenres { @@ -29,3 +39,159 @@ query UserOverview($id: Int, $userName: String, $asHtml: Boolean = false) { } } } + + +fragment userStatistics on UserStatistics { + chaptersRead + count + countries { + chaptersRead + count + country + meanScore + mediaIds + minutesWatched + } + episodesWatched + formats { + chaptersRead + count + format + meanScore + mediaIds + minutesWatched + } + genres { + chaptersRead + count + genre + meanScore + mediaIds + minutesWatched + } + lengths { + chaptersRead + count + length + meanScore + mediaIds + minutesWatched + } + meanScore + minutesWatched + releaseYears { + chaptersRead + count + releaseYear + meanScore + mediaIds + minutesWatched + } + scores { + chaptersRead + count + score + meanScore + mediaIds + minutesWatched + } + staff { + chaptersRead + count + staff { + ... on Staff { + id + name { + ... on StaffName { + first + last + native + } + } + isFavourite + language + image { + ... on StaffImage { + large + medium + } + } + } + } + meanScore + mediaIds + minutesWatched + } + standardDeviation + startYears { + chaptersRead + count + startYear + meanScore + mediaIds + minutesWatched + } + statuses { + chaptersRead + count + status + meanScore + mediaIds + minutesWatched + } + studios { + chaptersRead + count + studio { + ... on Studio { + id + name + siteUrl + isFavourite + } + } + meanScore + mediaIds + minutesWatched + } + tags { + chaptersRead + count + tag { + ... on MediaTag { + id + name + description + category + rank + isGeneralSpoiler + isAdult + } + } + meanScore + mediaIds + minutesWatched + } + voiceActors { + chaptersRead + count + voiceActor { + ... on Staff { + id + siteUrl + name { + ... on StaffName { + first + last + native + } + } + isFavourite + } + } + meanScore + mediaIds + minutesWatched + } + volumesRead +} From eb6eac55db5a162d149c588e55e9e61578ba5ff3 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Wed, 7 Aug 2019 00:08:07 +0200 Subject: [PATCH 31/81] Add Try Catch Blocks for Analytic Calls --- .../com/mxt/anitrend/util/AnalyticsUtil.java | 52 ++++++++++++++----- 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/com/mxt/anitrend/util/AnalyticsUtil.java b/app/src/main/java/com/mxt/anitrend/util/AnalyticsUtil.java index ac222eaaa..4ba242dd8 100644 --- a/app/src/main/java/com/mxt/anitrend/util/AnalyticsUtil.java +++ b/app/src/main/java/com/mxt/anitrend/util/AnalyticsUtil.java @@ -1,5 +1,7 @@ package com.mxt.anitrend.util; +import android.util.Log; + import androidx.annotation.NonNull; import androidx.fragment.app.FragmentActivity; @@ -13,29 +15,55 @@ public final class AnalyticsUtil { + private static final String TAG = AnalyticsUtil.class.getSimpleName(); + public static void logCurrentScreen(FragmentActivity fragmentActivity, @NonNull String tag) { - if(fragmentActivity != null) { - App app = ((App) fragmentActivity.getApplicationContext()); - if (app.getFabric() != null) - app.getFabric().setCurrentActivity(fragmentActivity); - if (app.getAnalytics() != null) - app.getAnalytics().setCurrentScreen(fragmentActivity, tag, null); + try { + if(fragmentActivity != null) { + App app = ((App) fragmentActivity.getApplicationContext()); + if (app.getFabric() != null) + app.getFabric().setCurrentActivity(fragmentActivity); + if (app.getAnalytics() != null) + app.getAnalytics().setCurrentScreen(fragmentActivity, tag, null); + } + } catch (Exception e) { + e.printStackTrace(); + if (e.getLocalizedMessage() != null) + Log.e(TAG, e.getLocalizedMessage()); } } public static void reportException(@NonNull String tag, @NonNull String message) { - Crashlytics.log(0, tag, message); + try { + Crashlytics.log(0, tag, message); + } catch (Exception e) { + e.printStackTrace(); + if (e.getLocalizedMessage() != null) + Log.e(TAG, e.getLocalizedMessage()); + } } public static void clearSession() { - Crashlytics.setUserIdentifier(""); + try { + Crashlytics.setUserIdentifier(""); + } catch (Exception e) { + e.printStackTrace(); + if (e.getLocalizedMessage() != null) + Log.e(TAG, e.getLocalizedMessage()); + } } public static void setCrashAnalyticsUser(FragmentActivity fragmentActivity, String userName) { - if(fragmentActivity != null) { - App app = ((App) fragmentActivity.getApplicationContext()); - if (app.getFabric() != null) - Crashlytics.setUserIdentifier(userName); + try { + if(fragmentActivity != null) { + App app = ((App) fragmentActivity.getApplicationContext()); + if (app.getFabric() != null) + Crashlytics.setUserIdentifier(userName); + } + } catch (Exception e) { + e.printStackTrace(); + if (e.getLocalizedMessage() != null) + Log.e(TAG, e.getLocalizedMessage()); } } } From a84ecf7e3b28195b4eb702af88c12ad0a066933c Mon Sep 17 00:00:00 2001 From: Maxwell Date: Wed, 7 Aug 2019 00:09:02 +0200 Subject: [PATCH 32/81] Release Patch 1.5.2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### Enhancements & Bug Fixes ☆ Added support for upcoming Android Q ✓ User stats not updating (due to deprecated stats) ✓ Improved error message for invalid token errors ✓ Remove embedded YoutubePlayer --- app/.meta/version.json | 4 ++-- app/release/output.json | 2 +- build.gradle | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/.meta/version.json b/app/.meta/version.json index 58c3ba695..00c2bd4cd 100644 --- a/app/.meta/version.json +++ b/app/.meta/version.json @@ -1,7 +1,7 @@ { - "code": 130, + "code": 131, "migration": false, "releaseNotes": "", - "version": "1.5.1", + "version": "1.5.2", "appId": "com.mxt.anitrend" } diff --git a/app/release/output.json b/app/release/output.json index 9335c7709..5ba6ddf8e 100644 --- a/app/release/output.json +++ b/app/release/output.json @@ -1 +1 @@ -[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":130,"versionName":"1.5.1","enabled":true,"outputFile":"anitrend_v1.5.1_rc_130.apk","fullName":"release","baseName":"release"},"path":"anitrend_v1.5.1_rc_130.apk","properties":{}}] \ No newline at end of file +[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":131,"versionName":"1.5.2","enabled":true,"outputFile":"anitrend_v1.5.2_rc_131.apk","fullName":"release","baseName":"release"},"path":"anitrend_v1.5.2_rc_131.apk","properties":{}}] \ No newline at end of file diff --git a/build.gradle b/build.gradle index b71f2263b..0d928c378 100644 --- a/build.gradle +++ b/build.gradle @@ -6,8 +6,8 @@ buildscript { targetSdk = 29 minSdk = 17 - versionCode = 130 - versionName = '1.5.1' + versionCode = 131 + versionName = '1.5.2' butterKnife = '10.1.0' From d6f26caebdcc3f3755f2756567e3ca88c806e8c6 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Fri, 9 Aug 2019 16:38:04 +0200 Subject: [PATCH 33/81] Fix Unclickable Media Overview Elements --- .../fragment/detail/MediaOverviewFragment.kt | 84 ++++++++++--------- 1 file changed, 46 insertions(+), 38 deletions(-) diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/MediaOverviewFragment.kt b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/MediaOverviewFragment.kt index 2a8fe1bad..f2a50275c 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/MediaOverviewFragment.kt +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/MediaOverviewFragment.kt @@ -50,8 +50,8 @@ class MediaOverviewFragment : FragmentBase() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) if (arguments != null) { - mediaId = arguments!!.getLong(KeyUtil.arg_id) - mediaType = arguments!!.getString(KeyUtil.arg_mediaType) + mediaId = arguments?.getLong(KeyUtil.arg_id) ?: 0 + mediaType = arguments?.getString(KeyUtil.arg_mediaType) } isMenuDisabled = true mColumnSize = R.integer.grid_list_x2 @@ -71,6 +71,14 @@ class MediaOverviewFragment : FragmentBase() { tagsRecycler.layoutManager = StaggeredGridLayoutManager(resources.getInteger(mColumnSize), StaggeredGridLayoutManager.VERTICAL) tagsRecycler.isNestedScrollingEnabled = false tagsRecycler.setHasFixedSize(true) + + listOf( + R.id.series_image, + R.id.anime_main_studio_container, + R.id.show_spoiler_tags + ).map { + root.findViewById(it) + }.forEach { it?.setOnClickListener(this@MediaOverviewFragment) } } return binding?.root @@ -85,27 +93,27 @@ class MediaOverviewFragment : FragmentBase() { * Is automatically called in the @onStart Method if overridden in list implementation */ override fun updateUI() { - if (activity != null && model!!.trailer != null && CompatUtil.equals(model!!.trailer.site, "youtube")) { + if (activity != null && model?.trailer != null && CompatUtil.equals(model?.trailer?.site, "youtube")) { childFragmentManager.beginTransaction() - .replace(R.id.youtube_view, YouTubeEmbedFragment.newInstance(model!!.trailer)) + .replace(R.id.youtube_view, YouTubeEmbedFragment.newInstance(model?.trailer)) .commit() } else - binding!!.youtubeView.visibility = View.GONE - binding!!.presenter = presenter - binding!!.model = model + binding?.youtubeView?.visibility = View.GONE + binding?.presenter = presenter + binding?.model = model - if (model!!.tags != null && model!!.tagsNoSpoilers != null) { - if (model!!.tagsNoSpoilers.size == model!!.tags.size) - binding!!.showSpoilerTags.visibility = View.GONE + if (model?.tags != null && model?.tagsNoSpoilers != null) { + if (model?.tagsNoSpoilers?.size == model?.tags?.size) + binding?.showSpoilerTags?.visibility = View.GONE else - binding!!.showSpoilerTags.visibility = View.VISIBLE + binding?.showSpoilerTags?.visibility = View.VISIBLE } if (genreAdapter == null) { genreAdapter = GenreAdapter(context) - genreAdapter!!.onItemsInserted(presenter.buildGenres(model)) - genreAdapter!!.setClickListener(object : ItemClickListener { + genreAdapter?.onItemsInserted(presenter.buildGenres(model)) + genreAdapter?.setClickListener(object : ItemClickListener { override fun onItemClick(target: View, data: IntPair) { when (target.id) { R.id.container -> { @@ -130,18 +138,17 @@ class MediaOverviewFragment : FragmentBase() { } }) } - binding!!.genreRecycler.adapter = genreAdapter - - if (tagAdapter == null) { - tagAdapter = TagAdapter(context) - tagAdapter!!.onItemsInserted(model!!.tagsNoSpoilers) - tagAdapter!!.setClickListener(object : ItemClickListener { - override fun onItemClick(target: View, data: IntPair) { - when (target.id) { - R.id.container -> DialogUtil.createTagMessage(activity, data.second.name, data.second.description, data.second.isMediaSpoiler, - R.string.More, R.string.Close) { dialog, which -> - when (which) { - DialogAction.POSITIVE -> { + binding?.genreRecycler?.adapter = genreAdapter + model?.tagsNoSpoilers?.also { + if (tagAdapter == null) { + tagAdapter = TagAdapter(context) + tagAdapter?.onItemsInserted(it) + tagAdapter?.setClickListener(object : ItemClickListener { + override fun onItemClick(target: View, data: IntPair) { + when (target.id) { + R.id.container -> DialogUtil.createTagMessage(activity, data.second.name, data.second.description, data.second.isMediaSpoiler, + R.string.More, R.string.Close) { _, which -> + if (which == DialogAction.POSITIVE) { val args = Bundle() val intent = Intent(activity, MediaBrowseActivity::class.java) args.putParcelable(KeyUtil.arg_graph_params, GraphUtil.getDefaultQuery(true) @@ -158,16 +165,16 @@ class MediaOverviewFragment : FragmentBase() { } } } - } - override fun onItemLongClick(target: View, data: IntPair) { + override fun onItemLongClick(target: View, data: IntPair) { - } - }) + } + }) + } + binding?.tagsRecycler?.adapter = tagAdapter } - binding!!.tagsRecycler.adapter = tagAdapter - binding!!.stateLayout.showContent() + binding?.stateLayout?.showContent() } /** @@ -191,9 +198,9 @@ class MediaOverviewFragment : FragmentBase() { this.model = model updateUI() } else - binding!!.stateLayout.showError(CompatUtil.getDrawable(context!!, R.drawable.ic_emoji_sweat), + binding?.stateLayout?.showError(CompatUtil.getDrawable(context!!, R.drawable.ic_emoji_sweat), getString(R.string.layout_empty_response), getString(R.string.try_again)) { view -> - binding!!.stateLayout.showLoading() + binding?.stateLayout?.showLoading() makeRequest() } } @@ -203,11 +210,10 @@ class MediaOverviewFragment : FragmentBase() { * * @param v The view that was clicked. */ - @OnClick(R.id.series_image, R.id.anime_main_studio_container, R.id.show_spoiler_tags) override fun onClick(v: View) { val intent: Intent when (v.id) { - R.id.series_image -> CompatUtil.imagePreview(activity, v, model!!.coverImage.large, R.string.image_preview_error_series_cover) + R.id.series_image -> CompatUtil.imagePreview(activity, v, model?.coverImage?.large, R.string.image_preview_error_series_cover) R.id.anime_main_studio_container -> { val studioBase = presenter.getMainStudioObject(model) if (studioBase != null) { @@ -217,9 +223,11 @@ class MediaOverviewFragment : FragmentBase() { } } R.id.show_spoiler_tags -> { - tagAdapter!!.onItemRangeChanged(model!!.tags) - tagAdapter!!.notifyDataSetChanged() - v.visibility = View.GONE + model?.tags?.also { + tagAdapter?.onItemRangeChanged(it) + tagAdapter?.notifyDataSetChanged() + v.visibility = View.GONE + } } else -> super.onClick(v) } From 56da61913e1aff006cfe5a31ba1d497139f4d317 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Fri, 9 Aug 2019 17:18:07 +0200 Subject: [PATCH 34/81] Update .travis Configuration --- .travis.yml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9b937647f..9fe826477 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,8 +5,8 @@ sudo: false env: global: - - ANDROID_API_LEVEL=28 - - ANDROID_BUILD_TOOLS_VERSION=28.0.3 + - ANDROID_API_LEVEL=29 + - ANDROID_BUILD_TOOLS_VERSION=29.0.3 - TRAVIS_SECURE_ENV_VARS=true android: @@ -54,15 +54,13 @@ cache: - $HOME/.gradle/wrapper/ - $HOME/.android/build-cache -# Move our test play-services configuration to the appropreiate config location before_script: - mv app/.travic-ci/google-services.json app/google-services.json - mv app/.travic-ci/secrets ./secrets.properties - + script: - ./gradlew test - before_install: - chmod +x gradlew - yes | sdkmanager "platforms;android-28" From 1940ac8f851707fb4d1a3c68fe6ec33e4f466018 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Thu, 15 Aug 2019 09:34:23 +0200 Subject: [PATCH 35/81] Update String Resources Adds additional strings for application migrations and revised on boarding message --- app/src/main/res/values-ar/strings.xml | 5 ++++- app/src/main/res/values-de/strings.xml | 5 ++++- app/src/main/res/values-es/strings.xml | 3 +++ app/src/main/res/values-fr/strings.xml | 7 +++++-- app/src/main/res/values-it/strings.xml | 3 +++ app/src/main/res/values-nl/strings.xml | 5 ++++- app/src/main/res/values-pl/strings.xml | 3 +++ app/src/main/res/values-pt/strings.xml | 3 +++ app/src/main/res/values-sv/strings.xml | 3 +++ app/src/main/res/values/strings.xml | 3 +++ 10 files changed, 35 insertions(+), 5 deletions(-) diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index b8cf2cf07..2ed0a6d9a 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -154,7 +154,7 @@ أنيمي ومانغا وخصائص بحث أخرى! فيديو يستخدم مشغل مقاطع الفيديو الخاص بيوتيوب مدمج معه! - أهلا بك في AniTrend + أهلا بك في AniTrend, this is not a streaming app! الفرز حسب: @@ -971,4 +971,7 @@ New Related Media Added Use black theme for devices that have OLED displays to save power Invalid session, please log out and back in + Application is upgrading, please wait + Upgrade Failed + diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 7938d84aa..428c042ba 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -137,7 +137,7 @@ Suche Anime, Manga & Weitere Suchfunktionen! Verwendet eingebauten Youtube Video Player! - Wilkommen bei AniTrend! + Wilkommen bei AniTrend, this is not a streaming app! Sortieren nach? @@ -968,4 +968,7 @@ Get Started Videos Invalid session, please log out and back in + Application is upgrading, please wait + Upgrade Failed + \ 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 4fabb84ef..9b6a2acd7 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -971,4 +971,7 @@ elementos de tus favoritos al presionar en el icono del corazón . Videos General Invalid session, please log out and back in + Application is upgrading, please wait + Upgrade Failed + diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index dfc10363d..c43a01248 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -1,4 +1,4 @@ - + @string/drawer_title_filter @@ -138,7 +138,7 @@ Anime, Manga et pleins d\'autres critères de recherche ! Vidéos Les vidéos peuvent être visionner dans l\'application ! - Bienvenue sur AniTrend ! + Bienvenue sur AniTrend, this is not a streaming app! Trier par ? @@ -972,4 +972,7 @@ About Configuration Invalid session, please log out and back in + Application is upgrading, please wait + Upgrade Failed + \ 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 6eaa73b49..5b5808c10 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -969,4 +969,7 @@ Account Videos Invalid session, please log out and back in + Application is upgrading, please wait + Upgrade Failed + diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 3f754d2ba..c92339574 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -972,6 +972,9 @@ Get Started Videos Searching - Welcome to AniTrend! + Welcome to AniTrend, this is not a streaming app! Invalid session, please log out and back in + Application is upgrading, please wait + Upgrade Failed + diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 14a973067..52dd4dcfc 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -973,4 +973,7 @@ Studio Use black theme for devices that have OLED displays to save power Invalid session, please log out and back in + Application is upgrading, please wait + Upgrade Failed + diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index dcff9da9f..84d240bf2 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -975,4 +975,7 @@ Extras Videos Invalid session, please log out and back in + Application is upgrading, please wait + Upgrade Failed + \ 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 292a4270b..713049275 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -972,4 +972,7 @@ Support AniTrend Hub Invalid session, please log out and back in + Application is upgrading, please wait + Upgrade Failed + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2ca96659a..bddfd3c49 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1032,4 +1032,7 @@ Invalid session, please log out and back in + Application is upgrading, please wait + Upgrade Failed + From 2c64b0212a3696708f464647ad33fa91aead1994 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Thu, 15 Aug 2019 09:35:22 +0200 Subject: [PATCH 36/81] Remove YouTube Feature from Welcome Screen --- .../anitrend/view/activity/base/WelcomeActivity.java | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) 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 ba9f361a1..6a45d911f 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 @@ -47,10 +47,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { R.drawable.ic_bubble_chart_white_24dp)), applyStyle(new AhoyOnboarderCard(getString(R.string.app_intro_search_title), getString(R.string.app_intro_search_text), - R.drawable.ic_search_white_24dp)), - applyStyle(new AhoyOnboarderCard(getString(R.string.app_intro_videos_title), - getString(R.string.app_intro_videos_text), - R.drawable.ic_slow_motion_video_white_24dp)) + R.drawable.ic_search_white_24dp)) )); } else { ahoyPages = new ArrayList<>(CompatUtil.INSTANCE.constructListFrom( @@ -65,10 +62,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { R.drawable.ic_bubble_chart_white_48dp)), applyStyle(new AhoyOnboarderCard(getString(R.string.app_intro_search_title), getString(R.string.app_intro_search_text), - R.drawable.ic_search_white_48dp)), - applyStyle(new AhoyOnboarderCard(getString(R.string.app_intro_videos_title), - getString(R.string.app_intro_videos_text), - R.drawable.ic_slow_motion_video_white_48dp)) + R.drawable.ic_search_white_48dp)) )); } From ec03f32de7825cc52aa8df017e8c2d0cdec1f084 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Thu, 15 Aug 2019 09:36:41 +0200 Subject: [PATCH 37/81] Convert Splash Screen to Kotlin with Additional Migration Checker Call --- .../view/activity/index/SplashActivity.java | 101 ---------------- .../view/activity/index/SplashActivity.kt | 108 ++++++++++++++++++ 2 files changed, 108 insertions(+), 101 deletions(-) delete mode 100644 app/src/main/java/com/mxt/anitrend/view/activity/index/SplashActivity.java create mode 100644 app/src/main/java/com/mxt/anitrend/view/activity/index/SplashActivity.kt 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 deleted file mode 100644 index c219fb53a..000000000 --- a/app/src/main/java/com/mxt/anitrend/view/activity/index/SplashActivity.java +++ /dev/null @@ -1,101 +0,0 @@ -package com.mxt.anitrend.view.activity.index; - -import android.content.Intent; -import android.os.Bundle; -import androidx.annotation.Nullable; - -import com.mxt.anitrend.R; -import com.mxt.anitrend.base.custom.activity.ActivityBase; -import com.mxt.anitrend.base.custom.view.image.WideImageView; -import com.mxt.anitrend.model.entity.base.VersionBase; -import com.mxt.anitrend.presenter.base.BasePresenter; -import com.mxt.anitrend.util.CompatUtil; -import com.mxt.anitrend.util.DateUtil; -import com.mxt.anitrend.util.KeyUtil; -import com.mxt.anitrend.view.activity.base.WelcomeActivity; - -import butterknife.BindView; -import butterknife.ButterKnife; - -/** - * Created by max on 2017/10/04. - * Base splash screen - */ - -public class SplashActivity extends ActivityBase { - - protected @BindView(R.id.preview_credits) - WideImageView giphyCitation; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_splash); - ButterKnife.bind(this); - setPresenter(new BasePresenter(this)); - setViewModel(true); - } - - @Override - protected void onPostCreate(@Nullable Bundle savedInstanceState) { - super.onPostCreate(savedInstanceState); - giphyCitation.setImageResource(!CompatUtil.INSTANCE.isLightTheme(this) ? R.drawable.powered_by_giphy_light : R.drawable.powered_by_giphy_dark); - onActivityReady(); - } - - /** - * Make decisions, check for permissions or fire background threads from this method - * N.B. Must be called after onPostCreate - */ - @Override - protected void onActivityReady() { - getPresenter().checkGenresAndTags(this); - getPresenter().checkValidAuth(); - makeRequest(); - } - - @Override - protected void updateUI() { - if(isAlive()) { - boolean freshInstall = getPresenter().getApplicationPref().isFreshInstall(); - Intent intent = new Intent(SplashActivity.this, freshInstall?WelcomeActivity.class:MainActivity.class); - startActivity(intent); - finish(); - } - } - - @Override - protected void makeRequest() { - VersionBase versionBase = getPresenter().getDatabase().getRemoteVersion(); - // How frequent the application checks for updates on startup - 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()); - } - else - updateUI(); - } - - /** - * Called when the model state is changed. - * - * @param model The new data - */ - @Override - public void onChanged(@Nullable VersionBase model) { - super.onChanged(model); - if(model != null) - getPresenter().getDatabase().saveRemoteVersion(model); - updateUI(); - } - - @Override - public void showError(String error) { - updateUI(); - } - - @Override - public void showEmpty(String message) { - updateUI(); - } -} diff --git a/app/src/main/java/com/mxt/anitrend/view/activity/index/SplashActivity.kt b/app/src/main/java/com/mxt/anitrend/view/activity/index/SplashActivity.kt new file mode 100644 index 000000000..a454b8572 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/view/activity/index/SplashActivity.kt @@ -0,0 +1,108 @@ +package com.mxt.anitrend.view.activity.index + +import android.content.Intent +import android.os.Bundle +import android.widget.Toast + +import com.mxt.anitrend.R +import com.mxt.anitrend.base.custom.activity.ActivityBase +import com.mxt.anitrend.base.custom.view.image.WideImageView +import com.mxt.anitrend.model.entity.base.VersionBase +import com.mxt.anitrend.presenter.base.BasePresenter +import com.mxt.anitrend.view.activity.base.WelcomeActivity + +import butterknife.BindView +import butterknife.ButterKnife +import com.afollestad.materialdialogs.MaterialDialog +import com.mxt.anitrend.util.* + +/** + * Created by max on 2017/10/04. + * Base splash screen + */ + +class SplashActivity : ActivityBase() { + + @BindView(R.id.preview_credits) + lateinit var giphyCitation: WideImageView + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_splash) + ButterKnife.bind(this) + setPresenter(BasePresenter(this)) + setViewModel(true) + } + + override fun onPostCreate(savedInstanceState: Bundle?) { + super.onPostCreate(savedInstanceState) + giphyCitation.setImageResource(if (!CompatUtil.isLightTheme(this)) R.drawable.powered_by_giphy_light else R.drawable.powered_by_giphy_dark) + onActivityReady() + } + + /** + * Make decisions, check for permissions or fire background threads from this method + * N.B. Must be called after onPostCreate + */ + override fun onActivityReady() { + presenter.checkGenresAndTags(this) + presenter.checkValidAuth() + makeRequest() + } + + override fun updateUI() { + if (isAlive) { + if(presenter.checkIfMigrationIsNeeded(this)) { + val freshInstall = presenter.applicationPref.isFreshInstall + val intent = Intent( + this@SplashActivity, + if (freshInstall) + WelcomeActivity::class.java + else + MainActivity::class.java + ) + startActivity(intent) + finish() + } else { + DialogUtil.createMessage( + this, + R.string.title_migration_failed, + R.string.text_migration_failed + ) { dialog, _ -> + dialog.dismiss() + finish() + } + } + } + } + + override fun makeRequest() { + val versionBase = presenter.database.remoteVersion + // How frequent the application checks for updates on startup + if (versionBase == null || DateUtil.timeDifferenceSatisfied(KeyUtil.TIME_UNIT_HOURS, versionBase.lastChecked, 2)) { + viewModel.params.putString(KeyUtil.arg_branch_name, presenter.applicationPref.updateChannel) + viewModel.requestData(KeyUtil.UPDATE_CHECKER_REQ, applicationContext) + } else + updateUI() + } + + /** + * Called when the model state is changed. + * + * @param model The new data + */ + override fun onChanged(model: VersionBase?) { + super.onChanged(model) + if (model != null) + presenter.database.saveRemoteVersion(model) + updateUI() + } + + override fun showError(error: String) { + updateUI() + } + + override fun showEmpty(message: String) { + updateUI() + } +} From 149d87309728e8a7feab721bb2790e706fc624f2 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Thu, 15 Aug 2019 09:38:13 +0200 Subject: [PATCH 38/81] Add Migration Facade to Presenter --- .../mxt/anitrend/presenter/base/BasePresenter.kt | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/mxt/anitrend/presenter/base/BasePresenter.kt b/app/src/main/java/com/mxt/anitrend/presenter/base/BasePresenter.kt index 2e6174852..4b5a24bb3 100644 --- a/app/src/main/java/com/mxt/anitrend/presenter/base/BasePresenter.kt +++ b/app/src/main/java/com/mxt/anitrend/presenter/base/BasePresenter.kt @@ -3,17 +3,21 @@ package com.mxt.anitrend.presenter.base import android.content.Context import android.content.Intent import android.util.Log +import android.widget.Toast import androidx.fragment.app.FragmentActivity import com.annimon.stream.Stream +import com.mxt.anitrend.R import com.mxt.anitrend.base.custom.async.WebTokenRequest import com.mxt.anitrend.base.custom.presenter.CommonPresenter import com.mxt.anitrend.model.entity.anilist.user.UserStatisticTypes -import com.mxt.anitrend.model.entity.anilist.user.statistics.UserGenreStatistic import com.mxt.anitrend.model.entity.base.UserBase import com.mxt.anitrend.model.entity.crunchy.MediaContent import com.mxt.anitrend.model.entity.crunchy.Thumbnail import com.mxt.anitrend.service.TagGenreService import com.mxt.anitrend.util.CompatUtil +import com.mxt.anitrend.util.NotifyUtil +import com.mxt.anitrend.util.migration.MigrationUtil +import com.mxt.anitrend.util.migration.Migrations import java.util.* import java.util.concurrent.TimeUnit @@ -29,6 +33,14 @@ open class BasePresenter(context: Context?) : CommonPresenter(context) { private var favouriteYears: List? = null private var favouriteFormats: List? = null + fun checkIfMigrationIsNeeded(fragmentActivity: FragmentActivity): Boolean { + NotifyUtil.makeText(fragmentActivity, R.string.text_migration_in_progress, Toast.LENGTH_SHORT) + val migrationUtil = MigrationUtil.Builder() + .addMigration(Migrations.MIGRATION_109_132) + .build() + return migrationUtil.applyMigration() + } + fun checkGenresAndTags(fragmentActivity: FragmentActivity) { val intent = Intent(fragmentActivity, TagGenreService::class.java) fragmentActivity.startService(intent) @@ -72,7 +84,7 @@ open class BasePresenter(context: Context?) : CommonPresenter(context) { val userStats: UserStatisticTypes? = database.currentUser.statistics if (database.currentUser != null && userStats != null) { if (!userStats.anime.tags.isNullOrEmpty()) { - favouriteTags = Stream.of(userStats.anime.tags!!) + favouriteTags = Stream.of(userStats.anime.tags) .sortBy { (_, _, count) -> -count } .filter { (tag) -> tag != null } .map { (tag) -> tag!!.name } From e3ffa80056c956885bdc4fc3d79cf9eb7f272137 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Thu, 15 Aug 2019 09:40:37 +0200 Subject: [PATCH 39/81] Add New Migration Checker Adds new feature that allows us to target certain versions of the application a successful update. This feature is only possible if the application can at least start the splash screen without crashing --- .../mxt/anitrend/util/migration/Migration.kt | 16 ++++++ .../anitrend/util/migration/MigrationUtil.kt | 57 +++++++++++++++++++ .../mxt/anitrend/util/migration/Migrations.kt | 30 ++++++++++ .../util/migration/contract/IMigrationUtil.kt | 8 +++ 4 files changed, 111 insertions(+) create mode 100644 app/src/main/java/com/mxt/anitrend/util/migration/Migration.kt create mode 100644 app/src/main/java/com/mxt/anitrend/util/migration/MigrationUtil.kt create mode 100644 app/src/main/java/com/mxt/anitrend/util/migration/Migrations.kt create mode 100644 app/src/main/java/com/mxt/anitrend/util/migration/contract/IMigrationUtil.kt diff --git a/app/src/main/java/com/mxt/anitrend/util/migration/Migration.kt b/app/src/main/java/com/mxt/anitrend/util/migration/Migration.kt new file mode 100644 index 000000000..bb65c46c6 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/util/migration/Migration.kt @@ -0,0 +1,16 @@ +package com.mxt.anitrend.util.migration + +import com.mxt.anitrend.util.ApplicationPref + +/** + * Creates a new migration between [startVersion] and [endVersion]. + * + * @param startVersion The start version of the application. + * @param endVersion The end version of the application after this migration is applied. + */ +abstract class Migration( + val startVersion: Int, + val endVersion: Int +) { + abstract fun applyMigration(applicationPref: ApplicationPref) +} \ No newline at end of file diff --git a/app/src/main/java/com/mxt/anitrend/util/migration/MigrationUtil.kt b/app/src/main/java/com/mxt/anitrend/util/migration/MigrationUtil.kt new file mode 100644 index 000000000..aa98499ba --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/util/migration/MigrationUtil.kt @@ -0,0 +1,57 @@ +package com.mxt.anitrend.util.migration + +import android.util.Log +import com.mxt.anitrend.BuildConfig +import com.mxt.anitrend.util.ApplicationPref +import com.mxt.anitrend.util.migration.contract.IMigrationUtil +import org.koin.core.KoinComponent +import org.koin.core.inject + +class MigrationUtil private constructor( + private val migrations: List +) : IMigrationUtil, KoinComponent { + + private val applicationPref by inject() + + /** + * Applies migration of the application if necessary + */ + override fun applyMigration(): Boolean { + if (applicationPref.isUpdated) { + Log.d(TAG, "Application has been updated: from ${applicationPref.versionCode} - ${BuildConfig.VERSION_CODE}, checking for migration scripts") + val applicableMigrations = migrations.takeWhile { + applicationPref.versionCode >= it.startVersion && it.endVersion <= BuildConfig.VERSION_CODE + } + if (applicableMigrations.isNotEmpty()) + return try { + applicableMigrations.forEach { + Log.d(TAG, "Applying migration for: ${it.startVersion} - ${it.endVersion}") + it.applyMigration(applicationPref) + } + true + } catch (ex: Exception) { + ex.printStackTrace() + false + } + } + Log.d(TAG, "No migrations to run for this version of the application") + return true + } + + class Builder { + private val migrations: MutableList = ArrayList() + + fun addMigration(migration: Migration): Builder { + migrations.add(migration) + return this + } + + fun build(): MigrationUtil { + return MigrationUtil(migrations) + } + } + + companion object { + private val TAG = MigrationUtil::class.java.simpleName + } +} \ No newline at end of file diff --git a/app/src/main/java/com/mxt/anitrend/util/migration/Migrations.kt b/app/src/main/java/com/mxt/anitrend/util/migration/Migrations.kt new file mode 100644 index 000000000..785259423 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/util/migration/Migrations.kt @@ -0,0 +1,30 @@ +package com.mxt.anitrend.util.migration + +import android.os.Build +import androidx.core.content.edit +import com.mxt.anitrend.data.DatabaseHelper +import com.mxt.anitrend.extension.appContext +import com.mxt.anitrend.model.api.retro.WebFactory +import com.mxt.anitrend.util.AnalyticsUtil +import com.mxt.anitrend.util.ApplicationPref +import com.mxt.anitrend.util.JobSchedulerUtil +import com.mxt.anitrend.util.ShortcutUtil +import org.koin.core.KoinComponent + +object Migrations : KoinComponent { + + val MIGRATION_109_132 = object : Migration(109, 132) { + override fun applyMigration(applicationPref: ApplicationPref) { + applicationPref.sharedPreferences.edit { + clear() + apply() + } + DatabaseHelper().invalidateBoxStores() + JobSchedulerUtil.cancelJob() + WebFactory.invalidate() + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) + ShortcutUtil.removeAllDynamicShortcuts(appContext) + AnalyticsUtil.clearSession() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/mxt/anitrend/util/migration/contract/IMigrationUtil.kt b/app/src/main/java/com/mxt/anitrend/util/migration/contract/IMigrationUtil.kt new file mode 100644 index 000000000..bc39775d7 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/util/migration/contract/IMigrationUtil.kt @@ -0,0 +1,8 @@ +package com.mxt.anitrend.util.migration.contract + +interface IMigrationUtil { + /** + * Applies migration of the application if necessary + */ + fun applyMigration(): Boolean +} \ No newline at end of file From 38a957acf64927cf8a133abb09298bb2eb8d14e4 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Thu, 15 Aug 2019 09:42:14 +0200 Subject: [PATCH 40/81] Refactor Authentication Worker --- .../java/com/mxt/anitrend/worker/AuthenticatorWorker.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/mxt/anitrend/worker/AuthenticatorWorker.kt b/app/src/main/java/com/mxt/anitrend/worker/AuthenticatorWorker.kt index 9c226ace9..a06d1196b 100644 --- a/app/src/main/java/com/mxt/anitrend/worker/AuthenticatorWorker.kt +++ b/app/src/main/java/com/mxt/anitrend/worker/AuthenticatorWorker.kt @@ -45,17 +45,17 @@ class AuthenticatorWorker(context: Context, workerParams: WorkerParameters) : Wo * [Result.failure] or * [Result.failure] */ - override fun doWork(): ListenableWorker.Result { + override fun doWork(): Result { val errorDataBuilder = Data.Builder() try { val authorizationCode = authenticatorUri.getQueryParameter(BuildConfig.RESPONSE_TYPE) if (!TextUtils.isEmpty(authorizationCode)) { - val isSuccess = WebTokenRequest.getToken(applicationContext, authorizationCode) + val isSuccess = WebTokenRequest.getToken(authorizationCode) presenter.applicationPref.isAuthenticated = isSuccess val outputData = Data.Builder() .putBoolean(KeyUtil.arg_model, isSuccess) .build() - return ListenableWorker.Result.success(outputData) + return Result.success(outputData) } else Log.e(toString(), "Authorization authenticatorUri was empty or null, cannot authenticate with the current state") } catch (e: ExecutionException) { @@ -72,6 +72,6 @@ class AuthenticatorWorker(context: Context, workerParams: WorkerParameters) : Wo .putString(KeyUtil.arg_uri_error_description, authenticatorUri .getQueryParameter(KeyUtil.arg_uri_error_description)) .build() - return ListenableWorker.Result.failure(workerErrorOutputData) + return Result.failure(workerErrorOutputData) } } From c7bcd7188b4c39a691df759104631a09dc273b46 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Thu, 15 Aug 2019 10:58:02 +0200 Subject: [PATCH 41/81] Refactor LocaleUtil --- app/src/main/java/com/mxt/anitrend/App.kt | 3 +-- .../base/custom/activity/ActivityBase.java | 4 +--- .../java/com/mxt/anitrend/util/LocaleUtil.kt | 18 +++++++----------- 3 files changed, 9 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/com/mxt/anitrend/App.kt b/app/src/main/java/com/mxt/anitrend/App.kt index b32f3202f..212c911d8 100644 --- a/app/src/main/java/com/mxt/anitrend/App.kt +++ b/app/src/main/java/com/mxt/anitrend/App.kt @@ -112,8 +112,7 @@ class App : MultiDexApplication() { } override fun attachBaseContext(base: Context) { - val appPrefs = ApplicationPref(base) - super.attachBaseContext(LocaleUtil.onAttach(base, appPrefs)) + super.attachBaseContext(LocaleUtil.onAttach(base)) MultiDex.install(this) } } 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 54f63a371..13e191e92 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 @@ -101,9 +101,7 @@ protected void configureActivity() { @Override protected void attachBaseContext(Context base) { - if (applicationPref == null) - applicationPref = new ApplicationPref(base); - super.attachBaseContext(LocaleUtil.INSTANCE.onAttach(base, applicationPref)); + super.attachBaseContext(LocaleUtil.INSTANCE.onAttach(base)); } @Override diff --git a/app/src/main/java/com/mxt/anitrend/util/LocaleUtil.kt b/app/src/main/java/com/mxt/anitrend/util/LocaleUtil.kt index 056c69442..ecd855e12 100644 --- a/app/src/main/java/com/mxt/anitrend/util/LocaleUtil.kt +++ b/app/src/main/java/com/mxt/anitrend/util/LocaleUtil.kt @@ -3,9 +3,7 @@ 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 +import java.util.* /** * This class is used to change the application locale. @@ -14,18 +12,17 @@ import java.util.Locale */ object LocaleUtil { - fun onAttach(context: Context, applicationPref: ApplicationPref): Context { - val language = applicationPref.userLanguage + fun onAttach(context: Context): Context { + val language = ApplicationPref(context).userLanguage ?: Locale.getDefault().language return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - updateResources(context, language) - } else updateResourcesLegacy(context, language) + updateResources(context, Locale(language)) + } else updateResourcesLegacy(context, Locale(language)) } @TargetApi(Build.VERSION_CODES.N) - private fun updateResources(context: Context, language: String?): Context { - val locale = Locale(language) + private fun updateResources(context: Context, locale: Locale): Context { Locale.setDefault(locale) val configuration = context.resources.configuration @@ -35,8 +32,7 @@ object LocaleUtil { return context.createConfigurationContext(configuration) } - private fun updateResourcesLegacy(context: Context, language: String?): Context { - val locale = Locale(language) + private fun updateResourcesLegacy(context: Context, locale: Locale): Context { Locale.setDefault(locale) val resources = context.resources From ef6db53ce5013a780d320cf5689105d72988e6a3 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Thu, 15 Aug 2019 10:59:52 +0200 Subject: [PATCH 42/81] Add Explicit Lazy Initialization Type --- app/src/main/java/com/mxt/anitrend/util/ApplicationPref.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/mxt/anitrend/util/ApplicationPref.kt b/app/src/main/java/com/mxt/anitrend/util/ApplicationPref.kt index dd0d79d6d..c3a8c9540 100644 --- a/app/src/main/java/com/mxt/anitrend/util/ApplicationPref.kt +++ b/app/src/main/java/com/mxt/anitrend/util/ApplicationPref.kt @@ -24,7 +24,7 @@ class ApplicationPref(private val context: Context) { private val _freshInstall = "_freshInstall" private val _isAuthenticated = "_isAuthenticated" - val sharedPreferences: SharedPreferences by lazy { + val sharedPreferences: SharedPreferences by lazy(LazyThreadSafetyMode.NONE) { PreferenceManager.getDefaultSharedPreferences(context) } From 9df75acfa07613ab9199873727ec98730bc70464 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Thu, 15 Aug 2019 11:00:15 +0200 Subject: [PATCH 43/81] Optimize Imports for Application Preferences --- app/src/main/java/com/mxt/anitrend/util/ApplicationPref.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/com/mxt/anitrend/util/ApplicationPref.kt b/app/src/main/java/com/mxt/anitrend/util/ApplicationPref.kt index c3a8c9540..c5868c4f7 100644 --- a/app/src/main/java/com/mxt/anitrend/util/ApplicationPref.kt +++ b/app/src/main/java/com/mxt/anitrend/util/ApplicationPref.kt @@ -2,13 +2,12 @@ package com.mxt.anitrend.util import android.content.Context import android.content.SharedPreferences -import android.preference.PreferenceManager import androidx.annotation.IdRes import androidx.annotation.StyleRes +import androidx.preference.PreferenceManager import com.mxt.anitrend.BuildConfig import com.mxt.anitrend.R -import com.mxt.anitrend.util.ApplicationPref.Companion._isLightTheme import java.util.Locale From 0736bc8d7bf81353a45c2725204107692d7a9970 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Thu, 15 Aug 2019 11:01:28 +0200 Subject: [PATCH 44/81] Expose Application Version Code Allows us to check what the previous application version code was --- app/src/main/java/com/mxt/anitrend/util/ApplicationPref.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/java/com/mxt/anitrend/util/ApplicationPref.kt b/app/src/main/java/com/mxt/anitrend/util/ApplicationPref.kt index c5868c4f7..8944ebbc4 100644 --- a/app/src/main/java/com/mxt/anitrend/util/ApplicationPref.kt +++ b/app/src/main/java/com/mxt/anitrend/util/ApplicationPref.kt @@ -203,6 +203,9 @@ class ApplicationPref(private val context: Context) { val isUpdated: Boolean get() = sharedPreferences.getInt(_versionCode, 1) < BuildConfig.VERSION_CODE + val versionCode: Int + get() = sharedPreferences.getInt(_versionCode, 1) + var selectedGenres: Map? get() { val selected = sharedPreferences.getString(_genreFilter, null) From b796b3cca938d64507016b4878d5575c8c8b71b6 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Thu, 15 Aug 2019 11:02:22 +0200 Subject: [PATCH 45/81] Add Dependency Injection Through Koin --- app/src/main/java/com/mxt/anitrend/App.kt | 72 +++++++++---------- .../base/custom/async/WebTokenRequest.java | 4 +- .../custom/presenter/CommonPresenter.java | 2 +- .../com/mxt/anitrend/data/DatabaseHelper.kt | 12 ++-- .../java/com/mxt/anitrend/extension/AppExt.kt | 8 +++ .../java/com/mxt/anitrend/koin/AppModule.kt | 35 +++++++++ 6 files changed, 85 insertions(+), 48 deletions(-) create mode 100644 app/src/main/java/com/mxt/anitrend/extension/AppExt.kt create mode 100644 app/src/main/java/com/mxt/anitrend/koin/AppModule.kt diff --git a/app/src/main/java/com/mxt/anitrend/App.kt b/app/src/main/java/com/mxt/anitrend/App.kt index 212c911d8..ecb121e2c 100644 --- a/app/src/main/java/com/mxt/anitrend/App.kt +++ b/app/src/main/java/com/mxt/anitrend/App.kt @@ -8,14 +8,16 @@ import androidx.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.koin.AppModule.appModule 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 +import org.koin.android.ext.android.inject +import org.koin.android.ext.koin.androidContext +import org.koin.android.ext.koin.androidLogger +import org.koin.core.context.startKoin /** * Created by max on 2017/10/22. @@ -24,7 +26,7 @@ import org.greenrobot.eventbus.EventBus class App : MultiDexApplication() { - val applicationPref = ApplicationPref(this) + val applicationPref by inject() init { EventBus.builder().logNoSubscriberMessages(BuildConfig.DEBUG) @@ -39,15 +41,14 @@ class App : MultiDexApplication() { * * @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 - */ - lateinit var boxStore: BoxStore - private set + val analytics: FirebaseAnalytics? by lazy { + if (applicationPref.isUsageAnalyticsEnabled == true) { + FirebaseAnalytics.getInstance(this@App).apply { + setAnalyticsCollectionEnabled(applicationPref.isUsageAnalyticsEnabled!!) + } + } + null + } /** * Get application global registered fabric instance, depending on @@ -56,35 +57,36 @@ class App : MultiDexApplication() { * * @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() { + val fabric: Fabric? by lazy { if (!BuildConfig.DEBUG) if (applicationPref.isCrashReportsEnabled == true) { val crashlyticsCore = CrashlyticsCore.Builder() .build() - fabric = Fabric.with(Fabric.Builder(this) + Fabric.with(Fabric.Builder(this) .kits(crashlyticsCore) .appIdentifier(BuildConfig.BUILD_TYPE) .build()) } + null } - private fun initApp() { - if (applicationPref.isUsageAnalyticsEnabled == true) { - analytics = FirebaseAnalytics.getInstance(this).apply { - setAnalyticsCollectionEnabled(applicationPref.isUsageAnalyticsEnabled!!) - } + /** [Koin](https://insert-koin.io/docs/2.0/getting-started/) + * Initializes Koin dependency injection + */ + private fun initializeDependencyInjection() { + startKoin { + androidLogger() + androidContext(applicationContext) + modules(listOf(appModule)) } - try { + } + + private fun initializeApplication() { + runCatching { + EmojiManager.initEmojiData(this) + }.exceptionOrNull()?.printStackTrace() + runCatching { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) ProviderInstaller.installIfNeededAsync( applicationContext, @@ -98,17 +100,13 @@ class App : MultiDexApplication() { } } ) - EmojiManager.initEmojiData(this) - } catch (e: Exception) { - e.printStackTrace() - } + }.exceptionOrNull()?.printStackTrace() } override fun onCreate() { super.onCreate() - setCrashAnalytics() - setupBoxStore() - initApp() + initializeDependencyInjection() + initializeApplication() } override fun attachBaseContext(base: Context) { 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 53c7fb7a0..f91ec0b08 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 @@ -88,11 +88,11 @@ public static void getToken(Context context) { * Request a new access token using access code for authenticated content, * and replace the current token with the new one from the server after authentication */ - public static synchronized boolean getToken(Context context, String code) throws ExecutionException, InterruptedException { + public static synchronized boolean getToken(String code) throws ExecutionException, InterruptedException { WebToken authenticatedToken = new AuthenticationCodeAsync().execute(code).get(); if(authenticatedToken != null) { createNewTokenReference(authenticatedToken); - BoxQuery boxQuery = new DatabaseHelper(context); + BoxQuery boxQuery = new DatabaseHelper(); boxQuery.saveWebToken(authenticatedToken); boxQuery.saveAuthCode(new AuthBase(code, authenticatedToken.getRefresh_token())); return true; diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/presenter/CommonPresenter.java b/app/src/main/java/com/mxt/anitrend/base/custom/presenter/CommonPresenter.java index 3f7028ddf..a4828dd37 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/presenter/CommonPresenter.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/presenter/CommonPresenter.java @@ -45,7 +45,7 @@ public void setParams(Bundle bundle) { public BoxQuery getDatabase() { if(databaseHelper == null) - databaseHelper = new DatabaseHelper(context); + databaseHelper = new DatabaseHelper(); return databaseHelper; } 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 a59f9e5e0..4cd4569cd 100644 --- a/app/src/main/java/com/mxt/anitrend/data/DatabaseHelper.kt +++ b/app/src/main/java/com/mxt/anitrend/data/DatabaseHelper.kt @@ -1,8 +1,5 @@ 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 @@ -12,20 +9,19 @@ 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 +import org.koin.core.KoinComponent +import org.koin.core.inject /** * Created by max on 2017/11/02. * Database helper class */ -class DatabaseHelper(context: Context) : BoxQuery { +class DatabaseHelper : BoxQuery, KoinComponent { - private val boxStore: BoxStore by lazy { - (context.applicationContext as App).boxStore - } + private val boxStore by inject() // Frequently used instance variables private var user: User? = null diff --git a/app/src/main/java/com/mxt/anitrend/extension/AppExt.kt b/app/src/main/java/com/mxt/anitrend/extension/AppExt.kt new file mode 100644 index 000000000..b8d713bb0 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/extension/AppExt.kt @@ -0,0 +1,8 @@ +package com.mxt.anitrend.extension + +import android.content.Context +import org.koin.core.context.GlobalContext + +val appContext by lazy { + GlobalContext.get().koin.get() +} \ No newline at end of file diff --git a/app/src/main/java/com/mxt/anitrend/koin/AppModule.kt b/app/src/main/java/com/mxt/anitrend/koin/AppModule.kt new file mode 100644 index 000000000..306fa5e1e --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/koin/AppModule.kt @@ -0,0 +1,35 @@ +package com.mxt.anitrend.koin + +import com.mxt.anitrend.model.entity.MyObjectBox +import com.mxt.anitrend.presenter.base.BasePresenter +import com.mxt.anitrend.presenter.fragment.MediaPresenter +import com.mxt.anitrend.util.ApplicationPref +import org.koin.android.ext.koin.androidContext +import org.koin.core.KoinComponent +import org.koin.dsl.module + +object AppModule : KoinComponent { + val appModule = module { + single { + MyObjectBox.builder() + .androidContext(androidContext()) + .build() + } + factory { + ApplicationPref(androidContext()) + } + factory { + BasePresenter(androidContext()) + } + factory { + MediaPresenter(androidContext()) + } + } + + @JvmStatic + fun get(`class`: Class): T = getKoin().get( + `class`::class, + null, + null + ) +} \ No newline at end of file From e0e5bd88fb9845c801cf3c0124c5e12c83eda865 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Thu, 15 Aug 2019 11:15:49 +0200 Subject: [PATCH 46/81] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 34a6937c5..ca5d56d81 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# [ :biohazard: W.I.P v2.0 :biohazard: ] AniTrend v1.5.1   [![license](https://img.shields.io/github/license/mashape/apistatus.svg?style=flat-square)](https://github.com/AniTrend/anitrend-app/blob/master/LICENSE.md) +# [ :biohazard: W.I.P v2.0 :biohazard: ] AniTrend v1.5.3   [![license](https://img.shields.io/github/license/mashape/apistatus.svg?style=flat-square)](https://github.com/AniTrend/anitrend-app/blob/master/LICENSE.md) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/30a8f983c55541cbb504671ecc32786c)](https://www.codacy.com/app/wax911/anitrend-app?utm_source=github.com&utm_medium=referral&utm_content=wax911/anitrend-app&utm_campaign=Badge_Grade)   [![Build Status](https://travis-ci.org/AniTrend/anitrend-app.svg?branch=master)](https://travis-ci.org/AniTrend/anitrend-app)   [![Discord](https://img.shields.io/discord/314442908478472203.svg?color=%237289da&label=Join%20Anitrend%21&logo=discord&logoColor=%23fff)](https://discordapp.com/invite/2wzTqnF) Discover anime or manga with AniTrend which is a free [AniList](https://anilist.co) android client written in java.(AniTrend does not offer streaming capabilities, but official website links such as Hulu, Chrunchyroll, Netflix will be provided if available) From 5ebac5e3cbea5f1901182f8e1afc5df4c1738908 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Thu, 15 Aug 2019 11:16:27 +0200 Subject: [PATCH 47/81] Add Preference AndroidX Dependency --- app/build.gradle | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 09c5ab690..07c79d137 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,8 +1,8 @@ plugins { id("com.android.application") - id("kotlin-kapt") id("kotlin-android") id("kotlin-android-extensions") + id("kotlin-kapt") id("io.objectbox") } @@ -101,6 +101,7 @@ dependencies { /** Material Design */ implementation "com.google.android.material:material:$material" + implementation 'androidx.preference:preference:1.1.0-rc01' implementation "androidx.constraintlayout:constraintlayout:$constraint" implementation 'androidx.appcompat:appcompat:1.0.2' implementation 'com.google.android.material:material:1.0.0' From c1a767aca4216f91a8a2990ada414ec640c582df Mon Sep 17 00:00:00 2001 From: Maxwell Date: Thu, 15 Aug 2019 11:17:37 +0200 Subject: [PATCH 48/81] Bump Application Version from 1.5.2 to 1.5.3 --- app/.meta/version.json | 6 +++--- app/release/output.json | 2 +- build.gradle | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/.meta/version.json b/app/.meta/version.json index 00c2bd4cd..84beff4de 100644 --- a/app/.meta/version.json +++ b/app/.meta/version.json @@ -1,7 +1,7 @@ { - "code": 131, - "migration": false, + "code": 132, + "migration": true, "releaseNotes": "", - "version": "1.5.2", + "version": "1.5.3", "appId": "com.mxt.anitrend" } diff --git a/app/release/output.json b/app/release/output.json index 5ba6ddf8e..215e6b091 100644 --- a/app/release/output.json +++ b/app/release/output.json @@ -1 +1 @@ -[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":131,"versionName":"1.5.2","enabled":true,"outputFile":"anitrend_v1.5.2_rc_131.apk","fullName":"release","baseName":"release"},"path":"anitrend_v1.5.2_rc_131.apk","properties":{}}] \ No newline at end of file +[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":132,"versionName":"1.5.3","enabled":true,"outputFile":"anitrend_v1.5.3_rc_132.apk","fullName":"release","baseName":"release"},"path":"anitrend_v1.5.3_rc_132.apk","properties":{}}] \ No newline at end of file diff --git a/build.gradle b/build.gradle index 0d928c378..95981f94a 100644 --- a/build.gradle +++ b/build.gradle @@ -6,8 +6,8 @@ buildscript { targetSdk = 29 minSdk = 17 - versionCode = 131 - versionName = '1.5.2' + versionCode = 132 + versionName = '1.5.3' butterKnife = '10.1.0' From 0c1efbcb93d21f98649170eb9588b257430e0d5c Mon Sep 17 00:00:00 2001 From: Maxwell Date: Fri, 16 Aug 2019 23:57:01 +0200 Subject: [PATCH 49/81] Major Refactoring with Kotlin Conversions --- app/build.gradle | 9 +- app/src/main/AndroidManifest.xml | 16 +- app/src/main/java/com/mxt/anitrend/App.kt | 62 +-- .../pager/detail/AnimePageAdapter.java | 4 +- .../pager/detail/MangaPageAdapter.java | 4 +- .../pager/index/SearchPageAdapter.java | 4 +- .../anitrend/analytics/AnalyticsLogging.kt | 111 +++++ .../analytics/contract/ISupportAnalytics.kt | 19 + .../base/custom/activity/ActivityBase.java | 58 ++- .../annotation/processor/GraphProcessor.java | 21 +- .../base/custom/async/RequestHandler.java | 241 ---------- .../base/custom/async/RequestHandler.kt | 166 +++++++ .../base/custom/async/ThreadPool.java | 40 -- .../anitrend/base/custom/async/ThreadPool.kt | 15 + .../base/custom/async/WebTokenRequest.java | 28 +- .../base/custom/fragment/FragmentBase.java | 49 +- .../custom/fragment/FragmentChannelBase.java | 49 +- .../custom/presenter/CommonPresenter.java | 16 +- .../base/custom/sheet/BottomSheetBase.java | 5 +- .../base/custom/sheet/BottomSheetList.java | 3 +- .../custom/view/image/AvatarImageView.java | 66 --- .../base/custom/view/image/AvatarImageView.kt | 47 ++ .../view/image/AvatarIndicatorView.java | 142 ------ .../custom/view/image/AvatarIndicatorView.kt | 127 ++++++ .../base/custom/view/text/RatingTextView.java | 2 +- .../custom/view/text/RichMarkdownTextView.kt | 25 +- .../custom/view/widget/AboutPanelWidget.java | 21 +- .../view/widget/AutoIncrementWidget.java | 6 +- .../view/widget/FavouriteToolbarWidget.java | 28 +- .../custom/view/widget/FavouriteWidget.java | 6 +- .../custom/view/widget/FollowStateWidget.java | 6 +- .../view/widget/ProfileStatsWidget.java | 6 +- .../view/widget/StatusDeleteWidget.java | 6 +- .../base/custom/view/widget/VoteWidget.java | 9 +- .../base/custom/viewmodel/ViewModelBase.kt | 18 +- .../base/interfaces/dao/BoxQuery.java | 89 ---- .../anitrend/base/interfaces/dao/BoxQuery.kt | 57 +++ .../mxt/anitrend/binding/ImageExtensions.kt | 24 + .../binding/RichMarkdownExtensions.kt | 38 +- .../com/mxt/anitrend/data/DatabaseHelper.kt | 157 +++---- .../java/com/mxt/anitrend/extension/AppExt.kt | 20 +- .../mxt/anitrend/extension/CoroutineExt.kt | 16 + .../com/mxt/anitrend/extension/KoinExt.kt | 54 +++ .../java/com/mxt/anitrend/koin/AppModule.kt | 70 ++- .../model/api/converter/GraphQLConverter.java | 9 +- .../model/api/interceptor/AuthInterceptor.kt | 8 +- .../anitrend/model/api/retro/WebFactory.java | 13 +- .../anitrend/presenter/base/BasePresenter.kt | 52 ++- .../anitrend/service/JobDispatcherService.kt | 79 ++-- .../mxt/anitrend/service/TagGenreService.kt | 17 +- .../com/mxt/anitrend/util/AnalyticsUtil.java | 69 --- .../com/mxt/anitrend/util/ApplicationPref.kt | 299 ------------ .../java/com/mxt/anitrend/util/CompatUtil.kt | 27 +- .../com/mxt/anitrend/util/DialogUtil.java | 2 +- .../java/com/mxt/anitrend/util/ErrorUtil.kt | 4 +- .../java/com/mxt/anitrend/util/GraphUtil.kt | 8 +- .../com/mxt/anitrend/util/JobSchedulerUtil.kt | 2 +- .../java/com/mxt/anitrend/util/LocaleUtil.kt | 2 +- .../com/mxt/anitrend/util/MarkDownUtil.kt | 5 +- .../mxt/anitrend/util/MediaActionUtil.java | 6 +- .../mxt/anitrend/util/MediaDialogUtil.java | 13 +- .../com/mxt/anitrend/util/NotificationUtil.kt | 27 +- .../java/com/mxt/anitrend/util/Settings.kt | 427 ++++++++++++++++++ .../com/mxt/anitrend/util/TutorialUtil.java | 50 +- .../mxt/anitrend/util/migration/Migration.kt | 29 +- .../anitrend/util/migration/MigrationUtil.kt | 47 +- .../mxt/anitrend/util/migration/Migrations.kt | 52 ++- .../view/activity/base/AboutActivity.kt | 4 + .../base/AppCompatPreferenceActivity.java | 10 +- .../activity/base/ImagePreviewActivity.java | 3 +- .../view/activity/base/LoggingActivity.kt | 140 ++++++ .../view/activity/base/ReportActivity.java | 79 ---- .../view/activity/base/SettingsActivity.java | 12 +- .../activity/base/SharedContentActivity.java | 4 +- .../activity/detail/CharacterActivity.java | 2 +- .../view/activity/detail/MediaActivity.java | 6 +- .../view/activity/detail/ProfileActivity.java | 4 +- .../view/activity/detail/StaffActivity.java | 2 +- .../view/activity/detail/StudioActivity.java | 2 +- .../view/activity/index/LoginActivity.java | 242 ---------- .../view/activity/index/LoginActivity.kt | 221 +++++++++ .../view/activity/index/MainActivity.java | 54 ++- .../view/activity/index/SplashActivity.kt | 28 +- .../view/fragment/detail/AboutFragment.kt | 41 +- .../fragment/detail/BrowseReviewFragment.java | 14 +- .../view/fragment/detail/CommentFragment.java | 2 +- .../fragment/detail/MediaOverviewFragment.kt | 2 +- .../fragment/detail/NotificationFragment.kt | 62 ++- .../view/fragment/detail/ReviewFragment.java | 4 +- .../fragment/detail/StudioMediaFragment.java | 14 +- .../fragment/detail/UserFeedFragment.java | 2 +- .../favourite/MediaFavouriteFragment.java | 2 +- .../group/CharacterActorsFragment.java | 2 +- .../fragment/group/MediaFormatFragment.java | 2 +- .../fragment/group/MediaRelationFragment.java | 2 +- .../group/MediaStaffRoleFragment.java | 2 +- .../fragment/list/AiringListFragment.java | 2 +- .../view/fragment/list/FeedListFragment.java | 6 +- .../fragment/list/MediaBrowseFragment.java | 46 +- .../view/fragment/list/MediaListFragment.java | 28 +- .../fragment/list/SuggestionListFragment.java | 12 +- .../view/fragment/list/WatchListFragment.java | 6 +- .../fragment/search/MediaSearchFragment.java | 2 +- .../anitrend/view/sheet/BottomSheetGiphy.java | 4 +- .../anitrend/worker/AuthenticatorWorker.kt | 20 +- .../res/drawable/ic_save_grey_600_24dp.xml | 4 + .../ic_system_update_grey_600_24dp.xml | 4 + app/src/main/res/layout/activity_logging.xml | 18 + app/src/main/res/layout/activity_report.xml | 22 - app/src/main/res/layout/content_logging.xml | 61 +++ app/src/main/res/menu/logging_menu.xml | 20 + app/src/main/res/values-ar/strings.xml | 9 + app/src/main/res/values-de/strings.xml | 9 + app/src/main/res/values-es/strings.xml | 9 + app/src/main/res/values-fr/strings.xml | 9 + app/src/main/res/values-it/strings.xml | 9 + app/src/main/res/values-nl/strings.xml | 9 + app/src/main/res/values-pl/strings.xml | 9 + app/src/main/res/values-pt/strings.xml | 9 + app/src/main/res/values-sv/strings.xml | 9 + app/src/main/res/values/strings.xml | 9 + build.gradle | 6 +- 122 files changed, 2507 insertions(+), 2015 deletions(-) create mode 100644 app/src/main/java/com/mxt/anitrend/analytics/AnalyticsLogging.kt create mode 100644 app/src/main/java/com/mxt/anitrend/analytics/contract/ISupportAnalytics.kt delete mode 100644 app/src/main/java/com/mxt/anitrend/base/custom/async/RequestHandler.java create mode 100644 app/src/main/java/com/mxt/anitrend/base/custom/async/RequestHandler.kt delete mode 100644 app/src/main/java/com/mxt/anitrend/base/custom/async/ThreadPool.java create mode 100644 app/src/main/java/com/mxt/anitrend/base/custom/async/ThreadPool.kt delete mode 100644 app/src/main/java/com/mxt/anitrend/base/custom/view/image/AvatarImageView.java create mode 100644 app/src/main/java/com/mxt/anitrend/base/custom/view/image/AvatarImageView.kt delete mode 100644 app/src/main/java/com/mxt/anitrend/base/custom/view/image/AvatarIndicatorView.java create mode 100644 app/src/main/java/com/mxt/anitrend/base/custom/view/image/AvatarIndicatorView.kt delete mode 100644 app/src/main/java/com/mxt/anitrend/base/interfaces/dao/BoxQuery.java create mode 100644 app/src/main/java/com/mxt/anitrend/base/interfaces/dao/BoxQuery.kt create mode 100644 app/src/main/java/com/mxt/anitrend/binding/ImageExtensions.kt create mode 100644 app/src/main/java/com/mxt/anitrend/extension/CoroutineExt.kt create mode 100644 app/src/main/java/com/mxt/anitrend/extension/KoinExt.kt delete mode 100644 app/src/main/java/com/mxt/anitrend/util/AnalyticsUtil.java delete mode 100644 app/src/main/java/com/mxt/anitrend/util/ApplicationPref.kt create mode 100644 app/src/main/java/com/mxt/anitrend/util/Settings.kt create mode 100644 app/src/main/java/com/mxt/anitrend/view/activity/base/LoggingActivity.kt delete mode 100644 app/src/main/java/com/mxt/anitrend/view/activity/base/ReportActivity.java delete mode 100644 app/src/main/java/com/mxt/anitrend/view/activity/index/LoginActivity.java create mode 100644 app/src/main/java/com/mxt/anitrend/view/activity/index/LoginActivity.kt create mode 100644 app/src/main/res/drawable/ic_save_grey_600_24dp.xml create mode 100644 app/src/main/res/drawable/ic_system_update_grey_600_24dp.xml create mode 100644 app/src/main/res/layout/activity_logging.xml delete mode 100644 app/src/main/res/layout/activity_report.xml create mode 100644 app/src/main/res/layout/content_logging.xml create mode 100644 app/src/main/res/menu/logging_menu.xml diff --git a/app/build.gradle b/app/build.gradle index 07c79d137..86de8c8fd 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -101,7 +101,7 @@ dependencies { /** Material Design */ implementation "com.google.android.material:material:$material" - implementation 'androidx.preference:preference:1.1.0-rc01' + implementation 'androidx.preference:preference-ktx:1.1.0-rc01' implementation "androidx.constraintlayout:constraintlayout:$constraint" implementation 'androidx.appcompat:appcompat:1.0.2' implementation 'com.google.android.material:material:1.0.0' @@ -116,11 +116,10 @@ dependencies { /** Fire-base Libraries */ implementation "com.google.firebase:firebase-core:$firebase" + implementation "com.google.firebase:firebase-analytics:$firebase" /** Crash Analytics */ - implementation("com.crashlytics.sdk.android:crashlytics:$crashlytics") { - transitive = true - } + implementation("com.crashlytics.sdk.android:crashlytics:$crashlytics") /** Glide Libraries */ implementation "com.github.bumptech.glide:glide:$glide" @@ -176,7 +175,7 @@ dependencies { //implementation "com.github.anitrend:retrofit-graphql:$graphql" /** Timber */ - //implementation "com.jakewharton.timber:timber:$timber" + implementation "com.jakewharton.timber:timber:$timber" /** Pretty Time */ implementation 'org.ocpsoft.prettytime:prettytime:4.0.2.Final' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6c5e1cedb..a79fa8f2c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -153,8 +153,8 @@ android:label="@string/nav_about" android:launchMode="singleTop" /> - + + + + + + diff --git a/app/src/main/java/com/mxt/anitrend/App.kt b/app/src/main/java/com/mxt/anitrend/App.kt index ecb121e2c..ca61f42b7 100644 --- a/app/src/main/java/com/mxt/anitrend/App.kt +++ b/app/src/main/java/com/mxt/anitrend/App.kt @@ -5,19 +5,20 @@ import android.content.Intent import android.os.Build import androidx.multidex.MultiDex import androidx.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.analytics.AnalyticsLogging +import com.mxt.anitrend.analytics.contract.ISupportAnalytics import com.mxt.anitrend.koin.AppModule.appModule -import com.mxt.anitrend.util.ApplicationPref +import com.mxt.anitrend.koin.AppModule.presenterModule +import com.mxt.anitrend.koin.AppModule.widgetModule import com.mxt.anitrend.util.LocaleUtil -import io.fabric.sdk.android.Fabric import io.wax911.emojify.EmojiManager import org.greenrobot.eventbus.EventBus import org.koin.android.ext.android.inject import org.koin.android.ext.koin.androidContext import org.koin.android.ext.koin.androidLogger import org.koin.core.context.startKoin +import timber.log.Timber /** * Created by max on 2017/10/22. @@ -26,49 +27,24 @@ import org.koin.core.context.startKoin class App : MultiDexApplication() { - val applicationPref by inject() - - init { - EventBus.builder().logNoSubscriberMessages(BuildConfig.DEBUG) - .sendNoSubscriberEvent(BuildConfig.DEBUG) - .sendSubscriberExceptionEvent(BuildConfig.DEBUG) - .throwSubscriberException(BuildConfig.DEBUG) - .installDefaultEventBus() - } + private val supportAnalytics by inject() /** - * @return Application global registered firebase analytics - * - * @see com.mxt.anitrend.util.AnalyticsUtil + * Timber logging tree depending on the build type we plant the appropriate tree */ - val analytics: FirebaseAnalytics? by lazy { - if (applicationPref.isUsageAnalyticsEnabled == true) { - FirebaseAnalytics.getInstance(this@App).apply { - setAnalyticsCollectionEnabled(applicationPref.isUsageAnalyticsEnabled!!) - } + private fun plantLoggingTree() { + when (BuildConfig.DEBUG) { + true -> Timber.plant(Timber.DebugTree()) + else -> Timber.plant(supportAnalytics as AnalyticsLogging) } - null } - /** - * 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 - */ - val fabric: Fabric? by lazy { - if (!BuildConfig.DEBUG) - if (applicationPref.isCrashReportsEnabled == true) { - val crashlyticsCore = CrashlyticsCore.Builder() - .build() - - Fabric.with(Fabric.Builder(this) - .kits(crashlyticsCore) - .appIdentifier(BuildConfig.BUILD_TYPE) - .build()) - } - null + private fun initializeEventBus() { + EventBus.builder().logNoSubscriberMessages(BuildConfig.DEBUG) + .sendNoSubscriberEvent(BuildConfig.DEBUG) + .sendSubscriberExceptionEvent(BuildConfig.DEBUG) + .throwSubscriberException(BuildConfig.DEBUG) + .installDefaultEventBus() } /** [Koin](https://insert-koin.io/docs/2.0/getting-started/) @@ -78,7 +54,7 @@ class App : MultiDexApplication() { startKoin { androidLogger() androidContext(applicationContext) - modules(listOf(appModule)) + modules(listOf(appModule, widgetModule, presenterModule)) } } @@ -107,6 +83,8 @@ class App : MultiDexApplication() { super.onCreate() initializeDependencyInjection() initializeApplication() + initializeEventBus() + plantLoggingTree() } override fun attachBaseContext(base: Context) { 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 7e77ac007..31d83ad1c 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 @@ -6,7 +6,7 @@ import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.pager.BaseStatePageAdapter; -import com.mxt.anitrend.util.ApplicationPref; +import com.mxt.anitrend.util.Settings; import com.mxt.anitrend.util.GraphUtil; import com.mxt.anitrend.util.KeyUtil; import com.mxt.anitrend.view.fragment.detail.MediaFeedFragment; @@ -29,7 +29,7 @@ public class AnimePageAdapter extends BaseStatePageAdapter { public AnimePageAdapter(FragmentManager fragmentManager, Context context) { super(fragmentManager, context); setPagerTitles(R.array.anime_page_titles); - isAuthenticated = new ApplicationPref(context).isAuthenticated(); + isAuthenticated = new Settings(context).isAuthenticated(); } @Override 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 d1a16f981..14cf4498e 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 @@ -6,7 +6,7 @@ import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.pager.BaseStatePageAdapter; -import com.mxt.anitrend.util.ApplicationPref; +import com.mxt.anitrend.util.Settings; import com.mxt.anitrend.util.GraphUtil; import com.mxt.anitrend.util.KeyUtil; import com.mxt.anitrend.view.fragment.detail.MediaFeedFragment; @@ -28,7 +28,7 @@ public class MangaPageAdapter extends BaseStatePageAdapter { public MangaPageAdapter(FragmentManager fragmentManager, Context context) { super(fragmentManager, context); setPagerTitles(R.array.manga_page_titles); - isAuthenticated = new ApplicationPref(context).isAuthenticated(); + isAuthenticated = new Settings(context).isAuthenticated(); } @Override diff --git a/app/src/main/java/com/mxt/anitrend/adapter/pager/index/SearchPageAdapter.java b/app/src/main/java/com/mxt/anitrend/adapter/pager/index/SearchPageAdapter.java index 933498e46..b743cfa61 100644 --- a/app/src/main/java/com/mxt/anitrend/adapter/pager/index/SearchPageAdapter.java +++ b/app/src/main/java/com/mxt/anitrend/adapter/pager/index/SearchPageAdapter.java @@ -6,7 +6,7 @@ import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.pager.BaseStatePageAdapter; -import com.mxt.anitrend.util.ApplicationPref; +import com.mxt.anitrend.util.Settings; import com.mxt.anitrend.util.KeyUtil; import com.mxt.anitrend.view.fragment.search.CharacterSearchFragment; import com.mxt.anitrend.view.fragment.search.MediaSearchFragment; @@ -22,7 +22,7 @@ public class SearchPageAdapter extends BaseStatePageAdapter { public SearchPageAdapter(FragmentManager fragmentManager, Context context) { super(fragmentManager, context); - setPagerTitles(new ApplicationPref(context).isAuthenticated()? R.array.search_titles_auth : R.array.search_titles); + setPagerTitles(new Settings(context).isAuthenticated()? R.array.search_titles_auth : R.array.search_titles); } /** diff --git a/app/src/main/java/com/mxt/anitrend/analytics/AnalyticsLogging.kt b/app/src/main/java/com/mxt/anitrend/analytics/AnalyticsLogging.kt new file mode 100644 index 000000000..eaacbf0e6 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/analytics/AnalyticsLogging.kt @@ -0,0 +1,111 @@ +package com.mxt.anitrend.analytics + +import android.content.Context +import android.os.Bundle +import android.util.Log +import androidx.fragment.app.FragmentActivity +import com.crashlytics.android.Crashlytics +import com.google.firebase.analytics.FirebaseAnalytics +import com.mxt.anitrend.BuildConfig +import com.mxt.anitrend.analytics.contract.ISupportAnalytics +import com.mxt.anitrend.extension.empty +import com.mxt.anitrend.util.Settings +import io.fabric.sdk.android.Fabric +import org.koin.android.ext.koin.androidContext +import org.koin.core.KoinComponent +import timber.log.Timber + +class AnalyticsLogging( + context: Context, + settings: Settings +): Timber.Tree(), ISupportAnalytics, KoinComponent { + + private var fabric: Fabric? = null + + init { + if (settings.isCrashReportsEnabled) + fabric = Fabric.with(Fabric.Builder(context) + .kits(Crashlytics()) + .appIdentifier(BuildConfig.BUILD_TYPE) + .build()) + } + + private val analytics by lazy { + FirebaseAnalytics.getInstance(context).apply { + setAnalyticsCollectionEnabled( + settings.isUsageAnalyticsEnabled + ) + } + } + + /** + * Write a log message to its destination. Called for all level-specific methods by default. + * + * @param priority Log level. See [Log] for constants. + * @param tag Explicit or inferred tag. May be `null`. + * @param message Formatted log message. May be `null`, but then `t` will not be. + * @param throwable Accompanying exceptions. May be `null`, but then `message` will not be. + */ + override fun log(priority: Int, tag: String?, message: String, throwable: Throwable?) { + if (priority < Log.INFO) + return + + Crashlytics.setInt(PRIORITY, priority) + Crashlytics.setString(TAG, tag) + Crashlytics.setString(MESSAGE, message) + + when (throwable) { + null -> log(priority, tag, message) + else -> logException(throwable) + } + } + + override fun logCurrentScreen(context: FragmentActivity, tag : String) { + runCatching { + fabric?.currentActivity = context + analytics.setCurrentScreen(context, tag, null) + }.exceptionOrNull()?.printStackTrace() + } + + override fun logCurrentState(tag: String, bundle: Bundle?) { + runCatching { + bundle?.also { analytics.logEvent(tag, it) } + }.exceptionOrNull()?.printStackTrace() + } + + override fun logException(throwable: Throwable) { + runCatching { + Crashlytics.logException(throwable) + }.exceptionOrNull()?.printStackTrace() + } + + override fun log(priority: Int, tag: String?, message: String) { + runCatching { + Crashlytics.log(priority, tag, message) + }.exceptionOrNull()?.printStackTrace() + } + + override fun clearUserSession() { + runCatching { + Crashlytics.setUserIdentifier(String.empty()) + }.exceptionOrNull()?.printStackTrace() + } + + override fun setCrashAnalyticUser(userIdentifier: String) { + runCatching { + Crashlytics.setUserIdentifier(userIdentifier) + }.exceptionOrNull()?.printStackTrace() + } + + override fun resetAnalyticsData() { + runCatching { + analytics.resetAnalyticsData() + }.exceptionOrNull()?.printStackTrace() + } + + companion object { + private const val PRIORITY = "priority" + private const val TAG = "tag" + private const val MESSAGE = "message" + } +} \ No newline at end of file diff --git a/app/src/main/java/com/mxt/anitrend/analytics/contract/ISupportAnalytics.kt b/app/src/main/java/com/mxt/anitrend/analytics/contract/ISupportAnalytics.kt new file mode 100644 index 000000000..f8cddc09f --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/analytics/contract/ISupportAnalytics.kt @@ -0,0 +1,19 @@ +package com.mxt.anitrend.analytics.contract + +import android.os.Bundle +import android.util.Log +import androidx.fragment.app.FragmentActivity + +interface ISupportAnalytics { + + fun logCurrentScreen(context: FragmentActivity, tag: String) + fun logCurrentState(tag: String, bundle: Bundle?) + + fun logException(throwable: Throwable) + fun log(priority: Int = Log.VERBOSE, tag: String?, message: String) + + fun clearUserSession() + fun setCrashAnalyticUser(userIdentifier: String) + + fun resetAnalyticsData() +} \ No newline at end of file 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 13e191e92..d1caa4d2c 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 @@ -1,22 +1,12 @@ package com.mxt.anitrend.base.custom.activity; -import androidx.lifecycle.Observer; -import androidx.lifecycle.ViewModelProviders; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.os.Build; import android.os.Bundle; import android.speech.RecognizerIntent; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.StyleRes; -import androidx.core.app.ActivityCompat; -import androidx.core.content.ContextCompat; -import androidx.appcompat.app.ActionBar; -import androidx.appcompat.app.AppCompatActivity; import android.text.TextUtils; -import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; @@ -24,22 +14,32 @@ import android.widget.Toast; import android.widget.Toolbar; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.StyleRes; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatDelegate; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; +import androidx.lifecycle.Observer; +import androidx.lifecycle.ViewModelProviders; + import com.miguelcatalan.materialsearchview.MaterialSearchView; -import com.mxt.anitrend.App; import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.fragment.FragmentBase; import com.mxt.anitrend.base.custom.presenter.CommonPresenter; import com.mxt.anitrend.base.custom.sheet.BottomSheetBase; import com.mxt.anitrend.base.custom.viewmodel.ViewModelBase; import com.mxt.anitrend.base.interfaces.event.ResponseCallback; -import com.mxt.anitrend.util.AnalyticsUtil; -import com.mxt.anitrend.util.ApplicationPref; +import com.mxt.anitrend.extension.KoinExt; import com.mxt.anitrend.util.CompatUtil; import com.mxt.anitrend.util.IntentBundleUtil; import com.mxt.anitrend.util.KeyUtil; import com.mxt.anitrend.util.LocaleUtil; import com.mxt.anitrend.util.MediaActionUtil; import com.mxt.anitrend.util.NotifyUtil; +import com.mxt.anitrend.util.Settings; import com.mxt.anitrend.view.activity.index.MainActivity; import com.mxt.anitrend.view.activity.index.SearchActivity; @@ -49,6 +49,7 @@ import java.util.Locale; import butterknife.BindView; +import timber.log.Timber; /** @@ -81,22 +82,21 @@ public abstract class ActivityBase extends AppComp private CommonPresenter presenter; - private ApplicationPref applicationPref; - - private @StyleRes int style; - /** * Some activities may have custom themes and if that's the case * override this method and set your own theme style. */ protected void configureActivity() { - if (applicationPref == null) - applicationPref = ((App)getApplicationContext()).getApplicationPref(); - style = applicationPref.getTheme(); - if(!CompatUtil.INSTANCE.isLightTheme(style) && applicationPref.isBlackThemeEnabled()) + final Settings settings = KoinExt.get(Settings.class); + final @StyleRes int style = settings.getTheme(); + if(!CompatUtil.INSTANCE.isLightTheme(style) && settings.isBlackThemeEnabled()) { + AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES); setTheme(R.style.AppThemeBlack); - else + } + else { + AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO); setTheme(style); + } } @Override @@ -106,11 +106,11 @@ protected void attachBaseContext(Context base) { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { - TAG = getClass().getSimpleName(); configureActivity(); + TAG = getClass().getSimpleName(); + configureActivity(); super.onCreate(savedInstanceState); intentBundleUtil = new IntentBundleUtil(getIntent()); intentBundleUtil.checkIntentData(this); - AnalyticsUtil.logCurrentScreen(this, TAG); } @Override @@ -249,7 +249,7 @@ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permis * @param permission the current permission granted */ protected void onPermissionGranted(@NonNull String permission) { - Log.i(TAG, "Granted " + permission); + Timber.tag(TAG).i("Granted %s", permission); } /** @@ -369,16 +369,14 @@ protected void setViewModel(boolean stateSupported) { */ @Override public void onChanged(@Nullable M model) { - Log.i(TAG, "onChanged() from view model has received data"); + Timber.tag(TAG).i("onChanged() from view model has received data"); } @Override public void showError(String error) { if(!TextUtils.isEmpty(error)) - Log.e(TAG, error); + Timber.tag(TAG).d(error); if(isAlive()) { - if (getPresenter() != null && getPresenter().getApplicationPref().isCrashReportsEnabled()) - AnalyticsUtil.reportException(TAG, error); NotifyUtil.createAlerter(this, getString(R.string.text_error_request), error, R.drawable.ic_warning_white_18dp, R.color.colorStateOrange, KeyUtil.DURATION_MEDIUM); @@ -389,7 +387,7 @@ public void showError(String error) { @Override public void showEmpty(String message) { if(!TextUtils.isEmpty(message)) - Log.d(TAG, message); + Timber.tag(TAG).i(message); if (isAlive()) { NotifyUtil.createAlerter(this, getString(R.string.text_error_request), message, R.drawable.ic_warning_white_18dp, R.color.colorStateBlue, diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/annotation/processor/GraphProcessor.java b/app/src/main/java/com/mxt/anitrend/base/custom/annotation/processor/GraphProcessor.java index 03306b9db..f8a285ea4 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/annotation/processor/GraphProcessor.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/annotation/processor/GraphProcessor.java @@ -13,12 +13,14 @@ import java.util.HashMap; import java.util.Map; +import timber.log.Timber; + /** * Created by max on 2018/03/12. * GraphQL annotation processor */ public class GraphProcessor { - + private final String TAG = GraphProcessor.class.getSimpleName(); private static GraphProcessor ourInstance; private final static Object lock = new Object(); private final static String defaultExtension = ".graphql", defaultDirectory = "graphql"; @@ -31,16 +33,16 @@ public static GraphProcessor getInstance(Context context) { private GraphProcessor(Context context) { synchronized (lock) { - Log.d("GraphProcessor", Thread.currentThread().getName() + ": has obtained a synchronized lock on the object"); + Timber.tag(TAG).i("%s: has obtained a synchronized lock on the object", Thread.currentThread().getName()); if(this.graphFiles == null) this.graphFiles = new HashMap<>(); if(isEmpty()) { - Log.d("GraphProcessor", Thread.currentThread().getName() + ": is initializing query files"); + Timber.tag(TAG).i("%s: is initializing query files", Thread.currentThread().getName()); initialize(defaultDirectory, context); - Log.d("GraphProcessor", Thread.currentThread().getName() + ": has completed initializing all files"); - Log.d("GraphProcessor", Thread.currentThread().getName() + ": Total count of graphFiles -> size: "+ graphFiles.size()); + Timber.tag(TAG).i("%s: has completed initializing all files", Thread.currentThread().getName()); + Timber.tag(TAG).i(Thread.currentThread().getName() + ": Total count of graphFiles -> size: " + graphFiles.size()); } else - Log.d("GraphProcessor", Thread.currentThread().getName() + ": skipped initialization of graphFiles -> size: "+ graphFiles.size()); + Timber.tag(TAG).i(Thread.currentThread().getName() + ": skipped initialization of graphFiles -> size: " + graphFiles.size()); } } @@ -57,11 +59,11 @@ public String getQuery(Annotation[] annotations) { if(graphFiles != null && graphQuery != null) { String fileName = String.format("%s%s", graphQuery.value(), defaultExtension); - Log.d("GraphProcessor", fileName); + Timber.tag(TAG).i(fileName); if(graphFiles.containsKey(fileName)) return graphFiles.get(fileName); - Log.e(this.toString(), String.format("The request query %s could not be found!", graphQuery.value())); - Log.e(this.toString(), String.format("Current size of graphFiles -> size: %d", graphFiles.size())); + Timber.tag(TAG).e("The request query %s could not be found!", graphQuery.value()); + Timber.tag(TAG).e("Current size of graphFiles -> size: %d", graphFiles.size()); } return null; } @@ -84,6 +86,7 @@ private synchronized void initialize(String path, Context context) { } } catch (IOException e) { e.printStackTrace(); + Timber.tag(TAG).e(e); } } diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/async/RequestHandler.java b/app/src/main/java/com/mxt/anitrend/base/custom/async/RequestHandler.java deleted file mode 100644 index ea1b3c391..000000000 --- a/app/src/main/java/com/mxt/anitrend/base/custom/async/RequestHandler.java +++ /dev/null @@ -1,241 +0,0 @@ -package com.mxt.anitrend.base.custom.async; - -import android.content.Context; -import android.os.AsyncTask; -import android.os.Bundle; - -import com.mxt.anitrend.BuildConfig; -import com.mxt.anitrend.model.api.retro.WebFactory; -import com.mxt.anitrend.model.api.retro.anilist.BaseModel; -import com.mxt.anitrend.model.api.retro.anilist.BrowseModel; -import com.mxt.anitrend.model.api.retro.anilist.CharacterModel; -import com.mxt.anitrend.model.api.retro.anilist.FeedModel; -import com.mxt.anitrend.model.api.retro.anilist.MediaModel; -import com.mxt.anitrend.model.api.retro.anilist.SearchModel; -import com.mxt.anitrend.model.api.retro.anilist.StaffModel; -import com.mxt.anitrend.model.api.retro.anilist.StudioModel; -import com.mxt.anitrend.model.api.retro.anilist.UserModel; -import com.mxt.anitrend.util.KeyUtil; - -import retrofit2.Call; -import retrofit2.Callback; - -import static com.mxt.anitrend.util.KeyUtil.EPISODE_FEED_REQ; -import static com.mxt.anitrend.util.KeyUtil.EPISODE_LATEST_REQ; -import static com.mxt.anitrend.util.KeyUtil.EPISODE_POPULAR_REQ; -import static com.mxt.anitrend.util.KeyUtil.GENRE_COLLECTION_REQ; -import static com.mxt.anitrend.util.KeyUtil.GIPHY_SEARCH_REQ; -import static com.mxt.anitrend.util.KeyUtil.GIPHY_TRENDING_REQ; -import static com.mxt.anitrend.util.KeyUtil.MEDIA_TAG_REQ; -import static com.mxt.anitrend.util.KeyUtil.PAGING_LIMIT; -import static com.mxt.anitrend.util.KeyUtil.RequestType; -import static com.mxt.anitrend.util.KeyUtil.UPDATE_CHECKER_REQ; -import static com.mxt.anitrend.util.KeyUtil.arg_branch_name; -import static com.mxt.anitrend.util.KeyUtil.arg_feed; -import static com.mxt.anitrend.util.KeyUtil.arg_graph_params; -import static com.mxt.anitrend.util.KeyUtil.arg_page_offset; -import static com.mxt.anitrend.util.KeyUtil.arg_search; - -/** - * Created by max on 2017/09/16. - * Handles all service creation for Retrofit Endpoints on a background task, - * which allows us to perform heavy operations such as token refreshing on demand - */ - -@SuppressWarnings("unchecked") -public class RequestHandler extends AsyncTask> { - - private Bundle param; - private Callback callback; - private @RequestType - int requestType; - - public RequestHandler(Bundle param, Callback callback, int requestType) { - this.param = param; - this.callback = callback; - this.requestType = requestType; - } - - @Override - protected Call doInBackground(Context... contexts) { - if(!isCancelled() && callback != null) { - Context context = contexts[0]; - switch (requestType) { - case GENRE_COLLECTION_REQ: - return (Call) WebFactory.createService(BaseModel.class, context).getGenres(param.getParcelable(arg_graph_params)); - case MEDIA_TAG_REQ: - return (Call) WebFactory.createService(BaseModel.class, context).getTags(param.getParcelable(arg_graph_params)); - - - case EPISODE_FEED_REQ: - return (Call) WebFactory.createCrunchyService(param.getBoolean(arg_feed), context).getRSS(param.getString(arg_search)); - case EPISODE_LATEST_REQ: - return (Call) WebFactory.createCrunchyService(param.getBoolean(arg_feed), context).getLatestFeed(); - case EPISODE_POPULAR_REQ: - return (Call) WebFactory.createCrunchyService(param.getBoolean(arg_feed), context).getPopularFeed(); - - - case GIPHY_SEARCH_REQ: - return (Call) WebFactory.createGiphyService(context).findGif(BuildConfig.GIPHY_KEY, param.getString(arg_search), - PAGING_LIMIT, param.getInt(arg_page_offset), "PG", "en"); - case GIPHY_TRENDING_REQ: - return (Call) WebFactory.createGiphyService(context).getTrending(BuildConfig.GIPHY_KEY, PAGING_LIMIT, param.getInt(arg_page_offset), "PG"); - - - case UPDATE_CHECKER_REQ: - return (Call) WebFactory.createRepositoryService().checkVersion(param.getString(arg_branch_name)); - - - case KeyUtil.MEDIA_LIST_COLLECTION_REQ: - return (Call) WebFactory.createService(BrowseModel.class, context).getMediaListCollection(param.getParcelable(arg_graph_params)); - case KeyUtil.MEDIA_BROWSE_REQ: - return (Call) WebFactory.createService(BrowseModel.class, context).getMediaBrowse(param.getParcelable(arg_graph_params)); - case KeyUtil.MEDIA_LIST_BROWSE_REQ: - return (Call) WebFactory.createService(BrowseModel.class, context).getMediaListBrowse(param.getParcelable(arg_graph_params)); - case KeyUtil.MEDIA_LIST_REQ: - return (Call) WebFactory.createService(BrowseModel.class, context).getMediaList(param.getParcelable(arg_graph_params)); - case KeyUtil.MEDIA_WITH_LIST_REQ: - return (Call) WebFactory.createService(BrowseModel.class, context).getMediaWithList(param.getParcelable(arg_graph_params)); - - - case KeyUtil.CHARACTER_ACTORS_REQ: - return (Call) WebFactory.createService(CharacterModel.class, context).getCharacterActors(param.getParcelable(arg_graph_params)); - case KeyUtil.CHARACTER_BASE_REQ: - return (Call) WebFactory.createService(CharacterModel.class, context).getCharacterBase(param.getParcelable(arg_graph_params)); - case KeyUtil.CHARACTER_MEDIA_REQ: - return (Call) WebFactory.createService(CharacterModel.class, context).getCharacterMedia(param.getParcelable(arg_graph_params)); - case KeyUtil.CHARACTER_OVERVIEW_REQ: - return (Call) WebFactory.createService(CharacterModel.class, context).getCharacterOverview(param.getParcelable(arg_graph_params)); - case KeyUtil.CHARACTER_SEARCH_REQ: - return (Call) WebFactory.createService(SearchModel.class, context).getCharacterSearch(param.getParcelable(arg_graph_params)); - - - case KeyUtil.FEED_LIST_REPLY_REQ: - return (Call) WebFactory.createService(FeedModel.class, context).getFeedListReply(param.getParcelable(arg_graph_params)); - case KeyUtil.FEED_LIST_REQ: - return (Call) WebFactory.createService(FeedModel.class, context).getFeedList(param.getParcelable(arg_graph_params)); - case KeyUtil.FEED_MESSAGE_REQ: - return (Call) WebFactory.createService(FeedModel.class, context).getFeedMessage(param.getParcelable(arg_graph_params)); - - - case KeyUtil.MEDIA_BASE_REQ: - return (Call) WebFactory.createService(MediaModel.class, context).getMediaBase(param.getParcelable(arg_graph_params)); - case KeyUtil.MEDIA_CHARACTERS_REQ: - return (Call) WebFactory.createService(MediaModel.class, context).getMediaCharacters(param.getParcelable(arg_graph_params)); - case KeyUtil.MEDIA_EPISODES_REQ: - return (Call) WebFactory.createService(MediaModel.class, context).getMediaEpisodes(param.getParcelable(arg_graph_params)); - case KeyUtil.MEDIA_OVERVIEW_REQ: - return (Call) WebFactory.createService(MediaModel.class, context).getMediaOverview(param.getParcelable(arg_graph_params)); - case KeyUtil.MEDIA_RELATION_REQ: - return (Call) WebFactory.createService(MediaModel.class, context).getMediaRelations(param.getParcelable(arg_graph_params)); - case KeyUtil.MEDIA_REVIEWS_REQ: - return (Call) WebFactory.createService(BrowseModel.class, context).getReviewBrowse(param.getParcelable(arg_graph_params)); - case KeyUtil.MEDIA_SEARCH_REQ: - return (Call) WebFactory.createService(SearchModel.class, context).getMediaSearch(param.getParcelable(arg_graph_params)); - case KeyUtil.MEDIA_SOCIAL_REQ: - return (Call) WebFactory.createService(MediaModel.class, context).getMediaSocial(param.getParcelable(arg_graph_params)); - case KeyUtil.MEDIA_STAFF_REQ: - return (Call) WebFactory.createService(MediaModel.class, context).getMediaStaff(param.getParcelable(arg_graph_params)); - case KeyUtil.MEDIA_STATS_REQ: - return (Call) WebFactory.createService(MediaModel.class, context).getMediaStats(param.getParcelable(arg_graph_params)); - /*case KeyUtils.MEDIA_TREND_REQ: - return (Call) WebFactory.createService(BrowseModel.class, context).getMediaTrends(param.getParcelable(arg_graph_params));*/ - - - case KeyUtil.MUT_DELETE_FEED_REPLY: - return (Call) WebFactory.createService(FeedModel.class, context).deleteActivityReply(param.getParcelable(arg_graph_params)); - case KeyUtil.MUT_DELETE_FEED: - return (Call) WebFactory.createService(FeedModel.class, context).deleteActivity(param.getParcelable(arg_graph_params)); - case KeyUtil.MUT_DELETE_MEDIA_LIST: - return (Call) WebFactory.createService(BrowseModel.class, context).deleteMediaListEntry(param.getParcelable(arg_graph_params)); - case KeyUtil.MUT_DELETE_REVIEW: - return (Call) WebFactory.createService(BrowseModel.class, context).deleteReview(param.getParcelable(arg_graph_params)); - case KeyUtil.MUT_RATE_REVIEW: - return (Call) WebFactory.createService(BrowseModel.class, context).rateReview(param.getParcelable(arg_graph_params)); - case KeyUtil.MUT_SAVE_FEED_REPLY: - return (Call) WebFactory.createService(FeedModel.class, context).saveActivityReply(param.getParcelable(arg_graph_params)); - case KeyUtil.MUT_SAVE_MEDIA_LIST: - return (Call) WebFactory.createService(BrowseModel.class, context).saveMediaListEntry(param.getParcelable(arg_graph_params)); - case KeyUtil.MUT_SAVE_MESSAGE_FEED: - return (Call) WebFactory.createService(FeedModel.class, context).saveMessageActivity(param.getParcelable(arg_graph_params)); - case KeyUtil.MUT_SAVE_REVIEW: - return (Call) WebFactory.createService(BrowseModel.class, context).saveReview(param.getParcelable(arg_graph_params)); - case KeyUtil.MUT_SAVE_TEXT_FEED: - return (Call) WebFactory.createService(FeedModel.class, context).saveTextActivity(param.getParcelable(arg_graph_params)); - case KeyUtil.MUT_TOGGLE_FAVOURITE: - return (Call) WebFactory.createService(BaseModel.class, context).toggleFavourite(param.getParcelable(arg_graph_params)); - case KeyUtil.MUT_TOGGLE_FOLLOW: - return (Call) WebFactory.createService(UserModel.class, context).toggleFollow(param.getParcelable(arg_graph_params)); - case KeyUtil.MUT_TOGGLE_LIKE: - return (Call) WebFactory.createService(BaseModel.class, context).toggleLike(param.getParcelable(arg_graph_params)); - case KeyUtil.MUT_UPDATE_MEDIA_LISTS: - return (Call) WebFactory.createService(BrowseModel.class, context).updateMediaListEntries(param.getParcelable(arg_graph_params)); - - - case KeyUtil.STAFF_BASE_REQ: - return (Call) WebFactory.createService(StaffModel.class, context).getStaffBase(param.getParcelable(arg_graph_params)); - case KeyUtil.STAFF_MEDIA_REQ: - return (Call) WebFactory.createService(StaffModel.class, context).getStaffMedia(param.getParcelable(arg_graph_params)); - case KeyUtil.STAFF_OVERVIEW_REQ: - return (Call) WebFactory.createService(StaffModel.class, context).getStaffOverview(param.getParcelable(arg_graph_params)); - case KeyUtil.STAFF_ROLES_REQ: - return (Call) WebFactory.createService(StaffModel.class, context).getStaffRoles(param.getParcelable(arg_graph_params)); - case KeyUtil.STAFF_SEARCH_REQ: - return (Call) WebFactory.createService(SearchModel.class, context).getStaffSearch(param.getParcelable(arg_graph_params)); - - - case KeyUtil.STUDIO_BASE_REQ: - return (Call) WebFactory.createService(StudioModel.class, context).getStudioBase(param.getParcelable(arg_graph_params)); - case KeyUtil.STUDIO_MEDIA_REQ: - return (Call) WebFactory.createService(StudioModel.class, context).getStudioMedia(param.getParcelable(arg_graph_params)); - case KeyUtil.STUDIO_SEARCH_REQ: - return (Call) WebFactory.createService(SearchModel.class, context).getStudioSearch(param.getParcelable(arg_graph_params)); - - - case KeyUtil.USER_ANIME_FAVOURITES_REQ: - return (Call) WebFactory.createService(UserModel.class, context).getAnimeFavourites(param.getParcelable(arg_graph_params)); - case KeyUtil.USER_BASE_REQ: - return (Call) WebFactory.createService(UserModel.class, context).getUserBase(param.getParcelable(arg_graph_params)); - case KeyUtil.USER_CHARACTER_FAVOURITES_REQ: - return (Call) WebFactory.createService(UserModel.class, context).getCharacterFavourites(param.getParcelable(arg_graph_params)); - case KeyUtil.USER_CURRENT_REQ: - return (Call) WebFactory.createService(UserModel.class, context).getCurrentUser(param.getParcelable(arg_graph_params)); - case KeyUtil.USER_FAVOURITES_COUNT_REQ: - return (Call) WebFactory.createService(UserModel.class, context).getFavouritesCount(param.getParcelable(arg_graph_params)); - case KeyUtil.USER_FOLLOWERS_REQ: - return (Call) WebFactory.createService(UserModel.class, context).getFollowers(param.getParcelable(arg_graph_params)); - case KeyUtil.USER_FOLLOWING_REQ: - return (Call) WebFactory.createService(UserModel.class, context).getFollowing(param.getParcelable(arg_graph_params)); - case KeyUtil.USER_MANGA_FAVOURITES_REQ: - return (Call) WebFactory.createService(UserModel.class, context).getMangaFavourites(param.getParcelable(arg_graph_params)); - case KeyUtil.USER_OVERVIEW_REQ: - return (Call) WebFactory.createService(UserModel.class, context).getUserOverview(param.getParcelable(arg_graph_params)); - case KeyUtil.USER_SEARCH_REQ: - return (Call) WebFactory.createService(SearchModel.class, context).getUserSearch(param.getParcelable(arg_graph_params)); - case KeyUtil.USER_STAFF_FAVOURITES_REQ: - return (Call) WebFactory.createService(UserModel.class, context).getStaffFavourites(param.getParcelable(arg_graph_params)); - case KeyUtil.USER_STATS_REQ: - return (Call) WebFactory.createService(UserModel.class, context).getUserStats(param.getParcelable(arg_graph_params)); - case KeyUtil.USER_STUDIO_FAVOURITES_REQ: - return (Call) WebFactory.createService(UserModel.class, context).getStudioFavourites(param.getParcelable(arg_graph_params)); - case KeyUtil.USER_NOTIFICATION_REQ: - return (Call) WebFactory.createService(UserModel.class, context).getUserNotifications(param.getParcelable(arg_graph_params)); - } - } - return null; - } - - @Override - protected void onPostExecute(Call call) { - if(!isCancelled() && call != null && callback != null) - call.enqueue(callback); - } - - @Override - protected void onCancelled(Call call) { - if(call != null) - call.cancel(); - callback = null; - super.onCancelled(call); - } -} diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/async/RequestHandler.kt b/app/src/main/java/com/mxt/anitrend/base/custom/async/RequestHandler.kt new file mode 100644 index 000000000..0a1e78442 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/base/custom/async/RequestHandler.kt @@ -0,0 +1,166 @@ +package com.mxt.anitrend.base.custom.async + +import android.content.Context +import android.os.AsyncTask +import android.os.Bundle + +import com.mxt.anitrend.BuildConfig +import com.mxt.anitrend.model.api.retro.WebFactory +import com.mxt.anitrend.model.api.retro.anilist.BaseModel +import com.mxt.anitrend.model.api.retro.anilist.BrowseModel +import com.mxt.anitrend.model.api.retro.anilist.CharacterModel +import com.mxt.anitrend.model.api.retro.anilist.FeedModel +import com.mxt.anitrend.model.api.retro.anilist.MediaModel +import com.mxt.anitrend.model.api.retro.anilist.SearchModel +import com.mxt.anitrend.model.api.retro.anilist.StaffModel +import com.mxt.anitrend.model.api.retro.anilist.StudioModel +import com.mxt.anitrend.model.api.retro.anilist.UserModel +import com.mxt.anitrend.util.KeyUtil + +import retrofit2.Call +import retrofit2.Callback + +import com.mxt.anitrend.util.KeyUtil.EPISODE_FEED_REQ +import com.mxt.anitrend.util.KeyUtil.EPISODE_LATEST_REQ +import com.mxt.anitrend.util.KeyUtil.EPISODE_POPULAR_REQ +import com.mxt.anitrend.util.KeyUtil.GENRE_COLLECTION_REQ +import com.mxt.anitrend.util.KeyUtil.GIPHY_SEARCH_REQ +import com.mxt.anitrend.util.KeyUtil.GIPHY_TRENDING_REQ +import com.mxt.anitrend.util.KeyUtil.MEDIA_TAG_REQ +import com.mxt.anitrend.util.KeyUtil.PAGING_LIMIT +import com.mxt.anitrend.util.KeyUtil.RequestType +import com.mxt.anitrend.util.KeyUtil.UPDATE_CHECKER_REQ +import com.mxt.anitrend.util.KeyUtil.arg_branch_name +import com.mxt.anitrend.util.KeyUtil.arg_feed +import com.mxt.anitrend.util.KeyUtil.arg_graph_params +import com.mxt.anitrend.util.KeyUtil.arg_page_offset +import com.mxt.anitrend.util.KeyUtil.arg_search + +/** + * Created by max on 2017/09/16. + * Handles all service creation for Retrofit Endpoints on a background task, + * which allows us to perform heavy operations such as token refreshing on demand + */ + +@Suppress("UNCHECKED_CAST") +class RequestHandler( + private val param: Bundle, + private var callback: Callback?, + @field:RequestType + private val requestType: Int +) : AsyncTask>() { + + override fun doInBackground(vararg contexts: Context): Call? { + if (!isCancelled && callback != null) { + val context = contexts[0] + when (requestType) { + GENRE_COLLECTION_REQ -> return WebFactory.createService(BaseModel::class.java, context).getGenres(param.getParcelable(arg_graph_params)) as Call + MEDIA_TAG_REQ -> return WebFactory.createService(BaseModel::class.java, context).getTags(param.getParcelable(arg_graph_params)) as Call + + + EPISODE_FEED_REQ -> return WebFactory.createCrunchyService(param.getBoolean(arg_feed), context).getRSS(param.getString(arg_search)) as Call + EPISODE_LATEST_REQ -> return WebFactory.createCrunchyService(param.getBoolean(arg_feed), context).latestFeed as Call + EPISODE_POPULAR_REQ -> return WebFactory.createCrunchyService(param.getBoolean(arg_feed), context).popularFeed as Call + + + GIPHY_SEARCH_REQ -> return WebFactory.createGiphyService(context).findGif(BuildConfig.GIPHY_KEY, param.getString(arg_search), + PAGING_LIMIT, param.getInt(arg_page_offset), "PG", "en") as Call + GIPHY_TRENDING_REQ -> return WebFactory.createGiphyService(context).getTrending(BuildConfig.GIPHY_KEY, PAGING_LIMIT, param.getInt(arg_page_offset), "PG") as Call + + + UPDATE_CHECKER_REQ -> return WebFactory.createRepositoryService().checkVersion(param.getString(arg_branch_name)) as Call + + + KeyUtil.MEDIA_LIST_COLLECTION_REQ -> return WebFactory.createService(BrowseModel::class.java, context).getMediaListCollection(param.getParcelable(arg_graph_params)) as Call + KeyUtil.MEDIA_BROWSE_REQ -> return WebFactory.createService(BrowseModel::class.java, context).getMediaBrowse(param.getParcelable(arg_graph_params)) as Call + KeyUtil.MEDIA_LIST_BROWSE_REQ -> return WebFactory.createService(BrowseModel::class.java, context).getMediaListBrowse(param.getParcelable(arg_graph_params)) as Call + KeyUtil.MEDIA_LIST_REQ -> return WebFactory.createService(BrowseModel::class.java, context).getMediaList(param.getParcelable(arg_graph_params)) as Call + KeyUtil.MEDIA_WITH_LIST_REQ -> return WebFactory.createService(BrowseModel::class.java, context).getMediaWithList(param.getParcelable(arg_graph_params)) as Call + + + KeyUtil.CHARACTER_ACTORS_REQ -> return WebFactory.createService(CharacterModel::class.java, context).getCharacterActors(param.getParcelable(arg_graph_params)) as Call + KeyUtil.CHARACTER_BASE_REQ -> return WebFactory.createService(CharacterModel::class.java, context).getCharacterBase(param.getParcelable(arg_graph_params)) as Call + KeyUtil.CHARACTER_MEDIA_REQ -> return WebFactory.createService(CharacterModel::class.java, context).getCharacterMedia(param.getParcelable(arg_graph_params)) as Call + KeyUtil.CHARACTER_OVERVIEW_REQ -> return WebFactory.createService(CharacterModel::class.java, context).getCharacterOverview(param.getParcelable(arg_graph_params)) as Call + KeyUtil.CHARACTER_SEARCH_REQ -> return WebFactory.createService(SearchModel::class.java, context).getCharacterSearch(param.getParcelable(arg_graph_params)) as Call + + + KeyUtil.FEED_LIST_REPLY_REQ -> return WebFactory.createService(FeedModel::class.java, context).getFeedListReply(param.getParcelable(arg_graph_params)) as Call + KeyUtil.FEED_LIST_REQ -> return WebFactory.createService(FeedModel::class.java, context).getFeedList(param.getParcelable(arg_graph_params)) as Call + KeyUtil.FEED_MESSAGE_REQ -> return WebFactory.createService(FeedModel::class.java, context).getFeedMessage(param.getParcelable(arg_graph_params)) as Call + + + KeyUtil.MEDIA_BASE_REQ -> return WebFactory.createService(MediaModel::class.java, context).getMediaBase(param.getParcelable(arg_graph_params)) as Call + KeyUtil.MEDIA_CHARACTERS_REQ -> return WebFactory.createService(MediaModel::class.java, context).getMediaCharacters(param.getParcelable(arg_graph_params)) as Call + KeyUtil.MEDIA_EPISODES_REQ -> return WebFactory.createService(MediaModel::class.java, context).getMediaEpisodes(param.getParcelable(arg_graph_params)) as Call + KeyUtil.MEDIA_OVERVIEW_REQ -> return WebFactory.createService(MediaModel::class.java, context).getMediaOverview(param.getParcelable(arg_graph_params)) as Call + KeyUtil.MEDIA_RELATION_REQ -> return WebFactory.createService(MediaModel::class.java, context).getMediaRelations(param.getParcelable(arg_graph_params)) as Call + KeyUtil.MEDIA_REVIEWS_REQ -> return WebFactory.createService(BrowseModel::class.java, context).getReviewBrowse(param.getParcelable(arg_graph_params)) as Call + KeyUtil.MEDIA_SEARCH_REQ -> return WebFactory.createService(SearchModel::class.java, context).getMediaSearch(param.getParcelable(arg_graph_params)) as Call + KeyUtil.MEDIA_SOCIAL_REQ -> return WebFactory.createService(MediaModel::class.java, context).getMediaSocial(param.getParcelable(arg_graph_params)) as Call + KeyUtil.MEDIA_STAFF_REQ -> return WebFactory.createService(MediaModel::class.java, context).getMediaStaff(param.getParcelable(arg_graph_params)) as Call + KeyUtil.MEDIA_STATS_REQ -> return WebFactory.createService(MediaModel::class.java, context).getMediaStats(param.getParcelable(arg_graph_params)) as Call + /*case KeyUtils.MEDIA_TREND_REQ: + return (Call) WebFactory.createService(BrowseModel.class, context).getMediaTrends(param.getParcelable(arg_graph_params));*/ + + + KeyUtil.MUT_DELETE_FEED_REPLY -> return WebFactory.createService(FeedModel::class.java, context).deleteActivityReply(param.getParcelable(arg_graph_params)) as Call + KeyUtil.MUT_DELETE_FEED -> return WebFactory.createService(FeedModel::class.java, context).deleteActivity(param.getParcelable(arg_graph_params)) as Call + KeyUtil.MUT_DELETE_MEDIA_LIST -> return WebFactory.createService(BrowseModel::class.java, context).deleteMediaListEntry(param.getParcelable(arg_graph_params)) as Call + KeyUtil.MUT_DELETE_REVIEW -> return WebFactory.createService(BrowseModel::class.java, context).deleteReview(param.getParcelable(arg_graph_params)) as Call + KeyUtil.MUT_RATE_REVIEW -> return WebFactory.createService(BrowseModel::class.java, context).rateReview(param.getParcelable(arg_graph_params)) as Call + KeyUtil.MUT_SAVE_FEED_REPLY -> return WebFactory.createService(FeedModel::class.java, context).saveActivityReply(param.getParcelable(arg_graph_params)) as Call + KeyUtil.MUT_SAVE_MEDIA_LIST -> return WebFactory.createService(BrowseModel::class.java, context).saveMediaListEntry(param.getParcelable(arg_graph_params)) as Call + KeyUtil.MUT_SAVE_MESSAGE_FEED -> return WebFactory.createService(FeedModel::class.java, context).saveMessageActivity(param.getParcelable(arg_graph_params)) as Call + KeyUtil.MUT_SAVE_REVIEW -> return WebFactory.createService(BrowseModel::class.java, context).saveReview(param.getParcelable(arg_graph_params)) as Call + KeyUtil.MUT_SAVE_TEXT_FEED -> return WebFactory.createService(FeedModel::class.java, context).saveTextActivity(param.getParcelable(arg_graph_params)) as Call + KeyUtil.MUT_TOGGLE_FAVOURITE -> return WebFactory.createService(BaseModel::class.java, context).toggleFavourite(param.getParcelable(arg_graph_params)) as Call + KeyUtil.MUT_TOGGLE_FOLLOW -> return WebFactory.createService(UserModel::class.java, context).toggleFollow(param.getParcelable(arg_graph_params)) as Call + KeyUtil.MUT_TOGGLE_LIKE -> return WebFactory.createService(BaseModel::class.java, context).toggleLike(param.getParcelable(arg_graph_params)) as Call + KeyUtil.MUT_UPDATE_MEDIA_LISTS -> return WebFactory.createService(BrowseModel::class.java, context).updateMediaListEntries(param.getParcelable(arg_graph_params)) as Call + + + KeyUtil.STAFF_BASE_REQ -> return WebFactory.createService(StaffModel::class.java, context).getStaffBase(param.getParcelable(arg_graph_params)) as Call + KeyUtil.STAFF_MEDIA_REQ -> return WebFactory.createService(StaffModel::class.java, context).getStaffMedia(param.getParcelable(arg_graph_params)) as Call + KeyUtil.STAFF_OVERVIEW_REQ -> return WebFactory.createService(StaffModel::class.java, context).getStaffOverview(param.getParcelable(arg_graph_params)) as Call + KeyUtil.STAFF_ROLES_REQ -> return WebFactory.createService(StaffModel::class.java, context).getStaffRoles(param.getParcelable(arg_graph_params)) as Call + KeyUtil.STAFF_SEARCH_REQ -> return WebFactory.createService(SearchModel::class.java, context).getStaffSearch(param.getParcelable(arg_graph_params)) as Call + + + KeyUtil.STUDIO_BASE_REQ -> return WebFactory.createService(StudioModel::class.java, context).getStudioBase(param.getParcelable(arg_graph_params)) as Call + KeyUtil.STUDIO_MEDIA_REQ -> return WebFactory.createService(StudioModel::class.java, context).getStudioMedia(param.getParcelable(arg_graph_params)) as Call + KeyUtil.STUDIO_SEARCH_REQ -> return WebFactory.createService(SearchModel::class.java, context).getStudioSearch(param.getParcelable(arg_graph_params)) as Call + + + KeyUtil.USER_ANIME_FAVOURITES_REQ -> return WebFactory.createService(UserModel::class.java, context).getAnimeFavourites(param.getParcelable(arg_graph_params)) as Call + KeyUtil.USER_BASE_REQ -> return WebFactory.createService(UserModel::class.java, context).getUserBase(param.getParcelable(arg_graph_params)) as Call + KeyUtil.USER_CHARACTER_FAVOURITES_REQ -> return WebFactory.createService(UserModel::class.java, context).getCharacterFavourites(param.getParcelable(arg_graph_params)) as Call + KeyUtil.USER_CURRENT_REQ -> return WebFactory.createService(UserModel::class.java, context).getCurrentUser(param.getParcelable(arg_graph_params)) as Call + KeyUtil.USER_FAVOURITES_COUNT_REQ -> return WebFactory.createService(UserModel::class.java, context).getFavouritesCount(param.getParcelable(arg_graph_params)) as Call + KeyUtil.USER_FOLLOWERS_REQ -> return WebFactory.createService(UserModel::class.java, context).getFollowers(param.getParcelable(arg_graph_params)) as Call + KeyUtil.USER_FOLLOWING_REQ -> return WebFactory.createService(UserModel::class.java, context).getFollowing(param.getParcelable(arg_graph_params)) as Call + KeyUtil.USER_MANGA_FAVOURITES_REQ -> return WebFactory.createService(UserModel::class.java, context).getMangaFavourites(param.getParcelable(arg_graph_params)) as Call + KeyUtil.USER_OVERVIEW_REQ -> return WebFactory.createService(UserModel::class.java, context).getUserOverview(param.getParcelable(arg_graph_params)) as Call + KeyUtil.USER_SEARCH_REQ -> return WebFactory.createService(SearchModel::class.java, context).getUserSearch(param.getParcelable(arg_graph_params)) as Call + KeyUtil.USER_STAFF_FAVOURITES_REQ -> return WebFactory.createService(UserModel::class.java, context).getStaffFavourites(param.getParcelable(arg_graph_params)) as Call + KeyUtil.USER_STATS_REQ -> return WebFactory.createService(UserModel::class.java, context).getUserStats(param.getParcelable(arg_graph_params)) as Call + KeyUtil.USER_STUDIO_FAVOURITES_REQ -> return WebFactory.createService(UserModel::class.java, context).getStudioFavourites(param.getParcelable(arg_graph_params)) as Call + KeyUtil.USER_NOTIFICATION_REQ -> return WebFactory.createService(UserModel::class.java, context).getUserNotifications(param.getParcelable(arg_graph_params)) as Call + } + } + return null + } + + override fun onPostExecute(call: Call?) { + if (!isCancelled && call != null) + callback?.also { + call.enqueue(it) + } + } + + override fun onCancelled(call: Call?) { + call?.cancel() + callback = null + super.onCancelled(call) + } +} diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/async/ThreadPool.java b/app/src/main/java/com/mxt/anitrend/base/custom/async/ThreadPool.java deleted file mode 100644 index 863d44ab8..000000000 --- a/app/src/main/java/com/mxt/anitrend/base/custom/async/ThreadPool.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.mxt.anitrend.base.custom.async; - -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -/** - * Created by max on 2018/02/20. - */ - -public class ThreadPool { - - private ExecutorService executorService; - - private ThreadPool() { - - } - - public ExecutorService getExecutorService() { - if(executorService == null) - executorService = Executors.newCachedThreadPool(); - return executorService; - } - - public void execute(Runnable runnable) { - getExecutorService().execute(runnable); - } - - public static class Builder { - - private ThreadPool threadPool; - - public Builder() { - this.threadPool = new ThreadPool(); - } - - public ThreadPool build() { - return threadPool; - } - } -} diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/async/ThreadPool.kt b/app/src/main/java/com/mxt/anitrend/base/custom/async/ThreadPool.kt new file mode 100644 index 000000000..a9cb15a14 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/base/custom/async/ThreadPool.kt @@ -0,0 +1,15 @@ +package com.mxt.anitrend.base.custom.async + +import java.util.concurrent.Executors + +/** + * Created by max on 2018/02/20. + */ + +object ThreadPool { + + private val executorService = Executors.newCachedThreadPool() + + fun execute(task: () -> Unit) = + executorService.execute(task) +} 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 f91ec0b08..9299a9782 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 @@ -6,20 +6,24 @@ import androidx.annotation.NonNull; import android.util.Log; +import com.mxt.anitrend.analytics.contract.ISupportAnalytics; import com.mxt.anitrend.base.custom.presenter.CommonPresenter; import com.mxt.anitrend.base.interfaces.dao.BoxQuery; import com.mxt.anitrend.data.DatabaseHelper; +import com.mxt.anitrend.extension.AppExtKt; +import com.mxt.anitrend.extension.KoinExt; import com.mxt.anitrend.model.api.retro.WebFactory; import com.mxt.anitrend.model.entity.anilist.WebToken; import com.mxt.anitrend.model.entity.base.AuthBase; import com.mxt.anitrend.presenter.base.BasePresenter; -import com.mxt.anitrend.util.AnalyticsUtil; -import com.mxt.anitrend.util.ApplicationPref; +import com.mxt.anitrend.util.Settings; import com.mxt.anitrend.util.JobSchedulerUtil; import com.mxt.anitrend.util.ShortcutUtil; import java.util.concurrent.ExecutionException; +import timber.log.Timber; + /** * Created by max on 2017/10/14. * Web token requester @@ -29,6 +33,7 @@ public class WebTokenRequest { private static final Object lock = new Object(); + private final static String TAG = "WebTokenRequest"; private static volatile WebToken token; public static WebToken getInstance() { @@ -41,14 +46,14 @@ public static WebToken getInstance() { */ public static void invalidateInstance(Context context) { CommonPresenter presenter = new BasePresenter(context); - presenter.getApplicationPref().setAuthenticated(false); + presenter.getSettings().setAuthenticated(false); presenter.getDatabase().invalidateBoxStores(); JobSchedulerUtil.INSTANCE.cancelJob(); WebFactory.invalidate(); token = null; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) ShortcutUtil.removeAllDynamicShortcuts(context); - AnalyticsUtil.clearSession(); + KoinExt.get(ISupportAnalytics.class).clearUserSession(); } /** @@ -60,10 +65,11 @@ private static void checkTokenState(Context context, BasePresenter presenter) { WebToken response = WebFactory.requestCodeTokenSync(presenter.getDatabase().getAuthCode().getCode()); if(response != null) { createNewTokenReference(response); - presenter.getDatabase().saveWebToken(response); - Log.d("WebTokenRequest", "Token refreshed & saved at time stamp: " + System.currentTimeMillis()/1000L); + presenter.getDatabase().setWebToken(response); + Timber.tag(TAG).d("Token refreshed & saved at time stamp: %s", System.currentTimeMillis() / 1000L); } - else Log.e("WebTokenRequest", "Token had an invalid instance from context: "+context); + else + Timber.tag(TAG).e("Token had an invalid instance from context: %s", context); } } @@ -74,7 +80,7 @@ private static void checkTokenState(Context context, BasePresenter presenter) { */ public static void getToken(Context context) { synchronized (lock) { - if(new ApplicationPref(context).isAuthenticated()) { + if(new Settings(context).isAuthenticated()) { BasePresenter presenter = new BasePresenter(context); if (token == null || token.getExpires() < (System.currentTimeMillis() / 1000L)) { token = presenter.getDatabase().getWebToken(); @@ -93,8 +99,8 @@ public static synchronized boolean getToken(String code) throws ExecutionExcepti if(authenticatedToken != null) { createNewTokenReference(authenticatedToken); BoxQuery boxQuery = new DatabaseHelper(); - boxQuery.saveWebToken(authenticatedToken); - boxQuery.saveAuthCode(new AuthBase(code, authenticatedToken.getRefresh_token())); + boxQuery.setWebToken(authenticatedToken); + boxQuery.setAuthCode(new AuthBase(code, authenticatedToken.getRefresh_token())); return true; } return false; @@ -109,7 +115,7 @@ private static void createNewTokenReference(@NonNull WebToken webToken) { webToken.calculateExpires(); token = webToken.clone(); } catch (CloneNotSupportedException e) { - Log.e("createNewTokenReference", e.getMessage()); + Timber.tag(TAG).e(e,"createNewTokenReference failed"); } } diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/fragment/FragmentBase.java b/app/src/main/java/com/mxt/anitrend/base/custom/fragment/FragmentBase.java index 77764aa39..4e4342652 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/fragment/FragmentBase.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/fragment/FragmentBase.java @@ -1,6 +1,8 @@ package com.mxt.anitrend.base.custom.fragment; import android.app.Activity; + +import androidx.lifecycle.Lifecycle; import androidx.lifecycle.Observer; import androidx.lifecycle.ViewModelProviders; import android.content.SharedPreferences; @@ -23,19 +25,22 @@ import com.annimon.stream.IntPair; import com.mxt.anitrend.R; +import com.mxt.anitrend.analytics.contract.ISupportAnalytics; import com.mxt.anitrend.base.custom.presenter.CommonPresenter; import com.mxt.anitrend.base.custom.sheet.BottomSheetBase; import com.mxt.anitrend.base.custom.viewmodel.ViewModelBase; import com.mxt.anitrend.base.interfaces.event.ActionModeListener; import com.mxt.anitrend.base.interfaces.event.ItemClickListener; import com.mxt.anitrend.base.interfaces.event.ResponseCallback; +import com.mxt.anitrend.extension.AppExtKt; +import com.mxt.anitrend.extension.KoinExt; import com.mxt.anitrend.util.ActionModeUtil; -import com.mxt.anitrend.util.AnalyticsUtil; import com.mxt.anitrend.util.MediaActionUtil; import org.greenrobot.eventbus.EventBus; import butterknife.Unbinder; +import timber.log.Timber; public abstract class FragmentBase extends Fragment implements View.OnClickListener, ActionModeListener, SharedPreferences.OnSharedPreferenceChangeListener, CommonPresenter.AbstractPresenter

, Observer, ResponseCallback, ItemClickListener { @@ -53,14 +58,14 @@ public abstract class FragmentBase extends Fra protected Unbinder unbinder; protected @IntegerRes int mColumnSize; - public String TAG; + public final String TAG = getClass().getSimpleName(); @Override public void onCreate(@Nullable Bundle savedInstanceState) { - TAG = this.toString(); super.onCreate(savedInstanceState); setRetainInstance(true); - AnalyticsUtil.logCurrentScreen(getActivity(), TAG); + if (getActivity() != null) + KoinExt.get(ISupportAnalytics.class).logCurrentScreen(getActivity(), TAG); } /** @@ -105,11 +110,6 @@ public void onDestroyView() { actionMode = null; } - /** - * Called when the Fragment is visible to the user. This is generally - * tied to {@link Activity#onStart() Activity.onStart} of the containing - * Activity's lifecycle. - */ @Override public void onStart() { super.onStart(); @@ -119,11 +119,6 @@ public void onStart() { setHasOptionsMenu(true); } - /** - * Called when the Fragment is no longer started. This is generally - * tied to {@link Activity#onStop() Activity.onStop} of the containing - * Activity's lifecycle. - */ @Override public void onStop() { if(EventBus.getDefault().isRegistered(this)) @@ -131,11 +126,6 @@ public void onStop() { super.onStop(); } - /** - * Called when the Fragment is no longer resumed. This is generally - * tied to {@link Activity#onPause() Activity.onPause} of the containing - * Activity's lifecycle. - */ @Override public void onPause() { super.onPause(); @@ -145,12 +135,6 @@ public void onPause() { presenter.onPause(this); } - /** - * Called when the fragment is visible to the user and actively running. - * This is generally - * tied to {@link Activity#onResume() Activity.onResume} of the containing - * Activity's lifecycle. - */ @Override public void onResume() { super.onResume(); @@ -195,8 +179,8 @@ public void setInflateMenu(@MenuRes int inflateMenu) { * @return true if the fragment is still valid otherwise false */ protected boolean isAlive() { - //return getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED); - return isVisible() || !isDetached() || !isRemoving(); + return getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED); + // return isVisible() || !isDetached() || !isRemoving(); } /** @@ -331,22 +315,19 @@ public void onDestroyActionMode(ActionMode mode) { @Override public void showError(String error) { - if(!TextUtils.isEmpty(error)) { - Log.e(TAG, error); - if (getPresenter() != null && getPresenter().getApplicationPref().isCrashReportsEnabled()) - AnalyticsUtil.reportException(TAG, error); - } + if(!TextUtils.isEmpty(error)) + Timber.tag(TAG).d(error); } @Override public void showEmpty(String message) { if(!TextUtils.isEmpty(message)) - Log.d(TAG, message); + Timber.tag(TAG).i(message); } @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - Log.i(TAG, key); + Timber.tag(TAG).i(key); } protected void showBottomSheet() { 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 069f4b5b9..4e3a056a2 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 @@ -45,6 +45,7 @@ import butterknife.BindView; import butterknife.ButterKnife; +import timber.log.Timber; /** * Created by max on 2017/11/04. @@ -66,6 +67,8 @@ public abstract class FragmentChannelBase extends FragmentBase mAdapter; private StaggeredGridLayoutManager mLayoutManager; + private final String TAG = FragmentBase.class.getSimpleName(); + private final View.OnClickListener stateLayoutOnClick = view -> { if(swipeRefreshLayout.isRefreshing()) swipeRefreshLayout.setRefreshing(false); @@ -334,7 +337,7 @@ public void onChanged(@Nullable Rss content) { showEmpty(getString(R.string.layout_empty_response)); } catch (Exception e) { e.printStackTrace(); - Log.e("onChanged(Rss content)", e.getLocalizedMessage()); + Timber.tag("onChanged(Rss content)").e(e); showEmpty(getString(R.string.layout_empty_response)); } } @@ -349,29 +352,27 @@ public void onChanged(@Nullable Rss content) { */ @Override public void onItemClick(View target, IntPair data) { - switch (target.getId()) { - case R.id.series_image: - DialogUtil.createMessage(getActivity(), data.getSecond().getTitle(), data.getSecond().getDescription()+"

"+copyright, - R.string.Watch, R.string.Dismiss, R.string.action_search, (dialog, which) -> { - Intent intent; - switch (which) { - case POSITIVE: - if(data.getSecond().getLink() != null) { - intent = new Intent(Intent.ACTION_VIEW, Uri.parse(data.getSecond().getLink())); - startActivity(intent); - } else - NotifyUtil.makeText(getActivity(), R.string.text_premium_show, Toast.LENGTH_SHORT).show(); - break; - case NEUTRAL: - if(getActivity() != null) { - intent = new Intent(getActivity(), SearchActivity.class); - intent.putExtra(KeyUtil.arg_search, EpisodeUtil.INSTANCE.getActualTile(data.getSecond().getTitle())); - getActivity().startActivity(intent); - } - break; - } - }); - break; + if (target.getId() == R.id.series_image) { + DialogUtil.createMessage(getActivity(), data.getSecond().getTitle(), data.getSecond().getDescription() + "

" + copyright, + R.string.Watch, R.string.Dismiss, R.string.action_search, (dialog, which) -> { + Intent intent; + switch (which) { + case POSITIVE: + if (data.getSecond().getLink() != null) { + intent = new Intent(Intent.ACTION_VIEW, Uri.parse(data.getSecond().getLink())); + startActivity(intent); + } else + NotifyUtil.makeText(getActivity(), R.string.text_premium_show, Toast.LENGTH_SHORT).show(); + break; + case NEUTRAL: + if (getActivity() != null) { + intent = new Intent(getActivity(), SearchActivity.class); + 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/presenter/CommonPresenter.java b/app/src/main/java/com/mxt/anitrend/base/custom/presenter/CommonPresenter.java index a4828dd37..07d920076 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/presenter/CommonPresenter.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/presenter/CommonPresenter.java @@ -8,7 +8,7 @@ import com.mxt.anitrend.base.interfaces.dao.BoxQuery; import com.mxt.anitrend.base.interfaces.event.LifecycleListener; import com.mxt.anitrend.data.DatabaseHelper; -import com.mxt.anitrend.util.ApplicationPref; +import com.mxt.anitrend.util.Settings; import org.greenrobot.eventbus.EventBus; @@ -23,7 +23,7 @@ public abstract class CommonPresenter extends RecyclerScrollListener implements private Bundle bundle; private Context context; private BoxQuery databaseHelper; - private ApplicationPref applicationPref; + private Settings settings; public CommonPresenter(Context context) { this.context = context; @@ -55,7 +55,7 @@ public BoxQuery getDatabase() { @Override public void onPause(SharedPreferences.OnSharedPreferenceChangeListener changeListener) { if(changeListener != null) - getApplicationPref().getSharedPreferences() + getSettings().getSharedPreferences() .unregisterOnSharedPreferenceChangeListener(changeListener); } @@ -65,7 +65,7 @@ public void onPause(SharedPreferences.OnSharedPreferenceChangeListener changeLis @Override public void onResume(SharedPreferences.OnSharedPreferenceChangeListener changeListener) { if(changeListener != null) - getApplicationPref().getSharedPreferences() + getSettings().getSharedPreferences() .registerOnSharedPreferenceChangeListener(changeListener); } @@ -78,10 +78,10 @@ public void onDestroy() { bundle = null; } - public ApplicationPref getApplicationPref() { - if(applicationPref == null) - applicationPref = new ApplicationPref(context); - return applicationPref; + public Settings getSettings() { + if(settings == null) + settings = new Settings(context); + return settings; } /** 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 112c0fa8d..28e002ae5 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 @@ -27,6 +27,7 @@ import butterknife.BindView; import butterknife.Unbinder; +import timber.log.Timber; /** * Created by max on 2017/11/02. @@ -230,11 +231,11 @@ public BottomSheetBuilder setNegativeText(@StringRes int negativeText) { @Override public void showError(String error) { - Log.e(TAG, error); + Timber.tag(TAG).e(error); } @Override public void showEmpty(String message) { - Log.d(TAG, message); + Timber.tag(TAG).d(message); } } 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 42525bdcf..99eb7a6d3 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 @@ -22,6 +22,7 @@ import java.util.List; import butterknife.BindView; +import timber.log.Timber; public abstract class BottomSheetList extends BottomSheetBase> implements ItemClickListener, Observer>, RecyclerLoadListener, CustomSwipeRefreshLayout.OnRefreshAndLoadListener { @@ -152,7 +153,7 @@ public void onLoadMore() { */ @Override public void onChanged(@Nullable List data) { - Log.d(TAG, "onChanged(@Nullable List data) invoked"); + Timber.tag(TAG).d("onChanged(@Nullable List data) invoked"); } @Override diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/image/AvatarImageView.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/image/AvatarImageView.java deleted file mode 100644 index 40847362c..000000000 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/image/AvatarImageView.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.mxt.anitrend.base.custom.view.image; - -import android.content.Context; -import androidx.databinding.BindingAdapter; -import androidx.appcompat.widget.AppCompatImageView; -import android.util.AttributeSet; - -import com.bumptech.glide.Glide; -import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions; -import com.bumptech.glide.request.RequestOptions; -import com.mxt.anitrend.R; -import com.mxt.anitrend.base.interfaces.view.CustomView; -import com.mxt.anitrend.model.entity.anilist.meta.ImageBase; - -/** - * Created by max on 2017/10/29. - * Circle image view - */ - -public class AvatarImageView extends AppCompatImageView implements CustomView { - - public AvatarImageView(Context context) { - super(context); - onInit(); - } - - public AvatarImageView(Context context, AttributeSet attrs) { - super(context, attrs); - onInit(); - } - - public AvatarImageView(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - onInit(); - } - - /** - * Optionally included when constructing custom views - */ - @Override - public void onInit() { - - } - - /** - * Clean up any resources that won't be needed - */ - @Override - public void onViewRecycled() { - - } - - @BindingAdapter({"avatarUrl"}) - public static void setImage(AvatarImageView view, String url) { - Glide.with(view.getContext()).load(url).apply(RequestOptions.centerCropTransform()) - .apply(RequestOptions.placeholderOf(R.drawable.avatar_placeholder)) - .transition(DrawableTransitionOptions.withCrossFade(150)) - .apply(RequestOptions.circleCropTransform()) - .into(view); - } - - @BindingAdapter({"avatarUrl"}) - public static void setImage(AvatarImageView view, ImageBase imageBase) { - setImage(view, imageBase.getLarge()); - } -} diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/image/AvatarImageView.kt b/app/src/main/java/com/mxt/anitrend/base/custom/view/image/AvatarImageView.kt new file mode 100644 index 000000000..9b58f6c28 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/image/AvatarImageView.kt @@ -0,0 +1,47 @@ +package com.mxt.anitrend.base.custom.view.image + +import android.content.Context +import androidx.databinding.BindingAdapter +import androidx.appcompat.widget.AppCompatImageView +import android.util.AttributeSet + +import com.bumptech.glide.Glide +import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions +import com.bumptech.glide.request.RequestOptions +import com.mxt.anitrend.R +import com.mxt.anitrend.base.interfaces.view.CustomView +import com.mxt.anitrend.model.entity.anilist.meta.ImageBase + +/** + * Created by max on 2017/10/29. + * Circle image view + */ + +class AvatarImageView : AppCompatImageView, 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() + } + + /** + * Optionally included when constructing custom views + */ + override fun onInit() { + + } + + /** + * Clean up any resources that won't be needed + */ + override fun onViewRecycled() { + Glide.with(context).clear(this) + } +} diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/image/AvatarIndicatorView.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/image/AvatarIndicatorView.java deleted file mode 100644 index 6cb4708ea..000000000 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/image/AvatarIndicatorView.java +++ /dev/null @@ -1,142 +0,0 @@ -package com.mxt.anitrend.base.custom.view.image; - -import android.content.Context; -import android.content.Intent; -import android.util.AttributeSet; -import android.view.View; -import android.widget.FrameLayout; - -import com.mxt.anitrend.R; -import com.mxt.anitrend.base.custom.consumer.BaseConsumer; -import com.mxt.anitrend.base.interfaces.view.CustomView; -import com.mxt.anitrend.databinding.WidgetAvatarIndicatorBinding; -import com.mxt.anitrend.model.entity.anilist.User; -import com.mxt.anitrend.presenter.base.BasePresenter; -import com.mxt.anitrend.presenter.widget.WidgetPresenter; -import com.mxt.anitrend.util.CompatUtil; -import com.mxt.anitrend.util.DateUtil; -import com.mxt.anitrend.util.KeyUtil; -import com.mxt.anitrend.view.activity.detail.NotificationActivity; -import com.mxt.anitrend.view.activity.detail.ProfileActivity; -import com.mxt.anitrend.view.activity.index.LoginActivity; - -import org.greenrobot.eventbus.EventBus; -import org.greenrobot.eventbus.Subscribe; -import org.greenrobot.eventbus.ThreadMode; - -/** - * Created by max on 2017/11/30. - * avatar image view which will be capable of displaying - * current notification count. - */ - -public class AvatarIndicatorView extends FrameLayout implements CustomView, View.OnClickListener, BaseConsumer.onRequestModelChange { - - private WidgetAvatarIndicatorBinding binding; - private BasePresenter presenter; - private User currentUser; - private long mLastSynced; - - public AvatarIndicatorView(Context context) { - super(context); - onInit(); - } - - public AvatarIndicatorView(Context context, AttributeSet attrs) { - super(context, attrs); - onInit(); - } - - public AvatarIndicatorView(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - onInit(); - } - - @Override - public void onInit() { - presenter = new WidgetPresenter<>(getContext()); - binding = WidgetAvatarIndicatorBinding.inflate(CompatUtil.INSTANCE.getLayoutInflater(getContext()), this, true); - binding.setOnClickListener(this); - checkLastSyncTime(); - } - - private void checkLastSyncTime() { - if(presenter.getApplicationPref().isAuthenticated()) { - if((currentUser = presenter.getDatabase().getCurrentUser()) != null) { - AvatarImageView.setImage(binding.userAvatar, currentUser.getAvatar()); - if (currentUser.getUnreadNotificationCount() > 0) { - binding.notificationCount.setText(String.valueOf(currentUser.getUnreadNotificationCount())); - showNotificationWidget(); - } else - hideNotificationCountWidget(); - } else - hideNotificationCountWidget(); - } - } - - @Override - public void onViewRecycled() { - if(presenter != null) - presenter.onDestroy(); - } - - @Override @Subscribe(threadMode = ThreadMode.MAIN_ORDERED) - public void onModelChanged(BaseConsumer consumer) { - if(consumer.getRequestMode() == KeyUtil.USER_CURRENT_REQ) { - if (DateUtil.INSTANCE.timeDifferenceSatisfied(KeyUtil.TIME_UNIT_MINUTES, mLastSynced, 15)) - mLastSynced = System.currentTimeMillis(); - checkLastSyncTime(); - } - } - - private void showNotificationWidget() { - binding.notificationCount.setVisibility(VISIBLE); - binding.container.setVisibility(VISIBLE); - binding.executePendingBindings(); - invalidate(); - } - - private void hideNotificationCountWidget() { - binding.notificationCount.setVisibility(GONE); - binding.container.setVisibility(GONE); - binding.executePendingBindings(); - invalidate(); - } - - @Override - public void onClick(View view) { - if(presenter.getApplicationPref().isAuthenticated() && currentUser != null) { - if (view.getId() == R.id.user_avatar) { - Intent intent; - if (currentUser.getUnreadNotificationCount() > 0) { - intent = new Intent(getContext(), NotificationActivity.class); - hideNotificationCountWidget(); - } - else { - intent = new Intent(getContext(), ProfileActivity.class); - intent.putExtra(KeyUtil.arg_userName, currentUser.getName()); - } - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - getContext().startActivity(intent); - } - } else { - Intent intent = new Intent(getContext(), LoginActivity.class); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - getContext().startActivity(intent); - } - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - if(!EventBus.getDefault().isRegistered(this)) - EventBus.getDefault().register(this); - } - - @Override - protected void onDetachedFromWindow() { - if(EventBus.getDefault().isRegistered(this)) - EventBus.getDefault().unregister(this); - super.onDetachedFromWindow(); - } -} diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/image/AvatarIndicatorView.kt b/app/src/main/java/com/mxt/anitrend/base/custom/view/image/AvatarIndicatorView.kt new file mode 100644 index 000000000..05ee2ccdf --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/image/AvatarIndicatorView.kt @@ -0,0 +1,127 @@ +package com.mxt.anitrend.base.custom.view.image + +import android.content.Context +import android.content.Intent +import android.util.AttributeSet +import android.view.View +import android.widget.FrameLayout +import com.mxt.anitrend.R +import com.mxt.anitrend.base.custom.consumer.BaseConsumer +import com.mxt.anitrend.base.interfaces.view.CustomView +import com.mxt.anitrend.binding.setImage +import com.mxt.anitrend.databinding.WidgetAvatarIndicatorBinding +import com.mxt.anitrend.model.entity.anilist.User +import com.mxt.anitrend.presenter.widget.WidgetPresenter +import com.mxt.anitrend.util.CompatUtil +import com.mxt.anitrend.util.DateUtil +import com.mxt.anitrend.util.KeyUtil +import com.mxt.anitrend.view.activity.detail.NotificationActivity +import com.mxt.anitrend.view.activity.detail.ProfileActivity +import com.mxt.anitrend.view.activity.index.LoginActivity +import org.greenrobot.eventbus.EventBus +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode +import org.koin.core.KoinComponent +import org.koin.core.inject + +/** + * Created by max on 2017/11/30. + * avatar image view which will be capable of displaying + * current notification count. + */ + +class AvatarIndicatorView : FrameLayout, CustomView, View.OnClickListener, BaseConsumer.onRequestModelChange, KoinComponent { + + 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() } + + private val presenter: WidgetPresenter by inject() + + private val currentUser: User? + get() = presenter.database?.currentUser + + private lateinit var binding: WidgetAvatarIndicatorBinding + private var mLastSynced: Long = 0 + + override fun onInit() { + binding = WidgetAvatarIndicatorBinding.inflate(CompatUtil.getLayoutInflater(context), this, true) + binding.onClickListener = this + checkLastSyncTime() + } + + private fun checkLastSyncTime() { + if (presenter.settings?.isAuthenticated == true) { + if (currentUser != null) { + binding.userAvatar.setImage(currentUser?.avatar) + if ((currentUser?.unreadNotificationCount ?: 0) > 0) { + binding.notificationCount.text = currentUser?.unreadNotificationCount.toString() + showNotificationWidget() + } else + hideNotificationCountWidget() + } else + hideNotificationCountWidget() + } + } + + override fun onViewRecycled() { + presenter.onDestroy() + } + + @Subscribe(threadMode = ThreadMode.MAIN_ORDERED) + override fun onModelChanged(consumer: BaseConsumer) { + if (consumer.requestMode == KeyUtil.USER_CURRENT_REQ) { + if (DateUtil.timeDifferenceSatisfied(KeyUtil.TIME_UNIT_MINUTES, mLastSynced, 15)) + mLastSynced = System.currentTimeMillis() + checkLastSyncTime() + } + } + + private fun showNotificationWidget() { + binding.notificationCount.visibility = View.VISIBLE + binding.container.visibility = View.VISIBLE + } + + private fun hideNotificationCountWidget() { + binding.notificationCount.visibility = View.GONE + binding.container.visibility = View.GONE + } + + override fun onClick(view: View) { + if (presenter.settings.isAuthenticated && currentUser != null) { + if (view.id == R.id.user_avatar) { + val intent: Intent + if ((currentUser?.unreadNotificationCount ?: 0) > 0) { + intent = Intent(context, NotificationActivity::class.java) + hideNotificationCountWidget() + } else { + intent = Intent(context, ProfileActivity::class.java) + intent.putExtra(KeyUtil.arg_userName, currentUser?.name) + } + intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK + context.startActivity(intent) + } + } else { + val intent = Intent(context, LoginActivity::class.java) + intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK + context.startActivity(intent) + } + } + + override fun onAttachedToWindow() { + super.onAttachedToWindow() + if (!EventBus.getDefault().isRegistered(this)) + EventBus.getDefault().register(this) + } + + override fun onDetachedFromWindow() { + if (EventBus.getDefault().isRegistered(this)) + EventBus.getDefault().unregister(this) + super.onDetachedFromWindow() + } +} 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 a5c2ceeba..744e2577f 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 @@ -60,7 +60,7 @@ public RatingTextView(Context context, AttributeSet attrs, int defStyleAttr, int public void onInit() { binding = CustomRatingWidgetBinding.inflate(CompatUtil.INSTANCE.getLayoutInflater(getContext()), this, true); BasePresenter basePresenter = new BasePresenter(getContext()); - if(basePresenter.getApplicationPref().isAuthenticated()) + if(basePresenter.getSettings().isAuthenticated()) mediaListOptions = basePresenter.getDatabase().getCurrentUser().getMediaListOptions(); } 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 f38a7f1f9..29d5d10d8 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 @@ -30,9 +30,11 @@ import io.noties.markwon.image.AsyncDrawable import io.noties.markwon.image.AsyncDrawableScheduler import io.noties.markwon.image.glide.GlideImagesPlugin import io.noties.markwon.linkify.LinkifyPlugin +import org.koin.core.KoinComponent +import org.koin.core.inject import java.util.Arrays.asList -class RichMarkdownTextView : AppCompatTextView, CustomView { +class RichMarkdownTextView : AppCompatTextView, CustomView, KoinComponent { constructor(context: Context) : super(context) { onInit() } @@ -43,26 +45,7 @@ class RichMarkdownTextView : AppCompatTextView, CustomView { constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { onInit() } - val markwon by lazy { - Markwon.builder(context) - .usePlugin(HtmlPlugin.create()) - .usePlugin(LinkifyPlugin.create()) - .usePlugin(GlideImagesPlugin.create(Glide.with(context))) - .usePlugin(GlideImagesPlugin.create(object : GlideImagesPlugin.GlideStore { - override fun cancel(target: Target<*>) { - Glide.with(context).clear(target) - } - - override fun load(drawable: AsyncDrawable): RequestBuilder { - return Glide.with(context).load(drawable.destination) - .transition(DrawableTransitionOptions.withCrossFade(250)) - .transform( - CenterCrop(), - RoundedCorners(context.resources.getDimensionPixelSize(R.dimen.md_margin)) - ) - } - })).build() - } + val markwon by inject() /** * Optionally included when constructing custom views 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 0fb3e9feb..935aaf70e 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 @@ -1,19 +1,19 @@ package com.mxt.anitrend.base.custom.view.widget; -import androidx.lifecycle.Lifecycle; import android.content.Context; import android.content.Intent; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.fragment.app.FragmentActivity; -import androidx.fragment.app.FragmentManager; import android.util.AttributeSet; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.widget.FrameLayout; import android.widget.Toast; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.FragmentActivity; +import androidx.fragment.app.FragmentManager; +import androidx.lifecycle.Lifecycle; + import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.consumer.BaseConsumer; import com.mxt.anitrend.base.custom.sheet.BottomSheetBase; @@ -40,6 +40,7 @@ import retrofit2.Call; import retrofit2.Response; +import timber.log.Timber; /** * Created by max on 2017/11/27. @@ -52,6 +53,8 @@ public class AboutPanelWidget extends FrameLayout implements CustomView, View.On private Lifecycle lifecycle; private long userId; + private final String TAG = AboutPanelWidget.class.getSimpleName(); + private long mLastSynced; private QueryContainerBuilder queryContainer; @@ -127,7 +130,7 @@ public void onResponse(@NonNull Call> call, @NonNull Res public void onFailure(@NonNull Call> call, @NonNull Throwable throwable) { if(isAlive()) { throwable.printStackTrace(); - Log.e(this.toString(), throwable.getMessage()); + Timber.tag(TAG).e(throwable); } } }); @@ -154,7 +157,7 @@ public void onResponse(@NonNull Call> call, @NonNull Res public void onFailure(@NonNull Call> call, @NonNull Throwable throwable) { if(isAlive()) { throwable.printStackTrace(); - Log.e(this.toString(), throwable.getMessage()); + Timber.tag(TAG).e(throwable); } } }); @@ -196,7 +199,7 @@ public void onResponse(@NonNull Call> call, @NonN public void onFailure(@NonNull Call> call, @NonNull Throwable throwable) { if(isAlive()) { throwable.printStackTrace(); - Log.e(this.toString(), throwable.getMessage()); + Timber.tag(TAG).e(throwable); } } }); 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 d61181e82..2ec408e96 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 @@ -28,6 +28,7 @@ import retrofit2.Call; import retrofit2.Response; +import timber.log.Timber; /** * Created by max on 2018/02/22. @@ -43,6 +44,7 @@ public class AutoIncrementWidget extends LinearLayout implements CustomView, Vie private MediaList model; private String currentUser; + private final String TAG = AutoIncrementWidget.class.getSimpleName(); public AutoIncrementWidget(Context context) { super(context); @@ -127,7 +129,7 @@ public void onResponse(@NonNull Call call, @NonNull Response call, @NonNull Response call, @NonNull Throwable throwable) { try { - Log.e(toString(), throwable.getLocalizedMessage()); + Timber.tag(TAG).e(throwable); throwable.printStackTrace(); resetFlipperState(); } catch (Exception e) { 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 11f86bd38..3eaec71d5 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 @@ -31,6 +31,7 @@ import okhttp3.ResponseBody; import retrofit2.Call; import retrofit2.Response; +import timber.log.Timber; /** * Created by max on 2018/01/31. @@ -49,6 +50,8 @@ public class FavouriteToolbarWidget extends FrameLayout implements CustomView, R private QueryContainerBuilder queryContainer; + private final String TAG = FavouriteToolbarWidget.class.getSimpleName(); + public FavouriteToolbarWidget(@NonNull Context context) { super(context); onInit(); @@ -133,19 +136,16 @@ public boolean isModelSet() { @Override public void onClick(View view) { - if(presenter.getApplicationPref().isAuthenticated()) - switch (view.getId()) { - case R.id.widget_flipper: - if (isModelSet()) { - if (binding.widgetFlipper.getDisplayedChild() == WidgetPresenter.CONTENT_STATE) { - binding.widgetFlipper.showNext(); - presenter.requestData(KeyUtil.MUT_TOGGLE_FAVOURITE, getContext(), this); - } - else - NotifyUtil.makeText(getContext(), R.string.busy_please_wait, Toast.LENGTH_SHORT).show(); + if(presenter.getSettings().isAuthenticated()) + if (view.getId() == R.id.widget_flipper) { + if (isModelSet()) { + if (binding.widgetFlipper.getDisplayedChild() == WidgetPresenter.CONTENT_STATE) { + binding.widgetFlipper.showNext(); + presenter.requestData(KeyUtil.MUT_TOGGLE_FAVOURITE, getContext(), this); } else - NotifyUtil.makeText(getContext(), R.string.text_activity_loading, Toast.LENGTH_SHORT).show(); - break; + NotifyUtil.makeText(getContext(), R.string.busy_please_wait, Toast.LENGTH_SHORT).show(); + } else + NotifyUtil.makeText(getContext(), R.string.text_activity_loading, Toast.LENGTH_SHORT).show(); } else NotifyUtil.makeText(getContext(), R.string.info_login_req, R.drawable.ic_group_add_grey_600_18dp, Toast.LENGTH_SHORT).show(); @@ -189,7 +189,7 @@ else if (characterBase != null) characterBase.toggleFavourite(); setIconType(); } else { - Log.e(toString(), ErrorUtil.INSTANCE.getError(response)); + Timber.tag(TAG).e(ErrorUtil.INSTANCE.getError(response)); NotifyUtil.makeText(getContext(), R.string.text_error_request, Toast.LENGTH_SHORT).show(); } } catch (Exception e) { @@ -200,7 +200,7 @@ else if (characterBase != null) @Override public void onFailure(@NonNull Call call, @NonNull Throwable throwable) { try { - Log.e(toString(), throwable.getLocalizedMessage()); + Timber.tag(TAG).e(throwable.getLocalizedMessage()); throwable.printStackTrace(); resetFlipperState(); } 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 538dfb367..b9a40abc4 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 @@ -26,6 +26,7 @@ import retrofit2.Call; import retrofit2.Response; +import timber.log.Timber; /** * Created by max on 2017/10/29. @@ -36,6 +37,7 @@ public class FavouriteWidget extends FrameLayout implements CustomView, RetroCal private WidgetPresenter> presenter; private WidgetFavouriteBinding binding; private @Nullable List model; + private final String TAG = FavouriteWidget.class.getSimpleName(); public FavouriteWidget(Context context) { super(context); @@ -134,7 +136,7 @@ public void onResponse(@NonNull Call> call, @NonNull Response> call, @NonNull Response> call, @NonNull Throwable throwable) { try { - Log.e(toString(), throwable.getLocalizedMessage()); + Timber.tag(TAG).e(throwable.getLocalizedMessage()); throwable.printStackTrace(); 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 3f382abc7..c471e283d 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 @@ -24,6 +24,7 @@ import retrofit2.Call; import retrofit2.Response; +import timber.log.Timber; /** * Created by max on 2017/11/16. @@ -36,6 +37,7 @@ public class FollowStateWidget extends FrameLayout implements CustomView, View.O private UserBase model; private WidgetButtonStateBinding binding; private WidgetPresenter presenter; + private final String TAG = FollowStateWidget.class.getSimpleName(); public FollowStateWidget(Context context) { super(context); @@ -64,7 +66,7 @@ public void onInit() { public void setUserModel(UserBase model) { this.model = model; - if(presenter.getApplicationPref().isAuthenticated()) + if(presenter.getSettings().isAuthenticated()) if(!presenter.isCurrentUser(model)) setControlText(); else @@ -134,7 +136,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.INSTANCE.getError(response)); + Timber.tag(TAG).e(ErrorUtil.INSTANCE.getError(response)); setControlText(); } } catch (Exception e) { 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 c2e828f31..aa6a44faf 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 @@ -38,6 +38,7 @@ import retrofit2.Call; import retrofit2.Response; +import timber.log.Timber; /** * Created by max on 2017/11/26. @@ -54,6 +55,7 @@ public class ProfileStatsWidget extends FrameLayout implements CustomView, View. private QueryContainerBuilder queryContainer; private Bundle bundle; + private final String TAG = ProfileStatsWidget.class.getSimpleName(); private final String placeHolder = ".."; @@ -178,7 +180,7 @@ public void onResponse(@NonNull Call> ca updateUI(); } } else - Log.e(this.toString(), ErrorUtil.INSTANCE.getError(response)); + Timber.tag(TAG).e(ErrorUtil.INSTANCE.getError(response)); } catch (Exception e) { e.printStackTrace(); } @@ -188,7 +190,7 @@ public void onResponse(@NonNull Call> ca public void onFailure(@NonNull Call> call, @NonNull Throwable throwable) { try { if (throwable.getLocalizedMessage() != null) - Log.e(toString(), throwable.getLocalizedMessage()); + Timber.tag(TAG).e(throwable.getLocalizedMessage()); throwable.printStackTrace(); } catch (Exception e) { e.printStackTrace(); 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 bf762c530..86a130180 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 @@ -26,6 +26,7 @@ import retrofit2.Call; import retrofit2.Response; +import timber.log.Timber; public class StatusDeleteWidget extends FrameLayout implements CustomView, RetroCallback, View.OnClickListener { @@ -34,6 +35,7 @@ public class StatusDeleteWidget extends FrameLayout implements CustomView, Retro private @KeyUtil.RequestType int requestType; private FeedList feedList; private FeedReply feedReply; + private final String TAG = StatusDeleteWidget.class.getSimpleName(); public StatusDeleteWidget(Context context) { super(context); @@ -133,7 +135,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.INSTANCE.getError(response)); + Timber.tag(TAG).e(ErrorUtil.INSTANCE.getError(response)); } catch (Exception e) { e.printStackTrace(); } @@ -149,7 +151,7 @@ else if (requestType == KeyUtil.MUT_DELETE_FEED_REPLY) @Override public void onFailure(@NonNull Call call, @NonNull Throwable throwable) { try { - Log.e(toString(), throwable.getLocalizedMessage()); + Timber.tag(TAG).e(throwable.getLocalizedMessage()); throwable.printStackTrace(); resetFlipperState(); } catch (Exception e) { 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 9d316863f..96828d7f1 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 @@ -30,6 +30,7 @@ import retrofit2.Call; import retrofit2.Response; +import timber.log.Timber; /** * Created by max on 2017/11/05. @@ -41,7 +42,7 @@ public class VoteWidget extends LinearLayout implements CustomView, View.OnClick private WidgetPresenter presenter; private WidgetVoteBinding binding; private Review model; - + private final String TAG = VoteWidget.class.getSimpleName(); private @ColorRes int colorStyle; public VoteWidget(@NonNull Context context) { @@ -75,7 +76,7 @@ private void setParameters(@KeyUtil.ReviewRating String ratingType) { @Override public void onClick(View view) { - if(presenter.getApplicationPref().isAuthenticated()) { + if(presenter.getSettings().isAuthenticated()) { switch (view.getId()) { case R.id.widget_thumb_up_flipper: if (binding.widgetThumbUpFlipper.getDisplayedChild() == WidgetPresenter.CONTENT_STATE) { @@ -188,7 +189,7 @@ public void onResponse(@NonNull Call call, @NonNull Response res this.model.setUserRating(model.getUserRating()); setReviewStatus(); } else { - Log.e(this.toString(), ErrorUtil.INSTANCE.getError(response)); + Timber.w(ErrorUtil.INSTANCE.getError(response)); resetFlipperState(); } } catch (Exception e) { @@ -206,7 +207,7 @@ public void onResponse(@NonNull Call call, @NonNull Response res @Override public void onFailure(@NonNull Call call, @NonNull Throwable throwable) { try { - Log.e(toString(), throwable.getLocalizedMessage()); + Timber.tag(TAG).e(throwable); throwable.printStackTrace(); resetFlipperState(); } catch (Exception e) { 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 index a942f1790..6ef1e3d2c 100644 --- 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 @@ -15,15 +15,19 @@ import com.mxt.anitrend.util.KeyUtil import io.objectbox.android.ObjectBoxLiveData import io.objectbox.query.Query +import kotlinx.coroutines.* import retrofit2.Call import retrofit2.Response +import kotlin.coroutines.CoroutineContext /** * Created by max on 2017/10/14. * View model abstraction contains the generic data model */ -class ViewModelBase: ViewModel(), RetroCallback { +class ViewModelBase: ViewModel(), RetroCallback, CoroutineScope { + + private val job: Job = SupervisorJob() val model by lazy { MutableLiveData() @@ -67,6 +71,7 @@ class ViewModelBase: ViewModel(), RetroCallback { * prevent a leak of this ViewModel. */ override fun onCleared() { + cancel() if (mLoader?.status != AsyncTask.Status.FINISHED) mLoader?.cancel(true) mLoader = null @@ -93,6 +98,8 @@ class ViewModelBase: ViewModel(), RetroCallback { // Hacky fix that I'm ashamed of if (response.code() == 400 && error.contains("Invalid token")) state?.showError(tokenMessage) + else if (response.code() == 401) + state?.showError(tokenMessage) else state?.showError(error) } @@ -109,4 +116,13 @@ class ViewModelBase: ViewModel(), RetroCallback { state?.showEmpty(throwable.message) throwable.printStackTrace() } + + /** + * The context of this scope. + * Context is encapsulated by the scope and used for implementation of coroutine builders that are extensions on the scope. + * Accessing this property in general code is not recommended for any purposes except accessing the [Job] instance for advanced usages. + * + * By convention, should contain an instance of a [job][Job] to enforce structured concurrency. + */ + override val coroutineContext: CoroutineContext = Dispatchers.IO + job } diff --git a/app/src/main/java/com/mxt/anitrend/base/interfaces/dao/BoxQuery.java b/app/src/main/java/com/mxt/anitrend/base/interfaces/dao/BoxQuery.java deleted file mode 100644 index 434c79f30..000000000 --- a/app/src/main/java/com/mxt/anitrend/base/interfaces/dao/BoxQuery.java +++ /dev/null @@ -1,89 +0,0 @@ -package com.mxt.anitrend.base.interfaces.dao; - -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.VersionBase; - -import java.util.List; - -import io.objectbox.Box; - -public interface BoxQuery { - - /** - * 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 - */ - Box getBoxStore(Class classType); - - /** - * Used when the application is logging out a user preferably - */ - void invalidateBoxStores(); - - /** - * Gets current authenticated user - */ - User getCurrentUser(); - - /** - * Get default authentication code - */ - AuthBase getAuthCode(); - - /** - * Get web token - */ - WebToken getWebToken(); - - /** - * Get the application version on github - */ - VersionBase getRemoteVersion(); - - /** - * Gets all saved tags - */ - List getMediaTags(); - - /** - * Gets all saved genres - */ - List getGenreCollection(); - - /** - * Saves current authenticated user - */ - void saveCurrentUser(User user); - - /** - * Get default authentication code - */ - void saveAuthCode(AuthBase authBase); - - /** - * Get web token - */ - void saveWebToken(WebToken webToken); - - /** - * Save the application version on github - */ - void saveRemoteVersion(VersionBase versionBase); - - /** - * Saves all saved mediaTags - */ - void saveMediaTags(List mediaTags); - - /** - * Saves all saved genres - */ - void saveGenreCollection(List genres); -} diff --git a/app/src/main/java/com/mxt/anitrend/base/interfaces/dao/BoxQuery.kt b/app/src/main/java/com/mxt/anitrend/base/interfaces/dao/BoxQuery.kt new file mode 100644 index 000000000..f1941f72f --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/base/interfaces/dao/BoxQuery.kt @@ -0,0 +1,57 @@ +package com.mxt.anitrend.base.interfaces.dao + +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.VersionBase + +import io.objectbox.Box + +interface BoxQuery { + + /** + * Gets current authenticated user + */ + var currentUser: User? + + /** + * Get default authentication code + */ + var authCode: AuthBase? + + /** + * Get web token + */ + var webToken: WebToken? + + /** + * Get the application version on github + */ + var remoteVersion: VersionBase? + + /** + * Gets all saved tags + */ + var mediaTags: List + + /** + * Gets all saved genres + */ + var genreCollection: List + + /** + * 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 + */ + fun getBoxStore(classType: Class): Box + + /** + * Used when the application is logging out a user preferably + */ + fun invalidateBoxStores() +} diff --git a/app/src/main/java/com/mxt/anitrend/binding/ImageExtensions.kt b/app/src/main/java/com/mxt/anitrend/binding/ImageExtensions.kt new file mode 100644 index 000000000..67df9081f --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/binding/ImageExtensions.kt @@ -0,0 +1,24 @@ +package com.mxt.anitrend.binding + +import androidx.databinding.BindingAdapter +import com.bumptech.glide.Glide +import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions +import com.bumptech.glide.request.RequestOptions +import com.mxt.anitrend.R +import com.mxt.anitrend.base.custom.view.image.AvatarImageView +import com.mxt.anitrend.model.entity.anilist.meta.ImageBase + + +@BindingAdapter("avatarUrl") +fun AvatarImageView.setImage(url: String?) { + Glide.with(context).load(url).apply(RequestOptions.centerCropTransform()) + .apply(RequestOptions.placeholderOf(R.drawable.avatar_placeholder)) + .transition(DrawableTransitionOptions.withCrossFade(150)) + .apply(RequestOptions.circleCropTransform()) + .into(this) +} + +@BindingAdapter("avatarUrl") +fun AvatarImageView.setImage(imageBase: ImageBase?) { + setImage(imageBase?.large) +} \ No newline at end of file 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 37744b923..76ed33218 100644 --- a/app/src/main/java/com/mxt/anitrend/binding/RichMarkdownExtensions.kt +++ b/app/src/main/java/com/mxt/anitrend/binding/RichMarkdownExtensions.kt @@ -4,42 +4,42 @@ import androidx.databinding.BindingAdapter import androidx.annotation.StringRes import android.text.Html import android.widget.TextView +import com.mxt.anitrend.R 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?) { +fun RichMarkdownTextView.markDown(markdown: String?) { val strippedText = RegexUtil.removeTags(markdown) - val markdownSpan = MarkDownUtil.convert(strippedText, richMarkdownTextView.context, richMarkdownTextView) - richMarkdownTextView.setText(markdownSpan, TextView.BufferType.SPANNABLE) + val markdownSpan = MarkDownUtil.convert(strippedText, context, this) + 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) +fun RichMarkdownTextView.htmlText(html: String?) { + val markdownSpan = MarkDownUtil.convert(html, context, this) + setText(markdownSpan, TextView.BufferType.SPANNABLE) } @BindingAdapter("basicHtml") -fun basicText(richMarkdownTextView: RichMarkdownTextView, html: String?) { +fun RichMarkdownTextView.basicText(html: String?) { val htmlSpan = Html.fromHtml(html) - richMarkdownTextView.text = htmlSpan + 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) +fun RichMarkdownTextView.htmlText(@StringRes resId: Int) { + val text = context.getString(resId) + val markdownSpan = MarkDownUtil.convert(text, context, this) + setText(markdownSpan, TextView.BufferType.SPANNABLE) } @BindingAdapter("richMarkDown") -fun richMarkDown(richMarkdownTextView: RichMarkdownTextView, markdown: String?) { - richMarkdownTextView.also { - val tagsStripped = RegexUtil.removeTags(markdown) - val userTagsConverted = RegexUtil.findUserTags(tagsStripped) - val standardMarkdown = RegexUtil.convertToStandardMarkdown(userTagsConverted) - it.markwon.setMarkdown(it, standardMarkdown) - } +fun RichMarkdownTextView.richMarkDown(markdown: String?) { + val tagsStripped = RegexUtil.removeTags(markdown) + val userTagsConverted = RegexUtil.findUserTags(tagsStripped) + val standardMarkdown = RegexUtil.convertToStandardMarkdown(userTagsConverted) + markwon.setMarkdown(this, standardMarkdown) + } \ 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 index 4cd4569cd..f0ea9c289 100644 --- a/app/src/main/java/com/mxt/anitrend/data/DatabaseHelper.kt +++ b/app/src/main/java/com/mxt/anitrend/data/DatabaseHelper.kt @@ -13,6 +13,7 @@ import io.objectbox.Box import io.objectbox.BoxStore import org.koin.core.KoinComponent import org.koin.core.inject +import java.util.* /** * Created by max on 2017/11/02. @@ -23,9 +24,6 @@ class DatabaseHelper : BoxQuery, KoinComponent { private val boxStore by inject() - // Frequently used instance variables - private var user: User? = null - /** * Gets the object box from a requested class type. * @@ -51,126 +49,93 @@ class DatabaseHelper : BoxQuery, KoinComponent { /** * Gets current authenticated user */ - override fun getCurrentUser(): User? { - if (user == null) - user = getBoxStore(User::class.java).query() + override var currentUser: User? = null + get() { + return getBoxStore(User::class.java).query() .build().findFirst() - return user - } - + } + set(value) { + field = value + if (value != null) + getBoxStore(User::class.java).put(value) + } /** * Get default authentication code */ - override fun getAuthCode(): AuthBase? { - return getBoxStore(AuthBase::class.java) + override var authCode: AuthBase? = null + get() = getBoxStore(AuthBase::class.java) .query() .build() .findFirst() - } + set(value) { + field = value + if (value != null) { + getBoxStore(AuthBase::class.java).removeAll() + getBoxStore(AuthBase::class.java).put(value) + } + } /** * Get web token */ - override fun getWebToken(): WebToken? { - return getBoxStore(WebToken::class.java) + override var webToken: WebToken? = null + get() = getBoxStore(WebToken::class.java) .query() .build() .findFirst() - } - + set(value) { + field = value + if (value != null) { + getBoxStore(WebToken::class.java).removeAll() + getBoxStore(WebToken::class.java).put(value) + } + } /** * Get the application version on github */ - override fun getRemoteVersion(): VersionBase? { - return getBoxStore(VersionBase::class.java) - .query() - .build() - .findFirst() - } - + override var remoteVersion: VersionBase? = null + get() = getBoxStore(VersionBase::class.java) + .query().build().findFirst() + set(value) { + field = value + if (value != null) { + val versionBox = getBoxStore(VersionBase::class.java) + if (versionBox.count() != 0L) + versionBox.removeAll() + value.lastChecked = System.currentTimeMillis() + versionBox.put(value) + } + } /** * Gets all saved tags */ - override fun getMediaTags(): List { - return getBoxStore(MediaTag::class.java) + override var mediaTags: List = Collections.emptyList() + get() = getBoxStore(MediaTag::class.java) .query() .build() .findLazy() - } - + set(value) { + field = value + if (value.isNotEmpty()) { + val tagBox = getBoxStore(MediaTag::class.java) + if (tagBox.count() < value.size) + tagBox.put(value) + } + } /** * Gets all saved genres */ - override fun getGenreCollection(): List { - return getBoxStore(Genre::class.java) + override var genreCollection: List = Collections.emptyList() + get() = 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() != 0L) - 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) - } + set(value) { + field = value + if (value.isNotEmpty()) { + val genreBox = getBoxStore(Genre::class.java) + if (genreBox.count() < value.size) + genreBox.put(value) + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/mxt/anitrend/extension/AppExt.kt b/app/src/main/java/com/mxt/anitrend/extension/AppExt.kt index b8d713bb0..9b9af65e5 100644 --- a/app/src/main/java/com/mxt/anitrend/extension/AppExt.kt +++ b/app/src/main/java/com/mxt/anitrend/extension/AppExt.kt @@ -1,8 +1,26 @@ package com.mxt.anitrend.extension import android.content.Context +import androidx.annotation.StringRes +import com.mxt.anitrend.App +import com.mxt.anitrend.presenter.widget.WidgetPresenter +import org.koin.core.KoinComponent import org.koin.core.context.GlobalContext +import org.koin.core.definition.BeanDefinition +import org.koin.core.definition.Definition +import org.koin.core.definition.DefinitionFactory +import org.koin.core.definition.Options +import org.koin.core.module.Module +import org.koin.core.parameter.ParametersDefinition +import org.koin.core.qualifier.named +import org.koin.core.scope.Scope val appContext by lazy { GlobalContext.get().koin.get() -} \ No newline at end of file +} + +fun getString(@StringRes text: Int) = + appContext.getString(text) + +fun getString(@StringRes text: Int, vararg values: String) = + appContext.getString(text, *values) \ No newline at end of file diff --git a/app/src/main/java/com/mxt/anitrend/extension/CoroutineExt.kt b/app/src/main/java/com/mxt/anitrend/extension/CoroutineExt.kt new file mode 100644 index 000000000..f93a1276a --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/extension/CoroutineExt.kt @@ -0,0 +1,16 @@ +package com.mxt.anitrend.extension + +import kotlinx.coroutines.* +import timber.log.Timber +import kotlin.coroutines.CoroutineContext + +fun CoroutineScope.launchCatching( + coroutineContext: CoroutineContext = Dispatchers.Default, + errorHandler: ((Throwable) -> Unit)? = null, + block: suspend CoroutineScope.() -> Unit +) { + launch(coroutineContext + CoroutineExceptionHandler { _, e -> + Timber.e(e) + errorHandler?.invoke(e) + }, block = block) +} \ No newline at end of file diff --git a/app/src/main/java/com/mxt/anitrend/extension/KoinExt.kt b/app/src/main/java/com/mxt/anitrend/extension/KoinExt.kt new file mode 100644 index 000000000..fe880e523 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/extension/KoinExt.kt @@ -0,0 +1,54 @@ +package com.mxt.anitrend.extension + +import com.mxt.anitrend.presenter.widget.WidgetPresenter +import org.koin.core.KoinComponent +import org.koin.core.definition.BeanDefinition +import org.koin.core.definition.Definition +import org.koin.core.definition.DefinitionFactory +import org.koin.core.definition.Options +import org.koin.core.module.Module +import org.koin.core.parameter.ParametersDefinition +import org.koin.core.qualifier.named +import org.koin.core.scope.Scope + + +/** + * Declare a Factory definition for StateMachine generic type + * @param override + * @param definition - definition function + */ +inline fun Module.widgetPresenterFactory( + override: Boolean = false, + noinline definition: Definition> +): BeanDefinition> { + val beanDefinition = DefinitionFactory.createFactory( + named(), definition = definition + ) + declareDefinition(beanDefinition, Options(override = override)) + return beanDefinition +} + +/** + * Gets instance of WidgetPresenter for matching generic type + */ +inline fun Scope.getWdigetPresenter( + noinline parameters: ParametersDefinition? = null +): WidgetPresenter { + return getKoin().get(WidgetPresenter::class, named(), parameters) + ?: error("$this is not registered - Koin is null") +} + +fun String.Companion.empty() = "" + +object KoinExt : KoinComponent { + + /** + * Helper to retrieve dependencies by class definition + * + * @param `class` registered class in koin modules + */ + @JvmStatic + fun get(`class`: Class): T { + return getKoin().get(`class`.kotlin, null, null) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/mxt/anitrend/koin/AppModule.kt b/app/src/main/java/com/mxt/anitrend/koin/AppModule.kt index 306fa5e1e..c7b04a010 100644 --- a/app/src/main/java/com/mxt/anitrend/koin/AppModule.kt +++ b/app/src/main/java/com/mxt/anitrend/koin/AppModule.kt @@ -1,9 +1,28 @@ package com.mxt.anitrend.koin +import android.app.NotificationManager +import android.content.Context +import android.graphics.drawable.Drawable +import com.bumptech.glide.Glide +import com.bumptech.glide.RequestBuilder +import com.bumptech.glide.load.resource.bitmap.CenterCrop +import com.bumptech.glide.load.resource.bitmap.RoundedCorners +import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions +import com.bumptech.glide.request.target.Target +import com.mxt.anitrend.R +import com.mxt.anitrend.analytics.AnalyticsLogging +import com.mxt.anitrend.analytics.contract.ISupportAnalytics import com.mxt.anitrend.model.entity.MyObjectBox import com.mxt.anitrend.presenter.base.BasePresenter import com.mxt.anitrend.presenter.fragment.MediaPresenter -import com.mxt.anitrend.util.ApplicationPref +import com.mxt.anitrend.presenter.widget.WidgetPresenter +import com.mxt.anitrend.util.NotificationUtil +import com.mxt.anitrend.util.Settings +import io.noties.markwon.Markwon +import io.noties.markwon.html.HtmlPlugin +import io.noties.markwon.image.AsyncDrawable +import io.noties.markwon.image.glide.GlideImagesPlugin +import io.noties.markwon.linkify.LinkifyPlugin import org.koin.android.ext.koin.androidContext import org.koin.core.KoinComponent import org.koin.dsl.module @@ -15,12 +34,59 @@ object AppModule : KoinComponent { .androidContext(androidContext()) .build() } + + single { + AnalyticsLogging( + context = androidContext(), + settings = get() + ) + } + factory { - ApplicationPref(androidContext()) + Settings(androidContext()) } + + factory { + NotificationUtil( + androidContext(), + get(), + androidContext().getSystemService( + Context.NOTIFICATION_SERVICE + ) as NotificationManager? + ) + } + } + + val widgetModule = module { + single { + Markwon.builder(androidContext()) + .usePlugin(HtmlPlugin.create()) + .usePlugin(LinkifyPlugin.create()) + .usePlugin(GlideImagesPlugin.create(Glide.with(androidContext()))) + .usePlugin(GlideImagesPlugin.create(object : GlideImagesPlugin.GlideStore { + override fun cancel(target: Target<*>) { + Glide.with(androidContext()).clear(target) + } + + override fun load(drawable: AsyncDrawable): RequestBuilder { + return Glide.with(androidContext()).load(drawable.destination) + .transition(DrawableTransitionOptions.withCrossFade(250)) + .transform( + CenterCrop(), + RoundedCorners(androidContext().resources.getDimensionPixelSize(R.dimen.md_margin)) + ) + } + })).build() + } + } + + val presenterModule = module { factory { BasePresenter(androidContext()) } + factory { + WidgetPresenter(androidContext()) + } factory { MediaPresenter(androidContext()) } diff --git a/app/src/main/java/com/mxt/anitrend/model/api/converter/GraphQLConverter.java b/app/src/main/java/com/mxt/anitrend/model/api/converter/GraphQLConverter.java index 3b3223a3f..969daa8a8 100644 --- a/app/src/main/java/com/mxt/anitrend/model/api/converter/GraphQLConverter.java +++ b/app/src/main/java/com/mxt/anitrend/model/api/converter/GraphQLConverter.java @@ -21,6 +21,7 @@ import okhttp3.ResponseBody; import retrofit2.Converter; import retrofit2.Retrofit; +import timber.log.Timber; /** * Created by max on 2017/10/22. @@ -61,6 +62,7 @@ public Converter requestBodyConverter(Type t */ private class GraphResponseConverter implements Converter { private Type type; + private final String TAG = GraphRequestConverter.class.getSimpleName(); GraphResponseConverter(Type type) { this.type = type; @@ -78,10 +80,10 @@ public T convert(@NonNull ResponseBody responseBody) { targetResult = dataContainer.getResult(); } else for (GraphError error: container.getErrors()) - Log.e(this.toString(), error.toString()); + Timber.tag(TAG).e(error.toString()); } catch (Exception ex) { ex.printStackTrace(); - Log.e("GraphQLConverter", jsonResponse); + Timber.tag(TAG).e(jsonResponse); } finally { responseBody.close(); } @@ -94,6 +96,7 @@ public T convert(@NonNull ResponseBody responseBody) { */ private class GraphRequestConverter implements Converter { private Annotation[] methodAnnotations; + private final String TAG = GraphRequestConverter.class.getSimpleName(); GraphRequestConverter(Annotation[] methodAnnotations) { this.methodAnnotations = methodAnnotations; @@ -105,7 +108,7 @@ public RequestBody convert(@NonNull QueryContainerBuilder containerBuilder) { .setQuery(graphProcessor.getQuery(methodAnnotations)) .build(); String queryJson = gson.toJson(queryContainer); - Log.d("GraphRequestConverter", queryJson); + Timber.tag(TAG).i(queryJson); return RequestBody.create(MediaType.parse("application/graphql"), queryJson); } } 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 index 6996a42d2..fd98844c6 100644 --- 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 @@ -5,13 +5,13 @@ import android.util.Log import com.mxt.anitrend.BuildConfig import com.mxt.anitrend.base.custom.async.WebTokenRequest -import com.mxt.anitrend.util.ApplicationPref +import com.mxt.anitrend.util.Settings import java.io.IOException import okhttp3.Interceptor -import okhttp3.Request import okhttp3.Response +import timber.log.Timber /** * Created by max on 2017/06/14. @@ -21,7 +21,7 @@ import okhttp3.Response class AuthInterceptor(context: Context) : Interceptor { private val applicationPref by lazy { - ApplicationPref(context) + Settings(context) } @Throws(IOException::class) @@ -33,7 +33,7 @@ class AuthInterceptor(context: Context) : Interceptor { val request = builder.build() return chain.proceed(request) } else - Log.e("AuthInterceptor", "Authentication reference is null, this should not happen under normal conditions") + Timber.tag("AuthInterceptor").e("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/retro/WebFactory.java b/app/src/main/java/com/mxt/anitrend/model/api/retro/WebFactory.java index cff6bc580..a50d3de9c 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 @@ -33,6 +33,7 @@ import retrofit2.Retrofit; import retrofit2.converter.gson.GsonConverterFactory; import retrofit2.converter.simplexml.SimpleXmlConverterFactory; +import timber.log.Timber; /** * Created by max on 2017/10/14. @@ -93,7 +94,7 @@ public static S createService(@NonNull Class serviceClass, Context contex GraphProcessor.getInstance(context); if(mRetrofit == null) { OkHttpClient.Builder httpClient = createHttpClient(new AuthInterceptor(context), - HttpLoggingInterceptor.Level.NONE); + HttpLoggingInterceptor.Level.HEADERS); mRetrofit = new Retrofit.Builder().client(httpClient.build()) .addConverterFactory(GraphQLConverter.create(context)) @@ -106,7 +107,7 @@ public static S createService(@NonNull Class serviceClass, Context contex public static EpisodeModel createCrunchyService(boolean feeds, Context context) { Retrofit retrofit = new Retrofit.Builder().baseUrl(feeds?BuildConfig.FEEDS_LINK:BuildConfig.CRUNCHY_LINK) .addConverterFactory(SimpleXmlConverterFactory.createNonStrict()) - .client(createHttpClient(new CacheInterceptor(context, true), HttpLoggingInterceptor.Level.BASIC) + .client(createHttpClient(new CacheInterceptor(context, true), HttpLoggingInterceptor.Level.HEADERS) .addNetworkInterceptor(new NetworkCacheInterceptor(context, true)) .cache(CompatUtil.INSTANCE.cacheProvider(context)).build()) .build(); @@ -117,7 +118,7 @@ public static GiphyModel createGiphyService(Context context) { if(mGiphy == null) { mGiphy = new Retrofit.Builder().baseUrl(BuildConfig.GIPHY_LINK) .addConverterFactory(GsonConverterFactory.create(gson)) - .client(createHttpClient(new CacheInterceptor(context, true), HttpLoggingInterceptor.Level.BASIC) + .client(createHttpClient(new CacheInterceptor(context, true), HttpLoggingInterceptor.Level.HEADERS) .addNetworkInterceptor(new NetworkCacheInterceptor(context, true)) .cache(CompatUtil.INSTANCE.cacheProvider(context)).build()) .build(); @@ -127,7 +128,7 @@ public static GiphyModel createGiphyService(Context context) { public static RepositoryModel createRepositoryService() { return new Retrofit.Builder().addConverterFactory(GsonConverterFactory.create(gson)) - .client(createHttpClient(null, HttpLoggingInterceptor.Level.BODY).build()) + .client(createHttpClient(null, HttpLoggingInterceptor.Level.HEADERS).build()) .baseUrl(BuildConfig.APP_REPO).build().create(RepositoryModel.class); } @@ -137,7 +138,7 @@ public static RepositoryModel createRepositoryService() { public static @Nullable WebToken requestCodeTokenSync(String code) { try { Retrofit retrofit = new Retrofit.Builder() - .client(createHttpClient(null, HttpLoggingInterceptor.Level.NONE) + .client(createHttpClient(null, HttpLoggingInterceptor.Level.HEADERS) .build()).addConverterFactory(GsonConverterFactory.create(gson)) .baseUrl(BuildConfig.API_AUTH_LINK) .build(); @@ -147,7 +148,7 @@ public static RepositoryModel createRepositoryService() { Response response = refreshTokenCall.execute(); if(!response.isSuccessful()) - Log.e("requestCodeTokenSync", ErrorUtil.INSTANCE.getError(response)); + Timber.tag("requestCodeTokenSync").e(ErrorUtil.INSTANCE.getError(response)); return response.body(); } catch (Exception ex) { ex.printStackTrace(); diff --git a/app/src/main/java/com/mxt/anitrend/presenter/base/BasePresenter.kt b/app/src/main/java/com/mxt/anitrend/presenter/base/BasePresenter.kt index 4b5a24bb3..464855717 100644 --- a/app/src/main/java/com/mxt/anitrend/presenter/base/BasePresenter.kt +++ b/app/src/main/java/com/mxt/anitrend/presenter/base/BasePresenter.kt @@ -2,11 +2,8 @@ package com.mxt.anitrend.presenter.base import android.content.Context import android.content.Intent -import android.util.Log -import android.widget.Toast import androidx.fragment.app.FragmentActivity import com.annimon.stream.Stream -import com.mxt.anitrend.R import com.mxt.anitrend.base.custom.async.WebTokenRequest import com.mxt.anitrend.base.custom.presenter.CommonPresenter import com.mxt.anitrend.model.entity.anilist.user.UserStatisticTypes @@ -15,9 +12,9 @@ import com.mxt.anitrend.model.entity.crunchy.MediaContent import com.mxt.anitrend.model.entity.crunchy.Thumbnail import com.mxt.anitrend.service.TagGenreService import com.mxt.anitrend.util.CompatUtil -import com.mxt.anitrend.util.NotifyUtil import com.mxt.anitrend.util.migration.MigrationUtil import com.mxt.anitrend.util.migration.Migrations +import timber.log.Timber import java.util.* import java.util.concurrent.TimeUnit @@ -33,12 +30,20 @@ open class BasePresenter(context: Context?) : CommonPresenter(context) { private var favouriteYears: List? = null private var favouriteFormats: List? = null - fun checkIfMigrationIsNeeded(fragmentActivity: FragmentActivity): Boolean { - NotifyUtil.makeText(fragmentActivity, R.string.text_migration_in_progress, Toast.LENGTH_SHORT) - val migrationUtil = MigrationUtil.Builder() - .addMigration(Migrations.MIGRATION_109_132) - .build() - return migrationUtil.applyMigration() + fun checkIfMigrationIsNeeded(): Boolean { + if (!settings.isFreshInstall) { + val migrationUtil = MigrationUtil.Builder() + .addMigration(Migrations.MIGRATION_90_94) + .addMigration(Migrations.MIGRATION_95_100) + .addMigration(Migrations.MIGRATION_101_108) + .addMigration(Migrations.MIGRATION_109_132) + .addMigration(Migrations.MIGRATION_133_135) + .addMigration(Migrations.MIGRATION_136_140) + .addMigration(Migrations.MIGRATION_141_145) + .build() + return migrationUtil.applyMigration() + } + return true } fun checkGenresAndTags(fragmentActivity: FragmentActivity) { @@ -62,7 +67,7 @@ open class BasePresenter(context: Context?) : CommonPresenter(context) { fun getTopFavouriteGenres(limit: Int): List? { if (CompatUtil.isEmpty(favouriteGenres)) { - val userStats: UserStatisticTypes? = database.currentUser.statistics + val userStats: UserStatisticTypes? = database.currentUser?.statistics if (database.currentUser != null && userStats != null) { if (!userStats.anime.genres.isNullOrEmpty()) { favouriteGenres = userStats.anime.genres @@ -81,7 +86,7 @@ open class BasePresenter(context: Context?) : CommonPresenter(context) { fun getTopFavouriteTags(limit: Int): List? { if (CompatUtil.isEmpty(favouriteTags)) { - val userStats: UserStatisticTypes? = database.currentUser.statistics + val userStats: UserStatisticTypes? = database.currentUser?.statistics if (database.currentUser != null && userStats != null) { if (!userStats.anime.tags.isNullOrEmpty()) { favouriteTags = Stream.of(userStats.anime.tags) @@ -104,7 +109,7 @@ open class BasePresenter(context: Context?) : CommonPresenter(context) { fun getTopFavouriteYears(limit: Int): List? { if (CompatUtil.isEmpty(favouriteYears)) { - val userStats: UserStatisticTypes? = database.currentUser.statistics + val userStats: UserStatisticTypes? = database.currentUser?.statistics if (database.currentUser != null && userStats != null) { if (!userStats.anime.releaseYears.isNullOrEmpty()) { favouriteYears = userStats.anime.releaseYears @@ -123,7 +128,7 @@ open class BasePresenter(context: Context?) : CommonPresenter(context) { fun getTopFormats(limit: Int): List? { if (CompatUtil.isEmpty(favouriteFormats)) { - val userStats: UserStatisticTypes? = database.currentUser.statistics + val userStats: UserStatisticTypes? = database.currentUser?.statistics if (database.currentUser != null && userStats != null) { if (!userStats.anime.formats.isNullOrEmpty()) { favouriteFormats = userStats.anime.formats @@ -141,13 +146,13 @@ open class BasePresenter(context: Context?) : CommonPresenter(context) { } fun isCurrentUser(userId: Long): Boolean { - return applicationPref.isAuthenticated && database.currentUser != null && - userId != 0L && database.currentUser.id == userId + return settings.isAuthenticated && database.currentUser != null && + userId != 0L && database.currentUser?.id == userId } fun isCurrentUser(userName: String?): Boolean { - return applicationPref.isAuthenticated && database.currentUser != null && - userName != null && database.currentUser.name == userName + return settings.isAuthenticated && database.currentUser != null && + userName != null && database.currentUser?.name == userName } fun isCurrentUser(userId: Long, userName: String?): Boolean { @@ -159,12 +164,15 @@ open class BasePresenter(context: Context?) : CommonPresenter(context) { } fun checkValidAuth() { - if (applicationPref.isAuthenticated) { - val boxQuery = database - if (boxQuery.currentUser == null) { - Log.e("checkValidAuth", "Last attempt to authenticate failed, refreshing session!") + if (settings.isAuthenticated) { + if (database.currentUser == null) { + Timber.tag(TAG).w("Last attempt to authenticate failed, refreshing session!") WebTokenRequest.invalidateInstance(context) } } } + + companion object { + private val TAG = BasePresenter::class.java.simpleName + } } 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 baca6c5e1..5b3d261e4 100644 --- a/app/src/main/java/com/mxt/anitrend/service/JobDispatcherService.kt +++ b/app/src/main/java/com/mxt/anitrend/service/JobDispatcherService.kt @@ -1,8 +1,9 @@ package com.mxt.anitrend.service import android.content.Context -import android.util.Log - +import androidx.work.ListenableWorker +import androidx.work.Worker +import androidx.work.WorkerParameters 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 @@ -11,23 +12,21 @@ 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 java.util.* +import org.koin.core.KoinComponent +import org.koin.core.inject +import timber.log.Timber /** * Created by Maxwell on 1/22/2017. */ -class JobDispatcherService(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) { +class JobDispatcherService(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams), KoinComponent { - private val presenter by lazy { - BasePresenter(context) - } + private val presenter by inject() + + private val notificationUtil by inject() - private val notificationUtil by lazy { - NotificationUtil(applicationContext) + private val userEndpoint by lazy(LazyThreadSafetyMode.NONE) { + WebFactory.createService(UserModel::class.java, applicationContext) } /** @@ -48,34 +47,46 @@ class JobDispatcherService(context: Context, workerParams: WorkerParameters) : W * [Result.failure] */ override fun doWork(): Result { - if (presenter.applicationPref.isAuthenticated) { - val userModel = WebFactory.createService(UserModel::class.java, applicationContext) - val userRequest = userModel.getCurrentUser(GraphUtil.getDefaultQuery(false)) + if (presenter.settings.isAuthenticated) { try { - val userResponse = userRequest.execute() - val userGraphContainer: Any? = userResponse.body() - if (userResponse.isSuccessful && userGraphContainer != null) { - val currentUser = userGraphContainer as User? - 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) - } - } + requestUser()?.apply { + if (unreadNotificationCount != 0) { + presenter.notifyAllListeners( + BaseConsumer(KeyUtil.USER_CURRENT_REQ, this), + false + ) + requestNotifications(this) } - return Result.success() } + return Result.success() } catch (e: Exception) { - e.message?.apply { - Log.e(toString(), this) - } + Timber.tag(TAG).e(e) e.printStackTrace() } + return Result.retry() + } + return Result.failure() + } + private fun requestUser(): User? { + val userGraphContainer = userEndpoint.getCurrentUser( + GraphUtil.getDefaultQuery(false) + ).execute().body() as User? + + return (userGraphContainer).let { + it?.also { user -> + presenter.database.currentUser = user + } + it } - return Result.retry() + } + + private fun requestNotifications(user: User) { + if (user.unreadNotificationCount > 0) + notificationUtil.createNotification(user) + } + + companion object { + private val TAG = JobDispatcherService::class.java.simpleName } } diff --git a/app/src/main/java/com/mxt/anitrend/service/TagGenreService.kt b/app/src/main/java/com/mxt/anitrend/service/TagGenreService.kt index bffa0252b..6dd30d050 100644 --- a/app/src/main/java/com/mxt/anitrend/service/TagGenreService.kt +++ b/app/src/main/java/com/mxt/anitrend/service/TagGenreService.kt @@ -17,6 +17,7 @@ import com.mxt.anitrend.util.KeyUtil import retrofit2.Call import retrofit2.Response +import timber.log.Timber /** * Created by max on 2017/10/24. @@ -34,13 +35,13 @@ class TagGenreService : IntentService(ServiceName) { val responseBody: List? = response.body() if (response.isSuccessful && responseBody != null) if (!CompatUtil.isEmpty(responseBody)) - widgetPresenter.database.saveMediaTags(responseBody) + widgetPresenter.database.mediaTags = responseBody else - Log.e(ServiceName, ErrorUtil.getError(response)) + Timber.tag(ServiceName).e(ErrorUtil.getError(response)) } override fun onFailure(call: Call>, throwable: Throwable) { - Log.e("fetchAllMediaTags", throwable.message) + Timber.tag("fetchAllMediaTags").e(throwable) throwable.printStackTrace() } }) @@ -56,17 +57,17 @@ class TagGenreService : IntentService(ServiceName) { val responseBody: List? = response.body() if (response.isSuccessful && responseBody != null) { if (!CompatUtil.isEmpty(responseBody)) { - val genreList = Stream.of(responseBody!!) - .map { Genre(it) } + val genreList = Stream.of(responseBody) + .map { Genre(it) } .toList() - widgetPresenter.database.saveGenreCollection(genreList) + widgetPresenter.database.genreCollection = genreList } } else - Log.e(ServiceName, ErrorUtil.getError(response)) + Timber.tag(ServiceName).e(ErrorUtil.getError(response)) } override fun onFailure(call: Call>, throwable: Throwable) { - Log.e("fetchAllMediaGenres", throwable.message) + Timber.tag("fetchAllMediaGenres").e(throwable) throwable.printStackTrace() } }) diff --git a/app/src/main/java/com/mxt/anitrend/util/AnalyticsUtil.java b/app/src/main/java/com/mxt/anitrend/util/AnalyticsUtil.java deleted file mode 100644 index 4ba242dd8..000000000 --- a/app/src/main/java/com/mxt/anitrend/util/AnalyticsUtil.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.mxt.anitrend.util; - -import android.util.Log; - -import androidx.annotation.NonNull; -import androidx.fragment.app.FragmentActivity; - -import com.crashlytics.android.Crashlytics; -import com.mxt.anitrend.App; - -/** - * Created by max on 2017/12/16. - * Analytics helper - */ - -public final class AnalyticsUtil { - - private static final String TAG = AnalyticsUtil.class.getSimpleName(); - - public static void logCurrentScreen(FragmentActivity fragmentActivity, @NonNull String tag) { - try { - if(fragmentActivity != null) { - App app = ((App) fragmentActivity.getApplicationContext()); - if (app.getFabric() != null) - app.getFabric().setCurrentActivity(fragmentActivity); - if (app.getAnalytics() != null) - app.getAnalytics().setCurrentScreen(fragmentActivity, tag, null); - } - } catch (Exception e) { - e.printStackTrace(); - if (e.getLocalizedMessage() != null) - Log.e(TAG, e.getLocalizedMessage()); - } - } - - public static void reportException(@NonNull String tag, @NonNull String message) { - try { - Crashlytics.log(0, tag, message); - } catch (Exception e) { - e.printStackTrace(); - if (e.getLocalizedMessage() != null) - Log.e(TAG, e.getLocalizedMessage()); - } - } - - public static void clearSession() { - try { - Crashlytics.setUserIdentifier(""); - } catch (Exception e) { - e.printStackTrace(); - if (e.getLocalizedMessage() != null) - Log.e(TAG, e.getLocalizedMessage()); - } - } - - public static void setCrashAnalyticsUser(FragmentActivity fragmentActivity, String userName) { - try { - if(fragmentActivity != null) { - App app = ((App) fragmentActivity.getApplicationContext()); - if (app.getFabric() != null) - Crashlytics.setUserIdentifier(userName); - } - } catch (Exception e) { - e.printStackTrace(); - if (e.getLocalizedMessage() != null) - Log.e(TAG, e.getLocalizedMessage()); - } - } -} diff --git a/app/src/main/java/com/mxt/anitrend/util/ApplicationPref.kt b/app/src/main/java/com/mxt/anitrend/util/ApplicationPref.kt deleted file mode 100644 index 8944ebbc4..000000000 --- a/app/src/main/java/com/mxt/anitrend/util/ApplicationPref.kt +++ /dev/null @@ -1,299 +0,0 @@ -package com.mxt.anitrend.util - -import android.content.Context -import android.content.SharedPreferences -import androidx.annotation.IdRes -import androidx.annotation.StyleRes -import androidx.preference.PreferenceManager - -import com.mxt.anitrend.BuildConfig -import com.mxt.anitrend.R - -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(LazyThreadSafetyMode.NONE) { - 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 - - val versionCode: Int - get() = sharedPreferences.getInt(_versionCode, 1) - - 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/CompatUtil.kt b/app/src/main/java/com/mxt/anitrend/util/CompatUtil.kt index c8c1e2df1..92c9c1ce4 100644 --- a/app/src/main/java/com/mxt/anitrend/util/CompatUtil.kt +++ b/app/src/main/java/com/mxt/anitrend/util/CompatUtil.kt @@ -17,7 +17,6 @@ import androidx.core.content.ContextCompat import androidx.core.graphics.drawable.DrawableCompat import androidx.core.view.ViewCompat import androidx.appcompat.content.res.AppCompatResources -import android.text.TextUtils import android.view.LayoutInflater import android.view.View import android.view.WindowManager @@ -32,6 +31,8 @@ import com.mxt.anitrend.view.activity.base.ImagePreviewActivity import okhttp3.Cache import java.io.File import java.util.* +import kotlin.math.min +import kotlin.math.roundToInt /** * Created by max on 2017/09/16. @@ -46,6 +47,7 @@ object CompatUtil { inputMethodManager?.hideSoftInputFromWindow(activity?.window?.decorView?.windowToken, 0) } + @Suppress("DEPRECATION") fun isOnline(context: Context?): Boolean { val connectivityManager = context?.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager? val networkInfo: NetworkInfo? = connectivityManager?.activeNetworkInfo @@ -230,31 +232,20 @@ object CompatUtil { * @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) { + @Deprecated("Please use standard startActivity calls", level = DeprecationLevel.WARNING) + @JvmOverloads + fun startRevealAnim(activity: FragmentActivity?, target: View, data: Intent, finish: Boolean = false) { 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 + return Settings(context).theme == R.style.AppThemeLight } fun dipToPx(dpValue: Float): Int { @@ -269,7 +260,7 @@ object CompatUtil { fun spToPx(spValue: Float): Int { val scaledDensity = Resources.getSystem().displayMetrics.scaledDensity - return Math.round(spValue * scaledDensity) + return (spValue * scaledDensity).roundToInt() } /** @@ -280,7 +271,7 @@ object CompatUtil { val displayMetrics = Resources.getSystem().displayMetrics val widthDp = displayMetrics.widthPixels / displayMetrics.density val heightDp = displayMetrics.heightPixels / displayMetrics.density - val screenSw = Math.min(widthDp, heightDp) + val screenSw = min(widthDp, heightDp) return screenSw >= swDp } 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 17eceead1..851130c84 100644 --- a/app/src/main/java/com/mxt/anitrend/util/DialogUtil.java +++ b/app/src/main/java/com/mxt/anitrend/util/DialogUtil.java @@ -247,7 +247,7 @@ public static void createChangeLog(Context context) { * @param context from a fragment activity derived class * @see FragmentActivity */ - static MaterialDialog.Builder createDefaultDialog(Context context) { + public static MaterialDialog.Builder createDefaultDialog(Context context) { return new MaterialDialog.Builder(context) .typeface(Typeface.SANS_SERIF,Typeface.SANS_SERIF) .buttonRippleColorRes(R.color.colorAccentDark) diff --git a/app/src/main/java/com/mxt/anitrend/util/ErrorUtil.kt b/app/src/main/java/com/mxt/anitrend/util/ErrorUtil.kt index 2cc74fb45..915ad517a 100644 --- a/app/src/main/java/com/mxt/anitrend/util/ErrorUtil.kt +++ b/app/src/main/java/com/mxt/anitrend/util/ErrorUtil.kt @@ -1,10 +1,10 @@ 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 +import timber.log.Timber /** * Created by max on 2017/06/15. @@ -53,7 +53,7 @@ object ErrorUtil { private fun getGraphQLError(errorJson: String?): String? { return errorJson?.let { - Log.e(TAG, it) + Timber.tag(TAG).e(it) val tokenType = object : TypeToken>() {}.type val graphContainer = WebFactory.gson.fromJson>(it, tokenType) val errors = graphContainer.errors diff --git a/app/src/main/java/com/mxt/anitrend/util/GraphUtil.kt b/app/src/main/java/com/mxt/anitrend/util/GraphUtil.kt index d300c7968..fd4638712 100644 --- a/app/src/main/java/com/mxt/anitrend/util/GraphUtil.kt +++ b/app/src/main/java/com/mxt/anitrend/util/GraphUtil.kt @@ -5,13 +5,13 @@ 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 +import org.koin.core.KoinComponent /** * Created by max on 2018/03/22. * Graph request helper class */ - -object GraphUtil { +object GraphUtil : KoinComponent { /** * Builder provider helper method, that provides a default GraphQL Query and Variable Builder @@ -28,8 +28,8 @@ object GraphUtil { * 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) + return !CompatUtil.equals(preferenceKey, Settings._isLightTheme) && + !CompatUtil.equals(preferenceKey, Settings._updateChannel) } /** 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 5554e2aed..6dd4bf61d 100644 --- a/app/src/main/java/com/mxt/anitrend/util/JobSchedulerUtil.kt +++ b/app/src/main/java/com/mxt/anitrend/util/JobSchedulerUtil.kt @@ -25,7 +25,7 @@ object JobSchedulerUtil { * @param context any valid application context */ fun scheduleJob(context: Context) { - val applicationPref = ApplicationPref(context) + val applicationPref = Settings(context) if (applicationPref.isAuthenticated && applicationPref.isNotificationEnabled) { val periodicWorkRequest = PeriodicWorkRequest.Builder(JobDispatcherService::class.java, applicationPref.syncTime.toLong(), TimeUnit.MINUTES) diff --git a/app/src/main/java/com/mxt/anitrend/util/LocaleUtil.kt b/app/src/main/java/com/mxt/anitrend/util/LocaleUtil.kt index ecd855e12..1803dc9a2 100644 --- a/app/src/main/java/com/mxt/anitrend/util/LocaleUtil.kt +++ b/app/src/main/java/com/mxt/anitrend/util/LocaleUtil.kt @@ -13,7 +13,7 @@ import java.util.* object LocaleUtil { fun onAttach(context: Context): Context { - val language = ApplicationPref(context).userLanguage ?: Locale.getDefault().language + val language = Settings(context).userLanguage ?: Locale.getDefault().language return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { updateResources(context, Locale(language)) 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 06600e898..8429c690c 100644 --- a/app/src/main/java/com/mxt/anitrend/util/MarkDownUtil.kt +++ b/app/src/main/java/com/mxt/anitrend/util/MarkDownUtil.kt @@ -8,6 +8,7 @@ import android.text.SpannableStringBuilder import android.text.Spanned import android.util.Log import com.github.rjeschke.txtmark.Processor +import timber.log.Timber /** * Created by max on 2017/03/26. @@ -42,7 +43,7 @@ object MarkDownUtil { result = result.delete(result.lastIndex - 1, result.length) } catch (e: Exception) { e.printStackTrace() - Log.e("convert(input)", e.message) + Timber.tag("convert(input)").w(e) } return result @@ -62,7 +63,7 @@ object MarkDownUtil { result = result.delete(result.length - 1, result.length) } catch (e: Exception) { e.printStackTrace() - Log.e("convert(input...)", e.message) + Timber.tag("convert(input...)").w(e) } return result 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 80e56c1e7..eadad669d 100644 --- a/app/src/main/java/com/mxt/anitrend/util/MediaActionUtil.java +++ b/app/src/main/java/com/mxt/anitrend/util/MediaActionUtil.java @@ -18,6 +18,7 @@ import retrofit2.Call; import retrofit2.Response; +import timber.log.Timber; /** * Created by max on 2018/01/05. @@ -34,6 +35,7 @@ public class MediaActionUtil implements RetroCallback, LifecycleListe private Lifecycle lifecycle; private long mediaId; + private final String TAG = MediaActionUtil.class.getSimpleName(); MediaActionUtil(FragmentActivity context) { this.context = context; @@ -74,7 +76,7 @@ private void showActionDialog(@NonNull MediaBase mediaBase) { MediaDialogUtil.createSeriesManage(context, mediaBase); } catch (Exception e) { e.printStackTrace(); - Log.e(this.toString(), e.getLocalizedMessage()); + Timber.tag(TAG).e(e.getLocalizedMessage()); } } @@ -94,7 +96,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.INSTANCE.getError(response)); + Timber.tag(TAG).w(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) { e.printStackTrace(); - Log.e(this.toString(), e.getLocalizedMessage()); + Timber.tag(TAG).e(e.getLocalizedMessage()); } } @@ -109,7 +112,7 @@ public void onFailure(@NonNull Call call, @NonNull Throwable throwabl NotifyUtil.makeText(context, context.getString(R.string.text_error_request), R.drawable.ic_warning_white_18dp, Toast.LENGTH_SHORT).show(); } catch (Exception e) { e.printStackTrace(); - Log.e(this.toString(), e.getLocalizedMessage()); + Timber.e(e.getLocalizedMessage()); } } }); @@ -147,11 +150,12 @@ public void onResponse(@NonNull Call call, @NonNull Response call, @NonNull Throwable throwa NotifyUtil.makeText(context, context.getString(R.string.text_error_request), R.drawable.ic_warning_white_18dp, Toast.LENGTH_SHORT).show(); } catch (Exception e) { e.printStackTrace(); + Timber.tag(TAG).e(e); } } }); diff --git a/app/src/main/java/com/mxt/anitrend/util/NotificationUtil.kt b/app/src/main/java/com/mxt/anitrend/util/NotificationUtil.kt index ee7b77dbb..4294c0764 100644 --- a/app/src/main/java/com/mxt/anitrend/util/NotificationUtil.kt +++ b/app/src/main/java/com/mxt/anitrend/util/NotificationUtil.kt @@ -9,31 +9,25 @@ import android.graphics.Color import android.net.Uri import android.os.Build import androidx.core.app.NotificationCompat -import androidx.core.app.NotificationCompat.PRIORITY_DEFAULT import androidx.core.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 +import org.koin.core.KoinComponent /** * Created by max on 1/22/2017. * NotificationUtil */ -class NotificationUtil(private val context: Context) { +class NotificationUtil( + private val context: Context, + private val settings: Settings, + private val notificationManager: NotificationManager? +): KoinComponent { 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( @@ -48,15 +42,11 @@ class NotificationUtil(private val context: Context) { ) } - 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())) + .setSound(Uri.parse(settings.notificationsSound)) .setAutoCancel(true) .setPriority(PRIORITY_HIGH) @@ -95,7 +85,8 @@ class NotificationUtil(private val context: Context) { }, notificationCount) ) - notificationManager?.notify(defaultNotificationId.inc(), notificationBuilder.build()) + defaultNotificationId = defaultNotificationId.inc() + notificationManager?.notify(defaultNotificationId, notificationBuilder.build()) } } } diff --git a/app/src/main/java/com/mxt/anitrend/util/Settings.kt b/app/src/main/java/com/mxt/anitrend/util/Settings.kt new file mode 100644 index 000000000..a5d7cf875 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/util/Settings.kt @@ -0,0 +1,427 @@ +package com.mxt.anitrend.util + +import android.content.Context +import android.content.SharedPreferences +import androidx.annotation.IdRes +import androidx.annotation.StyleRes +import androidx.core.content.edit +import androidx.preference.PreferenceManager + +import com.mxt.anitrend.BuildConfig +import com.mxt.anitrend.R + +import java.util.Locale + +/** + * Created by max on 2017/09/16. + * Application preferences + */ + +class Settings(private val context: Context) { + + /** Base Application Values */ + private val _versionCode = "_versionCode" + private val _freshInstall = "_freshInstall" + private val _isAuthenticated = "_isAuthenticated" + + val sharedPreferences: SharedPreferences by lazy(LazyThreadSafetyMode.NONE) { + PreferenceManager.getDefaultSharedPreferences(context) + } + + var isAuthenticated: Boolean + get() = sharedPreferences.getBoolean(_isAuthenticated, false) + set(authenticated) { + sharedPreferences.edit { + putBoolean(_isAuthenticated, authenticated) + 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 + } + + var isFreshInstall: Boolean = true + get() = sharedPreferences.getBoolean(_freshInstall, true) + set(value) { + field = value + sharedPreferences.edit { + putBoolean(_freshInstall, field) + apply() + } + } + + var userLanguage: String = Locale.getDefault().language + get() { + return sharedPreferences.getString( + context.getString(R.string.pref_key_selected_Language), + Locale.getDefault().language + ) ?: Locale.getDefault().language + } + set(value) { + field = value + sharedPreferences.edit { + putString(context.getString(R.string.pref_key_selected_Language), field) + apply() + } + } + + //Returns amount of time in seconds + var syncTime: Int = 15 + get() { + return sharedPreferences.getString( + context.getString(R.string.pref_key_sync_frequency), + "15" + )?.toInt() ?: 15 + } + set(value) { + field = value + sharedPreferences.edit { + putInt(context.getString(R.string.pref_key_sync_frequency), field) + apply() + } + } + + var isNotificationEnabled: Boolean = true + get() = sharedPreferences.getBoolean(context.getString(R.string.pref_key_new_message_notifications), true) + set(value) { + field = value + sharedPreferences.edit { + putBoolean(context.getString(R.string.pref_key_new_message_notifications), field) + apply() + } + } + + var notificationsSound: String = "DEFAULT_SOUND" + get() { + return sharedPreferences.getString( + context.getString(R.string.pref_key_ringtone), + "DEFAULT_SOUND" + ) ?: "DEFAULT_SOUND" + } + set(value) { + field = value + sharedPreferences.edit { + putString(context.getString(R.string.pref_key_ringtone), field) + apply() + } + } + + var isCrashReportsEnabled: Boolean = false + get() = sharedPreferences.getBoolean(context.getString(R.string.pref_key_crash_reports), false) + set(value) { + field = value + sharedPreferences.edit { + putBoolean(context.getString(R.string.pref_key_crash_reports), field) + apply() + } + } + + var isUsageAnalyticsEnabled: Boolean = false + get() = sharedPreferences.getBoolean(context.getString(R.string.pref_key_usage_analytics), false) + set(value) { + field = value + sharedPreferences.edit { + putBoolean(context.getString(R.string.pref_key_usage_analytics), field) + apply() + } + } + + var seasonYear: Int = 0 + get() { + return sharedPreferences.getInt( + KeyUtil.arg_seasonYear, + DateUtil.getCurrentYear(0) + ) + } + set(value) { + field = value + sharedPreferences.edit { + putInt(KeyUtil.arg_seasonYear, field) + apply() + } + } + + @set:KeyUtil.SortOrderType + @get:KeyUtil.SortOrderType + var sortOrder: String = KeyUtil.DESC + get() { + return sharedPreferences.getString( + _sortOrder, + KeyUtil.DESC + ) ?: KeyUtil.DESC + } + set(value) { + field = value + sharedPreferences.edit { + putString(_sortOrder, value) + apply() + } + } + + @set:KeyUtil.MediaStatus + @get:KeyUtil.MediaStatus + var mediaStatus: String? + get() = sharedPreferences.getString(_mediaStatus, null) + set(mediaStatus) { + sharedPreferences.edit { + putString(_mediaStatus, mediaStatus) + apply() + } + } + + @set:KeyUtil.MediaFormat + @get:KeyUtil.MediaFormat + var mediaFormat: String? + get() = sharedPreferences.getString(_mediaFormat, null) + set(mediaFormat) { + sharedPreferences.edit { + putString(_mediaFormat, mediaFormat) + apply() + } + } + + @set:KeyUtil.AnimeFormat + @get:KeyUtil.AnimeFormat + var animeFormat: String? + get() = sharedPreferences.getString(_animeFormat, null) + set(animeFormat) { + sharedPreferences.edit { + putString(_animeFormat, animeFormat) + apply() + } + } + + @set:KeyUtil.MangaFormat + @get:KeyUtil.MangaFormat + var mangaFormat: String? + get() = sharedPreferences.getString(_mangaFormat, null) + set(mangaFormat) { + sharedPreferences.edit { + putString(_mangaFormat, mangaFormat) + apply() + } + } + + @set:KeyUtil.MediaSource + @get:KeyUtil.MediaSource + var mediaSource: String? + get() = sharedPreferences.getString(_mediaSource, null) + set(mediaSource) { + sharedPreferences.edit { + putString(_mediaSource, mediaSource) + apply() + } + } + + @set:KeyUtil.AiringSort + @get:KeyUtil.AiringSort + var airingSort: String? + get() = sharedPreferences.getString(_airingSort, KeyUtil.EPISODE) + set(airingSort) { + sharedPreferences.edit { + putString(_airingSort, airingSort) + apply() + } + } + + @set:KeyUtil.CharacterSort + @get:KeyUtil.CharacterSort + var characterSort: String? + get() = sharedPreferences.getString(_characterSort, KeyUtil.ROLE) + set(characterSort) { + sharedPreferences.edit { + putString(_characterSort, characterSort) + apply() + } + } + + @set:KeyUtil.MediaListSort + @get:KeyUtil.MediaListSort + var mediaListSort: String? + get() = sharedPreferences.getString(_mediaListSort, KeyUtil.PROGRESS) + set(mediaListSort) { + sharedPreferences.edit { + putString(_mediaListSort, mediaListSort) + apply() + } + } + + @set:KeyUtil.MediaSort + @get:KeyUtil.MediaSort + var mediaSort: String? + get() = sharedPreferences.getString(_mediaSort, KeyUtil.POPULARITY) + set(mediaSort) { + sharedPreferences.edit { + putString(_mediaSort, mediaSort) + apply() + } + } + @set:KeyUtil.MediaTrendSort + @get:KeyUtil.MediaTrendSort + var mediaTrendSort: String? + get() = sharedPreferences.getString(_mediaTrendSort, KeyUtil.TRENDING) + set(mediaTrendSort) { + sharedPreferences.edit { + putString(_mediaTrendSort, mediaTrendSort) + apply() + } + } + + @set:KeyUtil.ReviewSort + @get:KeyUtil.ReviewSort + var reviewSort: String? + get() = sharedPreferences.getString(_reviewSort, KeyUtil.ID) + set(reviewSort) { + sharedPreferences.edit { + putString(_reviewSort, reviewSort) + apply() + } + } + + @set:KeyUtil.StaffSort + @get:KeyUtil.StaffSort + var staffSort: String? + get() = sharedPreferences.getString(_staffSort, KeyUtil.ROLE) + set(staffSort) { + sharedPreferences.edit { + putString(_staffSort, staffSort) + apply() + } + } + + @set:KeyUtil.Channel + @get:KeyUtil.Channel + var updateChannel: String? + get() = sharedPreferences.getString(_updateChannel, KeyUtil.STABLE) + set(channel) { + sharedPreferences.edit { + putString(_updateChannel, channel) + apply() + } + } + + val isUpdated: Boolean + get() = versionCode < BuildConfig.VERSION_CODE + + var versionCode: Int = 1 + get() = sharedPreferences.getInt(_versionCode, 1) + set(value) { + field = value + sharedPreferences.edit { + putInt(_versionCode, value) + apply() + } + } + + var selectedGenres: Map? + get() { + val selected = sharedPreferences.getString(_genreFilter, null) + return GenreTagUtil().convertToEntity(selected) + } + set(selectedIndices) { + val selected = GenreTagUtil() + .convertToJson(selectedIndices) + sharedPreferences.edit { + putString(_genreFilter, selected) + apply() + } + } + + var selectedTags: Map? + get() { + val selected = sharedPreferences.getString(_tagFilter, null) + return GenreTagUtil().convertToEntity(selected) + } + set(selectedIndices) { + val selected = GenreTagUtil() + .convertToJson(selectedIndices) + sharedPreferences.edit { + putString(_tagFilter, selected) + apply() + } + } + + fun toggleTheme() { + sharedPreferences.edit { + putInt(_isLightTheme, if (theme == R.style.AppThemeLight) R.style.AppThemeDark else R.style.AppThemeLight) + apply() + } + } + + fun saveSeasonYear(year: Int) { + sharedPreferences.edit { + putInt(KeyUtil.arg_seasonYear, year) + apply() + } + } + + + fun shouldShowTipFor(@KeyUtil.TapTargetType tipType: String): Boolean { + return sharedPreferences.getBoolean(tipType, true) + } + + fun disableTipFor(@KeyUtil.TapTargetType tipType: String) { + sharedPreferences.edit { + putBoolean(tipType, false) + apply() + } + } + + fun saveSortOrder(@KeyUtil.SortOrderType sortOrder: String) { + sharedPreferences.edit { + putString(_sortOrder, sortOrder) + apply() + } + } + + fun setUpdated() { + sharedPreferences.edit { + putInt(_versionCode, BuildConfig.VERSION_CODE) + 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/TutorialUtil.java b/app/src/main/java/com/mxt/anitrend/util/TutorialUtil.java index 5a127feca..37e66c318 100644 --- a/app/src/main/java/com/mxt/anitrend/util/TutorialUtil.java +++ b/app/src/main/java/com/mxt/anitrend/util/TutorialUtil.java @@ -11,6 +11,7 @@ import com.mxt.anitrend.base.custom.presenter.CommonPresenter; +import timber.log.Timber; import uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt; import uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt.PromptStateChangeListener; @@ -23,7 +24,7 @@ * new TutorialUtil().setContext(this) * .setFocalColour(R.color.colorGrey600) * .setTapTarget(KeyUtil.KEY_NOTIFICATION_TIP) - * .setApplicationPref(getPresenter().getApplicationPref()) + * .setSettings(getPresenter().getSettings()) * .createTapTarget( * R.string.tip_notifications_title, * R.string.tip_notifications_text, @@ -39,7 +40,8 @@ public class TutorialUtil { private @Nullable PromptStateChangeListener listener; private FragmentActivity context; - private ApplicationPref applicationPref; + private Settings settings; + private final String TAG = TutorialUtil.class.getSimpleName(); /** * Optional. After the tip is dismissed, this helper class will automatically save @@ -88,10 +90,10 @@ public TutorialUtil setFocalColour(@ColorRes int focalColour) { * the presenters application preference object rather than creating a new one. *
* - * @see CommonPresenter#getApplicationPref() + * @see CommonPresenter#getSettings() */ - public TutorialUtil setApplicationPref(ApplicationPref applicationPref) { - this.applicationPref = applicationPref; + public TutorialUtil setSettings(Settings settings) { + this.settings = settings; return this; } @@ -102,11 +104,11 @@ public TutorialUtil setApplicationPref(ApplicationPref applicationPref) { * @param resource Item that should be focused on by the application tip */ public @Nullable MaterialTapTargetPrompt.Builder createTapTarget(@IdRes int resource) { - if(applicationPref == null) { - Log.e(toString(), "Did you forget to set the current application preferences?"); + if(settings == null) { + Timber.tag(TAG).i("Did you forget to set the current application preferences?"); return null; } - if (!TapTargetUtil.isActive(tapTarget) && applicationPref.shouldShowTipFor(tapTarget)) + if (!TapTargetUtil.isActive(tapTarget) && settings.shouldShowTipFor(tapTarget)) return TapTargetUtil.buildDefault(context, resource) .setPromptStateChangeListener(defaultStateChangeListener) .setFocalColour(CompatUtil.INSTANCE.getColor(context, focalColour)); @@ -122,11 +124,11 @@ public TutorialUtil setApplicationPref(ApplicationPref applicationPref) { * @param resource Item that should be focused on by the application tip */ public @Nullable MaterialTapTargetPrompt.Builder createTapTarget(@StringRes int primary, @StringRes int secondary, @IdRes int resource) { - if(applicationPref == null) { - Log.e(toString(), "Did you forget to set the current application preferences?"); + if(settings == null) { + Timber.tag(TAG).i("Did you forget to set the current application preferences?"); return null; } - if (!TapTargetUtil.isActive(tapTarget) && applicationPref.shouldShowTipFor(tapTarget)) + if (!TapTargetUtil.isActive(tapTarget) && settings.shouldShowTipFor(tapTarget)) return TapTargetUtil.buildDefault(context, primary, secondary, resource) .setPromptStateChangeListener(defaultStateChangeListener) .setFocalColour(CompatUtil.INSTANCE.getColor(context, focalColour)); @@ -142,11 +144,11 @@ public TutorialUtil setApplicationPref(ApplicationPref applicationPref) { * @param resource Item that should be focused on by the application tip */ public @Nullable MaterialTapTargetPrompt.Builder createTapTarget(@StringRes int primary, @StringRes int secondary, View resource) { - if(applicationPref == null) { - Log.e(toString(), "Did you forget to set the current application preferences?"); + if(settings == null) { + Timber.tag(TAG).i("Did you forget to set the current application preferences?"); return null; } - if (!TapTargetUtil.isActive(tapTarget) && applicationPref.shouldShowTipFor(tapTarget)) + if (!TapTargetUtil.isActive(tapTarget) && settings.shouldShowTipFor(tapTarget)) return TapTargetUtil.buildDefault(context, primary, secondary, resource) .setPromptStateChangeListener(defaultStateChangeListener) .setFocalColour(CompatUtil.INSTANCE.getColor(context, focalColour)); @@ -160,11 +162,11 @@ public TutorialUtil setApplicationPref(ApplicationPref applicationPref) { * @param resource Item that should be focused on by the application tip */ public void showTapTarget(@IdRes int resource) { - if(applicationPref == null) { - Log.e(toString(), "Did you forget to set the current application preferences?"); + if(settings == null) { + Timber.tag(TAG).i("Did you forget to set the current application preferences?"); return; } - if (!TapTargetUtil.isActive(tapTarget) && applicationPref.shouldShowTipFor(tapTarget)) + if (!TapTargetUtil.isActive(tapTarget) && settings.shouldShowTipFor(tapTarget)) TapTargetUtil.buildDefault(context, resource) .setPromptStateChangeListener(defaultStateChangeListener) .setFocalColour(CompatUtil.INSTANCE.getColor(context, focalColour)) @@ -180,11 +182,11 @@ public void showTapTarget(@IdRes int resource) { * @param resource Item that should be focused on by the application tip */ public void showTapTarget(@StringRes int primary, @StringRes int secondary, @IdRes int resource) { - if(applicationPref == null) { - Log.e(toString(), "Did you forget to set the current application preferences?"); + if(settings == null) { + Timber.tag(TAG).i("Did you forget to set the current application preferences?"); return; } - if (!TapTargetUtil.isActive(tapTarget) && applicationPref.shouldShowTipFor(tapTarget)) + if (!TapTargetUtil.isActive(tapTarget) && settings.shouldShowTipFor(tapTarget)) TapTargetUtil.buildDefault(context, primary, secondary, resource) .setPromptStateChangeListener(defaultStateChangeListener) .setFocalColour(CompatUtil.INSTANCE.getColor(context, focalColour)) @@ -200,11 +202,11 @@ public void showTapTarget(@StringRes int primary, @StringRes int secondary, @IdR * @param resource Item that should be focused on by the application tip */ public void showTapTarget(@StringRes int primary, @StringRes int secondary, View resource) { - if(applicationPref == null) { - Log.e(toString(), "Did you forget to set the current application preferences?"); + if(settings == null) { + Timber.tag(TAG).i("Did you forget to set the current application preferences?"); return; } - if (!TapTargetUtil.isActive(tapTarget) && applicationPref.shouldShowTipFor(tapTarget)) + if (!TapTargetUtil.isActive(tapTarget) && settings.shouldShowTipFor(tapTarget)) TapTargetUtil.buildDefault(context, primary, secondary, resource) .setPromptStateChangeListener(defaultStateChangeListener) .setFocalColour(CompatUtil.INSTANCE.getColor(context, focalColour)) @@ -217,7 +219,7 @@ public void onPromptStateChanged(@NonNull MaterialTapTargetPrompt prompt, int st switch (state) { case MaterialTapTargetPrompt.STATE_NON_FOCAL_PRESSED: case MaterialTapTargetPrompt.STATE_FOCAL_PRESSED: - applicationPref.disableTipFor(tapTarget); + settings.disableTipFor(tapTarget); break; case MaterialTapTargetPrompt.STATE_DISMISSED: TapTargetUtil.setActive(tapTarget, true); diff --git a/app/src/main/java/com/mxt/anitrend/util/migration/Migration.kt b/app/src/main/java/com/mxt/anitrend/util/migration/Migration.kt index bb65c46c6..3dd00a346 100644 --- a/app/src/main/java/com/mxt/anitrend/util/migration/Migration.kt +++ b/app/src/main/java/com/mxt/anitrend/util/migration/Migration.kt @@ -1,6 +1,6 @@ package com.mxt.anitrend.util.migration -import com.mxt.anitrend.util.ApplicationPref +import com.mxt.anitrend.util.Settings /** * Creates a new migration between [startVersion] and [endVersion]. @@ -12,5 +12,30 @@ abstract class Migration( val startVersion: Int, val endVersion: Int ) { - abstract fun applyMigration(applicationPref: ApplicationPref) + abstract fun applyMigration(settings: Settings) + + /** + * Indicates whether some other object is "equal to" this one. Implementations must fulfil the following + * requirements: + * + * * Reflexive: for any non-null value `x`, `x.equals(x)` should return true. + * * Symmetric: for any non-null values `x` and `y`, `x.equals(y)` should return true if and only if `y.equals(x)` returns true. + * * Transitive: for any non-null values `x`, `y`, and `z`, if `x.equals(y)` returns true and `y.equals(z)` returns true, then `x.equals(z)` should return true. + * * Consistent: for any non-null values `x` and `y`, multiple invocations of `x.equals(y)` consistently return true or consistently return false, provided no information used in `equals` comparisons on the objects is modified. + * * Never equal to null: for any non-null value `x`, `x.equals(null)` should return false. + * + * Read more about [equality](https://kotlinlang.org/docs/reference/equality.html) in Kotlin. + */ + override fun equals(other: Any?): Boolean { + return when (other) { + is Migration -> startVersion == other.startVersion && endVersion == other.endVersion + else -> super.equals(other) + } + } + + override fun hashCode(): Int { + var result = startVersion + result = 31 * result + endVersion + return result + } } \ No newline at end of file diff --git a/app/src/main/java/com/mxt/anitrend/util/migration/MigrationUtil.kt b/app/src/main/java/com/mxt/anitrend/util/migration/MigrationUtil.kt index aa98499ba..72bd7ed2d 100644 --- a/app/src/main/java/com/mxt/anitrend/util/migration/MigrationUtil.kt +++ b/app/src/main/java/com/mxt/anitrend/util/migration/MigrationUtil.kt @@ -1,40 +1,58 @@ package com.mxt.anitrend.util.migration -import android.util.Log +import androidx.annotation.VisibleForTesting import com.mxt.anitrend.BuildConfig -import com.mxt.anitrend.util.ApplicationPref +import com.mxt.anitrend.util.Settings import com.mxt.anitrend.util.migration.contract.IMigrationUtil import org.koin.core.KoinComponent import org.koin.core.inject +import timber.log.Timber class MigrationUtil private constructor( private val migrations: List ) : IMigrationUtil, KoinComponent { - private val applicationPref by inject() + private val settings by inject() + + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + fun getMigrationStrategies(): List { + val currentVersion = settings.versionCode + val minMigrations = migrations.filter { migration -> + IntRange( + migration.startVersion, + migration.endVersion + ).contains(currentVersion) + } + val maxMigrations = migrations.filter { migration -> + IntRange( + migration.startVersion, + migration.endVersion + ).contains(BuildConfig.VERSION_CODE) + } + + return minMigrations + maxMigrations + } /** * Applies migration of the application if necessary */ override fun applyMigration(): Boolean { - if (applicationPref.isUpdated) { - Log.d(TAG, "Application has been updated: from ${applicationPref.versionCode} - ${BuildConfig.VERSION_CODE}, checking for migration scripts") - val applicableMigrations = migrations.takeWhile { - applicationPref.versionCode >= it.startVersion && it.endVersion <= BuildConfig.VERSION_CODE - } - if (applicableMigrations.isNotEmpty()) + if (settings.isUpdated) { + Timber.tag(TAG).d("Application has been updated: from ${settings.versionCode} - ${BuildConfig.VERSION_CODE}, checking for migration scripts") + val strategies= getMigrationStrategies() + if (strategies.isNotEmpty()) return try { - applicableMigrations.forEach { - Log.d(TAG, "Applying migration for: ${it.startVersion} - ${it.endVersion}") - it.applyMigration(applicationPref) + strategies.forEach { strategy -> + strategy.applyMigration(settings) } true } catch (ex: Exception) { + Timber.tag(TAG).e(ex) ex.printStackTrace() false } } - Log.d(TAG, "No migrations to run for this version of the application") + Timber.tag(TAG).d("No migrations to run for this version of the application") return true } @@ -42,7 +60,8 @@ class MigrationUtil private constructor( private val migrations: MutableList = ArrayList() fun addMigration(migration: Migration): Builder { - migrations.add(migration) + if (!migrations.contains(migration)) + migrations.add(migration) return this } diff --git a/app/src/main/java/com/mxt/anitrend/util/migration/Migrations.kt b/app/src/main/java/com/mxt/anitrend/util/migration/Migrations.kt index 785259423..baeaac538 100644 --- a/app/src/main/java/com/mxt/anitrend/util/migration/Migrations.kt +++ b/app/src/main/java/com/mxt/anitrend/util/migration/Migrations.kt @@ -2,20 +2,44 @@ package com.mxt.anitrend.util.migration import android.os.Build import androidx.core.content.edit +import com.mxt.anitrend.App +import com.mxt.anitrend.analytics.contract.ISupportAnalytics import com.mxt.anitrend.data.DatabaseHelper import com.mxt.anitrend.extension.appContext import com.mxt.anitrend.model.api.retro.WebFactory -import com.mxt.anitrend.util.AnalyticsUtil -import com.mxt.anitrend.util.ApplicationPref import com.mxt.anitrend.util.JobSchedulerUtil +import com.mxt.anitrend.util.Settings import com.mxt.anitrend.util.ShortcutUtil import org.koin.core.KoinComponent +import org.koin.core.inject +import timber.log.Timber object Migrations : KoinComponent { + private val supportAnalytics by inject() + + val MIGRATION_90_94 = object : Migration(90, 94) { + override fun applyMigration(settings: Settings) { + Timber.i("Applying test migration from 90 - 94") + } + } + + val MIGRATION_95_100 = object : Migration(95, 100) { + override fun applyMigration(settings: Settings) { + Timber.i("Applying test migration from 95 - 100") + } + } + + val MIGRATION_101_108 = object : Migration(101, 108) { + override fun applyMigration(settings: Settings) { + Timber.i("Applying test migration from 101 - 109") + } + } + val MIGRATION_109_132 = object : Migration(109, 132) { - override fun applyMigration(applicationPref: ApplicationPref) { - applicationPref.sharedPreferences.edit { + override fun applyMigration(settings: Settings) { + Timber.i("Applying migration from 109 - 132") + settings.sharedPreferences.edit { clear() apply() } @@ -24,7 +48,25 @@ object Migrations : KoinComponent { WebFactory.invalidate() if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) ShortcutUtil.removeAllDynamicShortcuts(appContext) - AnalyticsUtil.clearSession() + supportAnalytics.resetAnalyticsData() + } + } + + val MIGRATION_133_135 = object : Migration(133, 135) { + override fun applyMigration(settings: Settings) { + Timber.i("Applying migration from 133 - 135") + } + } + + val MIGRATION_136_140 = object : Migration(136, 140) { + override fun applyMigration(settings: Settings) { + Timber.i("Applying migration from 136 - 140") + } + } + + val MIGRATION_141_145 = object : Migration(141, 145) { + override fun applyMigration(settings: Settings) { + Timber.i("Applying migration from 141 - 145") } } } \ No newline at end of file diff --git a/app/src/main/java/com/mxt/anitrend/view/activity/base/AboutActivity.kt b/app/src/main/java/com/mxt/anitrend/view/activity/base/AboutActivity.kt index 7a1226af0..55b5febad 100644 --- a/app/src/main/java/com/mxt/anitrend/view/activity/base/AboutActivity.kt +++ b/app/src/main/java/com/mxt/anitrend/view/activity/base/AboutActivity.kt @@ -1,12 +1,16 @@ package com.mxt.anitrend.view.activity.base import android.os.Bundle +import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.widget.Toolbar import butterknife.ButterKnife import com.mxt.anitrend.R import com.mxt.anitrend.base.custom.activity.ActivityBase import com.mxt.anitrend.presenter.base.BasePresenter +import com.mxt.anitrend.util.CompatUtil +import com.mxt.anitrend.util.Settings import com.mxt.anitrend.view.fragment.detail.AboutFragment +import org.koin.android.ext.android.inject class AboutActivity : ActivityBase() { 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 89f34694b..18acb8eb6 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 @@ -14,7 +14,7 @@ import android.view.ViewGroup; import com.mxt.anitrend.R; -import com.mxt.anitrend.util.ApplicationPref; +import com.mxt.anitrend.util.Settings; import com.mxt.anitrend.util.CompatUtil; /** @@ -25,11 +25,11 @@ public abstract class AppCompatPreferenceActivity extends PreferenceActivity { private AppCompatDelegate mDelegate; - protected ApplicationPref applicationPref; + protected Settings settings; protected void configureActivity() { - @StyleRes int style = applicationPref.getTheme(); - if(!CompatUtil.INSTANCE.isLightTheme(style) && applicationPref.isBlackThemeEnabled()) + @StyleRes int style = settings.getTheme(); + if(!CompatUtil.INSTANCE.isLightTheme(style) && settings.isBlackThemeEnabled()) setTheme(R.style.AppThemeBlack); else setTheme(style); @@ -39,7 +39,7 @@ protected void configureActivity() { protected void onCreate(Bundle savedInstanceState) { getDelegate().installViewFactory(); getDelegate().onCreate(savedInstanceState); - applicationPref = new ApplicationPref(this); + settings = new Settings(this); configureActivity(); super.onCreate(savedInstanceState); } 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 e4e8ea61e..8046f0a9a 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 @@ -30,6 +30,7 @@ import butterknife.BindView; import butterknife.ButterKnife; +import timber.log.Timber; /** * Created by max on 2017/11/14. @@ -113,7 +114,7 @@ else if(ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permi intent.setData(Uri.parse(mImageUri)); startActivity(intent); } catch (Exception e) { - Log.e(toString(), e.getLocalizedMessage()); + Timber.tag(TAG).e(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/LoggingActivity.kt b/app/src/main/java/com/mxt/anitrend/view/activity/base/LoggingActivity.kt new file mode 100644 index 000000000..f78fd18f7 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/view/activity/base/LoggingActivity.kt @@ -0,0 +1,140 @@ +package com.mxt.anitrend.view.activity.base + +import android.Manifest +import android.content.Intent +import android.os.Bundle +import android.os.Environment +import android.view.Menu +import android.view.MenuItem +import android.widget.Toast +import androidx.appcompat.widget.AppCompatTextView +import androidx.appcompat.widget.Toolbar +import butterknife.BindView +import butterknife.ButterKnife +import butterknife.Unbinder +import com.mxt.anitrend.BuildConfig +import com.mxt.anitrend.R +import com.mxt.anitrend.base.custom.activity.ActivityBase +import com.mxt.anitrend.base.custom.view.text.SingleLineTextView +import com.mxt.anitrend.extension.launchCatching +import com.mxt.anitrend.presenter.base.BasePresenter +import com.mxt.anitrend.util.NotifyUtil +import com.nguyenhoanglam.progresslayout.ProgressLayout +import kotlinx.coroutines.* +import timber.log.Timber +import java.io.File +import java.io.FileWriter +import java.io.IOException +import java.io.InputStreamReader + +class LoggingActivity : ActivityBase(), CoroutineScope by MainScope() { + + @BindView(R.id.toolbar) + lateinit var toolbar: Toolbar + + @BindView(R.id.report_display) + lateinit var reportLogTextView: AppCompatTextView + + @BindView(R.id.application_version) + lateinit var applicationVersionTextViwe: SingleLineTextView + + @BindView(R.id.stateLayout) + lateinit var progressLayout: ProgressLayout + + private var binder: Unbinder? = null + + private val log = StringBuilder() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_logging) + binder = ButterKnife.bind(this) + setSupportActionBar(toolbar) + } + + override fun onPostCreate(savedInstanceState: Bundle?) { + super.onPostCreate(savedInstanceState) + applicationVersionTextViwe.text = getString( + R.string.text_about_appication_version, + BuildConfig.VERSION_NAME + ) + } + + override fun onCreateOptionsMenu(menu: Menu?): Boolean { + menuInflater.inflate(R.menu.logging_menu, menu) + return true + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + R.id.action_save_log -> { + if (requestPermissionIfMissing(Manifest.permission.WRITE_EXTERNAL_STORAGE)) { + try { + val root = File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), + "AniTrend Logcat.txt") + FileWriter(root).use { + it.append(log.toString()) + } + NotifyUtil.makeText(applicationContext, R.string.bug_report_saved, Toast.LENGTH_SHORT).show() + } catch (e: IOException) { + Timber.tag(TAG).e(e) + e.printStackTrace() + } + } + } + R.id.action_share_log -> { + val intent = Intent().apply { + action = Intent.ACTION_SEND + putExtra(Intent.EXTRA_TEXT, log.toString()) + type = "text/plain" + } + startActivity(intent) + } + } + return super.onOptionsItemSelected(item) + } + + /** + * Dispatch onResume() to fragments. Note that for better inter-operation + * with older versions of the platform, at the point of this call the + * fragments attached to the activity are *not* resumed. This means + * that in some cases the previous state may still be saved, not allowing + * fragment transactions that modify the state. To correctly interact + * with fragments in their proper state, you should instead override + * [.onResumeFragments]. + */ + override fun onResume() { + super.onResume() + onActivityReady() + } + + override fun onActivityReady() { + progressLayout.showLoading() + makeRequest() + } + + override fun updateUI() { + progressLayout.showContent() + reportLogTextView.text = log.toString() + } + + override fun makeRequest() { + launchCatching (coroutineContext = Dispatchers.IO) { + val process = Runtime.getRuntime().exec("logcat -d -v threadtime com.mxt.anitrend:*") + InputStreamReader(process.inputStream).useLines { sequence -> + sequence.iterator().forEach { + log.append(it).append("\n") + } + } + withContext(Dispatchers.Main) { + updateUI() + } + } + } + + override fun onDestroy() { + super.onDestroy() + binder?.unbind() + cancel() + } +} diff --git a/app/src/main/java/com/mxt/anitrend/view/activity/base/ReportActivity.java b/app/src/main/java/com/mxt/anitrend/view/activity/base/ReportActivity.java deleted file mode 100644 index 1f901599e..000000000 --- a/app/src/main/java/com/mxt/anitrend/view/activity/base/ReportActivity.java +++ /dev/null @@ -1,79 +0,0 @@ -package com.mxt.anitrend.view.activity.base; - -import android.Manifest; -import android.os.Bundle; - -import com.mxt.anitrend.R; -import com.mxt.anitrend.base.custom.activity.ActivityBase; -import com.mxt.anitrend.presenter.base.BasePresenter; - -import android.os.Environment; -import androidx.annotation.Nullable; - -import android.widget.TextView; -import android.widget.Toast; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStreamReader; - -public class ReportActivity extends ActivityBase { - - private StringBuilder log; - - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_report); - log = new StringBuilder(); - } - - @Override - protected void onPostCreate(@Nullable Bundle savedInstanceState) { - super.onPostCreate(savedInstanceState); - findViewById(R.id.save_logcat_button).setOnClickListener(view -> { - if (requestPermissionIfMissing(Manifest.permission.WRITE_EXTERNAL_STORAGE)) { - try { - File root = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), - "AniTrend Logcat.txt"); - FileWriter writer = new FileWriter(root); - writer.append(log.toString()); - writer.flush(); - writer.close(); - Toast.makeText(getApplicationContext(), R.string.bug_report_saved, Toast.LENGTH_LONG).show(); - } catch (IOException e) { - e.printStackTrace(); - } - } - }); - onActivityReady(); - } - - @Override - protected void onActivityReady() { - updateUI(); - } - - @Override - protected void updateUI() { - try { - Process process = Runtime.getRuntime().exec("logcat -d -v threadtime com.mxt.anitrend:*"); - BufferedReader bufferedReader = new BufferedReader( - new InputStreamReader(process.getInputStream())); - - String line; - while ((line = bufferedReader.readLine()) != null) { - log.append(line).append("\n"); - } - ((TextView) findViewById(R.id.report_display)).setText(log.toString()); - } catch (IOException e) { - e.printStackTrace(); - } - } - - @Override - protected void makeRequest() { - } -} 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 a9272f12f..842f3d708 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 @@ -48,13 +48,13 @@ public class SettingsActivity extends AppCompatPreferenceActivity { // Change the application theme if the current theme is not in dark mode if (CompatUtil.INSTANCE.equals(key, getString(R.string.pref_key_black_theme))) if(CompatUtil.INSTANCE.isLightTheme(getApplicationContext())) - applicationPref.toggleTheme(); + settings.toggleTheme(); Toast.makeText(getApplicationContext(), R.string.text_application_restart_required, Toast.LENGTH_LONG).show(); } else if (CompatUtil.INSTANCE.equals(key, getString(R.string.pref_key_sync_frequency))) { JobSchedulerUtil.INSTANCE.cancelJob(); JobSchedulerUtil.INSTANCE.scheduleJob(getApplicationContext()); } else if (CompatUtil.INSTANCE.equals(key, getString(R.string.pref_key_new_message_notifications))) { - if (applicationPref.isNotificationEnabled()) + if (settings.isNotificationEnabled()) JobSchedulerUtil.INSTANCE.scheduleJob(getApplicationContext()); else JobSchedulerUtil.INSTANCE.cancelJob(); @@ -339,15 +339,15 @@ public boolean onOptionsItemSelected(MenuItem item) { @Override protected void onPostResume() { super.onPostResume(); - if (applicationPref != null) - applicationPref.getSharedPreferences() + if (settings != null) + settings.getSharedPreferences() .registerOnSharedPreferenceChangeListener(onSharedPreferenceChangeListener); } @Override protected void onPause() { - if (applicationPref != null) - applicationPref.getSharedPreferences() + if (settings != null) + settings.getSharedPreferences() .unregisterOnSharedPreferenceChangeListener(onSharedPreferenceChangeListener); super.onPause(); } 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 96fc95464..b7667ae4d 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 @@ -24,7 +24,7 @@ import com.mxt.anitrend.databinding.ActivityShareContentBinding; import com.mxt.anitrend.model.entity.anilist.FeedList; import com.mxt.anitrend.presenter.base.BasePresenter; -import com.mxt.anitrend.util.ApplicationPref; +import com.mxt.anitrend.util.Settings; import com.mxt.anitrend.util.CompatUtil; import com.mxt.anitrend.util.DialogUtil; import com.mxt.anitrend.util.KeyUtil; @@ -99,7 +99,7 @@ public void onSlide(@NonNull View bottomSheet, float slideOffset) { */ @Override protected void configureActivity() { - setTheme(new ApplicationPref(this).getTheme() == R.style.AppThemeLight ? + setTheme(new Settings(this).getTheme() == R.style.AppThemeLight ? R.style.AppThemeLight_Translucent: R.style.AppThemeDark_Translucent); } 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 4cbe291a5..3fd8241e7 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 @@ -64,7 +64,7 @@ protected void onPostCreate(@Nullable Bundle savedInstanceState) { @Override public boolean onCreateOptionsMenu(Menu menu) { - boolean isAuth = getPresenter().getApplicationPref().isAuthenticated(); + boolean isAuth = getPresenter().getSettings().isAuthenticated(); getMenuInflater().inflate(R.menu.custom_menu, menu); menu.findItem(R.id.action_favourite).setVisible(isAuth); if(isAuth) { 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 ce0e2950b..61d9638fe 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 @@ -80,7 +80,7 @@ protected void onPostCreate(@Nullable Bundle savedInstanceState) { @Override public boolean onCreateOptionsMenu(Menu menu) { - boolean isAuth = getPresenter().getApplicationPref().isAuthenticated(); + boolean isAuth = getPresenter().getSettings().isAuthenticated(); getMenuInflater().inflate(R.menu.media_base_menu, menu); menu.findItem(R.id.action_favourite).setVisible(isAuth); @@ -153,11 +153,11 @@ protected void updateUI() { binding.setOnClickListener(this); WideImageView.setImage(binding.seriesBanner, model.getBannerImage()); setFavouriteWidgetMenuItemIcon(); setManageMenuItemIcon(); - if(getPresenter().getApplicationPref().isAuthenticated()) { + if(getPresenter().getSettings().isAuthenticated()) { MaterialTapTargetPrompt.Builder favouritesPrompt = new TutorialUtil().setContext(this) .setFocalColour(R.color.colorGrey600) .setTapTarget(KeyUtil.KEY_DETAIL_TIP) - .setApplicationPref(getPresenter().getApplicationPref()) + .setSettings(getPresenter().getSettings()) .createTapTarget(R.string.tip_series_options_title, R.string.tip_series_options_message, R.id.action_manage); TapTargetUtil.showMultiplePrompts(favouritesPrompt); 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 9e637a719..f9f7a5ed3 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 @@ -134,14 +134,14 @@ protected void updateUI() { new TutorialUtil().setContext(this) .setFocalColour(R.color.colorGrey600) .setTapTarget(KeyUtil.KEY_NOTIFICATION_TIP) - .setApplicationPref(getPresenter().getApplicationPref()) + .setSettings(getPresenter().getSettings()) .showTapTarget(R.string.tip_notifications_title, R.string.tip_notifications_text, R.id.action_notification); } else { new TutorialUtil().setContext(this) .setFocalColour(R.color.colorGrey600) .setTapTarget(KeyUtil.KEY_MESSAGE_TIP) - .setApplicationPref(getPresenter().getApplicationPref()) + .setSettings(getPresenter().getSettings()) .showTapTarget(R.string.tip_compose_message_title, R.string.tip_compose_message_text, R.id.action_message); } 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 19becccf7..6a3c0adb1 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 @@ -63,7 +63,7 @@ protected void onPostCreate(@Nullable Bundle savedInstanceState) { @Override public boolean onCreateOptionsMenu(Menu menu) { - boolean isAuth = getPresenter().getApplicationPref().isAuthenticated(); + boolean isAuth = getPresenter().getSettings().isAuthenticated(); getMenuInflater().inflate(R.menu.custom_menu, menu); menu.findItem(R.id.action_favourite).setVisible(isAuth); if(isAuth) { 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 69533f6fb..1e49c9ff7 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 @@ -61,7 +61,7 @@ protected void onPostCreate(@Nullable Bundle savedInstanceState) { @Override public boolean onCreateOptionsMenu(Menu menu) { - boolean isAuth = getPresenter().getApplicationPref().isAuthenticated(); + boolean isAuth = getPresenter().getSettings().isAuthenticated(); getMenuInflater().inflate(R.menu.custom_menu, menu); menu.findItem(R.id.action_favourite).setVisible(isAuth); if(isAuth) { 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 deleted file mode 100644 index 07f5efe50..000000000 --- a/app/src/main/java/com/mxt/anitrend/view/activity/index/LoginActivity.java +++ /dev/null @@ -1,242 +0,0 @@ -package com.mxt.anitrend.view.activity.index; - -import androidx.lifecycle.Observer; -import android.content.Intent; -import androidx.databinding.DataBindingUtil; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import androidx.annotation.Nullable; -import android.text.TextUtils; -import android.util.Log; -import android.view.View; -import android.widget.Toast; - -import androidx.work.Data; -import androidx.work.OneTimeWorkRequest; -import androidx.work.WorkInfo; -import androidx.work.WorkManager; - -import com.mxt.anitrend.R; -import com.mxt.anitrend.base.custom.activity.ActivityBase; -import com.mxt.anitrend.base.custom.async.WebTokenRequest; -import com.mxt.anitrend.databinding.ActivityLoginBinding; -import com.mxt.anitrend.model.api.retro.WebFactory; -import com.mxt.anitrend.model.entity.anilist.User; -import com.mxt.anitrend.presenter.base.BasePresenter; -import com.mxt.anitrend.presenter.widget.WidgetPresenter; -import com.mxt.anitrend.util.AnalyticsUtil; -import com.mxt.anitrend.util.ApplicationPref; -import com.mxt.anitrend.util.GraphUtil; -import com.mxt.anitrend.util.JobSchedulerUtil; -import com.mxt.anitrend.util.KeyUtil; -import com.mxt.anitrend.util.NotifyUtil; -import com.mxt.anitrend.util.ShortcutUtil; -import com.mxt.anitrend.worker.AuthenticatorWorker; - -/** - * Created by max on 2017/11/03. - * Authentication activity - */ - -public class LoginActivity extends ActivityBase implements View.OnClickListener { - - private ActivityLoginBinding binding; - private User model; - - /** - * Some activities may have custom themes and if that's the case - * override this method and set your own theme style, also if you wish - * to apply the default navigation bar style for light themes - * @see ActivityBase#configureActivity() () if running android Oreo + - */ - @Override - protected void configureActivity() { - setTheme(new ApplicationPref(this).getTheme() == R.style.AppThemeLight ? - R.style.AppThemeLight_Translucent: R.style.AppThemeDark_Translucent); - } - - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - binding = DataBindingUtil.setContentView(this, R.layout.activity_login); - setPresenter(new BasePresenter(getApplicationContext())); - setViewModel(true); - } - - @Override - protected void onPostCreate(@Nullable Bundle savedInstanceState) { - super.onPostCreate(savedInstanceState); - onActivityReady(); - } - - /** - * Make decisions, check for permissions or fire background threads from this method - * N.B. Must be called after onPostCreate - */ - @Override - protected void onActivityReady() { - binding.setOnClickListener(this); - if(getPresenter().getApplicationPref().isAuthenticated()) { - NotifyUtil.makeText(this, R.string.text_already_authenticated, Toast.LENGTH_SHORT).show(); - binding.widgetFlipper.setVisibility(View.GONE); - } else - checkNewIntent(getIntent()); - } - - @Override - protected void updateUI() { - if(getPresenter().getApplicationPref().isNotificationEnabled()) - JobSchedulerUtil.INSTANCE.scheduleJob(getApplicationContext()); - createApplicationShortcuts(); - finish(); - } - - private void createApplicationShortcuts() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) { - Bundle SHORTCUT_MY_ANIME_BUNDLE = new Bundle(); - SHORTCUT_MY_ANIME_BUNDLE.putString(KeyUtil.arg_mediaType, KeyUtil.ANIME); - SHORTCUT_MY_ANIME_BUNDLE.putString(KeyUtil.arg_userName, model.getName()); - - Bundle SHORTCUT_MY_MANGA_BUNDLE = new Bundle(); - SHORTCUT_MY_MANGA_BUNDLE.putString(KeyUtil.arg_mediaType, KeyUtil.MANGA); - SHORTCUT_MY_MANGA_BUNDLE.putString(KeyUtil.arg_userName, model.getName()); - - Bundle SHORTCUT_PROFILE_BUNDLE = new Bundle(); - SHORTCUT_PROFILE_BUNDLE.putString(KeyUtil.arg_userName, model.getName()); - - ShortcutUtil.createShortcuts(LoginActivity.this, - new ShortcutUtil.ShortcutBuilder() - .setShortcutType(KeyUtil.SHORTCUT_NOTIFICATION) - .build(), - new ShortcutUtil.ShortcutBuilder() - .setShortcutType(KeyUtil.SHORTCUT_MY_ANIME) - .setShortcutParams(SHORTCUT_MY_ANIME_BUNDLE) - .build(), - new ShortcutUtil.ShortcutBuilder() - .setShortcutType(KeyUtil.SHORTCUT_MY_MANGA) - .setShortcutParams(SHORTCUT_MY_MANGA_BUNDLE) - .build(), - new ShortcutUtil.ShortcutBuilder() - .setShortcutType(KeyUtil.SHORTCUT_PROFILE) - .setShortcutParams(SHORTCUT_PROFILE_BUNDLE) - .build()); - } - } - - @Override - protected void makeRequest() { - - } - - @Override - public void onChanged(@Nullable User model) { - if(isAlive() && (this.model = model) != null) { - getPresenter().getDatabase().saveCurrentUser(model); - updateUI(); - } - } - - @Override - public void onClick(View view) { - switch (view.getId()) { - case R.id.auth_sign_in: - if(binding.widgetFlipper.getDisplayedChild() == WidgetPresenter.CONTENT_STATE) { - binding.widgetFlipper.showNext(); - try { - startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(WebFactory.API_AUTH_LINK))); - } catch (Exception e) { - e.printStackTrace(); - Log.e(TAG, e.getLocalizedMessage()); - NotifyUtil.makeText(this, R.string.text_unknown_error, Toast.LENGTH_SHORT).show(); - } - } else NotifyUtil.makeText(this, R.string.busy_please_wait, Toast.LENGTH_SHORT).show(); - break; - case R.id.container: - if(binding.widgetFlipper.getDisplayedChild() != WidgetPresenter.LOADING_STATE) - finish(); - else - NotifyUtil.makeText(this, R.string.busy_please_wait, Toast.LENGTH_SHORT).show(); - break; - } - } - - @Override - public void showError(String error) { - if(isAlive()) { - WebTokenRequest.invalidateInstance(getApplicationContext()); - if(error == null) error = getString(R.string.text_error_auth_login); - NotifyUtil.createAlerter(this, getString(R.string.login_error_title), - error, R.drawable.ic_warning_white_18dp, R.color.colorStateRed, KeyUtil.DURATION_LONG); - if (getPresenter() != null && getPresenter().getApplicationPref().isCrashReportsEnabled()) - AnalyticsUtil.reportException(TAG, error); - binding.widgetFlipper.showPrevious(); - Log.e(this.toString(), error); - } - } - - @Override - public void showEmpty(String message) { - if(isAlive()) { - WebTokenRequest.invalidateInstance(getApplicationContext()); - if(message == null) message = getString(R.string.text_error_auth_login); - NotifyUtil.createAlerter(this, getString(R.string.text_error_request), - message, R.drawable.ic_warning_white_18dp, R.color.colorStateOrange, KeyUtil.DURATION_LONG); - binding.widgetFlipper.showPrevious(); - Log.w(this.toString(), message); - } - } - - @Override - protected void onNewIntent(Intent intent) { - super.onNewIntent(intent); - setIntent(intent); - if(!getPresenter().getApplicationPref().isAuthenticated()) - checkNewIntent(intent); - } - - private void checkNewIntent(Intent intent) { - if (intent != null && intent.getData() != null) { - if (isAlive()) { - if (binding.widgetFlipper.getDisplayedChild() == WidgetPresenter.CONTENT_STATE) - binding.widgetFlipper.showNext(); - - Data workerInputData = new Data.Builder() - .putString(KeyUtil.arg_model, intent.getData().toString()) - .build(); - - OneTimeWorkRequest authenticatorWorker = new OneTimeWorkRequest.Builder(AuthenticatorWorker.class) - .addTag(KeyUtil.WorkAuthenticatorTag) - .setInputData(workerInputData) - .build(); - WorkManager.getInstance(getApplicationContext()).enqueue(authenticatorWorker); - WorkManager.getInstance(getApplicationContext()).getWorkInfoByIdLiveData(authenticatorWorker.getId()) - .observe(this, workInfoObserver); - } - } - } - - private final Observer workInfoObserver = new Observer() { - @Override - 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.INSTANCE.getDefaultQuery(false)); - getViewModel().requestData(KeyUtil.USER_CURRENT_REQ, getApplicationContext()); - } - else { - if (!TextUtils.isEmpty(outputData.getString(KeyUtil.arg_uri_error)) && !TextUtils.isEmpty(outputData.getString(KeyUtil.arg_uri_error_description))) - NotifyUtil.createAlerter(LoginActivity.this, outputData.getString(KeyUtil.arg_uri_error), - outputData.getString(KeyUtil.arg_uri_error_description), R.drawable.ic_warning_white_18dp, - R.color.colorStateOrange, KeyUtil.DURATION_LONG); - else - NotifyUtil.createAlerter(LoginActivity.this, R.string.login_error_title, - R.string.text_error_auth_login, R.drawable.ic_warning_white_18dp, - R.color.colorStateRed, KeyUtil.DURATION_LONG); - binding.widgetFlipper.showPrevious(); - } - } - } - }; -} diff --git a/app/src/main/java/com/mxt/anitrend/view/activity/index/LoginActivity.kt b/app/src/main/java/com/mxt/anitrend/view/activity/index/LoginActivity.kt new file mode 100644 index 000000000..a1f76ad0f --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/view/activity/index/LoginActivity.kt @@ -0,0 +1,221 @@ +package com.mxt.anitrend.view.activity.index + +import android.content.Intent +import android.net.Uri +import android.os.Build +import android.os.Bundle +import android.os.PersistableBundle +import android.text.TextUtils +import android.view.View +import android.widget.Toast +import androidx.databinding.DataBindingUtil +import androidx.lifecycle.Observer +import androidx.work.Data +import androidx.work.OneTimeWorkRequest +import androidx.work.WorkInfo +import androidx.work.WorkManager +import com.mxt.anitrend.R +import com.mxt.anitrend.base.custom.activity.ActivityBase +import com.mxt.anitrend.base.custom.async.WebTokenRequest +import com.mxt.anitrend.databinding.ActivityLoginBinding +import com.mxt.anitrend.model.api.retro.WebFactory +import com.mxt.anitrend.model.entity.anilist.User +import com.mxt.anitrend.presenter.base.BasePresenter +import com.mxt.anitrend.presenter.widget.WidgetPresenter +import com.mxt.anitrend.util.* +import com.mxt.anitrend.worker.AuthenticatorWorker +import timber.log.Timber + +/** + * Created by max on 2017/11/03. + * Authentication activity + */ + +class LoginActivity : ActivityBase(), View.OnClickListener { + + private lateinit var binding: ActivityLoginBinding + private var model: User? = null + + private val workInfoObserver = Observer { workInfo -> + if (workInfo != null && workInfo.state.isFinished) { + val outputData = workInfo.outputData + if (outputData.getBoolean(KeyUtil.arg_model, false)) { + viewModel.params.putParcelable(KeyUtil.arg_graph_params, GraphUtil.getDefaultQuery(false)) + viewModel.requestData(KeyUtil.USER_CURRENT_REQ, applicationContext) + } else { + if (!TextUtils.isEmpty(outputData.getString(KeyUtil.arg_uri_error)) && !TextUtils.isEmpty(outputData.getString(KeyUtil.arg_uri_error_description))) + NotifyUtil.createAlerter(this@LoginActivity, outputData.getString(KeyUtil.arg_uri_error), + outputData.getString(KeyUtil.arg_uri_error_description), R.drawable.ic_warning_white_18dp, + R.color.colorStateOrange, KeyUtil.DURATION_LONG) + else + NotifyUtil.createAlerter(this@LoginActivity, R.string.login_error_title, + R.string.text_error_auth_login, R.drawable.ic_warning_white_18dp, + R.color.colorStateRed, KeyUtil.DURATION_LONG) + binding.widgetFlipper.showPrevious() + } + } + } + + + /** + * Some activities may have custom themes and if that's the case + * override this method and set your own theme style, also if you wish + * to apply the default navigation bar style for light themes + * @see ActivityBase.configureActivity + */ + override fun configureActivity() { + setTheme(if (Settings(this).theme == R.style.AppThemeLight) + R.style.AppThemeLight_Translucent + else + R.style.AppThemeDark_Translucent) + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = DataBindingUtil.setContentView(this, R.layout.activity_login) + setPresenter(BasePresenter(applicationContext)) + setViewModel(true) + } + + override fun onPostCreate(savedInstanceState: Bundle?) { + super.onPostCreate(savedInstanceState) + binding.onClickListener = this + onActivityReady() + } + + /** + * Make decisions, check for permissions or fire background threads from this method + * N.B. Must be called after onPostCreate + */ + override fun onActivityReady() { + if (presenter.settings.isAuthenticated) + finish() + else + checkNewIntent(intent) + } + + override fun updateUI() { + if (presenter.settings.isNotificationEnabled) + JobSchedulerUtil.scheduleJob(applicationContext) + createApplicationShortcuts() + finish() + } + + private fun createApplicationShortcuts() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) { + val SHORTCUT_MY_ANIME_BUNDLE = Bundle() + SHORTCUT_MY_ANIME_BUNDLE.putString(KeyUtil.arg_mediaType, KeyUtil.ANIME) + SHORTCUT_MY_ANIME_BUNDLE.putString(KeyUtil.arg_userName, model?.name) + + val SHORTCUT_MY_MANGA_BUNDLE = Bundle() + SHORTCUT_MY_MANGA_BUNDLE.putString(KeyUtil.arg_mediaType, KeyUtil.MANGA) + SHORTCUT_MY_MANGA_BUNDLE.putString(KeyUtil.arg_userName, model?.name) + + val SHORTCUT_PROFILE_BUNDLE = Bundle() + SHORTCUT_PROFILE_BUNDLE.putString(KeyUtil.arg_userName, model?.name) + + ShortcutUtil.createShortcuts(this@LoginActivity, + ShortcutUtil.ShortcutBuilder() + .setShortcutType(KeyUtil.SHORTCUT_NOTIFICATION) + .build(), + ShortcutUtil.ShortcutBuilder() + .setShortcutType(KeyUtil.SHORTCUT_MY_ANIME) + .setShortcutParams(SHORTCUT_MY_ANIME_BUNDLE) + .build(), + ShortcutUtil.ShortcutBuilder() + .setShortcutType(KeyUtil.SHORTCUT_MY_MANGA) + .setShortcutParams(SHORTCUT_MY_MANGA_BUNDLE) + .build(), + ShortcutUtil.ShortcutBuilder() + .setShortcutType(KeyUtil.SHORTCUT_PROFILE) + .setShortcutParams(SHORTCUT_PROFILE_BUNDLE) + .build()) + } + } + + override fun makeRequest() { + + } + + override fun onChanged(model: User?) { + this.model = model + if (isAlive && model != null) { + presenter.database.currentUser = model + updateUI() + } + } + + override fun onClick(view: View) { + when (view.id) { + R.id.auth_sign_in -> if (binding.widgetFlipper.displayedChild == WidgetPresenter.CONTENT_STATE) { + binding.widgetFlipper.showNext() + try { + startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(WebFactory.API_AUTH_LINK))) + } catch (e: Exception) { + e.printStackTrace() + Timber.tag(TAG).e(e.localizedMessage) + NotifyUtil.makeText(this, R.string.text_unknown_error, Toast.LENGTH_SHORT).show() + } + + } else + NotifyUtil.makeText(this, R.string.busy_please_wait, Toast.LENGTH_SHORT).show() + R.id.container -> if (binding.widgetFlipper.displayedChild != WidgetPresenter.LOADING_STATE) + finish() + else + NotifyUtil.makeText(this, R.string.busy_please_wait, Toast.LENGTH_SHORT).show() + } + } + + override fun showError(error: String?) { + var errorMessage = error + if (isAlive) { + WebTokenRequest.invalidateInstance(applicationContext) + if (errorMessage == null) errorMessage = getString(R.string.text_error_auth_login) + NotifyUtil.createAlerter(this, getString(R.string.login_error_title), + errorMessage, R.drawable.ic_warning_white_18dp, R.color.colorStateRed, KeyUtil.DURATION_LONG) + binding.widgetFlipper.showPrevious() + Timber.tag(TAG).e(errorMessage) + } + } + + override fun showEmpty(message: String?) { + var emptyMessage = message + if (isAlive) { + WebTokenRequest.invalidateInstance(applicationContext) + if (emptyMessage == null) emptyMessage = getString(R.string.text_error_auth_login) + NotifyUtil.createAlerter(this, getString(R.string.text_error_request), + emptyMessage, R.drawable.ic_warning_white_18dp, R.color.colorStateOrange, KeyUtil.DURATION_LONG) + binding.widgetFlipper.showPrevious() + Timber.tag(TAG).w(emptyMessage) + } + } + + override fun onNewIntent(intent: Intent) { + super.onNewIntent(intent) + setIntent(intent) + if (!presenter.settings.isAuthenticated) + checkNewIntent(intent) + } + + private fun checkNewIntent(intent: Intent?) { + if (intent != null && intent.data != null) { + if (isAlive) { + if (binding.widgetFlipper.displayedChild == WidgetPresenter.CONTENT_STATE) + binding.widgetFlipper.showNext() + + val workerInputData = Data.Builder() + .putString(KeyUtil.arg_model, intent.data.toString()) + .build() + + val authenticatorWorker = OneTimeWorkRequest.Builder(AuthenticatorWorker::class.java) + .addTag(KeyUtil.WorkAuthenticatorTag) + .setInputData(workerInputData) + .build() + + WorkManager.getInstance(applicationContext).enqueue(authenticatorWorker) + WorkManager.getInstance(applicationContext).getWorkInfoByIdLiveData(authenticatorWorker.id) + .observe(this, workInfoObserver) + } + } + } +} 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 33bc96e1b..f0e641ce3 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 @@ -34,24 +34,25 @@ import com.mxt.anitrend.adapter.pager.index.ReviewPageAdapter; import com.mxt.anitrend.adapter.pager.index.SeasonPageAdapter; import com.mxt.anitrend.adapter.pager.index.TrendingPageAdapter; +import com.mxt.anitrend.analytics.contract.ISupportAnalytics; import com.mxt.anitrend.base.custom.activity.ActivityBase; import com.mxt.anitrend.base.custom.async.WebTokenRequest; import com.mxt.anitrend.base.custom.consumer.BaseConsumer; import com.mxt.anitrend.base.custom.view.image.AvatarIndicatorView; import com.mxt.anitrend.base.custom.view.image.HeaderImageView; import com.mxt.anitrend.base.interfaces.event.BottomSheetChoice; +import com.mxt.anitrend.extension.KoinExt; import com.mxt.anitrend.model.entity.anilist.User; import com.mxt.anitrend.model.entity.base.VersionBase; import com.mxt.anitrend.presenter.base.BasePresenter; import com.mxt.anitrend.service.DownloaderService; -import com.mxt.anitrend.util.AnalyticsUtil; import com.mxt.anitrend.util.CompatUtil; import com.mxt.anitrend.util.DateUtil; import com.mxt.anitrend.util.DialogUtil; import com.mxt.anitrend.util.KeyUtil; import com.mxt.anitrend.util.NotifyUtil; import com.mxt.anitrend.view.activity.base.AboutActivity; -import com.mxt.anitrend.view.activity.base.ReportActivity; +import com.mxt.anitrend.view.activity.base.LoggingActivity; import com.mxt.anitrend.view.activity.base.SettingsActivity; import com.mxt.anitrend.view.activity.detail.ProfileActivity; import com.mxt.anitrend.view.sheet.BottomSheetMessage; @@ -160,7 +161,7 @@ public boolean onOptionsItemSelected(MenuItem item) { startActivity(intent); return true; case R.id.action_report: - startActivity(new Intent(MainActivity.this, ReportActivity.class)); + startActivity(new Intent(MainActivity.this, LoggingActivity.class)); return true; } return super.onOptionsItemSelected(item); @@ -173,8 +174,8 @@ public boolean onOptionsItemSelected(MenuItem item) { @Override protected void onActivityReady() { if(selectedItem == 0) - selectedItem = getPresenter().getApplicationPref().isAuthenticated()? - (redirectShortcut == 0? getPresenter().getApplicationPref().getStartupPage() : redirectShortcut) + selectedItem = getPresenter().getSettings().isAuthenticated()? + (redirectShortcut == 0? getPresenter().getSettings().getStartupPage() : redirectShortcut) : (redirectShortcut == 0? R.id.nav_anime : redirectShortcut); mNavigationView.setCheckedItem(selectedItem); onNavigate(selectedItem); @@ -383,7 +384,7 @@ public void onNegativeButton() { } break; case R.id.nav_light_theme: - getPresenter().getApplicationPref().toggleTheme(); + getPresenter().getSettings().toggleTheme(); recreate(); break; default: @@ -423,7 +424,7 @@ protected void updateUI() { HeaderContainer.findViewById(R.id.banner_clickable).setOnClickListener(this); - if(getPresenter().getApplicationPref().isAuthenticated()) + if(getPresenter().getSettings().isAuthenticated()) setupUserItems(); else mHeaderView.setImageResource(R.drawable.reg_bg); @@ -448,9 +449,9 @@ private void setupUserItems() { mUserName.setText(user.getName()); mUserAvatar.onInit(); HeaderImageView.setImage(mHeaderView, user.getBannerImage()); - if (getPresenter().getApplicationPref().shouldShowTipFor(KeyUtil.KEY_LOGIN_TIP)) { + if (getPresenter().getSettings().shouldShowTipFor(KeyUtil.KEY_LOGIN_TIP)) { NotifyUtil.createLoginToast(MainActivity.this, user); - getPresenter().getApplicationPref().disableTipFor(KeyUtil.KEY_LOGIN_TIP); + getPresenter().getSettings().disableTipFor(KeyUtil.KEY_LOGIN_TIP); mBottomSheet = new BottomSheetMessage.Builder() .setText(R.string.login_message) .setTitle(R.string.login_title) @@ -458,7 +459,7 @@ private void setupUserItems() { .build(); showBottomSheet(); } - AnalyticsUtil.setCrashAnalyticsUser(this, user.getName()); + KoinExt.get(ISupportAnalytics.class).setCrashAnalyticUser(user.getName()); } mAccountLogin.setVisible(false); @@ -472,12 +473,12 @@ private void setupUserItems() { * Checks to see if this instance is a new installation */ private void checkNewInstallation() { - if (getPresenter().getApplicationPref().isUpdated()) { + if (getPresenter().getSettings().isUpdated()) { DialogUtil.createChangeLog(this); - getPresenter().getApplicationPref().setUpdated(); + getPresenter().getSettings().setUpdated(); } - if(getPresenter().getApplicationPref().isFreshInstall()) { - getPresenter().getApplicationPref().setFreshInstall(); + if(getPresenter().getSettings().isFreshInstall()) { + getPresenter().getSettings().setFreshInstall(false); mBottomSheet = new BottomSheetMessage.Builder() .setText(R.string.app_intro_guide) .setTitle(R.string.app_intro_title) @@ -488,20 +489,17 @@ private void checkNewInstallation() { @Override public void onClick(View view) { - switch (view.getId()){ - case R.id.banner_clickable: - if(getPresenter().getApplicationPref().isAuthenticated()) { - User user = getPresenter().getDatabase().getCurrentUser(); - if(user != null) { - Intent intent = new Intent(this, ProfileActivity.class); - intent.putExtra(KeyUtil.arg_userName, getPresenter().getDatabase().getCurrentUser().getName()); - 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(); - } - else - onNavigate(R.id.nav_sign_in); - break; + if (view.getId() == R.id.banner_clickable) { + if (getPresenter().getSettings().isAuthenticated()) { + User user = getPresenter().getDatabase().getCurrentUser(); + if (user != null) { + Intent intent = new Intent(this, ProfileActivity.class); + intent.putExtra(KeyUtil.arg_userName, getPresenter().getDatabase().getCurrentUser().getName()); + 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(); + } else + onNavigate(R.id.nav_sign_in); } } diff --git a/app/src/main/java/com/mxt/anitrend/view/activity/index/SplashActivity.kt b/app/src/main/java/com/mxt/anitrend/view/activity/index/SplashActivity.kt index a454b8572..4194df584 100644 --- a/app/src/main/java/com/mxt/anitrend/view/activity/index/SplashActivity.kt +++ b/app/src/main/java/com/mxt/anitrend/view/activity/index/SplashActivity.kt @@ -2,7 +2,6 @@ package com.mxt.anitrend.view.activity.index import android.content.Intent import android.os.Bundle -import android.widget.Toast import com.mxt.anitrend.R import com.mxt.anitrend.base.custom.activity.ActivityBase @@ -13,7 +12,6 @@ import com.mxt.anitrend.view.activity.base.WelcomeActivity import butterknife.BindView import butterknife.ButterKnife -import com.afollestad.materialdialogs.MaterialDialog import com.mxt.anitrend.util.* /** @@ -52,8 +50,8 @@ class SplashActivity : ActivityBase() { override fun updateUI() { if (isAlive) { - if(presenter.checkIfMigrationIsNeeded(this)) { - val freshInstall = presenter.applicationPref.isFreshInstall + if(presenter.checkIfMigrationIsNeeded()) { + val freshInstall = presenter.settings.isFreshInstall val intent = Intent( this@SplashActivity, if (freshInstall) @@ -64,14 +62,16 @@ class SplashActivity : ActivityBase() { startActivity(intent) finish() } else { - DialogUtil.createMessage( - this, - R.string.title_migration_failed, - R.string.text_migration_failed - ) { dialog, _ -> - dialog.dismiss() - finish() - } + DialogUtil.createDefaultDialog(this).autoDismiss(false) + .icon(CompatUtil.getTintedDrawable(this, + R.drawable.ic_system_update_grey_600_24dp) + ).positiveText(R.string.Ok) + .title(R.string.title_migration_failed) + .content(R.string.text_migration_failed) + .onAny { dialog, _ -> + dialog.dismiss() + finish() + }.show() } } } @@ -80,7 +80,7 @@ class SplashActivity : ActivityBase() { val versionBase = presenter.database.remoteVersion // How frequent the application checks for updates on startup if (versionBase == null || DateUtil.timeDifferenceSatisfied(KeyUtil.TIME_UNIT_HOURS, versionBase.lastChecked, 2)) { - viewModel.params.putString(KeyUtil.arg_branch_name, presenter.applicationPref.updateChannel) + viewModel.params.putString(KeyUtil.arg_branch_name, presenter.settings.updateChannel) viewModel.requestData(KeyUtil.UPDATE_CHECKER_REQ, applicationContext) } else updateUI() @@ -94,7 +94,7 @@ class SplashActivity : ActivityBase() { override fun onChanged(model: VersionBase?) { super.onChanged(model) if (model != null) - presenter.database.saveRemoteVersion(model) + presenter.database.remoteVersion = model updateUI() } diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/AboutFragment.kt b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/AboutFragment.kt index 285951e41..9028aa2de 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/AboutFragment.kt +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/AboutFragment.kt @@ -3,21 +3,14 @@ package com.mxt.anitrend.view.fragment.detail import android.content.Intent import android.net.Uri import android.os.Bundle -import androidx.appcompat.app.AppCompatDelegate import android.view.LayoutInflater import android.view.View import android.view.ViewGroup - import com.mxt.anitrend.BuildConfig import com.mxt.anitrend.R import com.mxt.anitrend.base.custom.fragment.FragmentBase -import com.mxt.anitrend.base.custom.presenter.CommonPresenter import com.mxt.anitrend.presenter.base.BasePresenter import com.mxt.anitrend.util.DialogUtil - -import org.greenrobot.eventbus.Subscribe -import org.greenrobot.eventbus.ThreadMode - import mehdi.sakout.aboutpage.AboutPage import mehdi.sakout.aboutpage.Element @@ -31,22 +24,38 @@ class AboutFragment : FragmentBase() { private val aboutPage by lazy(LazyThreadSafetyMode.NONE) { AboutPage(activity) .setImage(R.mipmap.ic_launcher) - .addGroup("General Information") + .addGroup(getString(R.string.text_about_general_information)) .setDescription(getString(R.string.app_description)) - .addItem(Element().setTitle(String.format("Version %s", BuildConfig.VERSION_NAME))) + .addItem(Element().setTitle(getString(R.string.text_about_appication_version, BuildConfig.VERSION_NAME))) .addPlayStore("com.mxt.anitrend") .addTwitter("anitrend_app") - .addGroup("Additional Information") + .addGroup(getString(R.string.text_about_additional_information)) .addGitHub("AniTrend") .addWebsite("https://anitrend.co") .addItem(Element().setTitle(getString(R.string.text_what_is_new)) - .setOnClickListener { v -> DialogUtil.createChangeLog(activity) } + .setOnClickListener { DialogUtil.createChangeLog(activity) } .setIconDrawable(R.drawable.ic_fiber_new_white_24dp)) - .addGroup("Legal Information") - .addItem(Element().setTitle("Terms & Conditions").setIconDrawable(R.drawable.ic_privacy_grey_600_24dp) - .setIntent(Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/AniTrend/anitrend-app/blob/develop/TERMS_OF_SERVICE.md")))) - .addItem(Element().setTitle("Code Of Conduct").setIconDrawable(R.drawable.ic_privacy_grey_600_24dp) - .setIntent(Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/AniTrend/anitrend-app/blob/develop/CODE_OF_CONDUCT.md")))) + .addItem(Element().setTitle(getString(R.string.text_about_frequently_asked_questions)) + .setIconDrawable(R.drawable.ic_help_grey_600_24dp) + .setIntent(Intent(Intent.ACTION_VIEW, + Uri.parse( + "https://anitrend.gitbook.io/project/faq" + )))) + .addGroup(getString(R.string.text_about_legal_information)) + .addItem(Element().setTitle(getString(R.string.text_about_terms_and_conditions)) + .setIconDrawable(R.drawable.ic_privacy_grey_600_24dp) + .setIntent(Intent(Intent.ACTION_VIEW, + Uri.parse( + "https://github.com/AniTrend/anitrend-app/blob/develop/TERMS_OF_SERVICE.md" + ) + ))) + .addItem(Element().setTitle(getString(R.string.text_about_code_of_conduct)) + .setIconDrawable(R.drawable.ic_privacy_grey_600_24dp) + .setIntent(Intent(Intent.ACTION_VIEW, + Uri.parse( + "https://github.com/AniTrend/anitrend-app/blob/develop/CODE_OF_CONDUCT.md" + ) + ))) } override fun onCreate(savedInstanceState: Bundle?) { 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 d1a9a53b2..a0907898b 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 @@ -19,7 +19,7 @@ import com.mxt.anitrend.model.entity.container.body.PageContainer; import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder; import com.mxt.anitrend.presenter.base.BasePresenter; -import com.mxt.anitrend.util.ApplicationPref; +import com.mxt.anitrend.util.Settings; import com.mxt.anitrend.util.CompatUtil; import com.mxt.anitrend.util.DialogUtil; import com.mxt.anitrend.util.GraphUtil; @@ -81,18 +81,18 @@ public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_sort: DialogUtil.createSelection(getContext(), R.string.app_filter_sort, CompatUtil.INSTANCE.getIndexOf(KeyUtil.ReviewSortType, - getPresenter().getApplicationPref().getReviewSort()), CompatUtil.INSTANCE.capitalizeWords(KeyUtil.ReviewSortType), + getPresenter().getSettings().getReviewSort()), CompatUtil.INSTANCE.capitalizeWords(KeyUtil.ReviewSortType), (dialog, which) -> { if(which == DialogAction.POSITIVE) - getPresenter().getApplicationPref().setReviewSort(KeyUtil.ReviewSortType[dialog.getSelectedIndex()]); + getPresenter().getSettings().setReviewSort(KeyUtil.ReviewSortType[dialog.getSelectedIndex()]); }); return true; case R.id.action_order: 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), + getPresenter().getSettings().getSortOrder()), CompatUtil.INSTANCE.getStringList(getContext(), R.array.order_by_types), (dialog, which) -> { if(which == DialogAction.POSITIVE) - getPresenter().getApplicationPref().saveSortOrder(KeyUtil.SortOrderType[dialog.getSelectedIndex()]); + getPresenter().getSettings().saveSortOrder(KeyUtil.SortOrderType[dialog.getSelectedIndex()]); }); return true; } @@ -112,7 +112,7 @@ protected void updateUI() { */ @Override public void makeRequest() { - ApplicationPref pref = getPresenter().getApplicationPref(); + Settings pref = getPresenter().getSettings(); QueryContainerBuilder queryContainer = GraphUtil.INSTANCE.getDefaultQuery(true) .putVariable(KeyUtil.arg_mediaType, mediaType) .putVariable(KeyUtil.arg_page, getPresenter().getCurrentPage()) @@ -175,7 +175,7 @@ public void onItemClick(View target, IntPair data) { public void onItemLongClick(View target, IntPair data) { switch (target.getId()) { case R.id.series_image: - if(getPresenter().getApplicationPref().isAuthenticated()) { + if(getPresenter().getSettings().isAuthenticated()) { mediaActionUtil = new MediaActionUtil.Builder() .setId(data.getSecond().getMedia().getId()).build(getActivity()); mediaActionUtil.startSeriesAction(); 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 06bd3dda7..2d26d8c9c 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 @@ -229,7 +229,7 @@ public void onItemClick(View target, IntPair data) { public void onItemLongClick(View target, IntPair data) { switch (target.getId()) { case R.id.series_image: - if(getPresenter().getApplicationPref().isAuthenticated()) { + if(getPresenter().getSettings().isAuthenticated()) { mediaActionUtil = new MediaActionUtil.Builder() .setId(data.getSecond().getMedia().getId()).build(getActivity()); mediaActionUtil.startSeriesAction(); diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/MediaOverviewFragment.kt b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/MediaOverviewFragment.kt index f2a50275c..72182fc15 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/MediaOverviewFragment.kt +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/MediaOverviewFragment.kt @@ -199,7 +199,7 @@ class MediaOverviewFragment : FragmentBase() { updateUI() } else binding?.stateLayout?.showError(CompatUtil.getDrawable(context!!, R.drawable.ic_emoji_sweat), - getString(R.string.layout_empty_response), getString(R.string.try_again)) { view -> + getString(R.string.layout_empty_response), getString(R.string.try_again)) { _ -> binding?.stateLayout?.showLoading() makeRequest() } diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/NotificationFragment.kt b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/NotificationFragment.kt index 7ea15a76d..b894c79d5 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/NotificationFragment.kt +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/NotificationFragment.kt @@ -15,11 +15,9 @@ import com.mxt.anitrend.adapter.recycler.detail.NotificationAdapter import com.mxt.anitrend.base.custom.async.ThreadPool import com.mxt.anitrend.base.custom.fragment.FragmentBaseList import com.mxt.anitrend.model.entity.anilist.Notification -import com.mxt.anitrend.model.entity.anilist.User import com.mxt.anitrend.model.entity.base.NotificationHistory import com.mxt.anitrend.model.entity.base.NotificationHistory_ import com.mxt.anitrend.model.entity.container.body.PageContainer -import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder import com.mxt.anitrend.presenter.base.BasePresenter import com.mxt.anitrend.util.CompatUtil import com.mxt.anitrend.util.DialogUtil @@ -31,8 +29,6 @@ import com.mxt.anitrend.view.activity.detail.CommentActivity import com.mxt.anitrend.view.activity.detail.MediaActivity import com.mxt.anitrend.view.activity.detail.ProfileActivity -import java.util.Collections - /** * Created by max on 2017/12/06. * NotificationFragment @@ -59,14 +55,17 @@ class NotificationFragment : FragmentBaseList { if (mAdapter.itemCount > 0) { - ThreadPool.Builder() - .build().execute { this.markAllNotificationsAsRead() } + ThreadPool.execute { markAllNotificationsAsRead() } } else NotifyUtil.makeText(context, R.string.text_activity_loading, Toast.LENGTH_SHORT) return true @@ -105,8 +103,7 @@ class NotificationFragment : FragmentBaseList item.activityId != 0L && item.activityId == data.activityId } - .map { item -> NotificationHistory(item.id) } - .toList() + ThreadPool.execute { + val isNotificationRead = presenter.database.getBoxStore(NotificationHistory::class.java) + .query().equal(NotificationHistory_.id, data.id).build().count() != 0L + if (!isNotificationRead) { + val dismissibleNotifications = Stream.of(mAdapter.data) + .filter { item -> item.activityId != 0L && item.activityId == data.activityId } + .map { item -> NotificationHistory(item.id) } + .toList() - if (!CompatUtil.isEmpty(dismissibleNotifications)) - presenter.database.getBoxStore(NotificationHistory::class.java) - .put(dismissibleNotifications) - else - presenter.database.getBoxStore(NotificationHistory::class.java) - .put(NotificationHistory(data.id)) - } - } + if (!CompatUtil.isEmpty(dismissibleNotifications)) + presenter.database.getBoxStore(NotificationHistory::class.java) + .put(dismissibleNotifications) + else + presenter.database.getBoxStore(NotificationHistory::class.java) + .put(NotificationHistory(data.id)) + } + } } /** @@ -249,7 +245,7 @@ class NotificationFragment : FragmentBaseList) { if (CompatUtil.equals(data.second.type, KeyUtil.AIRING)) { setItemAsRead(data.second) - if (presenter.applicationPref.isAuthenticated) { + if (presenter.settings.isAuthenticated) { mediaActionUtil = MediaActionUtil.Builder() .setId(data.second.media.id).build(activity) mediaActionUtil.startSeriesAction() 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 f7024e75d..b9ad29ef6 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 @@ -117,7 +117,7 @@ public void onItemClick(View target, IntPair data) { CompatUtil.INSTANCE.startRevealAnim(getActivity(), target, intent); break; case R.id.user_avatar: - if(getPresenter().getApplicationPref().isAuthenticated()) { + if(getPresenter().getSettings().isAuthenticated()) { intent = new Intent(getActivity(), ProfileActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.putExtra(KeyUtil.arg_id, data.getSecond().getUser().getId()); @@ -146,7 +146,7 @@ public void onItemClick(View target, IntPair data) { public void onItemLongClick(View target, IntPair data) { switch (target.getId()) { case R.id.series_image: - if(getPresenter().getApplicationPref().isAuthenticated()) { + if(getPresenter().getSettings().isAuthenticated()) { mediaActionUtil = new MediaActionUtil.Builder() .setId(data.getSecond().getMedia().getId()).build(getActivity()); mediaActionUtil.startSeriesAction(); 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 b7ab534fe..0b8f39479 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 @@ -19,7 +19,7 @@ import com.mxt.anitrend.model.entity.container.body.PageContainer; import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder; import com.mxt.anitrend.presenter.fragment.MediaPresenter; -import com.mxt.anitrend.util.ApplicationPref; +import com.mxt.anitrend.util.Settings; import com.mxt.anitrend.util.CompatUtil; import com.mxt.anitrend.util.DialogUtil; import com.mxt.anitrend.util.GraphUtil; @@ -73,18 +73,18 @@ public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_sort: DialogUtil.createSelection(getContext(), R.string.app_filter_sort, CompatUtil.INSTANCE.getIndexOf(KeyUtil.MediaSortType, - getPresenter().getApplicationPref().getMediaSort()), CompatUtil.INSTANCE.capitalizeWords(KeyUtil.MediaSortType), + getPresenter().getSettings().getMediaSort()), CompatUtil.INSTANCE.capitalizeWords(KeyUtil.MediaSortType), (dialog, which) -> { if(which == DialogAction.POSITIVE) - getPresenter().getApplicationPref().setMediaSort(KeyUtil.MediaSortType[dialog.getSelectedIndex()]); + getPresenter().getSettings().setMediaSort(KeyUtil.MediaSortType[dialog.getSelectedIndex()]); }); return true; case R.id.action_order: 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), + getPresenter().getSettings().getSortOrder()), CompatUtil.INSTANCE.getStringList(getContext(), R.array.order_by_types), (dialog, which) -> { if(which == DialogAction.POSITIVE) - getPresenter().getApplicationPref().saveSortOrder(KeyUtil.SortOrderType[dialog.getSelectedIndex()]); + getPresenter().getSettings().saveSortOrder(KeyUtil.SortOrderType[dialog.getSelectedIndex()]); }); return true; } @@ -99,7 +99,7 @@ protected void updateUI() { @Override public void makeRequest() { - ApplicationPref pref = getPresenter().getApplicationPref(); + Settings pref = getPresenter().getSettings(); QueryContainerBuilder queryContainer = GraphUtil.INSTANCE.getDefaultQuery(isPager) .putVariable(KeyUtil.arg_id, id) .putVariable(KeyUtil.arg_page, getPresenter().getCurrentPage()) @@ -156,7 +156,7 @@ public void onItemClick(View target, IntPair data) { public void onItemLongClick(View target, IntPair data) { switch (target.getId()) { case R.id.container: - if(getPresenter().getApplicationPref().isAuthenticated()) { + if(getPresenter().getSettings().isAuthenticated()) { mediaActionUtil = new MediaActionUtil.Builder() .setId(data.getSecond().getId()).build(getActivity()); mediaActionUtil.startSeriesAction(); diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/UserFeedFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/UserFeedFragment.java index 780e9db54..919deefa3 100644 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/UserFeedFragment.java +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/UserFeedFragment.java @@ -43,7 +43,7 @@ public void onCreate(@Nullable Bundle savedInstanceState) { @Override public void makeRequest() { - if(getPresenter().getApplicationPref().isAuthenticated() && getPresenter().isCurrentUser(userId, userName)) + if(getPresenter().getSettings().isAuthenticated() && getPresenter().isCurrentUser(userId, userName)) userId = getPresenter().getDatabase().getCurrentUser().getId(); if (userId > 0) 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 b01acb8d7..3057e14ef 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 @@ -122,7 +122,7 @@ public void onItemClick(View target, IntPair data) { public void onItemLongClick(View target, IntPair data) { switch (target.getId()) { case R.id.container: - if(getPresenter().getApplicationPref().isAuthenticated()) { + if(getPresenter().getSettings().isAuthenticated()) { mediaActionUtil = new MediaActionUtil.Builder() .setId(data.getSecond().getId()).build(getActivity()); mediaActionUtil.startSeriesAction(); 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 25e3930e6..328db148e 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 @@ -88,7 +88,7 @@ public void onItemClick(View target, IntPair data) { public void onItemLongClick(View target, IntPair data) { switch (target.getId()) { case R.id.container: - if(getPresenter().getApplicationPref().isAuthenticated()) { + if(getPresenter().getSettings().isAuthenticated()) { mediaActionUtil = new MediaActionUtil.Builder() .setId(((MediaBase) data.getSecond()).getId()).build(getActivity()); mediaActionUtil.startSeriesAction(); 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 8a8b75981..2041a4c7f 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 @@ -136,7 +136,7 @@ public void onItemClick(View target, IntPair data) { public void onItemLongClick(View target, IntPair data) { switch (target.getId()) { case R.id.container: - if(getPresenter().getApplicationPref().isAuthenticated()) { + if(getPresenter().getSettings().isAuthenticated()) { mediaActionUtil = new MediaActionUtil.Builder() .setId(((MediaBase)data.getSecond()).getId()).build(getActivity()); mediaActionUtil.startSeriesAction(); 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 365b2d653..e59305a57 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 @@ -129,7 +129,7 @@ public void onItemClick(View target, IntPair data) { public void onItemLongClick(View target, IntPair data) { switch (target.getId()) { case R.id.container: - if(getPresenter().getApplicationPref().isAuthenticated()) { + if(getPresenter().getSettings().isAuthenticated()) { mediaActionUtil = new MediaActionUtil.Builder() .setId(((MediaBase) data.getSecond()).getId()).build(getActivity()); mediaActionUtil.startSeriesAction(); 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 4e9e712d3..a12b8bddd 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 @@ -127,7 +127,7 @@ public void onItemClick(View target, IntPair data) { public void onItemLongClick(View target, IntPair data) { switch (target.getId()) { case R.id.container: - if(getPresenter().getApplicationPref().isAuthenticated()) { + if(getPresenter().getSettings().isAuthenticated()) { mediaActionUtil = new MediaActionUtil.Builder() .setId(((MediaBase)data.getSecond()).getId()).build(getActivity()); mediaActionUtil.startSeriesAction(); 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 8c46db0e3..06cfd74e4 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 @@ -60,7 +60,7 @@ public void onChanged(@Nullable PageContainer content) { .filter(media -> CompatUtil.INSTANCE.equals(media.getMedia().getStatus(), KeyUtil.RELEASING)) .toList(); - if(MediaListUtil.isTitleSort(getPresenter().getApplicationPref().getMediaListSort())) + if(MediaListUtil.isTitleSort(getPresenter().getSettings().getMediaListSort())) sortMediaListByTitle(mediaList); else onPostProcessed(mediaList); 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 0b1b21a24..612b1a76c 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 @@ -96,11 +96,11 @@ public boolean onOptionsItemSelected(MenuItem item) { protected void updateUI() { injectAdapter(); if(!TapTargetUtil.isActive(KeyUtil.KEY_POST_TYPE_TIP) && isFeed) { - if (getPresenter().getApplicationPref().shouldShowTipFor(KeyUtil.KEY_POST_TYPE_TIP)) { + if (getPresenter().getSettings().shouldShowTipFor(KeyUtil.KEY_POST_TYPE_TIP)) { TapTargetUtil.buildDefault(getActivity(), R.string.tip_status_post_title, R.string.tip_status_post_text, R.id.action_post) .setPromptStateChangeListener((prompt, state) -> { if (state == MaterialTapTargetPrompt.STATE_NON_FOCAL_PRESSED || state == MaterialTapTargetPrompt.STATE_FOCAL_PRESSED) - getPresenter().getApplicationPref().disableTipFor(KeyUtil.KEY_POST_TYPE_TIP); + getPresenter().getSettings().disableTipFor(KeyUtil.KEY_POST_TYPE_TIP); if (state == MaterialTapTargetPrompt.STATE_DISMISSED) TapTargetUtil.setActive(KeyUtil.KEY_POST_TYPE_TIP, true); }).show(); @@ -241,7 +241,7 @@ public void onItemClick(View target, IntPair data) { public void onItemLongClick(View target, IntPair data) { switch (target.getId()) { case R.id.series_image: - if(getPresenter().getApplicationPref().isAuthenticated()) { + if(getPresenter().getSettings().isAuthenticated()) { mediaActionUtil = new MediaActionUtil.Builder() .setId(data.getSecond().getMedia().getId()).build(getActivity()); mediaActionUtil.startSeriesAction(); 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 672f32169..cad8fe33c 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 @@ -21,7 +21,7 @@ import com.mxt.anitrend.model.entity.container.body.PageContainer; import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder; import com.mxt.anitrend.presenter.fragment.MediaPresenter; -import com.mxt.anitrend.util.ApplicationPref; +import com.mxt.anitrend.util.Settings; import com.mxt.anitrend.util.CompatUtil; import com.mxt.anitrend.util.DateUtil; import com.mxt.anitrend.util.DialogUtil; @@ -103,18 +103,18 @@ public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_sort: DialogUtil.createSelection(getContext(), R.string.app_filter_sort, CompatUtil.INSTANCE.getIndexOf(KeyUtil.MediaSortType, - getPresenter().getApplicationPref().getMediaSort()), CompatUtil.INSTANCE.capitalizeWords(KeyUtil.MediaSortType), + getPresenter().getSettings().getMediaSort()), CompatUtil.INSTANCE.capitalizeWords(KeyUtil.MediaSortType), (dialog, which) -> { if(which == DialogAction.POSITIVE) - getPresenter().getApplicationPref().setMediaSort(KeyUtil.MediaSortType[dialog.getSelectedIndex()]); + getPresenter().getSettings().setMediaSort(KeyUtil.MediaSortType[dialog.getSelectedIndex()]); }); return true; case R.id.action_order: 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), + getPresenter().getSettings().getSortOrder()), CompatUtil.INSTANCE.getStringList(getContext(), R.array.order_by_types), (dialog, which) -> { if(which == DialogAction.POSITIVE) - getPresenter().getApplicationPref().saveSortOrder(KeyUtil.SortOrderType[dialog.getSelectedIndex()]); + getPresenter().getSettings().saveSortOrder(KeyUtil.SortOrderType[dialog.getSelectedIndex()]); }); return true; case R.id.action_genre: @@ -124,7 +124,7 @@ public boolean onOptionsItemSelected(MenuItem item) { getPresenter().checkGenresAndTags(getActivity()); } else { Map genresIndexMap = getPresenter() - .getApplicationPref().getSelectedGenres(); + .getSettings().getSelectedGenres(); Integer[] selectedGenres = Stream.of(genresIndexMap) .map(Map.Entry::getKey) @@ -137,11 +137,11 @@ public boolean onOptionsItemSelected(MenuItem item) { Map selectedIndices = GenreTagUtil .createGenreSelectionMap(genres, dialog.getSelectedIndices()); - getPresenter().getApplicationPref() + getPresenter().getSettings() .setSelectedGenres(selectedIndices); break; case NEGATIVE: - getPresenter().getApplicationPref() + getPresenter().getSettings() .setSelectedGenres(new WeakHashMap<>()); break; } @@ -155,7 +155,7 @@ public boolean onOptionsItemSelected(MenuItem item) { getPresenter().checkGenresAndTags(getActivity()); } else { Map tagsIndexMap = getPresenter() - .getApplicationPref().getSelectedTags(); + .getSettings().getSelectedTags(); Integer[] selectedTags = Stream.of(tagsIndexMap) .map(Map.Entry::getKey) @@ -168,11 +168,11 @@ public boolean onOptionsItemSelected(MenuItem item) { Map selectedIndices = GenreTagUtil .createTagSelectionMap(tagList, dialog.getSelectedIndices()); - getPresenter().getApplicationPref() + getPresenter().getSettings() .setSelectedTags(selectedIndices); break; case NEGATIVE: - getPresenter().getApplicationPref() + getPresenter().getSettings() .setSelectedTags(new WeakHashMap<>()); break; } @@ -182,34 +182,34 @@ public boolean onOptionsItemSelected(MenuItem item) { case R.id.action_type: 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), + getPresenter().getSettings().getAnimeFormat()), CompatUtil.INSTANCE.getStringList(getContext(), R.array.anime_formats), (dialog, which) -> { if(which == DialogAction.POSITIVE) - getPresenter().getApplicationPref().setAnimeFormat(KeyUtil.AnimeFormat[dialog.getSelectedIndex()]); + getPresenter().getSettings().setAnimeFormat(KeyUtil.AnimeFormat[dialog.getSelectedIndex()]); }); } else { 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), + getPresenter().getSettings().getMangaFormat()), CompatUtil.INSTANCE.getStringList(getContext(), R.array.manga_formats), (dialog, which) -> { if(which == DialogAction.POSITIVE) - getPresenter().getApplicationPref().setMangaFormat(KeyUtil.MangaFormat[dialog.getSelectedIndex()]); + getPresenter().getSettings().setMangaFormat(KeyUtil.MangaFormat[dialog.getSelectedIndex()]); }); } return true; case R.id.action_year: final List yearRanges = DateUtil.INSTANCE.getYearRanges(1950, 1); - DialogUtil.createSelection(getContext(), R.string.app_filter_year, CompatUtil.INSTANCE.getIndexOf(yearRanges, getPresenter().getApplicationPref().getSeasonYear()), + DialogUtil.createSelection(getContext(), R.string.app_filter_year, CompatUtil.INSTANCE.getIndexOf(yearRanges, getPresenter().getSettings().getSeasonYear()), yearRanges, (dialog, which) -> { if(which == DialogAction.POSITIVE) - getPresenter().getApplicationPref().saveSeasonYear(yearRanges.get(dialog.getSelectedIndex())); + getPresenter().getSettings().saveSeasonYear(yearRanges.get(dialog.getSelectedIndex())); }); return true; case R.id.action_status: DialogUtil.createSelection(getContext(), R.string.anime, CompatUtil.INSTANCE.getIndexOf(KeyUtil.MediaStatus, - getPresenter().getApplicationPref().getMediaStatus()), CompatUtil.INSTANCE.getStringList(getContext(), R.array.media_status), + getPresenter().getSettings().getMediaStatus()), CompatUtil.INSTANCE.getStringList(getContext(), R.array.media_status), (dialog, which) -> { if(which == DialogAction.POSITIVE) - getPresenter().getApplicationPref().setMediaStatus(KeyUtil.MediaStatus[dialog.getSelectedIndex()]); + getPresenter().getSettings().setMediaStatus(KeyUtil.MediaStatus[dialog.getSelectedIndex()]); }); return true; } @@ -224,17 +224,17 @@ protected void updateUI() { @Override public void makeRequest() { Bundle bundle = getViewModel().getParams(); - ApplicationPref pref = getPresenter().getApplicationPref(); + Settings pref = getPresenter().getSettings(); queryContainer.putVariable(KeyUtil.arg_page, getPresenter().getCurrentPage()); if(isFilterable) { if(!mediaBrowseUtil.isBasicFilter()) { if (CompatUtil.INSTANCE.equals(queryContainer.getVariable(KeyUtil.arg_mediaType), KeyUtil.MANGA)) { queryContainer.putVariable(KeyUtil.arg_startDateLike, String.format(Locale.getDefault(), - "%d%%", getPresenter().getApplicationPref().getSeasonYear())) + "%d%%", getPresenter().getSettings().getSeasonYear())) .putVariable(KeyUtil.arg_format, pref.getMangaFormat()); } else { - queryContainer.putVariable(KeyUtil.arg_seasonYear, getPresenter().getApplicationPref().getSeasonYear()) + queryContainer.putVariable(KeyUtil.arg_seasonYear, getPresenter().getSettings().getSeasonYear()) .putVariable(KeyUtil.arg_format, pref.getAnimeFormat()); } @@ -293,7 +293,7 @@ public void onItemClick(View target, IntPair data) { public void onItemLongClick(View target, IntPair data) { switch (target.getId()) { case R.id.container: - if(getPresenter().getApplicationPref().isAuthenticated()) { + if(getPresenter().getSettings().isAuthenticated()) { mediaActionUtil = new MediaActionUtil.Builder() .setId(data.getSecond().getId()).build(getActivity()); mediaActionUtil.startSeriesAction(); 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 b61907fac..d7a391146 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 @@ -29,7 +29,7 @@ import com.mxt.anitrend.model.entity.container.body.PageContainer; import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder; import com.mxt.anitrend.presenter.fragment.MediaPresenter; -import com.mxt.anitrend.util.ApplicationPref; +import com.mxt.anitrend.util.Settings; import com.mxt.anitrend.util.CompatUtil; import com.mxt.anitrend.util.DialogUtil; import com.mxt.anitrend.util.GraphUtil; @@ -107,18 +107,18 @@ public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_sort: DialogUtil.createSelection(getContext(), R.string.app_filter_sort, CompatUtil.INSTANCE.getIndexOf(KeyUtil.MediaListSortType, - getPresenter().getApplicationPref().getMediaListSort()), CompatUtil.INSTANCE.capitalizeWords(KeyUtil.MediaListSortType), + getPresenter().getSettings().getMediaListSort()), CompatUtil.INSTANCE.capitalizeWords(KeyUtil.MediaListSortType), (dialog, which) -> { if(which == DialogAction.POSITIVE) - getPresenter().getApplicationPref().setMediaListSort(KeyUtil.MediaListSortType[dialog.getSelectedIndex()]); + getPresenter().getSettings().setMediaListSort(KeyUtil.MediaListSortType[dialog.getSelectedIndex()]); }); return true; case R.id.action_order: 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), + getPresenter().getSettings().getSortOrder()), CompatUtil.INSTANCE.getStringList(getContext(), R.array.order_by_types), (dialog, which) -> { if(which == DialogAction.POSITIVE) - getPresenter().getApplicationPref().saveSortOrder(KeyUtil.SortOrderType[dialog.getSelectedIndex()]); + getPresenter().getSettings().saveSortOrder(KeyUtil.SortOrderType[dialog.getSelectedIndex()]); }); return true; } @@ -153,11 +153,11 @@ public void makeRequest() { queryContainer.putVariable(KeyUtil.arg_scoreFormat, mediaListOptions.getScoreFormat()); // since anilist doesn't support sorting by title we set a temporary sorting key - if (!MediaListUtil.isTitleSort(getPresenter().getApplicationPref().getMediaListSort())) - queryContainer.putVariable(KeyUtil.arg_sort, getPresenter().getApplicationPref().getMediaListSort() + - getPresenter().getApplicationPref().getSortOrder()); + if (!MediaListUtil.isTitleSort(getPresenter().getSettings().getMediaListSort())) + queryContainer.putVariable(KeyUtil.arg_sort, getPresenter().getSettings().getMediaListSort() + + getPresenter().getSettings().getSortOrder()); else - queryContainer.putVariable(KeyUtil.arg_sort, KeyUtil.MEDIA_ID + getPresenter().getApplicationPref().getSortOrder()); + queryContainer.putVariable(KeyUtil.arg_sort, KeyUtil.MEDIA_ID + getPresenter().getSettings().getSortOrder()); getViewModel().getParams().putParcelable(KeyUtil.arg_graph_params, queryContainer); getViewModel().requestData(KeyUtil.MEDIA_LIST_COLLECTION_REQ, getContext()); @@ -167,8 +167,8 @@ public void makeRequest() { @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { if(getPresenter() != null && isFilterable && GraphUtil.INSTANCE.isKeyFilter(key)) { - @KeyUtil.MediaListSort String mediaListSort = getPresenter().getApplicationPref().getMediaListSort(); - if(CompatUtil.INSTANCE.equals(key, ApplicationPref._mediaListSort) && MediaListUtil.isTitleSort(mediaListSort)) { + @KeyUtil.MediaListSort String mediaListSort = getPresenter().getSettings().getMediaListSort(); + if(CompatUtil.INSTANCE.equals(key, Settings._mediaListSort) && MediaListUtil.isTitleSort(mediaListSort)) { swipeRefreshLayout.setRefreshing(true); sortMediaListByTitle(mAdapter.getData()); } @@ -213,7 +213,7 @@ public void onChanged(@Nullable PageContainer content) { Optional mediaOptional = Stream.of(content.getPageData()).findFirst(); if(mediaOptional.isPresent()) { MediaListCollection mediaListCollection = mediaOptional.get(); - if(MediaListUtil.isTitleSort(getPresenter().getApplicationPref().getMediaListSort())) + if(MediaListUtil.isTitleSort(getPresenter().getSettings().getMediaListSort())) sortMediaListByTitle(mediaListCollection.getEntries()); else onPostProcessed(mediaListCollection.getEntries()); @@ -262,7 +262,7 @@ public void onItemLongClick(View target, IntPair data) { switch (target.getId()) { case R.id.container: case R.id.series_image: - if(getPresenter().getApplicationPref().isAuthenticated()) { + if(getPresenter().getSettings().isAuthenticated()) { mediaActionUtil = new MediaActionUtil.Builder() .setId(data.getSecond().getMediaId()).build(getActivity()); mediaActionUtil.startSeriesAction(); @@ -273,7 +273,7 @@ public void onItemLongClick(View target, IntPair data) { } protected void sortMediaListByTitle(@NonNull List mediaLists) { - @KeyUtil.SortOrderType String sortOrder = getPresenter().getApplicationPref().getSortOrder(); + @KeyUtil.SortOrderType String sortOrder = getPresenter().getSettings().getSortOrder(); mAdapter.onItemsInserted(Stream.of(mediaLists) .sorted((first, second) -> { String firstTitle = MediaUtil.getMediaTitle(first.getMedia()); 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 98712a504..40a7a0447 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 @@ -7,7 +7,7 @@ import com.afollestad.materialdialogs.DialogAction; import com.mxt.anitrend.R; -import com.mxt.anitrend.util.ApplicationPref; +import com.mxt.anitrend.util.Settings; import com.mxt.anitrend.util.CompatUtil; import com.mxt.anitrend.util.DialogUtil; import com.mxt.anitrend.util.GraphUtil; @@ -31,7 +31,7 @@ public static SuggestionListFragment newInstance(Bundle params) { @Override public void makeRequest() { - ApplicationPref pref = getPresenter().getApplicationPref(); + Settings pref = getPresenter().getSettings(); Bundle bundle = getViewModel().getParams(); queryContainer.putVariable(KeyUtil.arg_tagsInclude, getPresenter().getTopFavouriteTags(6)) .putVariable(KeyUtil.arg_genresInclude, getPresenter().getTopFavouriteGenres(4)) @@ -57,18 +57,18 @@ public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_sort: DialogUtil.createSelection(getContext(), R.string.app_filter_sort, CompatUtil.INSTANCE.getIndexOf(KeyUtil.MediaSortType, - getPresenter().getApplicationPref().getMediaSort()), CompatUtil.INSTANCE.capitalizeWords(KeyUtil.MediaSortType), + getPresenter().getSettings().getMediaSort()), CompatUtil.INSTANCE.capitalizeWords(KeyUtil.MediaSortType), (dialog, which) -> { if(which == DialogAction.POSITIVE) - getPresenter().getApplicationPref().setMediaSort(KeyUtil.MediaSortType[dialog.getSelectedIndex()]); + getPresenter().getSettings().setMediaSort(KeyUtil.MediaSortType[dialog.getSelectedIndex()]); }); return true; case R.id.action_order: 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), + getPresenter().getSettings().getSortOrder()), CompatUtil.INSTANCE.getStringList(getContext(), R.array.order_by_types), (dialog, which) -> { if(which == DialogAction.POSITIVE) - getPresenter().getApplicationPref().saveSortOrder(KeyUtil.SortOrderType[dialog.getSelectedIndex()]); + getPresenter().getSettings().saveSortOrder(KeyUtil.SortOrderType[dialog.getSelectedIndex()]); }); return true; } 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 204f18e3c..c45d8aa78 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 @@ -26,6 +26,7 @@ import retrofit2.Call; import retrofit2.Response; +import timber.log.Timber; /** * Created by max on 2017/11/03. @@ -36,6 +37,7 @@ public class WatchListFragment extends FragmentChannelBase implements RetroCallb private long mediaId; private @KeyUtil.MediaType String mediaType; + private final String TAG = WatchListFragment.class.getSimpleName(); public static FragmentChannelBase newInstance(Bundle params, boolean popular) { Bundle args = new Bundle(params); @@ -121,7 +123,7 @@ public void onResponse(@NonNull Call>> ca makeRequest(); } } else - Log.e(TAG, ErrorUtil.INSTANCE.getError(response)); + Timber.tag(TAG).w(ErrorUtil.INSTANCE.getError(response)); } } @@ -129,7 +131,7 @@ public void onResponse(@NonNull Call>> ca public void onFailure(@NonNull Call>> call, @NonNull Throwable throwable) { if(isAlive() && getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED)) { throwable.printStackTrace(); - Log.e(TAG, throwable.getMessage()); + Timber.tag(TAG).e(throwable); } } } 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 31a1d0eb0..c5464cc0d 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 @@ -131,7 +131,7 @@ public void onItemClick(View target, IntPair data) { public void onItemLongClick(View target, IntPair data) { switch (target.getId()) { case R.id.container: - if(getPresenter().getApplicationPref().isAuthenticated()) { + if(getPresenter().getSettings().isAuthenticated()) { mediaActionUtil = new MediaActionUtil.Builder() .setId(data.getSecond().getId()).build(getActivity()); mediaActionUtil.startSeriesAction(); 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 9ff86185b..f5388add6 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 @@ -81,10 +81,10 @@ protected void updateUI() { searchView.setOnSearchViewListener(this); searchView.setOnQueryTextListener(this); injectAdapter(); - if(presenter.getApplicationPref().shouldShowTipFor(KeyUtil.KEY_GIPHY_TIP)) { + if(presenter.getSettings().shouldShowTipFor(KeyUtil.KEY_GIPHY_TIP)) { NotifyUtil.createAlerter(getActivity(), R.string.title_new_feature, R.string.text_giphy_feature, R.drawable.ic_gif_white_24dp, R.color.colorStateBlue, KeyUtil.DURATION_LONG); - presenter.getApplicationPref().disableTipFor(KeyUtil.KEY_GIPHY_TIP); + presenter.getSettings().disableTipFor(KeyUtil.KEY_GIPHY_TIP); } } diff --git a/app/src/main/java/com/mxt/anitrend/worker/AuthenticatorWorker.kt b/app/src/main/java/com/mxt/anitrend/worker/AuthenticatorWorker.kt index a06d1196b..5fef10ec4 100644 --- a/app/src/main/java/com/mxt/anitrend/worker/AuthenticatorWorker.kt +++ b/app/src/main/java/com/mxt/anitrend/worker/AuthenticatorWorker.kt @@ -16,13 +16,15 @@ import androidx.work.Data import androidx.work.ListenableWorker import androidx.work.Worker import androidx.work.WorkerParameters +import org.koin.core.KoinComponent +import org.koin.core.inject +import timber.log.Timber -class AuthenticatorWorker(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) { +class AuthenticatorWorker(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams), KoinComponent { - private val presenter by lazy { - BasePresenter(context) - } - private val authenticatorUri: Uri by lazy { + private val presenter by inject() + + private val authenticatorUri: Uri by lazy(LazyThreadSafetyMode.NONE) { Uri.parse(workerParams.inputData .getString(KeyUtil.arg_model)) } @@ -51,13 +53,13 @@ class AuthenticatorWorker(context: Context, workerParams: WorkerParameters) : Wo val authorizationCode = authenticatorUri.getQueryParameter(BuildConfig.RESPONSE_TYPE) if (!TextUtils.isEmpty(authorizationCode)) { val isSuccess = WebTokenRequest.getToken(authorizationCode) - presenter.applicationPref.isAuthenticated = isSuccess + presenter.settings.isAuthenticated = isSuccess val outputData = 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") + Timber.tag(TAG).e("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) @@ -74,4 +76,8 @@ class AuthenticatorWorker(context: Context, workerParams: WorkerParameters) : Wo .build() return Result.failure(workerErrorOutputData) } + + companion object { + private val TAG = AuthenticatorWorker::class.java.simpleName + } } diff --git a/app/src/main/res/drawable/ic_save_grey_600_24dp.xml b/app/src/main/res/drawable/ic_save_grey_600_24dp.xml new file mode 100644 index 000000000..03b2f6cdb --- /dev/null +++ b/app/src/main/res/drawable/ic_save_grey_600_24dp.xml @@ -0,0 +1,4 @@ + + + + diff --git a/app/src/main/res/drawable/ic_system_update_grey_600_24dp.xml b/app/src/main/res/drawable/ic_system_update_grey_600_24dp.xml new file mode 100644 index 000000000..e3ddc9322 --- /dev/null +++ b/app/src/main/res/drawable/ic_system_update_grey_600_24dp.xml @@ -0,0 +1,4 @@ + + + + diff --git a/app/src/main/res/layout/activity_logging.xml b/app/src/main/res/layout/activity_logging.xml new file mode 100644 index 000000000..e50818d02 --- /dev/null +++ b/app/src/main/res/layout/activity_logging.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_report.xml b/app/src/main/res/layout/activity_report.xml deleted file mode 100644 index 183fcef90..000000000 --- a/app/src/main/res/layout/activity_report.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - -