diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 000000000..88ea3aa1e --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,122 @@ + + + + + + + + + +
+ + + + xmlns:android + + ^$ + + + +
+
+ + + + xmlns:.* + + ^$ + + + BY_NAME + +
+
+ + + + .*:id + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + .*:name + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + name + + ^$ + + + +
+
+ + + + style + + ^$ + + + +
+
+ + + + .* + + ^$ + + + BY_NAME + +
+
+ + + + .* + + http://schemas.android.com/apk/res/android + + + ANDROID_ATTRIBUTE_ORDER + +
+
+ + + + .* + + .* + + + BY_NAME + +
+
+
+
+ + +
+
\ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 000000000..79ee123c2 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index dd7b89473..9fe826477 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,28 +1,39 @@ language: android jdk: oraclejdk8 +dist: trusty +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: 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,21 +48,21 @@ 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 +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" + - yes | sdkmanager "build-tools;28.0.3" + diff --git a/README.md b/README.md index 350215dfe..56c3ad916 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.5.6   [![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) diff --git a/app/.meta/version.json b/app/.meta/version.json index 845ed8a72..6468f6e81 100644 --- a/app/.meta/version.json +++ b/app/.meta/version.json @@ -1,7 +1,7 @@ { - "code": 111, - "migration": false, + "code": 136, + "migration": true, "releaseNotes": "", - "version": "1.4.7", + "version": "1.5.6", "appId": "com.mxt.anitrend" } diff --git a/app/build.gradle b/app/build.gradle index 63d3dc9a5..617a86c83 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,18 +1,20 @@ -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply plugin: 'io.objectbox' -apply plugin: 'kotlin-kapt' -apply plugin: 'io.fabric' +plugins { + id("com.android.application") + id("kotlin-android") + id("kotlin-android-extensions") + id("kotlin-kapt") + id("io.objectbox") +} 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 } @@ -31,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" @@ -58,12 +58,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 @@ -74,112 +80,144 @@ configurations.all { resolutionStrategy.force 'com.google.code.findbugs:jsr305:3.0.2' } +androidExtensions { + experimental = true +} + 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" + + /** Material Design */ + implementation "com.google.android.material:material:$material" - /** 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}" + implementation "androidx.constraintlayout:constraintlayout:$constraint" + implementation 'androidx.preference:preference-ktx:1.1.0-rc01' + 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" + implementation "com.google.firebase:firebase-analytics:$firebase" /** Crash Analytics */ - implementation('com.crashlytics.sdk.android:crashlytics:2.9.9@aar') { - transitive = true - } + implementation("com.crashlytics.sdk.android:crashlytics:$crashlytics") + + /** Glide Libraries */ + implementation "com.github.bumptech.glide:glide:$glide" + implementation 'androidx.preference:preference:1.1.0-rc01' + 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' - - /** Glide Libraries */ - implementation "com.github.bumptech.glide:glide:${rootProject.glide}" - kapt "com.github.bumptech.glide:compiler:${rootProject.glide}" + implementation "com.squareup.okhttp3:logging-interceptor:$okHttpLogger" /** Butter Knife Libraries */ - implementation "com.jakewharton:butterknife:${rootProject.butterKnife}" - kapt "com.jakewharton:butterknife-compiler:${rootProject.butterKnife}" - - /** State Layout Library */ - implementation 'com.github.nguyenhoanglam:ProgressLayout:1.0.1' - - /** Event Bus Library */ - implementation 'org.greenrobot:eventbus:3.1.1' + implementation "com.jakewharton:butterknife:$butterKnife" + kapt "com.jakewharton:butterknife-compiler:$butterKnife" - /** 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' + /** 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:$prettyTime" - /** Tap Target Prompt */ - implementation 'uk.co.samuelwall:material-tap-target-prompt:2.14.0' + /** Highly Customizable Video Player */ + implementation "cn.jzvd:jiaozivideoplayer:$jiaoziVideoPlayer" - /** Circular Progress View */ - implementation 'com.github.rahatarmanahmed:circularprogressview:2.5.0' + /** Photo View */ + implementation "com.github.chrisbanes:PhotoView:$photoView" /** On-boarding Experience */ - implementation 'com.codemybrainsout.onboarding:onboarder:1.0.4' + implementation "com.codemybrainsout.onboarding:onboarder:$onboarder" /** Charts */ - implementation'com.github.PhilJay:MPAndroidChart:v3.0.3' + implementation "com.github.PhilJay:MPAndroidChart:v$mpAndroidChart" /** About Library */ - implementation 'com.github.medyo:android-about-page:1.2.5' + implementation "com.github.medyo:android-about-page:$aboutPage" /** Multi Dex */ - implementation 'com.android.support:multidex:1.0.3' + implementation "androidx.multidex:multidex:$multidex" /** Material Search View */ - implementation 'com.miguelcatalan:materialsearchview:1.4.0' + implementation "com.github.ma-myair:MaterialSearchView:$materialSearchView" - implementation "com.github.wax911:android-emojify:$rootProject.emojify" + /** State Layout Library */ + implementation "com.github.nguyenhoanglam:ProgressLayout:$progressLayout" + + /** Event Bus Library */ + implementation "org.greenrobot:eventbus:$eventBus" + + /** Alerter */ + implementation "com.tapadoo.android:alerter:$alerter" + + /** Stream */ + implementation "com.annimon:stream:$stream" + + /** Circular Progress View */ + implementation "com.github.rahatarmanahmed:circularprogressview:$circularProgressView" + + /** 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/libs/YouTubeAndroidPlayerApi.jar b/app/libs/YouTubeAndroidPlayerApi.jar deleted file mode 100644 index 0acbebde9..000000000 Binary files a/app/libs/YouTubeAndroidPlayerApi.jar and /dev/null differ 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/release/output.json b/app/release/output.json index 8b04596b1..578850b30 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":136,"versionName":"1.5.6","enabled":true,"outputFile":"anitrend_v1.5.6_rc_136.apk","fullName":"release","baseName":"release"},"path":"anitrend_v1.5.6_rc_136.apk","properties":{}}] \ No newline at end of file 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" diff --git a/app/src/androidTest/java/com/mxt/anitrend/util/GroupingUtilTests.java b/app/src/androidTest/java/com/mxt/anitrend/util/GroupingUtilTests.java index a8a08b5d2..7a63daac3 100644 --- a/app/src/androidTest/java/com/mxt/anitrend/util/GroupingUtilTests.java +++ b/app/src/androidTest/java/com/mxt/anitrend/util/GroupingUtilTests.java @@ -8,6 +8,7 @@ import com.mxt.anitrend.model.entity.base.StaffBase; import com.mxt.anitrend.model.entity.group.RecyclerHeaderItem; import com.mxt.anitrend.model.entity.group.RecyclerItem; +import com.mxt.anitrend.util.collection.GroupingUtil; import org.hamcrest.Matcher; import org.hamcrest.Matchers; diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6c5e1cedb..3c62714d1 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,5 +1,5 @@ + @@ -7,197 +7,209 @@ + - - + android:theme="@style/AppTheme"> + + + + + + - - - - - - - + - - - - + android:launchMode="singleTop" + android:theme="@style/AppThemeLight.Translucent"> + + + android:host="com.mxt.anitrend" + android:scheme="intent" /> - + android:pathPattern="/user.*" + android:scheme="https" /> + + - - - + android:pathPattern="/manga.*" + android:scheme="https" /> + android:pathPattern="/anime.*" + android:scheme="https" /> + - - + android:pathPattern="/character.*" + android:scheme="https" /> + + - - + android:pathPattern="/staff.*" + android:scheme="https" /> + android:pathPattern="/actor.*" + android:scheme="https" /> + + - - + android:pathPattern="/studio.*" + android:scheme="https" /> + + - - - - - - - - - - - - - + android:pathPattern="/activity.*" + android:scheme="https" /> + + - - + android:launchMode="singleTop" + android:theme="@style/AppThemeLight.Translucent"> + + - - - - + + + - + + \ No newline at end of file diff --git a/app/src/main/assets/changelog.md b/app/src/main/assets/changelog.md index 83a7a7099..9635d8208 100644 --- a/app/src/main/assets/changelog.md +++ b/app/src/main/assets/changelog.md @@ -1,18 +1,22 @@ -__Anitrend v2.0 Coming Soon [W.I.P]__ All v1.X updates will focus on major bug fixes as all resources are being moved to v2.0 +__Anitrend v2.0 Coming Soon [W.I.P]__ All __v1.x.x__ updates will focus on major bug fixes as all resources are being moved to __v2.0__ __N.B__ v2.0 will be dropping support for Jellybean - Kitkat, due to missing or disabled _(TLS v1.2)_ which can result in authentication errors [read more](https://github.com/square/okhttp/issues/2372) #### Enhancements -- Minor UI tweaks, specifically view radius +- Support for Android Q +- Moved themes options to settings +- Support for higher quality posters +- Minor optimizations throughout the application #### Bug Fixes -- About page crashes -- Episode duration always displaying TBA (Swap) -- Missing notification type for subscribed activities (Mittens, Taichi) +- Replaced embedded YoutubePlayer +- Improved error message for invalid token errors +- User stats not updating (due to deprecated stats) #### Current Issues - Clicking on @username shows mixed feed +- Application logs are officially broken in **v1.5.x** - Sometimes image slide count doesn't change when you slowly scroll horizontally in feeds #### Special Thanks @@ -22,5 +26,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, Dustter_ diff --git a/app/src/main/assets/graphql/User/Query/User.graphql b/app/src/main/assets/graphql/User/Query/User.graphql deleted file mode 100644 index 2155cceda..000000000 --- a/app/src/main/assets/graphql/User/Query/User.graphql +++ /dev/null @@ -1,78 +0,0 @@ -query User($userId: Int, $username: String, $asHtml: Boolean = false) { - User(id: $userId, name: $username) { - ... on User { - id - name - avatar { - ... on UserAvatar { - large - medium - } - } - bannerImage - about(asHtml: $asHtml) - isFollowing - options { - ... on UserOptions { - titleLanguage - displayAdultContent - titleLanguage - profileColor - } - } - mediaListOptions { - ... on MediaListOptions { - scoreFormat - rowOrder - useLegacyLists - animeList { - ... on MediaListTypeOptions { - sectionOrder - splitCompletedSectionByFormat - customLists - advancedScoring - advancedScoringEnabled - } - } - mangaList { - ... on MediaListTypeOptions { - sectionOrder - splitCompletedSectionByFormat - customLists - advancedScoring - advancedScoringEnabled - } - } - } - } - stats { - ... on UserStats { - watchedTime - chaptersRead - animeStatusDistribution { - ... on StatusDistribution { - status - amount - } - } - mangaStatusDistribution { - ... on StatusDistribution { - status - amount - } - } - favouredGenresOverview { - ... on GenreStats { - genre - amount - meanScore - timeWatched - } - } - } - } - unreadNotificationCount - donatorTier - } - } -} diff --git a/app/src/main/assets/graphql/User/Query/UserOverview.graphql b/app/src/main/assets/graphql/User/Query/UserOverview.graphql deleted file mode 100644 index 2c9c5d923..000000000 --- a/app/src/main/assets/graphql/User/Query/UserOverview.graphql +++ /dev/null @@ -1,31 +0,0 @@ -query UserOverview($id: Int, $userName: String, $asHtml: Boolean = false) { - User(id: $id, name: $userName) { - ... on User { - id - name - avatar { - ... on UserAvatar { - large - medium - } - } - bannerImage - about(asHtml: $asHtml) - isFollowing - stats { - ... on UserStats { - favouredGenres { - ... on GenreStats { - genre - amount - meanScore - timeWatched - } - } - } - } - unreadNotificationCount - donatorTier - } - } -} diff --git a/app/src/main/assets/graphql/User/Query/UserStats.graphql b/app/src/main/assets/graphql/User/Query/UserStats.graphql deleted file mode 100644 index 29a968f98..000000000 --- a/app/src/main/assets/graphql/User/Query/UserStats.graphql +++ /dev/null @@ -1,24 +0,0 @@ -query UserStats($id: Int, $userName: String) { - User(id: $id, name: $userName) { - ... on User { - stats { - ... on UserStats { - watchedTime - chaptersRead - animeStatusDistribution { - ... on StatusDistribution { - status - amount - } - } - mangaStatusDistribution { - ... on StatusDistribution { - status - amount - } - } - } - } - } - } -} diff --git a/app/src/main/assets/graphql/Base/Mutation/ToggleFavourite.graphql b/app/src/main/assets/graphql/base/Mutation/ToggleFavourite.graphql similarity index 100% rename from app/src/main/assets/graphql/Base/Mutation/ToggleFavourite.graphql rename to app/src/main/assets/graphql/base/Mutation/ToggleFavourite.graphql diff --git a/app/src/main/assets/graphql/Base/Mutation/ToggleLike.graphql b/app/src/main/assets/graphql/base/Mutation/ToggleLike.graphql similarity index 100% rename from app/src/main/assets/graphql/Base/Mutation/ToggleLike.graphql rename to app/src/main/assets/graphql/base/Mutation/ToggleLike.graphql diff --git a/app/src/main/assets/graphql/Base/Query/Genres.graphql b/app/src/main/assets/graphql/base/Query/Genres.graphql similarity index 100% rename from app/src/main/assets/graphql/Base/Query/Genres.graphql rename to app/src/main/assets/graphql/base/Query/Genres.graphql diff --git a/app/src/main/assets/graphql/Base/Query/Tags.graphql b/app/src/main/assets/graphql/base/Query/Tags.graphql similarity index 100% rename from app/src/main/assets/graphql/Base/Query/Tags.graphql rename to app/src/main/assets/graphql/base/Query/Tags.graphql diff --git a/app/src/main/assets/graphql/Browse/Mutation/DeleteMediaListEntry.graphql b/app/src/main/assets/graphql/browse/Mutation/DeleteMediaListEntry.graphql similarity index 100% rename from app/src/main/assets/graphql/Browse/Mutation/DeleteMediaListEntry.graphql rename to app/src/main/assets/graphql/browse/Mutation/DeleteMediaListEntry.graphql diff --git a/app/src/main/assets/graphql/Browse/Mutation/DeleteReview.graphql b/app/src/main/assets/graphql/browse/Mutation/DeleteReview.graphql similarity index 100% rename from app/src/main/assets/graphql/Browse/Mutation/DeleteReview.graphql rename to app/src/main/assets/graphql/browse/Mutation/DeleteReview.graphql diff --git a/app/src/main/assets/graphql/Browse/Mutation/RateReview.graphql b/app/src/main/assets/graphql/browse/Mutation/RateReview.graphql similarity index 100% rename from app/src/main/assets/graphql/Browse/Mutation/RateReview.graphql rename to app/src/main/assets/graphql/browse/Mutation/RateReview.graphql diff --git a/app/src/main/assets/graphql/Browse/Mutation/SaveMediaListEntry.graphql b/app/src/main/assets/graphql/browse/Mutation/SaveMediaListEntry.graphql similarity index 100% rename from app/src/main/assets/graphql/Browse/Mutation/SaveMediaListEntry.graphql rename to app/src/main/assets/graphql/browse/Mutation/SaveMediaListEntry.graphql diff --git a/app/src/main/assets/graphql/Browse/Mutation/SaveReview.graphql b/app/src/main/assets/graphql/browse/Mutation/SaveReview.graphql similarity index 100% rename from app/src/main/assets/graphql/Browse/Mutation/SaveReview.graphql rename to app/src/main/assets/graphql/browse/Mutation/SaveReview.graphql diff --git a/app/src/main/assets/graphql/Browse/Mutation/UpdateMediaListEntries.graphql b/app/src/main/assets/graphql/browse/Mutation/UpdateMediaListEntries.graphql similarity index 100% rename from app/src/main/assets/graphql/Browse/Mutation/UpdateMediaListEntries.graphql rename to app/src/main/assets/graphql/browse/Mutation/UpdateMediaListEntries.graphql diff --git a/app/src/main/assets/graphql/Browse/Query/MediaBrowse.graphql b/app/src/main/assets/graphql/browse/Query/MediaBrowse.graphql similarity index 98% rename from app/src/main/assets/graphql/Browse/Query/MediaBrowse.graphql rename to app/src/main/assets/graphql/browse/Query/MediaBrowse.graphql index 195d3f363..844cc8552 100644 --- a/app/src/main/assets/graphql/Browse/Query/MediaBrowse.graphql +++ b/app/src/main/assets/graphql/browse/Query/MediaBrowse.graphql @@ -23,6 +23,7 @@ query MediaBrowse($id: Int, $page: Int, $perPage: Int, $seasonYear: Int, $type: ... on MediaCoverImage { large medium + extraLarge } } type diff --git a/app/src/main/assets/graphql/Browse/Query/MediaList.graphql b/app/src/main/assets/graphql/browse/Query/MediaList.graphql similarity index 98% rename from app/src/main/assets/graphql/Browse/Query/MediaList.graphql rename to app/src/main/assets/graphql/browse/Query/MediaList.graphql index fda8f5144..7d5b960b5 100644 --- a/app/src/main/assets/graphql/Browse/Query/MediaList.graphql +++ b/app/src/main/assets/graphql/browse/Query/MediaList.graphql @@ -43,6 +43,7 @@ query MediaList($id: Int, $mediaId: Int, $userName: String, $type: MediaType, $s ... on MediaCoverImage { large medium + extraLarge } } type diff --git a/app/src/main/assets/graphql/Browse/Query/MediaListBrowse.graphql b/app/src/main/assets/graphql/browse/Query/MediaListBrowse.graphql similarity index 98% rename from app/src/main/assets/graphql/Browse/Query/MediaListBrowse.graphql rename to app/src/main/assets/graphql/browse/Query/MediaListBrowse.graphql index 65734f534..00ff80931 100644 --- a/app/src/main/assets/graphql/Browse/Query/MediaListBrowse.graphql +++ b/app/src/main/assets/graphql/browse/Query/MediaListBrowse.graphql @@ -52,6 +52,7 @@ query MediaListBrowse($id: Int, $userId: Int, $userName: String, $page: Int, $pe ... on MediaCoverImage { large medium + extraLarge } } type diff --git a/app/src/main/assets/graphql/Browse/Query/MediaListCollection.graphql b/app/src/main/assets/graphql/browse/Query/MediaListCollection.graphql similarity index 98% rename from app/src/main/assets/graphql/Browse/Query/MediaListCollection.graphql rename to app/src/main/assets/graphql/browse/Query/MediaListCollection.graphql index a3b35939f..2edd4b3b9 100644 --- a/app/src/main/assets/graphql/Browse/Query/MediaListCollection.graphql +++ b/app/src/main/assets/graphql/browse/Query/MediaListCollection.graphql @@ -47,6 +47,7 @@ query MediaListCollection($userId: Int, $userName: String, $type: MediaType, $fo ... on MediaCoverImage { large medium + extraLarge } } type diff --git a/app/src/main/assets/graphql/Browse/Query/MediaWithList.graphql b/app/src/main/assets/graphql/browse/Query/MediaWithList.graphql similarity index 98% rename from app/src/main/assets/graphql/Browse/Query/MediaWithList.graphql rename to app/src/main/assets/graphql/browse/Query/MediaWithList.graphql index 72320abb7..2a9cf8c96 100644 --- a/app/src/main/assets/graphql/Browse/Query/MediaWithList.graphql +++ b/app/src/main/assets/graphql/browse/Query/MediaWithList.graphql @@ -14,6 +14,7 @@ query MediaWithList($id: Int, $type: MediaType, $onList: Boolean, $scoreFormat: ... on MediaCoverImage { large medium + extraLarge } } type diff --git a/app/src/main/assets/graphql/Browse/Query/ReviewBrowse.graphql b/app/src/main/assets/graphql/browse/Query/ReviewBrowse.graphql similarity index 98% rename from app/src/main/assets/graphql/Browse/Query/ReviewBrowse.graphql rename to app/src/main/assets/graphql/browse/Query/ReviewBrowse.graphql index 9c9cf705f..bd829205e 100644 --- a/app/src/main/assets/graphql/Browse/Query/ReviewBrowse.graphql +++ b/app/src/main/assets/graphql/browse/Query/ReviewBrowse.graphql @@ -48,6 +48,7 @@ query ReviewBrowse($page: Int, $perPage: Int, $mediaId: Int, $type: MediaType, $ ... on MediaCoverImage { large medium + extraLarge } } bannerImage diff --git a/app/src/main/assets/graphql/Character/Query/CharacterActors.graphql b/app/src/main/assets/graphql/character/Query/CharacterActors.graphql similarity index 100% rename from app/src/main/assets/graphql/Character/Query/CharacterActors.graphql rename to app/src/main/assets/graphql/character/Query/CharacterActors.graphql diff --git a/app/src/main/assets/graphql/Character/Query/CharacterBase.graphql b/app/src/main/assets/graphql/character/Query/CharacterBase.graphql similarity index 100% rename from app/src/main/assets/graphql/Character/Query/CharacterBase.graphql rename to app/src/main/assets/graphql/character/Query/CharacterBase.graphql diff --git a/app/src/main/assets/graphql/Character/Query/CharacterMedia.graphql b/app/src/main/assets/graphql/character/Query/CharacterMedia.graphql similarity index 98% rename from app/src/main/assets/graphql/Character/Query/CharacterMedia.graphql rename to app/src/main/assets/graphql/character/Query/CharacterMedia.graphql index 6021fd996..48c542492 100644 --- a/app/src/main/assets/graphql/Character/Query/CharacterMedia.graphql +++ b/app/src/main/assets/graphql/character/Query/CharacterMedia.graphql @@ -25,6 +25,7 @@ query CharacterMedia($id: Int!, $page: Int, $perPage: Int, $sort: [MediaSort] = ... on MediaCoverImage { large medium + extraLarge } } type diff --git a/app/src/main/assets/graphql/Character/Query/CharacterOverview.graphql b/app/src/main/assets/graphql/character/Query/CharacterOverview.graphql similarity index 100% rename from app/src/main/assets/graphql/Character/Query/CharacterOverview.graphql rename to app/src/main/assets/graphql/character/Query/CharacterOverview.graphql diff --git a/app/src/main/assets/graphql/Feed/Mutation/DeleteActivity.graphql b/app/src/main/assets/graphql/feed/Mutation/DeleteActivity.graphql similarity index 100% rename from app/src/main/assets/graphql/Feed/Mutation/DeleteActivity.graphql rename to app/src/main/assets/graphql/feed/Mutation/DeleteActivity.graphql diff --git a/app/src/main/assets/graphql/Feed/Mutation/DeleteActivityReply.graphql b/app/src/main/assets/graphql/feed/Mutation/DeleteActivityReply.graphql similarity index 100% rename from app/src/main/assets/graphql/Feed/Mutation/DeleteActivityReply.graphql rename to app/src/main/assets/graphql/feed/Mutation/DeleteActivityReply.graphql diff --git a/app/src/main/assets/graphql/Feed/Mutation/SaveActivityReply.graphql b/app/src/main/assets/graphql/feed/Mutation/SaveActivityReply.graphql similarity index 100% rename from app/src/main/assets/graphql/Feed/Mutation/SaveActivityReply.graphql rename to app/src/main/assets/graphql/feed/Mutation/SaveActivityReply.graphql diff --git a/app/src/main/assets/graphql/Feed/Mutation/SaveMessageActivity.graphql b/app/src/main/assets/graphql/feed/Mutation/SaveMessageActivity.graphql similarity index 100% rename from app/src/main/assets/graphql/Feed/Mutation/SaveMessageActivity.graphql rename to app/src/main/assets/graphql/feed/Mutation/SaveMessageActivity.graphql diff --git a/app/src/main/assets/graphql/Feed/Mutation/SaveTextActivity.graphql b/app/src/main/assets/graphql/feed/Mutation/SaveTextActivity.graphql similarity index 100% rename from app/src/main/assets/graphql/Feed/Mutation/SaveTextActivity.graphql rename to app/src/main/assets/graphql/feed/Mutation/SaveTextActivity.graphql diff --git a/app/src/main/assets/graphql/Feed/Query/FeedList.graphql b/app/src/main/assets/graphql/feed/Query/FeedList.graphql similarity index 99% rename from app/src/main/assets/graphql/Feed/Query/FeedList.graphql rename to app/src/main/assets/graphql/feed/Query/FeedList.graphql index f9aca2a62..6c5aa0ad8 100644 --- a/app/src/main/assets/graphql/Feed/Query/FeedList.graphql +++ b/app/src/main/assets/graphql/feed/Query/FeedList.graphql @@ -57,6 +57,7 @@ query FeedList($page: Int, $perPage: Int, $id: Int, $isFollowing: Boolean, $user ... on MediaCoverImage { large medium + extraLarge } } type diff --git a/app/src/main/assets/graphql/Feed/Query/FeedListReply.graphql b/app/src/main/assets/graphql/feed/Query/FeedListReply.graphql similarity index 99% rename from app/src/main/assets/graphql/Feed/Query/FeedListReply.graphql rename to app/src/main/assets/graphql/feed/Query/FeedListReply.graphql index 3daa5b448..113ce5897 100644 --- a/app/src/main/assets/graphql/Feed/Query/FeedListReply.graphql +++ b/app/src/main/assets/graphql/feed/Query/FeedListReply.graphql @@ -81,6 +81,7 @@ query FeedListReply($id: Int, $asHtml: Boolean = false) { ... on MediaCoverImage { large medium + extraLarge } } type diff --git a/app/src/main/assets/graphql/Feed/Query/FeedMessage.graphql b/app/src/main/assets/graphql/feed/Query/FeedMessage.graphql similarity index 100% rename from app/src/main/assets/graphql/Feed/Query/FeedMessage.graphql rename to app/src/main/assets/graphql/feed/Query/FeedMessage.graphql diff --git a/app/src/main/assets/graphql/Media/Query/MediaBase.graphql b/app/src/main/assets/graphql/media/Query/MediaBase.graphql similarity index 100% rename from app/src/main/assets/graphql/Media/Query/MediaBase.graphql rename to app/src/main/assets/graphql/media/Query/MediaBase.graphql diff --git a/app/src/main/assets/graphql/Media/Query/MediaCharacters.graphql b/app/src/main/assets/graphql/media/Query/MediaCharacters.graphql similarity index 100% rename from app/src/main/assets/graphql/Media/Query/MediaCharacters.graphql rename to app/src/main/assets/graphql/media/Query/MediaCharacters.graphql diff --git a/app/src/main/assets/graphql/Media/Query/MediaEpisodes.graphql b/app/src/main/assets/graphql/media/Query/MediaEpisodes.graphql similarity index 100% rename from app/src/main/assets/graphql/Media/Query/MediaEpisodes.graphql rename to app/src/main/assets/graphql/media/Query/MediaEpisodes.graphql diff --git a/app/src/main/assets/graphql/Media/Query/MediaOverview.graphql b/app/src/main/assets/graphql/media/Query/MediaOverview.graphql similarity index 98% rename from app/src/main/assets/graphql/Media/Query/MediaOverview.graphql rename to app/src/main/assets/graphql/media/Query/MediaOverview.graphql index cb4b1fc17..c8c6d9f47 100644 --- a/app/src/main/assets/graphql/Media/Query/MediaOverview.graphql +++ b/app/src/main/assets/graphql/media/Query/MediaOverview.graphql @@ -14,6 +14,7 @@ query MediaOverview($id: Int!, $type: MediaType, $isAdult: Boolean = false, $isM ... on MediaCoverImage { large medium + extraLarge } } bannerImage diff --git a/app/src/main/assets/graphql/Media/Query/MediaRelations.graphql b/app/src/main/assets/graphql/media/Query/MediaRelations.graphql similarity index 98% rename from app/src/main/assets/graphql/Media/Query/MediaRelations.graphql rename to app/src/main/assets/graphql/media/Query/MediaRelations.graphql index e010b695d..fd7295b91 100644 --- a/app/src/main/assets/graphql/Media/Query/MediaRelations.graphql +++ b/app/src/main/assets/graphql/media/Query/MediaRelations.graphql @@ -28,6 +28,7 @@ query MediaRelations($id: Int!, $type: MediaType, $isAdult: Boolean = false) { ... on MediaCoverImage { large medium + extraLarge } } type diff --git a/app/src/main/assets/graphql/Media/Query/MediaSocial.graphql b/app/src/main/assets/graphql/media/Query/MediaSocial.graphql similarity index 98% rename from app/src/main/assets/graphql/Media/Query/MediaSocial.graphql rename to app/src/main/assets/graphql/media/Query/MediaSocial.graphql index cdf5f213e..4c710f964 100644 --- a/app/src/main/assets/graphql/Media/Query/MediaSocial.graphql +++ b/app/src/main/assets/graphql/media/Query/MediaSocial.graphql @@ -57,6 +57,7 @@ query MediaSocial($mediaId: Int!, $isFollowing: Boolean = true, $page: Int, $per ... on MediaCoverImage { large medium + extraLarge } } type diff --git a/app/src/main/assets/graphql/Media/Query/MediaStaff.graphql b/app/src/main/assets/graphql/media/Query/MediaStaff.graphql similarity index 100% rename from app/src/main/assets/graphql/Media/Query/MediaStaff.graphql rename to app/src/main/assets/graphql/media/Query/MediaStaff.graphql diff --git a/app/src/main/assets/graphql/Media/Query/MediaStats.graphql b/app/src/main/assets/graphql/media/Query/MediaStats.graphql similarity index 100% rename from app/src/main/assets/graphql/Media/Query/MediaStats.graphql rename to app/src/main/assets/graphql/media/Query/MediaStats.graphql diff --git a/app/src/main/assets/graphql/Search/Query/CharacterSearch.graphql b/app/src/main/assets/graphql/search/Query/CharacterSearch.graphql similarity index 100% rename from app/src/main/assets/graphql/Search/Query/CharacterSearch.graphql rename to app/src/main/assets/graphql/search/Query/CharacterSearch.graphql diff --git a/app/src/main/assets/graphql/Search/Query/MediaSearch.graphql b/app/src/main/assets/graphql/search/Query/MediaSearch.graphql similarity index 98% rename from app/src/main/assets/graphql/Search/Query/MediaSearch.graphql rename to app/src/main/assets/graphql/search/Query/MediaSearch.graphql index 54cbd6be5..01a569a15 100644 --- a/app/src/main/assets/graphql/Search/Query/MediaSearch.graphql +++ b/app/src/main/assets/graphql/search/Query/MediaSearch.graphql @@ -21,6 +21,7 @@ query MediaSearch($id: Int, $page: Int, $perPage: Int, $search: String, $type: M } coverImage { ... on MediaCoverImage { + extraLarge large medium } diff --git a/app/src/main/assets/graphql/Search/Query/StaffSearch.graphql b/app/src/main/assets/graphql/search/Query/StaffSearch.graphql similarity index 100% rename from app/src/main/assets/graphql/Search/Query/StaffSearch.graphql rename to app/src/main/assets/graphql/search/Query/StaffSearch.graphql diff --git a/app/src/main/assets/graphql/Search/Query/StudioSearch.graphql b/app/src/main/assets/graphql/search/Query/StudioSearch.graphql similarity index 100% rename from app/src/main/assets/graphql/Search/Query/StudioSearch.graphql rename to app/src/main/assets/graphql/search/Query/StudioSearch.graphql diff --git a/app/src/main/assets/graphql/Search/Query/UserSearch.graphql b/app/src/main/assets/graphql/search/Query/UserSearch.graphql similarity index 100% rename from app/src/main/assets/graphql/Search/Query/UserSearch.graphql rename to app/src/main/assets/graphql/search/Query/UserSearch.graphql diff --git a/app/src/main/assets/graphql/Staff/Query/StaffBase.graphql b/app/src/main/assets/graphql/staff/Query/StaffBase.graphql similarity index 100% rename from app/src/main/assets/graphql/Staff/Query/StaffBase.graphql rename to app/src/main/assets/graphql/staff/Query/StaffBase.graphql diff --git a/app/src/main/assets/graphql/Staff/Query/StaffMedia.graphql b/app/src/main/assets/graphql/staff/Query/StaffMedia.graphql similarity index 98% rename from app/src/main/assets/graphql/Staff/Query/StaffMedia.graphql rename to app/src/main/assets/graphql/staff/Query/StaffMedia.graphql index a0bea9d50..fba787b75 100644 --- a/app/src/main/assets/graphql/Staff/Query/StaffMedia.graphql +++ b/app/src/main/assets/graphql/staff/Query/StaffMedia.graphql @@ -22,6 +22,7 @@ query StaffMedia($id: Int!, $page: Int, $perPage: Int, $sort: [MediaSort] = FORM } coverImage { ... on MediaCoverImage { + extraLarge large medium } diff --git a/app/src/main/assets/graphql/Staff/Query/StaffOverview.graphql b/app/src/main/assets/graphql/staff/Query/StaffOverview.graphql similarity index 100% rename from app/src/main/assets/graphql/Staff/Query/StaffOverview.graphql rename to app/src/main/assets/graphql/staff/Query/StaffOverview.graphql diff --git a/app/src/main/assets/graphql/Staff/Query/StaffRoles.graphql b/app/src/main/assets/graphql/staff/Query/StaffRoles.graphql similarity index 100% rename from app/src/main/assets/graphql/Staff/Query/StaffRoles.graphql rename to app/src/main/assets/graphql/staff/Query/StaffRoles.graphql diff --git a/app/src/main/assets/graphql/Studio/Query/StudioBase.graphql b/app/src/main/assets/graphql/studio/Query/StudioBase.graphql similarity index 100% rename from app/src/main/assets/graphql/Studio/Query/StudioBase.graphql rename to app/src/main/assets/graphql/studio/Query/StudioBase.graphql diff --git a/app/src/main/assets/graphql/Studio/Query/StudioMedia.graphql b/app/src/main/assets/graphql/studio/Query/StudioMedia.graphql similarity index 98% rename from app/src/main/assets/graphql/Studio/Query/StudioMedia.graphql rename to app/src/main/assets/graphql/studio/Query/StudioMedia.graphql index 994e76b5e..029be6b1f 100644 --- a/app/src/main/assets/graphql/Studio/Query/StudioMedia.graphql +++ b/app/src/main/assets/graphql/studio/Query/StudioMedia.graphql @@ -23,6 +23,7 @@ query StudioMedia($id: Int!, $page: Int, $perPage: Int, $sort: [MediaSort] = POP } coverImage { ... on MediaCoverImage { + extraLarge large medium } diff --git a/app/src/main/assets/graphql/User/Mutation/ToggleFollow.graphql b/app/src/main/assets/graphql/user/Mutation/ToggleFollow.graphql similarity index 100% rename from app/src/main/assets/graphql/User/Mutation/ToggleFollow.graphql rename to app/src/main/assets/graphql/user/Mutation/ToggleFollow.graphql diff --git a/app/src/main/assets/graphql/User/Query/Counters/UserFavouriteCount.graphql b/app/src/main/assets/graphql/user/Query/Counters/UserFavouriteCount.graphql similarity index 100% rename from app/src/main/assets/graphql/User/Query/Counters/UserFavouriteCount.graphql rename to app/src/main/assets/graphql/user/Query/Counters/UserFavouriteCount.graphql diff --git a/app/src/main/assets/graphql/User/Query/CurrentUser.graphql b/app/src/main/assets/graphql/user/Query/CurrentUser.graphql similarity index 100% rename from app/src/main/assets/graphql/User/Query/CurrentUser.graphql rename to app/src/main/assets/graphql/user/Query/CurrentUser.graphql diff --git a/app/src/main/assets/graphql/User/Query/Favourites/AnimeFavourites.graphql b/app/src/main/assets/graphql/user/Query/Favourites/AnimeFavourites.graphql similarity index 98% rename from app/src/main/assets/graphql/User/Query/Favourites/AnimeFavourites.graphql rename to app/src/main/assets/graphql/user/Query/Favourites/AnimeFavourites.graphql index 966e6b39b..c4d302399 100644 --- a/app/src/main/assets/graphql/User/Query/Favourites/AnimeFavourites.graphql +++ b/app/src/main/assets/graphql/user/Query/Favourites/AnimeFavourites.graphql @@ -25,6 +25,7 @@ query AnimeFavourites($id: Int, $userName: String, $page: Int, $perPage: Int) { ... on MediaCoverImage { large medium + extraLarge } } type diff --git a/app/src/main/assets/graphql/User/Query/Favourites/CharacterFavourites.graphql b/app/src/main/assets/graphql/user/Query/Favourites/CharacterFavourites.graphql similarity index 100% rename from app/src/main/assets/graphql/User/Query/Favourites/CharacterFavourites.graphql rename to app/src/main/assets/graphql/user/Query/Favourites/CharacterFavourites.graphql diff --git a/app/src/main/assets/graphql/User/Query/Favourites/MangaFavourites.graphql b/app/src/main/assets/graphql/user/Query/Favourites/MangaFavourites.graphql similarity index 98% rename from app/src/main/assets/graphql/User/Query/Favourites/MangaFavourites.graphql rename to app/src/main/assets/graphql/user/Query/Favourites/MangaFavourites.graphql index c2dd06a4e..36a83369b 100644 --- a/app/src/main/assets/graphql/User/Query/Favourites/MangaFavourites.graphql +++ b/app/src/main/assets/graphql/user/Query/Favourites/MangaFavourites.graphql @@ -25,6 +25,7 @@ query MangaFavourites($id: Int, $userName: String, $page: Int, $perPage: Int) { ... on MediaCoverImage { large medium + extraLarge } } type diff --git a/app/src/main/assets/graphql/User/Query/Favourites/StaffFavourites.graphql b/app/src/main/assets/graphql/user/Query/Favourites/StaffFavourites.graphql similarity index 100% rename from app/src/main/assets/graphql/User/Query/Favourites/StaffFavourites.graphql rename to app/src/main/assets/graphql/user/Query/Favourites/StaffFavourites.graphql diff --git a/app/src/main/assets/graphql/User/Query/Favourites/StudioFavourites.graphql b/app/src/main/assets/graphql/user/Query/Favourites/StudioFavourites.graphql similarity index 100% rename from app/src/main/assets/graphql/User/Query/Favourites/StudioFavourites.graphql rename to app/src/main/assets/graphql/user/Query/Favourites/StudioFavourites.graphql diff --git a/app/src/main/assets/graphql/User/Query/Notifications/UserNotifications.graphql b/app/src/main/assets/graphql/user/Query/Notifications/UserNotifications.graphql similarity index 99% rename from app/src/main/assets/graphql/User/Query/Notifications/UserNotifications.graphql rename to app/src/main/assets/graphql/user/Query/Notifications/UserNotifications.graphql index 43c27e625..ab69cdb8d 100644 --- a/app/src/main/assets/graphql/User/Query/Notifications/UserNotifications.graphql +++ b/app/src/main/assets/graphql/user/Query/Notifications/UserNotifications.graphql @@ -161,6 +161,7 @@ fragment mediaBase on Media { ... on MediaCoverImage { large medium + extraLarge } } type diff --git a/app/src/main/assets/graphql/user/Query/User.graphql b/app/src/main/assets/graphql/user/Query/User.graphql new file mode 100644 index 000000000..2279b7cc9 --- /dev/null +++ b/app/src/main/assets/graphql/user/Query/User.graphql @@ -0,0 +1,245 @@ +query User($userId: Int, $username: String, $asHtml: Boolean = false) { + User(id: $userId, name: $username) { + ... on User { + id + name + avatar { + ... on UserAvatar { + large + medium + } + } + bannerImage + about(asHtml: $asHtml) + isFollowing + options { + ... on UserOptions { + titleLanguage + displayAdultContent + titleLanguage + profileColor + } + } + mediaListOptions { + ... on MediaListOptions { + scoreFormat + rowOrder + useLegacyLists + animeList { + ... on MediaListTypeOptions { + sectionOrder + splitCompletedSectionByFormat + customLists + advancedScoring + advancedScoringEnabled + } + } + mangaList { + ... on MediaListTypeOptions { + sectionOrder + splitCompletedSectionByFormat + customLists + advancedScoring + advancedScoringEnabled + } + } + } + } + statistics { + ... on UserStatisticTypes { + anime { + ... userStatistics + } + manga { + ... userStatistics + } + } + } + stats { + ... on UserStats { + watchedTime + chaptersRead + animeStatusDistribution { + ... on StatusDistribution { + status + amount + } + } + mangaStatusDistribution { + ... on StatusDistribution { + status + amount + } + } + favouredGenresOverview { + ... on GenreStats { + genre + amount + meanScore + timeWatched + } + } + } + } + unreadNotificationCount + donatorTier + } + } +} + + +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/UserBase.graphql b/app/src/main/assets/graphql/user/Query/UserBase.graphql similarity index 100% rename from app/src/main/assets/graphql/User/Query/UserBase.graphql rename to app/src/main/assets/graphql/user/Query/UserBase.graphql diff --git a/app/src/main/assets/graphql/User/Query/UserFollowers.graphql b/app/src/main/assets/graphql/user/Query/UserFollowers.graphql similarity index 100% rename from app/src/main/assets/graphql/User/Query/UserFollowers.graphql rename to app/src/main/assets/graphql/user/Query/UserFollowers.graphql diff --git a/app/src/main/assets/graphql/User/Query/UserFollowing.graphql b/app/src/main/assets/graphql/user/Query/UserFollowing.graphql similarity index 100% rename from app/src/main/assets/graphql/User/Query/UserFollowing.graphql rename to app/src/main/assets/graphql/user/Query/UserFollowing.graphql diff --git a/app/src/main/assets/graphql/user/Query/UserOverview.graphql b/app/src/main/assets/graphql/user/Query/UserOverview.graphql new file mode 100644 index 000000000..06f3e628e --- /dev/null +++ b/app/src/main/assets/graphql/user/Query/UserOverview.graphql @@ -0,0 +1,197 @@ +query UserOverview($id: Int, $userName: String, $asHtml: Boolean = false) { + User(id: $id, name: $userName) { + ... on User { + id + name + avatar { + ... on UserAvatar { + large + medium + } + } + bannerImage + about(asHtml: $asHtml) + isFollowing + statistics { + ... on UserStatisticTypes { + anime { + ... userStatistics + } + manga { + ... userStatistics + } + } + } + stats { + ... on UserStats { + favouredGenres { + ... on GenreStats { + genre + amount + meanScore + timeWatched + } + } + } + } + unreadNotificationCount + donatorTier + } + } +} + + +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/UserStats.graphql b/app/src/main/assets/graphql/user/Query/UserStats.graphql new file mode 100644 index 000000000..2599989ff --- /dev/null +++ b/app/src/main/assets/graphql/user/Query/UserStats.graphql @@ -0,0 +1,171 @@ +query UserStats($id: Int, $userName: String) { + User(id: $id, name: $userName) { + ... on User { + statistics { + ... on UserStatisticTypes { + anime { + ... userStatistics + } + 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 +} diff --git a/app/src/main/java/com/mxt/anitrend/App.kt b/app/src/main/java/com/mxt/anitrend/App.kt index a8b743b1f..f08931039 100644 --- a/app/src/main/java/com/mxt/anitrend/App.kt +++ b/app/src/main/java/com/mxt/anitrend/App.kt @@ -3,19 +3,25 @@ package com.mxt.anitrend import android.content.Context import android.content.Intent import android.os.Build -import android.support.multidex.MultiDex -import android.support.multidex.MultiDexApplication -import com.crashlytics.android.core.CrashlyticsCore +import androidx.appcompat.app.AppCompatDelegate +import androidx.multidex.MultiDex +import androidx.multidex.MultiDexApplication import com.google.android.gms.security.ProviderInstaller -import com.google.firebase.analytics.FirebaseAnalytics -import com.mxt.anitrend.model.entity.MyObjectBox -import com.mxt.anitrend.util.ApplicationPref -import com.mxt.anitrend.util.JobSchedulerUtil -import com.mxt.anitrend.util.LocaleUtil -import io.fabric.sdk.android.Fabric -import io.objectbox.BoxStore +import com.mxt.anitrend.analytics.AnalyticsLogging +import com.mxt.anitrend.analytics.contract.ISupportAnalytics +import com.mxt.anitrend.koin.AppModule.appModule +import com.mxt.anitrend.koin.AppModule.presenterModule +import com.mxt.anitrend.koin.AppModule.widgetModule +import com.mxt.anitrend.util.CompatUtil +import com.mxt.anitrend.util.Settings +import com.mxt.anitrend.util.locale.LocaleUtil 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. @@ -24,9 +30,20 @@ import org.greenrobot.eventbus.EventBus class App : MultiDexApplication() { - val applicationPref = ApplicationPref(this) + private val supportAnalytics by inject() + private val settings by inject() - init { + /** + * Timber logging tree depending on the build type we plant the appropriate tree + */ + private fun plantLoggingTree() { + when (BuildConfig.DEBUG) { + true -> Timber.plant(Timber.DebugTree()) + else -> Timber.plant(supportAnalytics as AnalyticsLogging) + } + } + + private fun initializeEventBus() { EventBus.builder().logNoSubscriberMessages(BuildConfig.DEBUG) .sendNoSubscriberEvent(BuildConfig.DEBUG) .sendSubscriberExceptionEvent(BuildConfig.DEBUG) @@ -34,57 +51,22 @@ class App : MultiDexApplication() { .installDefaultEventBus() } - /** - * @return Application global registered firebase analytics - * - * @see com.mxt.anitrend.util.AnalyticsUtil - */ - var analytics: FirebaseAnalytics? = null - private set - /** - * @return Default application object box database instance - * - * @see com.mxt.anitrend.data.DatabaseHelper - */ - lateinit var boxStore: BoxStore - private set - - /** - * Get application global registered fabric instance, depending on - * the current application preferences the application may have - * disabled the current instance from sending any data - * - * @see com.mxt.anitrend.util.AnalyticsUtil + /** [Koin](https://insert-koin.io/docs/2.0/getting-started/) + * Initializes Koin dependency injection */ - var fabric: Fabric? = null - private set - - private fun setupBoxStore() { - boxStore = MyObjectBox.builder() - .androidContext(this@App) - .build() - } - - private fun setCrashAnalytics() { - if (!BuildConfig.DEBUG) - if (applicationPref.isCrashReportsEnabled == true) { - val crashlyticsCore = CrashlyticsCore.Builder() - .build() - - fabric = Fabric.with(Fabric.Builder(this) - .kits(crashlyticsCore) - .appIdentifier(BuildConfig.BUILD_TYPE) - .build()) - } + private fun initializeDependencyInjection() { + startKoin { + androidLogger() + androidContext(applicationContext) + modules(listOf(appModule, widgetModule, presenterModule)) + } } - private fun initApp() { - if (applicationPref.isUsageAnalyticsEnabled == true) { - analytics = FirebaseAnalytics.getInstance(this).apply { - setAnalyticsCollectionEnabled(applicationPref.isUsageAnalyticsEnabled!!) - } - } - try { + private fun initializeApplication() { + runCatching { + EmojiManager.initEmojiData(this) + }.exceptionOrNull()?.printStackTrace() + runCatching { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) ProviderInstaller.installIfNeededAsync( applicationContext, @@ -98,22 +80,27 @@ class App : MultiDexApplication() { } } ) - EmojiManager.initEmojiData(this) - } catch (e: Exception) { - e.printStackTrace() - } + }.exceptionOrNull()?.printStackTrace() + } + + fun applyTheme() { + if (CompatUtil.isLightTheme(settings.theme)) + AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO) + else + AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES) } override fun onCreate() { super.onCreate() - setCrashAnalytics() - setupBoxStore() - initApp() + initializeDependencyInjection() + initializeApplication() + initializeEventBus() + plantLoggingTree() + applyTheme() } 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/adapter/pager/detail/AnimePageAdapter.java b/app/src/main/java/com/mxt/anitrend/adapter/pager/detail/AnimePageAdapter.java index 2a9f0f687..57b668a03 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,14 +1,15 @@ 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; -import com.mxt.anitrend.util.ApplicationPref; -import com.mxt.anitrend.util.GraphUtil; import com.mxt.anitrend.util.KeyUtil; +import com.mxt.anitrend.util.Settings; +import com.mxt.anitrend.util.graphql.GraphUtil; import com.mxt.anitrend.view.fragment.detail.MediaFeedFragment; import com.mxt.anitrend.view.fragment.detail.MediaOverviewFragment; import com.mxt.anitrend.view.fragment.detail.MediaStaffFragment; @@ -29,7 +30,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 @@ -46,7 +47,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/CharacterPageAdapter.java b/app/src/main/java/com/mxt/anitrend/adapter/pager/detail/CharacterPageAdapter.java index 05575ca6c..72150fadb 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,9 @@ 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..06630cbde 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,9 @@ 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 32984bd54..5da9133b8 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,14 +1,15 @@ 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; -import com.mxt.anitrend.util.ApplicationPref; -import com.mxt.anitrend.util.GraphUtil; import com.mxt.anitrend.util.KeyUtil; +import com.mxt.anitrend.util.Settings; +import com.mxt.anitrend.util.graphql.GraphUtil; import com.mxt.anitrend.view.fragment.detail.MediaFeedFragment; import com.mxt.anitrend.view.fragment.detail.MediaOverviewFragment; import com.mxt.anitrend.view.fragment.detail.MediaStaffFragment; @@ -28,7 +29,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 @@ -45,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/MessagePageAdapter.java b/app/src/main/java/com/mxt/anitrend/adapter/pager/detail/MessagePageAdapter.java index f7580c42f..5ab23e46c 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,9 @@ 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..a7e8bd01d 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,13 +1,14 @@ 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; -import com.mxt.anitrend.util.GraphUtil; import com.mxt.anitrend.util.KeyUtil; +import com.mxt.anitrend.util.graphql.GraphUtil; import com.mxt.anitrend.view.fragment.detail.UserFeedFragment; import com.mxt.anitrend.view.fragment.detail.UserOverviewFragment; @@ -31,7 +32,7 @@ public ProfilePageAdapter(FragmentManager fragmentManager, Context context) { public Fragment getItem(int position) { switch (position) { case 0: - return UserOverviewFragment.newInstance(getParams()); + return UserOverviewFragment.Companion.newInstance(getParams()); case 1: return UserFeedFragment.newInstance(getParams(), GraphUtil.INSTANCE.getDefaultQuery(true) .putVariable(KeyUtil.arg_type, KeyUtil.MEDIA_LIST)); 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..f7ac82e13 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,9 @@ 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..7edfad871 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,9 @@ 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..69957063a 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,13 +1,14 @@ 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; -import com.mxt.anitrend.util.GraphUtil; import com.mxt.anitrend.util.KeyUtil; +import com.mxt.anitrend.util.graphql.GraphUtil; import com.mxt.anitrend.view.fragment.list.FeedListFragment; /** 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..dfd331af6 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,9 @@ 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..6db784dd1 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,13 +1,14 @@ 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; -import com.mxt.anitrend.util.GraphUtil; import com.mxt.anitrend.util.KeyUtil; +import com.mxt.anitrend.util.graphql.GraphUtil; import com.mxt.anitrend.view.fragment.list.MediaBrowseFragment; import com.mxt.anitrend.view.fragment.list.MediaLatestList; 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..605c1cc24 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,13 +1,14 @@ 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; -import com.mxt.anitrend.util.GraphUtil; import com.mxt.anitrend.util.KeyUtil; +import com.mxt.anitrend.util.graphql.GraphUtil; import com.mxt.anitrend.view.fragment.list.MediaListFragment; /** 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..d0c2e37b1 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,9 @@ 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..123028175 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,13 +1,14 @@ 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; -import com.mxt.anitrend.util.ApplicationPref; import com.mxt.anitrend.util.KeyUtil; +import com.mxt.anitrend.util.Settings; import com.mxt.anitrend.view.fragment.search.CharacterSearchFragment; import com.mxt.anitrend.view.fragment.search.MediaSearchFragment; import com.mxt.anitrend.view.fragment.search.StaffSearchFragment; @@ -22,7 +23,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/adapter/pager/index/SeasonPageAdapter.java b/app/src/main/java/com/mxt/anitrend/adapter/pager/index/SeasonPageAdapter.java index 864f4d966..ba696e4af 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,13 +1,14 @@ 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; -import com.mxt.anitrend.util.GraphUtil; import com.mxt.anitrend.util.KeyUtil; +import com.mxt.anitrend.util.graphql.GraphUtil; import com.mxt.anitrend.view.fragment.list.MediaBrowseFragment; /** 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..74d92c968 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,13 +1,14 @@ 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; -import com.mxt.anitrend.util.GraphUtil; import com.mxt.anitrend.util.KeyUtil; +import com.mxt.anitrend.util.graphql.GraphUtil; import com.mxt.anitrend.view.fragment.list.MediaLatestList; /** 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..1054439de 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,11 +1,12 @@ package com.mxt.anitrend.adapter.recycler.detail; import android.content.Context; -import android.support.annotation.NonNull; import android.view.View; import android.view.ViewGroup; import android.widget.Filter; +import androidx.annotation.NonNull; + import com.bumptech.glide.Glide; import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.recycler.RecyclerViewAdapter; 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..dfa69d201 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,11 +1,12 @@ package com.mxt.anitrend.adapter.recycler.detail; import android.content.Context; -import android.support.annotation.NonNull; import android.view.View; import android.view.ViewGroup; import android.widget.Filter; +import androidx.annotation.NonNull; + import com.bumptech.glide.Glide; import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.recycler.RecyclerViewAdapter; 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..0c70196a2 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,11 +1,12 @@ package com.mxt.anitrend.adapter.recycler.detail; import android.content.Context; -import android.support.annotation.NonNull; import android.view.View; import android.view.ViewGroup; import android.widget.Filter; +import androidx.annotation.NonNull; + import com.bumptech.glide.Glide; import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions; import com.bumptech.glide.request.RequestOptions; 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..130c172f1 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,24 +1,24 @@ package com.mxt.anitrend.adapter.recycler.detail; import android.content.Context; -import android.support.annotation.NonNull; -import android.support.v4.view.ViewCompat; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Filter; +import androidx.annotation.NonNull; +import androidx.core.view.ViewCompat; + import com.bumptech.glide.Glide; import com.bumptech.glide.load.resource.bitmap.CenterCrop; 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; import com.mxt.anitrend.databinding.AdapterFeedSlideBinding; -import com.mxt.anitrend.util.RegexUtil; +import com.mxt.anitrend.util.markdown.RegexUtil; import java.util.List; 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..9af2da5d3 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,11 +1,12 @@ package com.mxt.anitrend.adapter.recycler.detail; import android.content.Context; -import android.support.annotation.NonNull; import android.view.View; import android.view.ViewGroup; import android.widget.Filter; +import androidx.annotation.NonNull; + import com.bumptech.glide.Glide; import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.recycler.RecyclerViewAdapter; diff --git a/app/src/main/java/com/mxt/anitrend/adapter/recycler/detail/NotificationAdapter.kt b/app/src/main/java/com/mxt/anitrend/adapter/recycler/detail/NotificationAdapter.kt index 752c8903a..b90873630 100644 --- a/app/src/main/java/com/mxt/anitrend/adapter/recycler/detail/NotificationAdapter.kt +++ b/app/src/main/java/com/mxt/anitrend/adapter/recycler/detail/NotificationAdapter.kt @@ -5,7 +5,8 @@ import android.view.View import android.view.ViewGroup import android.widget.Adapter import android.widget.Filter - +import butterknife.OnClick +import butterknife.OnLongClick import com.bumptech.glide.Glide import com.mxt.anitrend.R import com.mxt.anitrend.adapter.recycler.shared.UnresolvedViewHolder @@ -14,15 +15,13 @@ import com.mxt.anitrend.base.custom.recycler.RecyclerViewHolder import com.mxt.anitrend.base.custom.view.image.AspectImageView import com.mxt.anitrend.databinding.AdapterNotificationBinding import com.mxt.anitrend.databinding.CustomRecyclerUnresolvedBinding +import com.mxt.anitrend.extension.getLayoutInflater import com.mxt.anitrend.model.entity.anilist.Notification import com.mxt.anitrend.model.entity.base.NotificationHistory import com.mxt.anitrend.model.entity.base.NotificationHistory_ import com.mxt.anitrend.util.CompatUtil -import com.mxt.anitrend.util.DateUtil import com.mxt.anitrend.util.KeyUtil - -import butterknife.OnClick -import butterknife.OnLongClick +import com.mxt.anitrend.util.date.DateUtil import io.objectbox.Box /** @@ -39,9 +38,9 @@ class NotificationAdapter(context: Context) : RecyclerViewAdapter( override fun onCreateViewHolder(parent: ViewGroup, @KeyUtil.RecyclerViewType viewType: Int): RecyclerViewHolder { return when (viewType) { KeyUtil.RECYCLER_TYPE_CONTENT -> - NotificationHolder(AdapterNotificationBinding.inflate(CompatUtil.getLayoutInflater(parent.context), parent, false)) + NotificationHolder(AdapterNotificationBinding.inflate(parent.context.getLayoutInflater(), parent, false)) else -> - UnresolvedViewHolder(CustomRecyclerUnresolvedBinding.inflate(CompatUtil.getLayoutInflater(parent.context), parent, false)) + UnresolvedViewHolder(CustomRecyclerUnresolvedBinding.inflate(parent.context.getLayoutInflater(), parent, false)) } } @@ -118,7 +117,7 @@ class NotificationAdapter(context: Context) : RecyclerViewAdapter( if (model.user != null && model.user.avatar != null) AspectImageView.setImage(binding.notificationImg, model.user.avatar.large) } else - AspectImageView.setImage(binding.notificationImg, model.media.coverImage.large) + AspectImageView.setImage(binding.notificationImg, model.media.coverImage.extraLarge) when (model.type) { KeyUtil.ACTIVITY_MESSAGE -> { 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..3b2bc9fcb 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,11 +1,12 @@ package com.mxt.anitrend.adapter.recycler.detail; import android.content.Context; -import android.support.annotation.NonNull; import android.view.View; import android.view.ViewGroup; import android.widget.Filter; +import androidx.annotation.NonNull; + import com.bumptech.glide.Glide; import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.recycler.RecyclerViewAdapter; 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..3685ef760 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,11 +1,12 @@ package com.mxt.anitrend.adapter.recycler.detail; import android.content.Context; -import android.support.annotation.NonNull; import android.view.View; import android.view.ViewGroup; import android.widget.Filter; +import androidx.annotation.NonNull; + import com.bumptech.glide.Glide; import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.recycler.RecyclerViewAdapter; 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..222706447 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,11 +1,12 @@ package com.mxt.anitrend.adapter.recycler.group; import android.content.Context; -import android.support.annotation.NonNull; import android.view.View; import android.view.ViewGroup; import android.widget.Filter; +import androidx.annotation.NonNull; + import com.bumptech.glide.Glide; import com.mxt.anitrend.R; import com.mxt.anitrend.adapter.recycler.shared.GroupMediaViewHolder; 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..f5c1dda94 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,12 +1,13 @@ package com.mxt.anitrend.adapter.recycler.group; import android.content.Context; -import android.support.annotation.NonNull; -import android.support.v7.widget.StaggeredGridLayoutManager; import android.view.View; import android.view.ViewGroup; import android.widget.Filter; +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.StaggeredGridLayoutManager; + import com.bumptech.glide.Glide; import com.mxt.anitrend.R; import com.mxt.anitrend.adapter.recycler.shared.GroupTitleViewHolder; 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..9e95b4935 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,11 +1,12 @@ package com.mxt.anitrend.adapter.recycler.group; import android.content.Context; -import android.support.annotation.NonNull; import android.view.View; import android.view.ViewGroup; import android.widget.Filter; +import androidx.annotation.NonNull; + import com.bumptech.glide.Glide; import com.mxt.anitrend.R; import com.mxt.anitrend.adapter.recycler.shared.GroupTitleViewHolder; 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..30d21603d 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,11 +1,12 @@ package com.mxt.anitrend.adapter.recycler.group; import android.content.Context; -import android.support.annotation.NonNull; import android.view.View; import android.view.ViewGroup; import android.widget.Filter; +import androidx.annotation.NonNull; + import com.bumptech.glide.Glide; import com.mxt.anitrend.R; import com.mxt.anitrend.adapter.recycler.shared.GroupTitleViewHolder; 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..e85183f17 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,12 +1,13 @@ package com.mxt.anitrend.adapter.recycler.index; import android.content.Context; -import android.support.annotation.NonNull; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Filter; +import androidx.annotation.NonNull; + import com.bumptech.glide.Glide; import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.recycler.RecyclerViewAdapter; 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..59361ffab 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,13 +1,14 @@ package com.mxt.anitrend.adapter.recycler.index; import android.content.Context; -import android.support.annotation.NonNull; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Filter; +import androidx.annotation.NonNull; + import com.bumptech.glide.Glide; import com.mxt.anitrend.R; import com.mxt.anitrend.adapter.recycler.shared.UnresolvedViewHolder; 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..5f153e209 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,12 +1,13 @@ package com.mxt.anitrend.adapter.recycler.index; import android.content.Context; -import android.support.annotation.NonNull; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Filter; +import androidx.annotation.NonNull; + import com.bumptech.glide.Glide; import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.recycler.RecyclerViewAdapter; 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..41d66ddad 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,13 +1,14 @@ package com.mxt.anitrend.adapter.recycler.index; import android.content.Context; -import android.support.annotation.NonNull; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Filter; +import androidx.annotation.NonNull; + import com.annimon.stream.Stream; import com.bumptech.glide.Glide; import com.mxt.anitrend.R; @@ -16,7 +17,7 @@ import com.mxt.anitrend.databinding.AdapterSeriesAiringBinding; import com.mxt.anitrend.model.entity.anilist.MediaList; import com.mxt.anitrend.util.CompatUtil; -import com.mxt.anitrend.util.MediaListUtil; +import com.mxt.anitrend.util.media.MediaListUtil; import java.util.ArrayList; import java.util.List; @@ -57,7 +58,7 @@ protected FilterResults performFiltering(CharSequence constraint) { clone = null; } else { results.values = Stream.of(clone) - .filter(c -> MediaListUtil.isFilterMatch(c, filter)) + .filter(c -> MediaListUtil.INSTANCE.isFilterMatch(c, filter)) .toList(); } return results; 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..c46249969 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,12 +1,13 @@ package com.mxt.anitrend.adapter.recycler.index; import android.content.Context; -import android.support.annotation.NonNull; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Filter; +import androidx.annotation.NonNull; + import com.bumptech.glide.Glide; import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.recycler.RecyclerViewAdapter; 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..8974e1ade 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,11 +1,12 @@ package com.mxt.anitrend.adapter.recycler.index; import android.content.Context; -import android.support.annotation.NonNull; import android.view.View; import android.view.ViewGroup; import android.widget.Filter; +import androidx.annotation.NonNull; + import com.bumptech.glide.Glide; import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.recycler.RecyclerViewAdapter; 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..1791723bc 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,11 +1,12 @@ package com.mxt.anitrend.adapter.recycler.index; import android.content.Context; -import android.support.annotation.NonNull; import android.view.View; import android.view.ViewGroup; import android.widget.Filter; +import androidx.annotation.NonNull; + import com.bumptech.glide.Glide; import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.recycler.RecyclerViewAdapter; 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..7afff28dd 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,13 +1,14 @@ package com.mxt.anitrend.adapter.recycler.index; import android.content.Context; -import android.support.annotation.NonNull; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Filter; +import androidx.annotation.NonNull; + import com.annimon.stream.Stream; import com.bumptech.glide.Glide; import com.mxt.anitrend.R; 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..30f69c75d 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,12 +1,13 @@ package com.mxt.anitrend.adapter.spinner; import android.content.Context; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.view.image.AppCompatTintImageView; import com.mxt.anitrend.base.custom.view.text.SingleLineTextView; 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..492f8265c --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/analytics/AnalyticsLogging.kt @@ -0,0 +1,109 @@ +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.core.KoinComponent +import timber.log.Timber + +class AnalyticsLogging( + context: Context, + settings: Settings +): Timber.Tree(), ISupportAnalytics, KoinComponent { + + private var fabric: Fabric? = null + private val analytics: FirebaseAnalytics = + FirebaseAnalytics.getInstance(context).apply { + setAnalyticsCollectionEnabled( + settings.isUsageAnalyticsEnabled + ) + } + + init { + if (settings.isCrashReportsEnabled) + fabric = Fabric.Builder(context).kits(Crashlytics()) + .appIdentifier(BuildConfig.BUILD_TYPE) + .build().let { Fabric.with(it) } + } + + /** + * 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 + + runCatching { + Crashlytics.setInt(PRIORITY, priority) + Crashlytics.setString(TAG, tag) + Crashlytics.setString(MESSAGE, message) + }.exceptionOrNull()?.printStackTrace() + + 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 05c3e0634..ea70b8994 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 android.arch.lifecycle.Observer; -import android.arch.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 android.text.TextUtils; -import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; @@ -24,22 +14,30 @@ import android.widget.Toast; import android.widget.Toolbar; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatActivity; +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.ConfigurationUtil; 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.locale.LocaleUtil; +import com.mxt.anitrend.util.media.MediaActionUtil; import com.mxt.anitrend.view.activity.index.MainActivity; import com.mxt.anitrend.view.activity.index.SearchActivity; @@ -49,6 +47,7 @@ import java.util.Locale; import butterknife.BindView; +import timber.log.Timber; /** @@ -80,39 +79,33 @@ public abstract class ActivityBase extends AppComp private boolean isClosing; private CommonPresenter presenter; - - private ApplicationPref applicationPref; - - private @StyleRes int style; + @Nullable + protected ConfigurationUtil configurationUtil; /** * Some activities may have custom themes and if that's the case * override this method and set your own theme style. + * + * @see ConfigurationUtil */ protected void configureActivity() { - if (applicationPref == null) - applicationPref = ((App)getApplicationContext()).getApplicationPref(); - style = applicationPref.getTheme(); - if(!CompatUtil.INSTANCE.isLightTheme(style) && applicationPref.isBlackThemeEnabled()) - setTheme(R.style.AppThemeBlack); - else - setTheme(style); + if (configurationUtil == null) + configurationUtil = KoinExt.get(ConfigurationUtil.class); + configurationUtil.onCreateAttach(this); } @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 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 @@ -143,7 +136,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(); } @@ -240,7 +233,7 @@ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permis if (grantResults[i] == PackageManager.PERMISSION_GRANTED) onPermissionGranted(permissions[i]); else - NotifyUtil.makeText(this, R.string.text_permission_required, R.drawable.ic_warning_white_18dp, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(this, R.string.text_permission_required, R.drawable.ic_warning_white_18dp, Toast.LENGTH_SHORT).show(); } } } @@ -251,7 +244,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); } /** @@ -280,6 +273,8 @@ protected void onPause() { @Override protected void onResume() { super.onResume(); + if (configurationUtil != null) + configurationUtil.onResumeAttach(this); if(mediaActionUtil != null) mediaActionUtil.onResume(null); if(presenter != null) @@ -307,7 +302,7 @@ public void onBackPressed() { mSearchView.closeSearch(); return; } if(this instanceof MainActivity && !isClosing) { - NotifyUtil.makeText(this, R.string.text_confirm_exit, R.drawable.ic_home_white_24dp, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(this, R.string.text_confirm_exit, R.drawable.ic_home_white_24dp, Toast.LENGTH_SHORT).show(); isClosing = true; return; } @@ -371,17 +366,15 @@ 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, + NotifyUtil.INSTANCE.createAlerter(this, getString(R.string.text_error_request), error, R.drawable.ic_warning_white_18dp, R.color.colorStateOrange, KeyUtil.DURATION_MEDIUM); } @@ -391,9 +384,9 @@ 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, + NotifyUtil.INSTANCE.createAlerter(this, getString(R.string.text_error_request), message, R.drawable.ic_warning_white_18dp, R.color.colorStateBlue, KeyUtil.DURATION_MEDIUM); } @@ -423,7 +416,7 @@ public boolean onQueryTextSubmit(String query) { CompatUtil.INSTANCE.startRevealAnim(this, mSearchView, intent); return true; } - NotifyUtil.makeText(this, R.string.text_search_empty, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(this, R.string.text_search_empty, Toast.LENGTH_SHORT).show(); return false; } diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/annotation/GraphQuery.java b/app/src/main/java/com/mxt/anitrend/base/custom/annotation/GraphQuery.java deleted file mode 100644 index 226c1d98e..000000000 --- a/app/src/main/java/com/mxt/anitrend/base/custom/annotation/GraphQuery.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.mxt.anitrend.base.custom.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Documented -@Target(ElementType.METHOD) -@Retention(RetentionPolicy.RUNTIME) -public @interface GraphQuery { - - String value() default ""; -} 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 deleted file mode 100644 index 03306b9db..000000000 --- a/app/src/main/java/com/mxt/anitrend/base/custom/annotation/processor/GraphProcessor.java +++ /dev/null @@ -1,104 +0,0 @@ -package com.mxt.anitrend.base.custom.annotation.processor; - -import android.content.Context; -import android.util.Log; - -import com.mxt.anitrend.base.custom.annotation.GraphQuery; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.lang.annotation.Annotation; -import java.util.HashMap; -import java.util.Map; - -/** - * Created by max on 2018/03/12. - * GraphQL annotation processor - */ -public class GraphProcessor { - - private static GraphProcessor ourInstance; - private final static Object lock = new Object(); - private final static String defaultExtension = ".graphql", defaultDirectory = "graphql"; - - public static GraphProcessor getInstance(Context context) { - if(ourInstance == null) - ourInstance = new GraphProcessor(context); - return ourInstance; - } - - private GraphProcessor(Context context) { - synchronized (lock) { - Log.d("GraphProcessor", Thread.currentThread().getName() + ": has obtained a synchronized lock on the object"); - if(this.graphFiles == null) - this.graphFiles = new HashMap<>(); - if(isEmpty()) { - Log.d("GraphProcessor", Thread.currentThread().getName() + ": is initializing query files"); - 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()); - } else - Log.d("GraphProcessor", Thread.currentThread().getName() + ": skipped initialization of graphFiles -> size: "+ graphFiles.size()); - } - } - - private volatile Map graphFiles; - - public String getQuery(Annotation[] annotations) { - GraphQuery graphQuery = null; - - for (Annotation annotation: annotations) - if(annotation instanceof GraphQuery) { - graphQuery = (GraphQuery) annotation; - break; - } - - if(graphFiles != null && graphQuery != null) { - String fileName = String.format("%s%s", graphQuery.value(), defaultExtension); - Log.d("GraphProcessor", 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())); - } - return null; - } - - private synchronized boolean isEmpty() { - return graphFiles.size() < 1; - } - - private synchronized void initialize(String path, Context context) { - try { - String[] paths = context.getAssets().list(path); - if (paths.length > 0) { - for (String item : paths) { - String absolute = path + "/" + item; - if (!item.endsWith(defaultExtension)) - initialize(absolute, context); - else - graphFiles.put(item, getFileContents(context.getAssets().open(absolute))); - } - } - } catch (IOException e) { - e.printStackTrace(); - } - } - - private synchronized String getFileContents(InputStream inputStream) { - StringBuilder queryBuffer = new StringBuilder(); - try { - InputStreamReader inputStreamReader = new InputStreamReader(inputStream); - BufferedReader bufferedReader = new BufferedReader(inputStreamReader); - for(String line; (line = bufferedReader.readLine()) != null;) - queryBuffer.append(line); - inputStreamReader.close(); - bufferedReader.close(); - } catch (IOException e) { - e.printStackTrace(); - } - return queryBuffer.toString(); - } -} 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..a6a721378 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/base/custom/async/RequestHandler.kt @@ -0,0 +1,141 @@ +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.* +import com.mxt.anitrend.util.KeyUtil +import com.mxt.anitrend.util.KeyUtil.* +import retrofit2.Call +import retrofit2.Callback + +/** + * 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 2bf277dd7..7e91f8eab 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,23 +3,26 @@ import android.content.Context; import android.os.AsyncTask; import android.os.Build; -import android.support.annotation.NonNull; -import android.util.Log; +import androidx.annotation.NonNull; + +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.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.JobSchedulerUtil; +import com.mxt.anitrend.util.Settings; 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 +32,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 +45,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(); + JobSchedulerUtil.INSTANCE.cancelJob(context); 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 +64,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 +79,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(); @@ -88,13 +93,13 @@ 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.saveWebToken(authenticatedToken); - boxQuery.saveAuthCode(new AuthBase(code, authenticatedToken.getRefresh_token())); + BoxQuery boxQuery = new DatabaseHelper(); + boxQuery.setWebToken(authenticatedToken); + boxQuery.setAuthCode(new AuthBase(code, authenticatedToken.getRefresh_token())); return true; } return false; @@ -109,7 +114,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 06d45da33..c3282a395 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,18 +1,9 @@ package com.mxt.anitrend.base.custom.fragment; import android.app.Activity; -import android.arch.lifecycle.Observer; -import android.arch.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 android.text.TextUtils; -import android.util.Log; import android.view.ActionMode; import android.view.LayoutInflater; import android.view.Menu; @@ -21,21 +12,33 @@ import android.view.View; import android.view.ViewGroup; +import androidx.annotation.IntegerRes; +import androidx.annotation.MenuRes; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.lifecycle.Lifecycle; +import androidx.lifecycle.Observer; +import androidx.lifecycle.ViewModelProviders; + import com.annimon.stream.IntPair; +import com.google.android.material.snackbar.Snackbar; 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.KoinExt; import com.mxt.anitrend.util.ActionModeUtil; -import com.mxt.anitrend.util.AnalyticsUtil; -import com.mxt.anitrend.util.MediaActionUtil; +import com.mxt.anitrend.util.media.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 +56,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 +108,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 +117,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 +124,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 +133,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 +177,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 +313,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/FragmentBaseComment.java b/app/src/main/java/com/mxt/anitrend/base/custom/fragment/FragmentBaseComment.java index 22dfd6a31..9463875ab 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,17 +3,18 @@ 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 android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.StaggeredGridLayoutManager; + import com.annimon.stream.IntPair; +import com.google.android.material.snackbar.Snackbar; import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.recycler.RecyclerViewAdapter; import com.mxt.anitrend.base.custom.recycler.StatefulRecyclerView; @@ -211,7 +212,7 @@ public void showError(String error) { if(getPresenter() != null && getPresenter().getCurrentPage() > 1 && isPager) { if(stateLayout.isLoading()) stateLayout.showContent(); - snackbar = NotifyUtil.make(stateLayout, R.string.text_unable_to_load_next_page, Snackbar.LENGTH_INDEFINITE) + snackbar = NotifyUtil.INSTANCE.make(stateLayout, R.string.text_unable_to_load_next_page, Snackbar.LENGTH_INDEFINITE) .setAction(R.string.try_again, snackBarOnClick); snackbar.show(); } @@ -233,7 +234,7 @@ public void showEmpty(String message) { if(getPresenter() != null && getPresenter().getCurrentPage() > 1 && isPager) { if(stateLayout.isLoading()) stateLayout.showContent(); - snackbar = NotifyUtil.make(stateLayout, R.string.text_unable_to_load_next_page, Snackbar.LENGTH_INDEFINITE) + snackbar = NotifyUtil.INSTANCE.make(stateLayout, R.string.text_unable_to_load_next_page, Snackbar.LENGTH_INDEFINITE) .setAction(R.string.try_again, snackBarOnClick); snackbar.show(); } 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..1efc543d5 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,16 +3,17 @@ 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 android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.StaggeredGridLayoutManager; + import com.annimon.stream.IntPair; +import com.google.android.material.snackbar.Snackbar; import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.presenter.CommonPresenter; import com.mxt.anitrend.base.custom.recycler.RecyclerViewAdapter; @@ -20,9 +21,9 @@ import com.mxt.anitrend.base.custom.view.container.CustomSwipeRefreshLayout; import com.mxt.anitrend.base.interfaces.event.RecyclerLoadListener; import com.mxt.anitrend.util.CompatUtil; -import com.mxt.anitrend.util.GraphUtil; import com.mxt.anitrend.util.KeyUtil; import com.mxt.anitrend.util.NotifyUtil; +import com.mxt.anitrend.util.graphql.GraphUtil; import com.nguyenhoanglam.progresslayout.ProgressLayout; import org.greenrobot.eventbus.EventBus; @@ -210,7 +211,7 @@ public void showError(String error) { if(getPresenter() != null && getPresenter().getCurrentPage() > 1 && isPager) { if(stateLayout.isLoading()) stateLayout.showContent(); - snackbar = NotifyUtil.make(stateLayout, R.string.text_unable_to_load_next_page, Snackbar.LENGTH_INDEFINITE) + snackbar = NotifyUtil.INSTANCE.make(stateLayout, R.string.text_unable_to_load_next_page, Snackbar.LENGTH_INDEFINITE) .setAction(R.string.try_again, snackBarOnClick); snackbar.show(); } @@ -231,7 +232,7 @@ public void showEmpty(String message) { if(getPresenter() != null && getPresenter().getCurrentPage() > 1 && isPager) { if(stateLayout.isLoading()) stateLayout.showContent(); - snackbar = NotifyUtil.make(stateLayout, R.string.text_unable_to_load_next_page, Snackbar.LENGTH_INDEFINITE) + snackbar = NotifyUtil.INSTANCE.make(stateLayout, R.string.text_unable_to_load_next_page, Snackbar.LENGTH_INDEFINITE) .setAction(R.string.try_again, snackBarOnClick); snackbar.show(); } 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..28fc891fb 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,18 +5,18 @@ 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 android.text.TextUtils; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Toast; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.StaggeredGridLayoutManager; + import com.annimon.stream.IntPair; +import com.google.android.material.snackbar.Snackbar; import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.recycler.RecyclerViewAdapter; import com.mxt.anitrend.base.custom.recycler.StatefulRecyclerView; @@ -31,9 +31,9 @@ import com.mxt.anitrend.presenter.widget.WidgetPresenter; import com.mxt.anitrend.util.CompatUtil; import com.mxt.anitrend.util.DialogUtil; -import com.mxt.anitrend.util.EpisodeUtil; import com.mxt.anitrend.util.KeyUtil; import com.mxt.anitrend.util.NotifyUtil; +import com.mxt.anitrend.util.collection.EpisodeUtil; import com.mxt.anitrend.view.activity.index.SearchActivity; import com.nguyenhoanglam.progresslayout.ProgressLayout; @@ -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); @@ -216,7 +219,7 @@ public void showError(String error) { if(getPresenter() != null && getPresenter().getCurrentPage() > 1 && isPager) { if(stateLayout.isLoading()) stateLayout.showContent(); - snackbar = NotifyUtil.make(stateLayout, R.string.text_unable_to_load_next_page, Snackbar.LENGTH_INDEFINITE) + snackbar = NotifyUtil.INSTANCE.make(stateLayout, R.string.text_unable_to_load_next_page, Snackbar.LENGTH_INDEFINITE) .setAction(R.string.try_again, snackBarOnClick); snackbar.show(); } @@ -237,7 +240,7 @@ public void showEmpty(String message) { if(getPresenter() != null && getPresenter().getCurrentPage() > 1 && isPager) { if(stateLayout.isLoading()) stateLayout.showContent(); - snackbar = NotifyUtil.make(stateLayout, R.string.text_unable_to_load_next_page, Snackbar.LENGTH_INDEFINITE) + snackbar = NotifyUtil.INSTANCE.make(stateLayout, R.string.text_unable_to_load_next_page, Snackbar.LENGTH_INDEFINITE) .setAction(R.string.try_again, snackBarOnClick); snackbar.show(); } @@ -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.INSTANCE.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/glide/GlideAppModule.kt b/app/src/main/java/com/mxt/anitrend/base/custom/glide/GlideAppModule.kt index a953a5237..261aac5b7 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/glide/GlideAppModule.kt +++ b/app/src/main/java/com/mxt/anitrend/base/custom/glide/GlideAppModule.kt @@ -12,6 +12,7 @@ import com.bumptech.glide.load.engine.cache.MemorySizeCalculator import com.bumptech.glide.module.AppGlideModule import com.bumptech.glide.request.RequestOptions import com.mxt.anitrend.R +import com.mxt.anitrend.extension.getCompatDrawable import com.mxt.anitrend.util.CompatUtil import com.mxt.anitrend.util.KeyUtil @@ -55,7 +56,7 @@ class GlideAppModule : AppGlideModule() { .format(if (isLowRamDevice) DecodeFormat.PREFER_RGB_565 else DecodeFormat.PREFER_ARGB_8888) .timeout(KeyUtil.GLIDE_REQUEST_TIMEOUT) .diskCacheStrategy(DiskCacheStrategy.AUTOMATIC) - .error(CompatUtil.getDrawable(context, R.drawable.ic_emoji_sweat)) + .error(context.getCompatDrawable(R.drawable.ic_emoji_sweat)) builder.setDefaultRequestOptions(options) } 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..5dd07776d 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,11 @@ 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/presenter/CommonPresenter.java b/app/src/main/java/com/mxt/anitrend/base/custom/presenter/CommonPresenter.java index 3f7028ddf..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; @@ -45,7 +45,7 @@ public void setParams(Bundle bundle) { public BoxQuery getDatabase() { if(databaseHelper == null) - databaseHelper = new DatabaseHelper(context); + databaseHelper = new DatabaseHelper(); return databaseHelper; } @@ -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/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..82e648e9e 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,14 +2,15 @@ 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 android.view.ViewGroup; import android.widget.Filterable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.recyclerview.widget.StaggeredGridLayoutManager; + import com.mxt.anitrend.base.custom.animation.ScaleAnimation; import com.mxt.anitrend.base.custom.animation.SlideInAnimation; import com.mxt.anitrend.base.interfaces.base.BaseAnimation; 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..115b43352 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,10 +1,11 @@ package com.mxt.anitrend.base.custom.recycler; import android.content.Context; -import android.support.annotation.NonNull; -import android.support.v7.widget.RecyclerView; import android.view.View; +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + import com.annimon.stream.IntPair; import com.mxt.anitrend.base.interfaces.event.ItemClickListener; import com.mxt.anitrend.util.ActionModeUtil; 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..e514f03b1 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,10 +1,11 @@ package com.mxt.anitrend.base.custom.recycler; import android.content.Context; -import android.support.annotation.Nullable; -import android.support.v7.widget.RecyclerView; import android.util.AttributeSet; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.RecyclerView; + 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..2f9481f2c 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,16 +2,16 @@ 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 android.util.Log; import android.view.View; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.StringRes; +import androidx.appcompat.widget.AppCompatImageView; +import androidx.coordinatorlayout.widget.CoordinatorLayout; + +import com.google.android.material.bottomsheet.BottomSheetBehavior; +import com.google.android.material.bottomsheet.BottomSheetDialogFragment; import com.miguelcatalan.materialsearchview.MaterialSearchView; import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.view.text.SingleLineTextView; @@ -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/BottomSheetGiphyList.java b/app/src/main/java/com/mxt/anitrend/base/custom/sheet/BottomSheetGiphyList.java index 0b993f1b5..b7615bbf9 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,16 +1,17 @@ package com.mxt.anitrend.base.custom.sheet; import android.app.Activity; -import android.arch.lifecycle.Observer; -import android.arch.lifecycle.ViewModelProviders; 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 androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.lifecycle.Observer; +import androidx.lifecycle.ViewModelProviders; +import androidx.recyclerview.widget.StaggeredGridLayoutManager; + import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.recycler.RecyclerViewAdapter; import com.mxt.anitrend.base.custom.recycler.StatefulRecyclerView; 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..d53b2bdc2 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,14 +1,14 @@ package com.mxt.anitrend.base.custom.sheet; -import android.arch.lifecycle.Observer; -import android.arch.lifecycle.ViewModelProviders; import android.os.Bundle; import android.os.Parcelable; -import android.support.annotation.Nullable; -import android.support.v7.widget.StaggeredGridLayoutManager; -import android.util.Log; import android.view.View; +import androidx.annotation.Nullable; +import androidx.lifecycle.Observer; +import androidx.lifecycle.ViewModelProviders; +import androidx.recyclerview.widget.StaggeredGridLayoutManager; + import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.recycler.RecyclerViewAdapter; import com.mxt.anitrend.base.custom.recycler.StatefulRecyclerView; @@ -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/container/CardViewBase.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/container/CardViewBase.java index e340f92d4..68b48d6cd 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,11 +1,12 @@ 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 android.util.AttributeSet; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.cardview.widget.CardView; + import com.mxt.anitrend.R; import com.mxt.anitrend.base.interfaces.view.CustomView; import com.mxt.anitrend.util.CompatUtil; 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..aef158da4 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,6 @@ 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 android.util.AttributeSet; import android.util.DisplayMetrics; import android.view.MotionEvent; @@ -24,6 +14,18 @@ import android.view.animation.Transformation; import android.widget.AbsListView; +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 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..34cfea204 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,12 @@ 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 android.util.AttributeSet; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + 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..6a8918a63 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,10 +1,11 @@ package com.mxt.anitrend.base.custom.view.container; import android.content.Context; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.util.AttributeSet; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + public class NotificationCardView extends CardViewBase { public NotificationCardView(@NonNull Context context) { 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..69a5cd472 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,6 @@ 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 android.util.DisplayMetrics; import android.view.View; import android.view.animation.Animation; @@ -22,6 +19,10 @@ import android.view.animation.LinearInterpolator; import android.view.animation.Transformation; +import androidx.annotation.IntDef; +import androidx.annotation.NonNull; +import androidx.interpolator.view.animation.FastOutSlowInInterpolator; + import com.mxt.anitrend.base.custom.view.container.CustomSwipeRefreshLayout; import java.lang.annotation.Retention; 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..705b1749d 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,18 +1,15 @@ package com.mxt.anitrend.base.custom.view.editor import android.annotation.SuppressLint -import android.arch.lifecycle.Lifecycle import android.content.Context import android.os.Build -import android.support.annotation.RequiresApi -import android.text.Editable -import android.text.TextUtils import android.util.AttributeSet import android.view.View import android.widget.EditText import android.widget.FrameLayout import android.widget.Toast - +import androidx.annotation.RequiresApi +import androidx.lifecycle.Lifecycle import com.annimon.stream.IntPair import com.mxt.anitrend.R import com.mxt.anitrend.base.custom.consumer.BaseConsumer @@ -20,31 +17,25 @@ import com.mxt.anitrend.base.interfaces.event.ItemClickListener import com.mxt.anitrend.base.interfaces.event.RetroCallback import com.mxt.anitrend.base.interfaces.view.CustomView import com.mxt.anitrend.databinding.WidgetComposerBinding +import com.mxt.anitrend.extension.getLayoutInflater import com.mxt.anitrend.model.entity.anilist.FeedList import com.mxt.anitrend.model.entity.anilist.FeedReply import com.mxt.anitrend.model.entity.base.UserBase -import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder -import com.mxt.anitrend.model.entity.giphy.Gif import com.mxt.anitrend.model.entity.giphy.Giphy import com.mxt.anitrend.presenter.widget.WidgetPresenter -import com.mxt.anitrend.util.CompatUtil -import com.mxt.anitrend.util.ErrorUtil -import com.mxt.anitrend.util.GraphUtil import com.mxt.anitrend.util.KeyUtil -import com.mxt.anitrend.util.MarkDownUtil import com.mxt.anitrend.util.NotifyUtil - +import com.mxt.anitrend.util.graphql.GraphUtil +import com.mxt.anitrend.util.graphql.apiError +import com.mxt.anitrend.util.markdown.MarkDownUtil +import io.wax911.emojify.parser.EmojiParser +import okhttp3.ResponseBody import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode - -import java.util.Locale - -import io.wax911.emojify.EmojiManager -import io.wax911.emojify.parser.EmojiParser -import okhttp3.ResponseBody import retrofit2.Call import retrofit2.Response +import java.util.* /** * Created by max on 2017/12/02. @@ -55,7 +46,7 @@ class ComposerWidget : FrameLayout, CustomView, View.OnClickListener, RetroCallb private val binding by lazy { WidgetComposerBinding.inflate( - CompatUtil.getLayoutInflater(context), + getLayoutInflater(), this, true ) } @@ -223,7 +214,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) @@ -239,7 +230,7 @@ class ComposerWidget : FrameLayout, CustomView, View.OnClickListener, RetroCallb presenter.notifyAllListeners(BaseConsumer(requestType), false) } } else - NotifyUtil.makeText(context, ErrorUtil.getError(response), Toast.LENGTH_SHORT).show() + NotifyUtil.makeText(context, response.apiError(), Toast.LENGTH_SHORT).show() presenter.onDestroy() } } 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..852f8f576 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,6 @@ import android.content.Context import android.graphics.Typeface import android.os.Build import android.os.Bundle -import android.support.annotation.IdRes -import android.support.design.widget.TextInputEditText -import android.support.v13.view.inputmethod.EditorInfoCompat -import android.support.v13.view.inputmethod.InputConnectionCompat -import android.support.v13.view.inputmethod.InputContentInfoCompat -import android.support.v4.content.ContextCompat import android.text.InputFilter import android.text.Spanned import android.text.TextUtils @@ -19,25 +13,20 @@ import android.view.Menu import android.view.MenuItem import android.view.inputmethod.EditorInfo import android.view.inputmethod.InputConnection - +import androidx.annotation.IdRes +import androidx.core.content.ContextCompat +import androidx.core.view.inputmethod.EditorInfoCompat +import androidx.core.view.inputmethod.InputConnectionCompat +import androidx.core.view.inputmethod.InputContentInfoCompat +import com.google.android.material.textfield.TextInputEditText import com.mxt.anitrend.R import com.mxt.anitrend.base.interfaces.view.CustomView import com.mxt.anitrend.util.CompatUtil import com.mxt.anitrend.util.KeyUtil -import com.mxt.anitrend.util.MarkDownUtil - +import com.mxt.anitrend.util.KeyUtil.* +import com.mxt.anitrend.util.markdown.MarkDownUtil import io.wax911.emojify.parser.EmojiParser -import com.mxt.anitrend.util.KeyUtil.MD_BOLD -import com.mxt.anitrend.util.KeyUtil.MD_BULLET -import com.mxt.anitrend.util.KeyUtil.MD_CENTER_ALIGN -import com.mxt.anitrend.util.KeyUtil.MD_CODE -import com.mxt.anitrend.util.KeyUtil.MD_HEADING -import com.mxt.anitrend.util.KeyUtil.MD_ITALIC -import com.mxt.anitrend.util.KeyUtil.MD_NUMBER -import com.mxt.anitrend.util.KeyUtil.MD_QUOTE -import com.mxt.anitrend.util.KeyUtil.MD_STRIKE - /** * Created by max on 2017/08/14. * Markdown input editor 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..2f245068c 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,13 +1,14 @@ 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 android.util.AttributeSet; +import androidx.annotation.AttrRes; +import androidx.annotation.ColorRes; +import androidx.annotation.DrawableRes; +import androidx.appcompat.widget.AppCompatImageView; +import androidx.databinding.BindingAdapter; + import com.mxt.anitrend.R; import com.mxt.anitrend.base.interfaces.view.CustomView; import com.mxt.anitrend.util.CompatUtil; 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..63e6cbea0 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,10 +1,11 @@ package com.mxt.anitrend.base.custom.view.image; import android.content.Context; -import android.databinding.BindingAdapter; import android.graphics.Point; import android.util.AttributeSet; +import androidx.databinding.BindingAdapter; + import com.bumptech.glide.Glide; import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions; import com.bumptech.glide.request.RequestOptions; @@ -21,7 +22,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; @@ -81,7 +82,11 @@ public static void setImage(AspectImageView view, String url) { @BindingAdapter({"imageUrl"}) public static void setImage(AspectImageView view, ImageBase imageBase) { - if(imageBase != null) - setImage(view, imageBase.getLarge()); + if(imageBase != null) { + if (imageBase.getExtraLarge() != null) + setImage(view, imageBase.getExtraLarge()); + else + setImage(view, imageBase.getLarge()); + } } } 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 a1050e0b2..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 android.databinding.BindingAdapter; -import android.support.v7.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..5794dd51d --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/image/AvatarImageView.kt @@ -0,0 +1,41 @@ +package com.mxt.anitrend.base.custom.view.image + +import android.content.Context +import android.util.AttributeSet +import androidx.appcompat.widget.AppCompatImageView +import com.bumptech.glide.Glide +import com.mxt.anitrend.base.interfaces.view.CustomView + +/** + * 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..85c9ebfbf --- /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.extension.getLayoutInflater +import com.mxt.anitrend.model.entity.anilist.User +import com.mxt.anitrend.presenter.widget.WidgetPresenter +import com.mxt.anitrend.util.KeyUtil +import com.mxt.anitrend.util.date.DateUtil +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(context.getLayoutInflater(), 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/image/BrandImageView.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/image/BrandImageView.java index 8d76c2cf1..6664fc76d 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,13 +14,14 @@ 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 android.text.TextPaint; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.view.Gravity; +import androidx.annotation.NonNull; +import androidx.appcompat.widget.AppCompatImageView; + import com.mxt.anitrend.R; import com.mxt.anitrend.base.interfaces.view.CustomView; import com.mxt.anitrend.util.CompatUtil; 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..d8abb5255 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,11 +8,12 @@ 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 android.util.AttributeSet; import android.view.animation.Animation; +import androidx.appcompat.widget.AppCompatImageView; +import androidx.core.view.ViewCompat; + import com.mxt.anitrend.base.custom.view.container.CustomSwipeRefreshLayout; /** @@ -63,7 +64,7 @@ public CircleImageView(Context context, int color, final float radius) { } else { OvalShape oval = new OvalShadow(mShadowRadius, diameter); circle = new ShapeDrawable(oval); - ViewCompat.setLayerType(this, ViewCompat.LAYER_TYPE_SOFTWARE, circle.getPaint()); + setLayerType(LAYER_TYPE_SOFTWARE, circle.getPaint()); circle.getPaint().setShadowLayer(mShadowRadius, shadowXOffset, shadowYOffset, KEY_SHADOW_COLOR); final int padding = mShadowRadius; 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..a0964508c 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,10 +1,11 @@ package com.mxt.anitrend.base.custom.view.image; import android.content.Context; -import android.databinding.BindingAdapter; -import android.support.v7.widget.AppCompatImageView; import android.util.AttributeSet; +import androidx.appcompat.widget.AppCompatImageView; +import androidx.databinding.BindingAdapter; + import com.bumptech.glide.Glide; import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions; import com.bumptech.glide.request.RequestOptions; 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..1aa04cdc1 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,10 +1,11 @@ package com.mxt.anitrend.base.custom.view.image; import android.content.Context; -import android.databinding.BindingAdapter; -import android.support.v7.widget.AppCompatImageView; import android.util.AttributeSet; +import androidx.appcompat.widget.AppCompatImageView; +import androidx.databinding.BindingAdapter; + import com.bumptech.glide.Glide; import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions; import com.bumptech.glide.request.RequestOptions; 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..e80c599b2 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,12 +1,13 @@ package com.mxt.anitrend.base.custom.view.text; import android.content.Context; -import android.databinding.BindingAdapter; import android.util.AttributeSet; +import androidx.databinding.BindingAdapter; + import com.mxt.anitrend.model.entity.base.MediaBase; import com.mxt.anitrend.util.CompatUtil; -import com.mxt.anitrend.util.DateUtil; +import com.mxt.anitrend.util.date.DateUtil; import javax.annotation.Nullable; 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..809dd4dee 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,12 +1,13 @@ package com.mxt.anitrend.base.custom.view.text; import android.content.Context; -import android.databinding.BindingAdapter; -import android.support.v7.widget.AppCompatTextView; import android.text.TextUtils; import android.util.AttributeSet; import android.util.TypedValue; +import androidx.appcompat.widget.AppCompatTextView; +import androidx.databinding.BindingAdapter; + import com.mxt.anitrend.R; import com.mxt.anitrend.base.interfaces.view.CustomView; import com.mxt.anitrend.model.entity.anilist.FeedList; 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 deleted file mode 100644 index 311af41fd..000000000 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/text/PageIndicator.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.mxt.anitrend.base.custom.view.text; - -import android.content.Context; -import android.graphics.Typeface; -import android.support.annotation.Nullable; -import android.support.v7.widget.AppCompatTextView; -import android.util.AttributeSet; -import android.util.TypedValue; - -import com.mxt.anitrend.R; -import com.mxt.anitrend.base.interfaces.view.CustomView; -import com.mxt.anitrend.util.CompatUtil; - -import java.util.Locale; - -/** - * Created by max on 2017/11/25. - */ - -public class PageIndicator extends AppCompatTextView implements CustomView { - - private int maximum; - - public PageIndicator(Context context) { - super(context); - onInit(); - } - - public PageIndicator(Context context, @Nullable AttributeSet attrs) { - super(context, attrs); - onInit(); - } - - public PageIndicator(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - onInit(); - } - - /** - * Optionally included when constructing custom views - */ - @Override - public void onInit() { - int padding = CompatUtil.INSTANCE.dipToPx(8); - - setTextColor(CompatUtil.INSTANCE.getColor(getContext(), R.color.colorTextLight)); - setBackground(CompatUtil.INSTANCE.getDrawable(getContext(), R.drawable.bubble_background)); - - setTextSize(TypedValue.COMPLEX_UNIT_SP, 10); - setPadding(padding, padding, padding, padding); - setTypeface(Typeface.DEFAULT_BOLD); - } - - public void setMaximum(int maximum) { - this.maximum = maximum; - } - - public void setCurrentPosition(int index) { - setText(String.format(Locale.getDefault(), "%d / %d", index, maximum)); - } - - /** - * Clean up any resources that won't be needed - */ - @Override - public void onViewRecycled() { - - } -} diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/text/PageIndicator.kt b/app/src/main/java/com/mxt/anitrend/base/custom/view/text/PageIndicator.kt new file mode 100644 index 000000000..8081e3674 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/text/PageIndicator.kt @@ -0,0 +1,59 @@ +package com.mxt.anitrend.base.custom.view.text + +import android.content.Context +import android.graphics.Typeface +import android.util.AttributeSet +import android.util.TypedValue +import androidx.appcompat.widget.AppCompatTextView +import com.mxt.anitrend.R +import com.mxt.anitrend.base.interfaces.view.CustomView +import com.mxt.anitrend.extension.getCompatColor +import com.mxt.anitrend.extension.getCompatDrawable +import com.mxt.anitrend.util.CompatUtil +import java.util.* + +/** + * Created by max on 2017/11/25. + */ + +class PageIndicator : AppCompatTextView, CustomView { + + var maximum: Int = 0 + + 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() { + val padding = CompatUtil.dipToPx(8f) + + setTextColor(context.getCompatColor(R.color.colorTextLight)) + background = context.getCompatDrawable(R.drawable.bubble_background) + + setTextSize(TypedValue.COMPLEX_UNIT_SP, 10f) + setPadding(padding, padding, padding, padding) + typeface = Typeface.DEFAULT_BOLD + } + + fun setCurrentPosition(index: Int) { + text = String.format(Locale.getDefault(), "%d / %d", index, maximum) + } + + /** + * Clean up any resources that won't be needed + */ + override fun onViewRecycled() { + + } +} 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..495da07cc 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,11 +1,12 @@ package com.mxt.anitrend.base.custom.view.text; import android.content.Context; -import android.databinding.BindingAdapter; import android.util.AttributeSet; +import androidx.databinding.BindingAdapter; + import com.mxt.anitrend.model.entity.anilist.meta.FuzzyDate; -import com.mxt.anitrend.util.DateUtil; +import com.mxt.anitrend.util.date.DateUtil; /** * Created by max on 2017/10/28. 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 deleted file mode 100644 index 34d3e4355..000000000 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/text/RatingTextView.java +++ /dev/null @@ -1,210 +0,0 @@ -package com.mxt.anitrend.base.custom.view.text; - -import android.content.Context; -import android.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 android.util.AttributeSet; -import android.widget.LinearLayout; - -import com.mxt.anitrend.R; -import com.mxt.anitrend.base.interfaces.view.CustomView; -import com.mxt.anitrend.databinding.CustomRatingWidgetBinding; -import com.mxt.anitrend.model.entity.anilist.MediaList; -import com.mxt.anitrend.model.entity.anilist.meta.MediaListOptions; -import com.mxt.anitrend.model.entity.base.MediaBase; -import com.mxt.anitrend.presenter.base.BasePresenter; -import com.mxt.anitrend.util.CompatUtil; -import com.mxt.anitrend.util.KeyUtil; - -import java.util.Locale; - -/** - * Created by max on 2018/01/27. - * Special text base rating view - */ - -public class RatingTextView extends LinearLayout implements CustomView { - - private @Nullable MediaListOptions mediaListOptions; - private CustomRatingWidgetBinding binding; - - public RatingTextView(Context context) { - super(context); - onInit(); - } - - public RatingTextView(Context context, @Nullable AttributeSet attrs) { - super(context, attrs); - onInit(); - } - - public RatingTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - onInit(); - } - - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) - public RatingTextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { - super(context, attrs, defStyleAttr, defStyleRes); - onInit(); - } - - /** - * Optionally included when constructing custom views - */ - @Override - public void onInit() { - binding = CustomRatingWidgetBinding.inflate(CompatUtil.INSTANCE.getLayoutInflater(getContext()), this, true); - BasePresenter basePresenter = new BasePresenter(getContext()); - if(basePresenter.getApplicationPref().isAuthenticated()) - mediaListOptions = basePresenter.getDatabase().getCurrentUser().getMediaListOptions(); - } - - private void setFavourState(boolean isFavourite) { - @ColorRes int colorTint = isFavourite ? R.color.colorStateYellow : R.color.white; - Drawable drawable = CompatUtil.INSTANCE.getDrawable(getContext(), R.drawable.ic_star_grey_600_24dp, colorTint); - binding.ratingFavourState.setImageDrawable(drawable); - } - - private void setListStatus(MediaBase mediaBase) { - if(mediaBase.getMediaListEntry() != null) { - binding.ratingListStatus.setVisibility(VISIBLE); - switch (mediaBase.getMediaListEntry().getStatus()) { - case KeyUtil.CURRENT: - binding.ratingListStatus.setTintDrawable(R.drawable.ic_remove_red_eye_white_18dp, - R.color.white); - break; - case KeyUtil.PLANNING: - binding.ratingListStatus.setTintDrawable(R.drawable.ic_bookmark_white_24dp, - R.color.white); - break; - case KeyUtil.COMPLETED: - binding.ratingListStatus.setTintDrawable(R.drawable.ic_done_all_grey_600_24dp, - R.color.white); - break; - case KeyUtil.DROPPED: - binding.ratingListStatus.setTintDrawable(R.drawable.ic_delete_red_600_18dp, - R.color.white); - break; - case KeyUtil.PAUSED: - binding.ratingListStatus.setTintDrawable(R.drawable.ic_pause_white_18dp, - R.color.white); - break; - case KeyUtil.REPEATING: - binding.ratingListStatus.setTintDrawable(R.drawable.ic_repeat_white_18dp, - R.color.white); - break; - } - } - else - binding.ratingListStatus.setVisibility(GONE); - } - - private void setListStatus() { - binding.ratingListStatus.setVisibility(GONE); - } - - private void setRating(MediaList mediaList) { - if(mediaListOptions != null) - switch (mediaListOptions.getScoreFormat()) { - case KeyUtil.POINT_10_DECIMAL: - binding.ratingValue.setText(String.format(Locale.getDefault(),"%.1f", mediaList.getScore())); - break; - case KeyUtil.POINT_100: - case KeyUtil.POINT_10: - case KeyUtil.POINT_5: - binding.ratingValue.setText(String.format(Locale.getDefault(),"%d", (int)mediaList.getScore())); - break; - case KeyUtil.POINT_3: - binding.ratingValue.setText(""); - int score = (int)mediaList.getScore(); - switch (score) { - case 0: - binding.ratingValue.setCompoundDrawablesWithIntrinsicBounds(CompatUtil.INSTANCE.getDrawable(getContext(), - R.drawable.ic_face_white_18dp), null, null, null); - break; - case 1: - binding.ratingValue.setCompoundDrawablesWithIntrinsicBounds(CompatUtil.INSTANCE.getDrawable(getContext(), - R.drawable.ic_sentiment_dissatisfied_white_18dp), null, null, null); - break; - case 2: - binding.ratingValue.setCompoundDrawablesWithIntrinsicBounds(CompatUtil.INSTANCE.getDrawable(getContext(), - R.drawable.ic_sentiment_neutral_white_18dp), null, null, null); - break; - case 3: - binding.ratingValue.setCompoundDrawablesWithIntrinsicBounds(CompatUtil.INSTANCE.getDrawable(getContext(), - R.drawable.ic_sentiment_satisfied_white_18dp), null, null, null); - break; - } - break; - } - else - binding.ratingValue.setText(String.format(Locale.getDefault(),"%d", (int)mediaList.getScore())); - } - - private void setRating(MediaBase mediaBase) { - float mediaScoreDefault = (float) mediaBase.getAverageScore() * 5 / 100f; - if(mediaListOptions != null) - switch (mediaListOptions.getScoreFormat()) { - case KeyUtil.POINT_10_DECIMAL: - mediaScoreDefault = (mediaBase.getAverageScore() / 10f); - binding.ratingValue.setText(String.format(Locale.getDefault(),"%.1f", mediaScoreDefault)); - break; - case KeyUtil.POINT_100: - binding.ratingValue.setText(String.format(Locale.getDefault(),"%d", mediaBase.getAverageScore())); - break; - case KeyUtil.POINT_10: - mediaScoreDefault = (mediaBase.getAverageScore() / 10f); - binding.ratingValue.setText(String.format(Locale.getDefault(),"%d", (int) mediaScoreDefault)); - break; - case KeyUtil.POINT_5: - binding.ratingValue.setText(String.format(Locale.getDefault(),"%d", (int) mediaScoreDefault)); - break; - case KeyUtil.POINT_3: - binding.ratingValue.setText(""); - if(mediaBase.getAverageScore() == 0) - binding.ratingValue.setCompoundDrawablesWithIntrinsicBounds(CompatUtil.INSTANCE.getDrawable(getContext(), - R.drawable.ic_face_white_18dp), null, null, null); - if(mediaBase.getAverageScore() > 0 && mediaBase.getAverageScore() <= 33) - binding.ratingValue.setCompoundDrawablesWithIntrinsicBounds(CompatUtil.INSTANCE.getDrawable(getContext(), - R.drawable.ic_sentiment_dissatisfied_white_18dp), null, null, null); - else if (mediaBase.getAverageScore() >= 34 && mediaBase.getAverageScore() <= 66) - binding.ratingValue.setCompoundDrawablesWithIntrinsicBounds(CompatUtil.INSTANCE.getDrawable(getContext(), - R.drawable.ic_sentiment_neutral_white_18dp), null, null, null); - else if (mediaBase.getAverageScore() >= 67 && mediaBase.getAverageScore() <= 100) - binding.ratingValue.setCompoundDrawablesWithIntrinsicBounds(CompatUtil.INSTANCE.getDrawable(getContext(), - R.drawable.ic_sentiment_satisfied_white_18dp), null, null, null); - break; - } - else - binding.ratingValue.setText(String.format(Locale.getDefault(),"%d", mediaBase.getAverageScore())); - } - - @BindingAdapter("rating") - public static void setAverageRating(RatingTextView view, MediaBase mediaBase) { - //float rating = (float) mediaBase.getAverageScore() * MAX / 100; - view.setRating(mediaBase); - view.setListStatus(mediaBase); - view.setFavourState(mediaBase.isFavourite()); - } - - @BindingAdapter("rating") - public static void setAverageRating(RatingTextView view, MediaList mediaList) { - //float rating = (float) mediaList.getScore() * MAX / 100; - view.setListStatus(); - view.setRating(mediaList); - view.setFavourState(mediaList.getMedia().isFavourite()); - } - - /** - * Clean up any resources that won't be needed - */ - @Override - public void onViewRecycled() { - - } -} diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/text/RatingTextView.kt b/app/src/main/java/com/mxt/anitrend/base/custom/view/text/RatingTextView.kt new file mode 100644 index 000000000..1104ed996 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/text/RatingTextView.kt @@ -0,0 +1,152 @@ +package com.mxt.anitrend.base.custom.view.text + +import android.content.Context +import android.os.Build +import android.util.AttributeSet +import android.view.View +import android.widget.LinearLayout +import androidx.annotation.ColorRes +import androidx.annotation.RequiresApi +import com.mxt.anitrend.R +import com.mxt.anitrend.base.interfaces.view.CustomView +import com.mxt.anitrend.databinding.CustomRatingWidgetBinding +import com.mxt.anitrend.extension.LAZY_MODE_UNSAFE +import com.mxt.anitrend.extension.getCompatDrawable +import com.mxt.anitrend.extension.getLayoutInflater +import com.mxt.anitrend.model.entity.anilist.MediaList +import com.mxt.anitrend.model.entity.anilist.meta.MediaListOptions +import com.mxt.anitrend.model.entity.base.MediaBase +import com.mxt.anitrend.presenter.base.BasePresenter +import com.mxt.anitrend.util.KeyUtil +import org.koin.core.KoinComponent +import org.koin.core.inject +import java.util.* + +/** + * Created by max on 2018/01/27. + * Special text base rating view + */ + +class RatingTextView : LinearLayout, CustomView, KoinComponent { + + private var mediaListOptions: MediaListOptions? = null + private val presenter by inject() + private val binding by lazy(LAZY_MODE_UNSAFE) { + CustomRatingWidgetBinding.inflate(getLayoutInflater(), this, true) + } + + 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() + } + + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) { + onInit() + } + + /** + * Optionally included when constructing custom views + */ + override fun onInit() { + val basePresenter = BasePresenter(context) + if (presenter.settings.isAuthenticated) + mediaListOptions = basePresenter.database.currentUser?.mediaListOptions + } + + fun setFavourState(isFavourite: Boolean) { + @ColorRes val colorTint = if (isFavourite) R.color.colorStateYellow else R.color.white + val drawable = context.getCompatDrawable(R.drawable.ic_star_grey_600_24dp, colorTint) + binding.ratingFavourState.setImageDrawable(drawable) + } + + fun setListStatus(mediaBase: MediaBase) { + if (mediaBase.mediaListEntry != null) { + binding.ratingListStatus.visibility = View.VISIBLE + when (mediaBase.mediaListEntry?.status) { + KeyUtil.CURRENT -> binding.ratingListStatus.setTintDrawable(R.drawable.ic_remove_red_eye_white_18dp, + R.color.white) + KeyUtil.PLANNING -> binding.ratingListStatus.setTintDrawable(R.drawable.ic_bookmark_white_24dp, + R.color.white) + KeyUtil.COMPLETED -> binding.ratingListStatus.setTintDrawable(R.drawable.ic_done_all_grey_600_24dp, + R.color.white) + KeyUtil.DROPPED -> binding.ratingListStatus.setTintDrawable(R.drawable.ic_delete_red_600_18dp, + R.color.white) + KeyUtil.PAUSED -> binding.ratingListStatus.setTintDrawable(R.drawable.ic_pause_white_18dp, + R.color.white) + KeyUtil.REPEATING -> binding.ratingListStatus.setTintDrawable(R.drawable.ic_repeat_white_18dp, + R.color.white) + } + } else + binding.ratingListStatus.visibility = View.GONE + } + + fun setListStatus() { + binding.ratingListStatus.visibility = View.GONE + } + + fun setRating(mediaList: MediaList) { + if (mediaListOptions != null) + when (mediaListOptions?.scoreFormat) { + KeyUtil.POINT_10_DECIMAL -> binding.ratingValue.text = String.format(Locale.getDefault(), "%.1f", mediaList.score) + KeyUtil.POINT_100, KeyUtil.POINT_10, KeyUtil.POINT_5 -> binding.ratingValue.text = String.format(Locale.getDefault(), "%d", mediaList.score.toInt()) + KeyUtil.POINT_3 -> { + binding.ratingValue.text = "" + when (mediaList.score.toInt()) { + 0 -> binding.ratingValue.setCompoundDrawablesWithIntrinsicBounds(context.getCompatDrawable(R.drawable.ic_face_white_18dp), null, null, null) + 1 -> binding.ratingValue.setCompoundDrawablesWithIntrinsicBounds(context.getCompatDrawable(R.drawable.ic_sentiment_dissatisfied_white_18dp), null, null, null) + 2 -> binding.ratingValue.setCompoundDrawablesWithIntrinsicBounds(context.getCompatDrawable(R.drawable.ic_sentiment_neutral_white_18dp), null, null, null) + 3 -> binding.ratingValue.setCompoundDrawablesWithIntrinsicBounds(context.getCompatDrawable(R.drawable.ic_sentiment_satisfied_white_18dp), null, null, null) + } + } + } + else + binding.ratingValue.text = String.format(Locale.getDefault(), "%d", mediaList.score.toInt()) + } + + fun setRating(mediaBase: MediaBase) { + var mediaScoreDefault = mediaBase.averageScore.toFloat() * 5 / 100f + if (mediaListOptions != null) + when (mediaListOptions?.scoreFormat) { + KeyUtil.POINT_10_DECIMAL -> { + mediaScoreDefault = mediaBase.averageScore / 10f + binding.ratingValue.text = String.format(Locale.getDefault(), "%.1f", mediaScoreDefault) + } + KeyUtil.POINT_100 -> binding.ratingValue.text = String.format(Locale.getDefault(), "%d", mediaBase.averageScore) + KeyUtil.POINT_10 -> { + mediaScoreDefault = mediaBase.averageScore / 10f + binding.ratingValue.text = String.format(Locale.getDefault(), "%d", mediaScoreDefault.toInt()) + } + KeyUtil.POINT_5 -> binding.ratingValue.text = String.format(Locale.getDefault(), "%d", mediaScoreDefault.toInt()) + KeyUtil.POINT_3 -> { + binding.ratingValue.text = "" + if (mediaBase.averageScore == 0) + binding.ratingValue.setCompoundDrawablesWithIntrinsicBounds(context.getCompatDrawable(R.drawable.ic_face_white_18dp), null, null, null) + when { + mediaBase.averageScore in 1..33 -> + binding.ratingValue.setCompoundDrawablesWithIntrinsicBounds(context.getCompatDrawable(R.drawable.ic_sentiment_dissatisfied_white_18dp), null, null, null) + mediaBase.averageScore in 34..66 -> + binding.ratingValue.setCompoundDrawablesWithIntrinsicBounds(context.getCompatDrawable(R.drawable.ic_sentiment_neutral_white_18dp), null, null, null) + mediaBase.averageScore in 67..100 -> + binding.ratingValue.setCompoundDrawablesWithIntrinsicBounds(context.getCompatDrawable(R.drawable.ic_sentiment_satisfied_white_18dp), null, null, null) + } + } + } + else + binding.ratingValue.text = String.format(Locale.getDefault(), "%d", mediaBase.averageScore) + } + + /** + * Clean up any resources that won't be needed + */ + override fun onViewRecycled() { + + } +} 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..c51ee3dd6 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,29 +1,19 @@ 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.text.Spanned import android.text.method.LinkMovementMethod import android.text.util.Linkify import android.util.AttributeSet -import android.widget.TextView +import androidx.appcompat.widget.AppCompatTextView +import androidx.core.text.util.LinkifyCompat 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 java.util.Arrays.asList +import com.mxt.anitrend.util.markdown.MarkDownUtil +import com.mxt.anitrend.util.markdown.RegexUtil +import io.noties.markwon.Markwon +import org.koin.core.KoinComponent +import org.koin.core.inject -class RichMarkdownTextView : AppCompatTextView, CustomView { +class RichMarkdownTextView : AppCompatTextView, CustomView, KoinComponent { constructor(context: Context) : super(context) { onInit() } @@ -34,34 +24,7 @@ class RichMarkdownTextView : AppCompatTextView, CustomView { constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { onInit() } - val markwon by lazy { - Markwon.builder(context) - .usePlugins(asList( - CorePlugin.create(), - ImagesPlugin.create(context), - OkHttpImagesPlugin.create(), - HtmlPlugin.create(), - object: AbstractMarkwonPlugin() { - @Override - override fun configureParser(builder: Parser.Builder) { - - } - - 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() - } + val markwon by inject() /** * Optionally included when constructing custom views @@ -81,7 +44,7 @@ class RichMarkdownTextView : AppCompatTextView, CustomView { fun setMarkDownText(markDownText: String?) { val strippedText = RegexUtil.removeTags(markDownText) - val markdownSpan = MarkDownUtil.convert(strippedText, context, this) + val markdownSpan = MarkDownUtil.convert(strippedText) setText(markdownSpan, BufferType.SPANNABLE) //richMarkDown(this, markDownText) } diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/text/SeriesProgressTextView.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/text/SeriesProgressTextView.java index 983c745c9..d895dd6e2 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/text/SeriesProgressTextView.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/text/SeriesProgressTextView.java @@ -8,7 +8,7 @@ import com.mxt.anitrend.model.entity.base.MediaBase; import com.mxt.anitrend.util.CompatUtil; import com.mxt.anitrend.util.KeyUtil; -import com.mxt.anitrend.util.MediaUtil; +import com.mxt.anitrend.util.media.MediaUtil; import java.util.Locale; 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..ba9fb8706 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,9 +1,10 @@ package com.mxt.anitrend.base.custom.view.text; import android.content.Context; -import android.databinding.BindingAdapter; import android.util.AttributeSet; +import androidx.databinding.BindingAdapter; + import com.mxt.anitrend.R; public class SeriesTypeView extends SingleLineTextView { 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..200b4dad8 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,9 +1,10 @@ package com.mxt.anitrend.base.custom.view.text; import android.content.Context; -import android.databinding.BindingAdapter; import android.util.AttributeSet; +import androidx.databinding.BindingAdapter; + import com.mxt.anitrend.R; import com.mxt.anitrend.model.entity.anilist.meta.FuzzyDate; import com.mxt.anitrend.model.entity.base.MediaBase; 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..bf5e55aa5 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,10 +2,11 @@ import android.content.Context; import android.content.res.AssetManager; -import android.databinding.BindingAdapter; import android.graphics.Typeface; import android.util.AttributeSet; +import androidx.databinding.BindingAdapter; + /** * Created by max on 2017/12/24. * custom font single line text view 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..70b7bc6c6 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,10 +1,11 @@ package com.mxt.anitrend.base.custom.view.text; import android.content.Context; -import android.support.v7.widget.AppCompatTextView; import android.text.TextUtils; import android.util.AttributeSet; +import androidx.appcompat.widget.AppCompatTextView; + import com.mxt.anitrend.base.interfaces.view.CustomView; /** 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..6803681f8 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,11 +1,12 @@ package com.mxt.anitrend.base.custom.view.text; import android.content.Context; -import android.databinding.BindingAdapter; -import android.text.TextUtils; import android.util.AttributeSet; -import com.mxt.anitrend.util.CompatUtil; + +import androidx.databinding.BindingAdapter; + import com.mxt.anitrend.R; +import com.mxt.anitrend.util.CompatUtil; public class SpoilerTagTextView extends SingleLineTextView { 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..3159b09e3 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 android.arch.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 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; @@ -25,12 +25,11 @@ import com.mxt.anitrend.model.entity.container.attribute.PageInfo; import com.mxt.anitrend.model.entity.container.body.ConnectionContainer; import com.mxt.anitrend.model.entity.container.body.PageContainer; -import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder; import com.mxt.anitrend.presenter.widget.WidgetPresenter; -import com.mxt.anitrend.util.DateUtil; -import com.mxt.anitrend.util.GraphUtil; import com.mxt.anitrend.util.KeyUtil; import com.mxt.anitrend.util.NotifyUtil; +import com.mxt.anitrend.util.date.DateUtil; +import com.mxt.anitrend.util.graphql.GraphUtil; import com.mxt.anitrend.view.activity.detail.FavouriteActivity; import com.mxt.anitrend.view.sheet.BottomSheetListUsers; @@ -38,8 +37,10 @@ import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; +import io.github.wax911.library.model.request.QueryContainerBuilder; 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); } } }); @@ -220,7 +223,7 @@ public void onClick(View view) { switch (view.getId()) { case R.id.user_favourites_container: if(favourites < 1) - NotifyUtil.makeText(getContext(), R.string.text_activity_loading, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(getContext(), R.string.text_activity_loading, Toast.LENGTH_SHORT).show(); else { Intent intent = new Intent(getContext(), FavouriteActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); @@ -230,7 +233,7 @@ public void onClick(View view) { break; case R.id.user_followers_container: if(followers == null || followers.getTotal() < 1) - NotifyUtil.makeText(getContext(), R.string.text_activity_loading, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(getContext(), R.string.text_activity_loading, Toast.LENGTH_SHORT).show(); else if (fragmentManager != null){ mBottomSheet = new BottomSheetListUsers.Builder().setUserId(userId) .setModelCount(followers.getTotal()) @@ -242,7 +245,7 @@ else if (fragmentManager != null){ break; case R.id.user_following_container: if(following == null || following.getTotal() < 1) - NotifyUtil.makeText(getContext(), R.string.text_activity_loading, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(getContext(), R.string.text_activity_loading, Toast.LENGTH_SHORT).show(); else if (fragmentManager != null){ mBottomSheet = new BottomSheetListUsers.Builder().setUserId(userId) .setModelCount(following.getTotal()) 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..b447a0fb4 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,14 +3,14 @@ import android.annotation.TargetApi; import android.content.Context; import android.os.Build; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.util.AttributeSet; -import android.util.Log; import android.view.View; import android.widget.LinearLayout; import android.widget.Toast; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.consumer.BaseConsumer; import com.mxt.anitrend.base.interfaces.event.RetroCallback; @@ -19,15 +19,16 @@ import com.mxt.anitrend.model.entity.anilist.MediaList; import com.mxt.anitrend.presenter.widget.WidgetPresenter; import com.mxt.anitrend.util.CompatUtil; -import com.mxt.anitrend.util.DateUtil; -import com.mxt.anitrend.util.ErrorUtil; import com.mxt.anitrend.util.KeyUtil; -import com.mxt.anitrend.util.MediaListUtil; -import com.mxt.anitrend.util.MediaUtil; import com.mxt.anitrend.util.NotifyUtil; +import com.mxt.anitrend.util.date.DateUtil; +import com.mxt.anitrend.util.graphql.AniGraphErrorUtilKt; +import com.mxt.anitrend.util.media.MediaListUtil; +import com.mxt.anitrend.util.media.MediaUtil; 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); @@ -82,11 +84,11 @@ public void onClick(View view) { binding.widgetFlipper.showNext(); updateModelState(); } else - NotifyUtil.makeText(getContext(), R.string.busy_please_wait, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(getContext(), R.string.busy_please_wait, Toast.LENGTH_SHORT).show(); break; } } else - NotifyUtil.makeText(getContext(), MediaUtil.isAnimeType(model.getMedia()) ? + NotifyUtil.INSTANCE.makeText(getContext(), MediaUtil.isAnimeType(model.getMedia()) ? R.string.text_unable_to_increment_episodes : R.string.text_unable_to_increment_chapters, R.drawable.ic_warning_white_18dp, Toast.LENGTH_SHORT).show(); } @@ -119,18 +121,19 @@ public void onResponse(@NonNull Call call, @NonNull Response(requestType, model), false); } else resetFlipperState(); } else { resetFlipperState(); - Log.e(this.toString(), ErrorUtil.INSTANCE.getError(response)); - NotifyUtil.makeText(getContext(), R.string.text_error_request, Toast.LENGTH_SHORT).show(); + Timber.tag(TAG).w(AniGraphErrorUtilKt.apiError(response)); + NotifyUtil.INSTANCE.makeText(getContext(), R.string.text_error_request, Toast.LENGTH_SHORT).show(); } } catch (Exception e) { + Timber.tag(TAG).w(e); e.printStackTrace(); } } @@ -138,10 +141,11 @@ public void onResponse(@NonNull Call call, @NonNull Response call, @NonNull Throwable throwable) { try { - Log.e(toString(), throwable.getLocalizedMessage()); + Timber.tag(TAG).e(throwable); throwable.printStackTrace(); resetFlipperState(); } catch (Exception e) { + Timber.tag(TAG).e(e); e.printStackTrace(); } } @@ -157,7 +161,7 @@ private void updateModelState() { model.setStatus(KeyUtil.COMPLETED); model.setCompletedAt(DateUtil.INSTANCE.getCurrentDate()); } - presenter.setParams(MediaListUtil.getMediaListParams(model, presenter.getDatabase() + presenter.setParams(MediaListUtil.INSTANCE.getMediaListParams(model, presenter.getDatabase() .getCurrentUser().getMediaListOptions().getScoreFormat())); presenter.requestData(requestType, getContext(), this); } diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/CommentWidget.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/CommentWidget.java index 3af14cd72..241c2f1d5 100644 --- a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/CommentWidget.java +++ b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/CommentWidget.java @@ -1,7 +1,6 @@ package com.mxt.anitrend.base.custom.view.widget; import android.content.Context; -import android.graphics.Typeface; import android.util.AttributeSet; import com.mxt.anitrend.R; 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..821bf896a 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,10 +6,11 @@ import android.graphics.PorterDuffColorFilter; import android.graphics.drawable.Drawable; import android.os.Build; -import android.support.annotation.Nullable; import android.util.AttributeSet; import android.widget.ProgressBar; +import androidx.annotation.Nullable; + import com.mxt.anitrend.R; import com.mxt.anitrend.base.interfaces.view.CustomView; import com.mxt.anitrend.util.CompatUtil; 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..71fc85410 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,10 +1,11 @@ package com.mxt.anitrend.base.custom.view.widget; import android.content.Context; -import android.databinding.BindingAdapter; -import android.support.v7.widget.AppCompatRatingBar; import android.util.AttributeSet; +import androidx.appcompat.widget.AppCompatRatingBar; +import androidx.databinding.BindingAdapter; + 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..7ca1ffe69 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,19 +3,20 @@ import android.content.Context; import android.os.Build; import android.os.Bundle; -import android.support.annotation.RequiresApi; import android.text.TextUtils; import android.util.AttributeSet; import android.view.View; import android.widget.AdapterView; import android.widget.Toast; +import androidx.annotation.RequiresApi; + import com.mxt.anitrend.R; import com.mxt.anitrend.databinding.CustomActionAnimeBinding; import com.mxt.anitrend.util.CompatUtil; import com.mxt.anitrend.util.KeyUtil; -import com.mxt.anitrend.util.MediaListUtil; import com.mxt.anitrend.util.NotifyUtil; +import com.mxt.anitrend.util.media.MediaListUtil; /** * Created by max on 2018/01/03. @@ -55,7 +56,7 @@ public void onInit() { * Saves the current views states into the model * and returns a bundle of the params * - * @see com.mxt.anitrend.util.MediaListUtil + * @see MediaListUtil */ @Override public Bundle persistChanges() { @@ -70,7 +71,7 @@ public Bundle persistChanges() { model.setHidden(binding.diaCurrentPrivacy.isChecked()); model.setNotes(binding.diaCurrentNotes.getFormattedText()); model.setStatus(KeyUtil.MediaListStatus[binding.diaCurrentStatus.getSelectedItemPosition()]); - return MediaListUtil.getMediaListParams(model, getMediaListOptions().getScoreFormat()); + return MediaListUtil.INSTANCE.getMediaListParams(model, getMediaListOptions().getScoreFormat()); } @Override @@ -120,13 +121,13 @@ public void onItemSelected(AdapterView adapterView, View view, int i, long l) switch (KeyUtil.MediaListStatus[i]) { case KeyUtil.CURRENT: if (CompatUtil.INSTANCE.equals(getSeriesModel().getStatus(), KeyUtil.NOT_YET_RELEASED)) - NotifyUtil.makeText(getContext(), R.string.warning_anime_not_airing, Toast.LENGTH_LONG).show(); + NotifyUtil.INSTANCE.makeText(getContext(), R.string.warning_anime_not_airing, Toast.LENGTH_LONG).show(); break; case KeyUtil.PLANNING: break; case KeyUtil.COMPLETED: if (!CompatUtil.INSTANCE.equals(getSeriesModel().getStatus(), KeyUtil.FINISHED)) - NotifyUtil.makeText(getContext(), R.string.warning_anime_is_airing, Toast.LENGTH_LONG).show(); + NotifyUtil.INSTANCE.makeText(getContext(), R.string.warning_anime_is_airing, Toast.LENGTH_LONG).show(); else { int total = getSeriesModel().getEpisodes(); model.setProgress(total); @@ -136,7 +137,7 @@ public void onItemSelected(AdapterView adapterView, View view, int i, long l) break; default: if (CompatUtil.INSTANCE.equals(getSeriesModel().getStatus(), KeyUtil.NOT_YET_RELEASED)) - NotifyUtil.makeText(getContext(), R.string.warning_anime_not_airing, Toast.LENGTH_LONG).show(); + NotifyUtil.INSTANCE.makeText(getContext(), R.string.warning_anime_not_airing, Toast.LENGTH_LONG).show(); break; } } diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/CustomSeriesManageBase.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/CustomSeriesManageBase.java index 585f38c2c..5ad91d193 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,12 +3,13 @@ import android.content.Context; import android.os.Build; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.RequiresApi; import android.util.AttributeSet; import android.widget.AdapterView; import android.widget.RelativeLayout; +import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; + import com.mxt.anitrend.R; import com.mxt.anitrend.adapter.spinner.IconArrayAdapter; import com.mxt.anitrend.base.interfaces.view.CustomView; @@ -17,6 +18,7 @@ import com.mxt.anitrend.model.entity.base.MediaBase; import com.mxt.anitrend.presenter.fragment.MediaPresenter; import com.mxt.anitrend.util.CompatUtil; +import com.mxt.anitrend.util.media.MediaListUtil; import java.util.HashMap; import java.util.Map; @@ -100,7 +102,7 @@ public MediaListOptions getMediaListOptions() { /** * Saves the current views states into the model * and returns a bundle of the params - * @see com.mxt.anitrend.util.MediaListUtil + * @see MediaListUtil */ public abstract Bundle persistChanges(); 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..f9dd43804 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,19 +3,20 @@ import android.content.Context; import android.os.Build; import android.os.Bundle; -import android.support.annotation.RequiresApi; import android.text.TextUtils; import android.util.AttributeSet; import android.view.View; import android.widget.AdapterView; import android.widget.Toast; +import androidx.annotation.RequiresApi; + import com.mxt.anitrend.R; import com.mxt.anitrend.databinding.CustomActionMangaBinding; import com.mxt.anitrend.util.CompatUtil; import com.mxt.anitrend.util.KeyUtil; -import com.mxt.anitrend.util.MediaListUtil; import com.mxt.anitrend.util.NotifyUtil; +import com.mxt.anitrend.util.media.MediaListUtil; /** * Created by max on 2018/01/03. @@ -54,7 +55,7 @@ public void onInit() { /** * Saves the current views states into the model * and returns a bundle of the params - * @see com.mxt.anitrend.util.MediaListUtil + * @see MediaListUtil */ @Override public Bundle persistChanges() { @@ -70,7 +71,7 @@ public Bundle persistChanges() { model.setHidden(binding.diaCurrentPrivacy.isChecked()); model.setNotes(binding.diaCurrentNotes.getFormattedText()); model.setStatus(KeyUtil.MediaListStatus[binding.diaCurrentStatus.getSelectedItemPosition()]); - return MediaListUtil.getMediaListParams(model, getMediaListOptions().getScoreFormat()); + return MediaListUtil.INSTANCE.getMediaListParams(model, getMediaListOptions().getScoreFormat()); } @Override @@ -124,13 +125,13 @@ public void onItemSelected(AdapterView adapterView, View view, int i, long l) switch (KeyUtil.MediaListStatus[i]) { case KeyUtil.CURRENT: if (CompatUtil.INSTANCE.equals(getSeriesModel().getStatus(), KeyUtil.NOT_YET_RELEASED)) - NotifyUtil.makeText(getContext(), R.string.warning_manga_not_publishing, Toast.LENGTH_LONG).show(); + NotifyUtil.INSTANCE.makeText(getContext(), R.string.warning_manga_not_publishing, Toast.LENGTH_LONG).show(); break; case KeyUtil.PLANNING: break; case KeyUtil.COMPLETED: if (!CompatUtil.INSTANCE.equals(getSeriesModel().getStatus(), KeyUtil.FINISHED)) - NotifyUtil.makeText(getContext(), R.string.warning_manga_publishing, Toast.LENGTH_LONG).show(); + NotifyUtil.INSTANCE.makeText(getContext(), R.string.warning_manga_publishing, Toast.LENGTH_LONG).show(); else { int total = getSeriesModel().getChapters(); model.setProgress(total); @@ -144,7 +145,7 @@ public void onItemSelected(AdapterView adapterView, View view, int i, long l) break; default: if (CompatUtil.INSTANCE.equals(getSeriesModel().getStatus(), KeyUtil.NOT_YET_RELEASED)) - NotifyUtil.makeText(getContext(), R.string.warning_manga_not_publishing, Toast.LENGTH_LONG).show(); + NotifyUtil.INSTANCE.makeText(getContext(), R.string.warning_manga_not_publishing, Toast.LENGTH_LONG).show(); break; } } diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/FavouriteToolbarWidget.java b/app/src/main/java/com/mxt/anitrend/base/custom/view/widget/FavouriteToolbarWidget.java index f31967d97..642e71beb 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,14 +3,14 @@ import android.annotation.TargetApi; import android.content.Context; import android.os.Build; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.util.AttributeSet; -import android.util.Log; import android.view.View; import android.widget.FrameLayout; import android.widget.Toast; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import com.mxt.anitrend.R; import com.mxt.anitrend.base.interfaces.event.RetroCallback; import com.mxt.anitrend.base.interfaces.view.CustomView; @@ -19,18 +19,19 @@ import com.mxt.anitrend.model.entity.base.MediaBase; import com.mxt.anitrend.model.entity.base.StaffBase; import com.mxt.anitrend.model.entity.base.StudioBase; -import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder; import com.mxt.anitrend.presenter.widget.WidgetPresenter; import com.mxt.anitrend.util.CompatUtil; -import com.mxt.anitrend.util.ErrorUtil; -import com.mxt.anitrend.util.GraphUtil; import com.mxt.anitrend.util.KeyUtil; -import com.mxt.anitrend.util.MediaUtil; import com.mxt.anitrend.util.NotifyUtil; +import com.mxt.anitrend.util.graphql.AniGraphErrorUtilKt; +import com.mxt.anitrend.util.graphql.GraphUtil; +import com.mxt.anitrend.util.media.MediaUtil; +import io.github.wax911.library.model.request.QueryContainerBuilder; 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,22 +136,19 @@ 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.INSTANCE.makeText(getContext(), R.string.busy_please_wait, Toast.LENGTH_SHORT).show(); + } else + NotifyUtil.INSTANCE.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(); + NotifyUtil.INSTANCE.makeText(getContext(), R.string.info_login_req, R.drawable.ic_group_add_grey_600_18dp, Toast.LENGTH_SHORT).show(); } private void setIconType() { @@ -189,10 +189,11 @@ else if (characterBase != null) characterBase.toggleFavourite(); setIconType(); } else { - Log.e(toString(), ErrorUtil.INSTANCE.getError(response)); - NotifyUtil.makeText(getContext(), R.string.text_error_request, Toast.LENGTH_SHORT).show(); + Timber.tag(TAG).w(AniGraphErrorUtilKt.apiError(response)); + NotifyUtil.INSTANCE.makeText(getContext(), R.string.text_error_request, Toast.LENGTH_SHORT).show(); } } catch (Exception e) { + Timber.tag(TAG).w(e); e.printStackTrace(); } } @@ -200,10 +201,10 @@ else if (characterBase != null) @Override public void onFailure(@NonNull Call call, @NonNull Throwable throwable) { try { - Log.e(toString(), throwable.getLocalizedMessage()); - throwable.printStackTrace(); + Timber.tag(TAG).e(throwable); resetFlipperState(); } catch (Exception e) { + Timber.tag(TAG).e(e); e.printStackTrace(); } } 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..23592bbfe 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,31 +1,32 @@ package com.mxt.anitrend.base.custom.view.widget; import android.content.Context; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.util.AttributeSet; -import android.util.Log; import android.view.View; import android.widget.FrameLayout; import android.widget.Toast; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import com.mxt.anitrend.R; import com.mxt.anitrend.base.interfaces.event.RetroCallback; import com.mxt.anitrend.base.interfaces.view.CustomView; import com.mxt.anitrend.databinding.WidgetFavouriteBinding; import com.mxt.anitrend.model.entity.base.UserBase; -import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder; import com.mxt.anitrend.presenter.widget.WidgetPresenter; import com.mxt.anitrend.util.CompatUtil; -import com.mxt.anitrend.util.ErrorUtil; -import com.mxt.anitrend.util.GraphUtil; import com.mxt.anitrend.util.KeyUtil; import com.mxt.anitrend.util.NotifyUtil; +import com.mxt.anitrend.util.graphql.AniGraphErrorUtilKt; +import com.mxt.anitrend.util.graphql.GraphUtil; import java.util.List; +import io.github.wax911.library.model.request.QueryContainerBuilder; 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); @@ -99,7 +101,7 @@ public void onClick(View view) { presenter.requestData(KeyUtil.MUT_TOGGLE_LIKE, getContext(), this); } else - NotifyUtil.makeText(getContext(), R.string.busy_please_wait, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(getContext(), R.string.busy_please_wait, Toast.LENGTH_SHORT).show(); break; } } @@ -134,10 +136,11 @@ public void onResponse(@NonNull Call> call, @NonNull Response> call, @NonNull Response> call, @NonNull Throwable throwable) { try { - Log.e(toString(), throwable.getLocalizedMessage()); - throwable.printStackTrace(); + Timber.tag(TAG).e(throwable); resetFlipperState(); } catch (Exception e) { + Timber.tag(TAG).e(throwable); e.printStackTrace(); } } 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..afd285a1b 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,29 +1,30 @@ package com.mxt.anitrend.base.custom.view.widget; import android.content.Context; -import android.support.annotation.NonNull; import android.util.AttributeSet; -import android.util.Log; import android.view.View; import android.widget.FrameLayout; import android.widget.Toast; +import androidx.annotation.NonNull; + import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.consumer.BaseConsumer; import com.mxt.anitrend.base.interfaces.event.RetroCallback; import com.mxt.anitrend.base.interfaces.view.CustomView; import com.mxt.anitrend.databinding.WidgetButtonStateBinding; import com.mxt.anitrend.model.entity.base.UserBase; -import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder; import com.mxt.anitrend.presenter.widget.WidgetPresenter; import com.mxt.anitrend.util.CompatUtil; -import com.mxt.anitrend.util.ErrorUtil; -import com.mxt.anitrend.util.GraphUtil; import com.mxt.anitrend.util.KeyUtil; import com.mxt.anitrend.util.NotifyUtil; +import com.mxt.anitrend.util.graphql.AniGraphErrorUtilKt; +import com.mxt.anitrend.util.graphql.GraphUtil; +import io.github.wax911.library.model.request.QueryContainerBuilder; 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 @@ -112,7 +114,7 @@ public void onClick(View view) { presenter.requestData(KeyUtil.MUT_TOGGLE_FOLLOW, getContext(), this); } else - NotifyUtil.makeText(getContext(), R.string.busy_please_wait, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(getContext(), R.string.busy_please_wait, Toast.LENGTH_SHORT).show(); break; } } @@ -134,10 +136,11 @@ 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).w(AniGraphErrorUtilKt.apiError(response)); setControlText(); } } catch (Exception e) { + Timber.tag(TAG).w(e); e.printStackTrace(); } } @@ -155,6 +158,7 @@ public void onFailure(@NonNull Call call, @NonNull Throwable throwable throwable.printStackTrace(); setControlText(); } catch (Exception e) { + Timber.tag(TAG).e(e); e.printStackTrace(); } } 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..517c0612b 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,18 +5,19 @@ import android.content.Context; import android.content.DialogInterface; import android.os.Build; -import android.support.annotation.Nullable; import android.util.AttributeSet; import android.view.View; import android.widget.DatePicker; import android.widget.FrameLayout; +import androidx.annotation.Nullable; + import com.mxt.anitrend.R; import com.mxt.anitrend.base.interfaces.view.CustomView; import com.mxt.anitrend.databinding.WidgetFuzzyDateBinding; import com.mxt.anitrend.model.entity.anilist.meta.FuzzyDate; import com.mxt.anitrend.util.CompatUtil; -import com.mxt.anitrend.util.DateUtil; +import com.mxt.anitrend.util.date.DateUtil; import java.util.Calendar; 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..bb851013e 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,9 +1,10 @@ package com.mxt.anitrend.base.custom.view.widget; import android.content.Context; -import android.support.v7.widget.AppCompatImageView; import android.util.AttributeSet; +import androidx.appcompat.widget.AppCompatImageView; + import com.mxt.anitrend.R; import com.mxt.anitrend.base.interfaces.view.CustomView; import com.mxt.anitrend.util.CompatUtil; 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..3f93f9971 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,53 +4,52 @@ 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 android.util.AttributeSet; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.widget.FrameLayout; -import com.annimon.stream.Stream; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; +import androidx.core.content.ContextCompat; + +import com.google.android.material.snackbar.Snackbar; import com.mxt.anitrend.R; import com.mxt.anitrend.base.interfaces.event.RetroCallback; import com.mxt.anitrend.base.interfaces.view.CustomView; 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.container.body.ConnectionContainer; -import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder; import com.mxt.anitrend.presenter.widget.WidgetPresenter; -import com.mxt.anitrend.util.CompatUtil; -import com.mxt.anitrend.util.ErrorUtil; -import com.mxt.anitrend.util.GraphUtil; import com.mxt.anitrend.util.KeyUtil; +import com.mxt.anitrend.util.graphql.AniGraphErrorUtilKt; +import com.mxt.anitrend.util.graphql.GraphUtil; import com.mxt.anitrend.view.activity.detail.MediaListActivity; -import java.util.List; import java.util.Locale; +import io.github.wax911.library.model.request.QueryContainerBuilder; import retrofit2.Call; import retrofit2.Response; +import timber.log.Timber; /** * Created by max on 2017/11/26. * 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; + private final String TAG = ProfileStatsWidget.class.getSimpleName(); private final String placeHolder = ".."; @@ -98,14 +97,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().getCount())); + binding.userMangaTotal.setText(getCount(model.getManga().getCount())); + } } public void setParams(Bundle bundle) { @@ -133,10 +130,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,35 +165,36 @@ 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(); updateUI(); } } else - Log.e(this.toString(), ErrorUtil.INSTANCE.getError(response)); + Timber.tag(TAG).w(AniGraphErrorUtilKt.apiError(response)); } catch (Exception e) { + Timber.tag(TAG).w(e); e.printStackTrace(); } } @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()); - throwable.printStackTrace(); + Timber.tag(TAG).w(throwable); } catch (Exception e) { + Timber.tag(TAG).e(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 +204,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); 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..8e22fb2cc 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,6 @@ import android.annotation.TargetApi; import android.content.Context; import android.os.Build; -import android.support.annotation.Nullable; import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; @@ -11,6 +10,8 @@ import android.view.View; import android.widget.FrameLayout; +import androidx.annotation.Nullable; + import com.mxt.anitrend.R; import com.mxt.anitrend.base.interfaces.view.CustomView; import com.mxt.anitrend.databinding.WidgetProgressBinding; 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..e7cfb8745 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,12 +14,13 @@ import android.graphics.RectF; import android.graphics.Shader; import android.os.Build; -import android.support.annotation.Nullable; -import android.support.annotation.RequiresApi; import android.util.AttributeSet; import android.view.View; import android.view.animation.LinearInterpolator; +import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; + import com.mxt.anitrend.R; import com.mxt.anitrend.base.interfaces.view.CustomView; import com.mxt.anitrend.model.entity.base.StatsRing; 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..424093c31 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,13 +1,14 @@ package com.mxt.anitrend.base.custom.view.widget; import android.content.Context; -import android.support.annotation.Nullable; import android.text.Editable; import android.text.TextUtils; import android.text.method.DigitsKeyListener; import android.util.AttributeSet; import android.view.View; +import androidx.annotation.Nullable; + import com.mxt.anitrend.R; import com.mxt.anitrend.util.CompatUtil; import com.mxt.anitrend.util.KeyUtil; 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..fae3941b8 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,14 +2,15 @@ import android.annotation.TargetApi; import android.content.Context; -import android.databinding.BindingAdapter; import android.os.Build; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.text.TextUtils; import android.util.AttributeSet; import android.widget.FrameLayout; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.databinding.BindingAdapter; + import com.mxt.anitrend.R; import com.mxt.anitrend.base.interfaces.view.CustomView; import com.mxt.anitrend.model.entity.anilist.Media; 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..475c18628 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,6 @@ 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 android.text.TextUtils; import android.util.AttributeSet; import android.view.LayoutInflater; @@ -17,6 +12,12 @@ import android.widget.LinearLayout; import android.widget.Toast; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.SnapHelper; + import com.annimon.stream.IntPair; import com.mxt.anitrend.R; import com.mxt.anitrend.adapter.recycler.detail.ImagePreviewAdapter; @@ -30,7 +31,7 @@ import com.mxt.anitrend.util.CompatUtil; import com.mxt.anitrend.util.KeyUtil; import com.mxt.anitrend.util.NotifyUtil; -import com.mxt.anitrend.util.RegexUtil; +import com.mxt.anitrend.util.markdown.RegexUtil; import com.mxt.anitrend.view.activity.base.ImagePreviewActivity; import com.mxt.anitrend.view.activity.base.VideoPlayerActivity; @@ -176,7 +177,7 @@ public void onItemClick(View target, IntPair data) { getContext().startActivity(intent); } catch (ActivityNotFoundException e) { e.printStackTrace(); - NotifyUtil.makeText(getContext(), R.string.init_youtube_missing, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(getContext(), R.string.init_youtube_missing, Toast.LENGTH_SHORT).show(); } break; } 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..930f06cfb 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,13 +1,13 @@ package com.mxt.anitrend.base.custom.view.widget; import android.content.Context; -import android.support.annotation.NonNull; import android.util.AttributeSet; -import android.util.Log; import android.view.View; import android.widget.FrameLayout; import android.widget.Toast; +import androidx.annotation.NonNull; + import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.consumer.BaseConsumer; import com.mxt.anitrend.base.interfaces.event.RetroCallback; @@ -16,16 +16,17 @@ import com.mxt.anitrend.model.entity.anilist.FeedList; import com.mxt.anitrend.model.entity.anilist.FeedReply; import com.mxt.anitrend.model.entity.anilist.meta.DeleteState; -import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder; import com.mxt.anitrend.presenter.widget.WidgetPresenter; import com.mxt.anitrend.util.CompatUtil; -import com.mxt.anitrend.util.ErrorUtil; -import com.mxt.anitrend.util.GraphUtil; import com.mxt.anitrend.util.KeyUtil; import com.mxt.anitrend.util.NotifyUtil; +import com.mxt.anitrend.util.graphql.AniGraphErrorUtilKt; +import com.mxt.anitrend.util.graphql.GraphUtil; +import io.github.wax911.library.model.request.QueryContainerBuilder; 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); @@ -105,7 +107,7 @@ public void onClick(View view) { presenter.requestData(requestType, getContext(), this); } else - NotifyUtil.makeText(getContext(), R.string.busy_please_wait, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(getContext(), R.string.busy_please_wait, Toast.LENGTH_SHORT).show(); break; } } @@ -131,10 +133,11 @@ public void onResponse(@NonNull Call call, @NonNull Response(requestType, feedReply), false); } else - NotifyUtil.makeText(getContext(), R.string.text_error_request, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(getContext(), R.string.text_error_request, Toast.LENGTH_SHORT).show(); } else - Log.e(this.toString(), ErrorUtil.INSTANCE.getError(response)); + Timber.tag(TAG).w(AniGraphErrorUtilKt.apiError(response)); } catch (Exception e) { + Timber.tag(TAG).w(e); e.printStackTrace(); } } @@ -149,7 +152,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 69d8a4f72..5ca07b773 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,34 +2,35 @@ 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 android.util.AttributeSet; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.widget.LinearLayout; import android.widget.Toast; +import androidx.annotation.ColorRes; +import androidx.annotation.DrawableRes; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; + import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.view.text.SingleLineTextView; import com.mxt.anitrend.base.interfaces.event.RetroCallback; import com.mxt.anitrend.base.interfaces.view.CustomView; import com.mxt.anitrend.databinding.WidgetVoteBinding; import com.mxt.anitrend.model.entity.anilist.Review; -import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder; import com.mxt.anitrend.presenter.widget.WidgetPresenter; import com.mxt.anitrend.util.CompatUtil; -import com.mxt.anitrend.util.ErrorUtil; -import com.mxt.anitrend.util.GraphUtil; import com.mxt.anitrend.util.KeyUtil; import com.mxt.anitrend.util.NotifyUtil; +import com.mxt.anitrend.util.graphql.AniGraphErrorUtilKt; +import com.mxt.anitrend.util.graphql.GraphUtil; +import io.github.wax911.library.model.request.QueryContainerBuilder; 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,25 +76,25 @@ 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) { binding.widgetThumbUpFlipper.showNext(); setParameters(CompatUtil.INSTANCE.equals(model.getUserRating(), KeyUtil.UP_VOTE) ? KeyUtil.NO_VOTE : KeyUtil.UP_VOTE); } else - NotifyUtil.makeText(getContext(), R.string.busy_please_wait, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(getContext(), R.string.busy_please_wait, Toast.LENGTH_SHORT).show(); break; case R.id.widget_thumb_down_flipper: if (binding.widgetThumbDownFlipper.getDisplayedChild() == WidgetPresenter.CONTENT_STATE) { binding.widgetThumbDownFlipper.showNext(); setParameters(CompatUtil.INSTANCE.equals(model.getUserRating(), KeyUtil.DOWN_VOTE) ? KeyUtil.NO_VOTE : KeyUtil.DOWN_VOTE); } else - NotifyUtil.makeText(getContext(), R.string.busy_please_wait, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(getContext(), R.string.busy_please_wait, Toast.LENGTH_SHORT).show(); break; } } else - NotifyUtil.makeText(getContext(), R.string.info_login_req, R.drawable.ic_group_add_grey_600_18dp, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(getContext(), R.string.info_login_req, R.drawable.ic_group_add_grey_600_18dp, Toast.LENGTH_SHORT).show(); } /** @@ -188,10 +189,11 @@ 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(AniGraphErrorUtilKt.apiError(response)); resetFlipperState(); } } catch (Exception e) { + Timber.tag(TAG).w(e); e.printStackTrace(); } } @@ -206,10 +208,10 @@ 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()); - throwable.printStackTrace(); + Timber.tag(TAG).e(throwable); resetFlipperState(); } catch (Exception e) { + Timber.tag(TAG).e(throwable); e.printStackTrace(); } } diff --git a/app/src/main/java/com/mxt/anitrend/base/custom/viewmodel/ViewModelBase.kt b/app/src/main/java/com/mxt/anitrend/base/custom/viewmodel/ViewModelBase.kt index da8a084ed..824994c5a 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,29 +1,29 @@ package com.mxt.anitrend.base.custom.viewmodel -import android.arch.lifecycle.MutableLiveData -import android.arch.lifecycle.ViewModel import android.content.Context import android.os.AsyncTask import android.os.Bundle - +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel import com.mxt.anitrend.R import com.mxt.anitrend.base.custom.async.RequestHandler import com.mxt.anitrend.base.interfaces.event.ResponseCallback import com.mxt.anitrend.base.interfaces.event.RetroCallback -import com.mxt.anitrend.util.ErrorUtil import com.mxt.anitrend.util.KeyUtil - -import io.objectbox.android.ObjectBoxLiveData -import io.objectbox.query.Query +import com.mxt.anitrend.util.graphql.apiError +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() @@ -33,17 +33,17 @@ class ViewModelBase: ViewModel(), RetroCallback { private var mLoader: RequestHandler? = null - private var emptyMessage: String? = null - private var errorMessage: String? = null + private lateinit var emptyMessage: String + private lateinit var errorMessage: String + private lateinit var tokenMessage: String - val params by lazy { - Bundle() - } + val params = Bundle() fun setContext(context: Context?) { context?.apply { emptyMessage = getString(R.string.layout_empty_response) errorMessage = getString(R.string.text_error_request) + tokenMessage = getString(R.string.text_error_auth_token) } } @@ -65,6 +65,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 @@ -86,8 +87,16 @@ 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 = response.apiError() + // 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) + } } /** @@ -98,7 +107,16 @@ class ViewModelBase: ViewModel(), RetroCallback { * @param throwable contains information about the error */ override fun onFailure(call: Call, throwable: Throwable) { - state?.showEmpty(throwable.message) + state?.showEmpty(throwable.message ?: errorMessage) 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/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/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/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/ResponseCallback.java b/app/src/main/java/com/mxt/anitrend/base/interfaces/event/ResponseCallback.java deleted file mode 100644 index 8cbbe3b17..000000000 --- a/app/src/main/java/com/mxt/anitrend/base/interfaces/event/ResponseCallback.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.mxt.anitrend.base.interfaces.event; - -/** - * Created by max on 2017/10/15. - * Callback for view model to communicate - * with parent class or activity after a request - */ - -public interface ResponseCallback { - - void showError(String error); - - void showEmpty(String message); -} diff --git a/app/src/main/java/com/mxt/anitrend/base/interfaces/event/ResponseCallback.kt b/app/src/main/java/com/mxt/anitrend/base/interfaces/event/ResponseCallback.kt new file mode 100644 index 000000000..9613f2153 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/base/interfaces/event/ResponseCallback.kt @@ -0,0 +1,14 @@ +package com.mxt.anitrend.base.interfaces.event + +/** + * Created by max on 2017/10/15. + * Callback for view model to communicate + * with parent class or activity after a request + */ + +interface ResponseCallback { + + fun showError(error: String) + + fun showEmpty(message: String) +} 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/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/RatingTextExtensions.kt b/app/src/main/java/com/mxt/anitrend/binding/RatingTextExtensions.kt new file mode 100644 index 000000000..5977079d0 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/binding/RatingTextExtensions.kt @@ -0,0 +1,21 @@ +package com.mxt.anitrend.binding + +import androidx.databinding.BindingAdapter +import com.mxt.anitrend.base.custom.view.text.RatingTextView +import com.mxt.anitrend.model.entity.anilist.MediaList +import com.mxt.anitrend.model.entity.base.MediaBase + + +@BindingAdapter("rating") +fun RatingTextView.setAverageRating(mediaBase: MediaBase) { + setRating(mediaBase) + setListStatus(mediaBase) + setFavourState(mediaBase.isFavourite) +} + +@BindingAdapter("rating") +fun RatingTextView.setAverageRating(mediaList: MediaList) { + setListStatus() + setRating(mediaList) + setFavourState(mediaList.media.isFavourite) +} \ 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 fcefeec39..b830cfd21 100644 --- a/app/src/main/java/com/mxt/anitrend/binding/RichMarkdownExtensions.kt +++ b/app/src/main/java/com/mxt/anitrend/binding/RichMarkdownExtensions.kt @@ -1,45 +1,44 @@ package com.mxt.anitrend.binding -import android.databinding.BindingAdapter -import android.support.annotation.StringRes import android.text.Html import android.widget.TextView +import androidx.annotation.StringRes +import androidx.databinding.BindingAdapter import com.mxt.anitrend.base.custom.view.text.RichMarkdownTextView -import com.mxt.anitrend.util.MarkDownUtil -import com.mxt.anitrend.util.RegexUtil +import com.mxt.anitrend.util.markdown.MarkDownUtil +import com.mxt.anitrend.util.markdown.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) + 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) + 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) + 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 a59f9e5e0..f0ea9c289 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,23 +9,20 @@ 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 +import java.util.* /** * Created by max on 2017/11/02. * Database helper class */ -class DatabaseHelper(context: Context) : BoxQuery { - - private val boxStore: BoxStore by lazy { - (context.applicationContext as App).boxStore - } +class DatabaseHelper : BoxQuery, KoinComponent { - // Frequently used instance variables - private var user: User? = null + private val boxStore by inject() /** * Gets the object box from a requested class type. @@ -55,126 +49,93 @@ class DatabaseHelper(context: Context) : BoxQuery { /** * 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/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 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..16a84de33 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/extension/AppExt.kt @@ -0,0 +1,125 @@ +package com.mxt.anitrend.extension + +import android.app.Activity +import android.content.Context +import android.content.Intent +import android.view.View +import android.view.inputmethod.InputMethodManager +import androidx.annotation.StringRes +import androidx.core.app.ActivityCompat +import androidx.core.app.ActivityOptionsCompat +import androidx.core.util.Pair +import androidx.core.view.ViewCompat +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentActivity +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleOwner +import com.mxt.anitrend.App +import org.koin.core.context.GlobalContext +import timber.log.Timber + +val appContext by lazy { + GlobalContext.get().koin.get() +} + +fun getString(@StringRes text: Int): String? = + runCatching { + appContext.getString(text) + }.also { + it.exceptionOrNull()?.printStackTrace() + }.getOrNull() + +fun getString(@StringRes text: Int, vararg values: String): String? = + runCatching { + appContext.getString(text, *values) + }.also { + it.exceptionOrNull()?.printStackTrace() + }.getOrNull() + +fun FragmentActivity.applyConfiguredTheme() { + runCatching{ + (applicationContext as App).applyTheme() + recreate() + }.exceptionOrNull()?.printStackTrace() +} + +/** + * Request to hide the soft input window from the context of the window + * that is currently accepting input. This should be called as a result + * of the user doing some actually than fairly explicitly requests to + * have the input window hidden. + */ +fun FragmentActivity?.hideKeyboard() = this?.apply { + val inputMethodManager = getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager + inputMethodManager.hideSoftInputFromWindow(window.decorView.windowToken, 0) +} + +/** + * Starts a shared transition of activities connected by views + * + * @param target The view from the calling activity with transition name + * @param data Intent with bundle and or activity to start + */ +fun FragmentActivity.startSharedTransitionActivity(target : View, data : Intent) { + try { + val participants = Pair(target, ViewCompat.getTransitionName(target)) + val transitionActivityOptions = ActivityOptionsCompat + .makeSceneTransitionAnimation(this, participants) + ActivityCompat.startActivity(this, data, transitionActivityOptions.toBundle()) + } catch (e: Exception) { + Timber.tag("SharedTransition").w(e) + e.printStackTrace() + } +} + + +/** + * Compares if this State is greater or equal to the given [Lifecycle.State]. + * + * @param state State to compare with + * @return true if this State is greater or equal to the given [Lifecycle.State] + */ +fun LifecycleOwner.isStateAtLeast(state: Lifecycle.State) = + lifecycle.currentState.isAtLeast(state) + +/** + * Lazy intent parameters for fragment activities + * + * @param key lookup key for the embedded item in the [FragmentActivity.getIntent] + * @param default default value to use when key does not exist + * + * @return [Lazy] of the target type + */ +@Suppress("UNCHECKED_CAST") +fun FragmentActivity.extras(key: String, default: T) = lazy(LAZY_MODE_PUBLICATION) { + try { + if (intent?.extras?.containsKey(key) == true) + intent?.extras?.get(key) as T + else + default + } catch (e: Exception) { + Timber.tag("AppExt.extras").e(e) + error(e) + } +} + +/** + * Lazy intent parameters for fragments + * + * @param key lookup key for the embedded item in the [Fragment.getArguments] + * @param default default value to use when key does not exist + * + * @return [Lazy] of the target type + */ +@Suppress("UNCHECKED_CAST") +fun Fragment.extras(key: String, default: T) = lazy(LAZY_MODE_PUBLICATION) { + try { + if (arguments?.containsKey(key) == true) + arguments?.get(key) as T + else + default + } catch (e: Exception) { + Timber.tag("AppExt.extras").e(e) + error(e) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/mxt/anitrend/extension/ContextExt.kt b/app/src/main/java/com/mxt/anitrend/extension/ContextExt.kt new file mode 100644 index 000000000..d21b3e69c --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/extension/ContextExt.kt @@ -0,0 +1,175 @@ +package com.mxt.anitrend.extension + +import android.app.ActivityManager +import android.content.Context +import android.content.Intent +import android.graphics.Point +import android.graphics.drawable.Drawable +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.WindowManager +import androidx.annotation.* +import androidx.appcompat.content.res.AppCompatResources +import androidx.core.app.ActivityManagerCompat +import androidx.core.content.ContextCompat +import androidx.core.graphics.drawable.DrawableCompat +import com.mxt.anitrend.R +import timber.log.Timber + +/** + * Exactly whether a device is low-RAM is ultimately up to the device configuration, but currently + * it generally means something in the class of a 512MB device with about a 800x480 or less screen. + * This is mostly intended to be used by apps to determine whether they should + * turn off certain features that require more RAM. + * + * @return true if this is a low-RAM device. + */ +fun Context?.isLowRamDevice() = this?.let { + val activityManager = it.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager + return ActivityManagerCompat.isLowRamDevice(activityManager) +} ?: false + +/** + * Start a new activity from context and avoid potential crashes from early API levels + */ +inline fun Context?.startNewActivity(params: Bundle? = null) { + try { + val intent = Intent(this, T::class.java) + with (intent) { + flags = Intent.FLAG_ACTIVITY_NEW_TASK + params?.also { putExtras(it) } + } + this?.startActivity(intent) + } catch (e: Exception) { + Timber.e(e) + } +} + +/** + * Creates a list of the array resource given + * + * @return The string list associated with the resource. + * @throws Exception if the given ID does not exist. + */ +fun Context.getStringList(@ArrayRes arrayRes : Int): List { + val array = resources.getStringArray(arrayRes) + return array.toList() +} + +fun View.getLayoutInflater(): LayoutInflater = + context.getLayoutInflater() + +fun Context.getLayoutInflater(): LayoutInflater = + getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater + +/** + * Gets the size of the display, in pixels. Value returned by this method does + * not necessarily represent the actual raw size (native resolution) of the display. + * + * @return A Point object to with the size information. + * @see Point + */ +fun Context.getScreenDimens(): Point { + val deviceDimens = Point() + (getSystemService(Context.WINDOW_SERVICE) as WindowManager).apply { + defaultDisplay?.getSize(deviceDimens) + } + return deviceDimens +} + +/** + * Creates a drawable from the given attribute resource which cannot be nullable type + * + * @param drawableAttr attribute resource for drawable + * @return Drawable for the attribute, or null if not defined. + * @throws UnsupportedOperationException if the attribute is defined but is + * not a color or drawable resource. + */ +fun Context.getDrawableFromAttr(@AttrRes drawableAttr : Int): Drawable? { + val drawableAttribute = obtainStyledAttributes(intArrayOf(drawableAttr)) + val drawable = drawableAttribute.getDrawable(0) + drawableAttribute.recycle() + return drawable +} + +/** + * Creates a color from the given attribute, If the attribute references a color resource holding a complex + * @link{android.content.res.ColorStateList}, then the default color from the set is returned. + * + * @param colorAttr attribute resource for color + * @return Attribute color value, or defValue if not defined. + * @throws UnsupportedOperationException if the attribute is defined but is + * not a color or drawable resource. + */ +fun Context.getCompatColorAttr(@AttrRes colorAttr : Int, defaultColor : Int = 0): Int { + val colorAttribute = obtainStyledAttributes(intArrayOf(colorAttr)) + @ColorInt val color = colorAttribute.getColor(0, defaultColor) + colorAttribute.recycle() + return color +} + +/** + * Starting in android Marshmallow, the returned + * color will be styled for the specified Context's theme. + * + * @see android.os.Build.VERSION_CODES.M + * @return A single color value in the form 0xAARRGGBB. + */ +fun Context.getCompatColor(@ColorRes colorRes: Int) = + ContextCompat.getColor(this, colorRes) + +/** + * Avoids resource not found when using vector drawables in API levels < Lollipop + * + * This method supports inflation of {@code }, {@code } and + * {@code } resources on devices where platform support is not available. + * + * @param resource The resource id of the drawable or vector drawable + * @see DrawableRes + * + * @return Drawable An object that can be used to draw this resource. + * @see Drawable + */ +fun Context.getCompatDrawable(@DrawableRes resource : Int) = + AppCompatResources.getDrawable(this, resource) + +/** + * Avoids resource not found when using vector drawables in API levels < Lollipop + * Also images loaded from this method apply the {@link Drawable#mutate()} to assure + * that the state of each drawable is not shared + * + * @param resource The resource id of the drawable or vector drawable + * @param tintColor A specific color to tint the drawable + * @return Drawable tinted with the tint color + */ +fun Context.getCompatDrawable(@DrawableRes resource : Int, @ColorRes tintColor : Int): Drawable? { + val drawableResource = AppCompatResources.getDrawable(this, resource) + if (drawableResource != null) { + val drawableResult = DrawableCompat.wrap(drawableResource).mutate() + if (tintColor != 0) + DrawableCompat.setTint(drawableResult, getCompatColor(tintColor)) + return drawableResource + } + return null +} + +/** + * Avoids resource not found when using vector drawables in API levels < Lollipop + * and tints the drawable depending on the current selected theme, images loaded + * from this method apply the {@link Drawable#mutate()} to assure that the state + * of each drawable is not shared + * + * @param resource The resource id of the drawable or vector drawable + * @param colorAttr A specific color to tint the drawable + * @return Drawable tinted with the tint color + */ +fun Context.getCompatTintedDrawable(@DrawableRes resource : Int, @AttrRes colorAttr : Int = R.attr.titleColor): Drawable? { + val originalDrawable = getCompatDrawable(resource) + var drawable : Drawable? = null + if (originalDrawable != null) { + drawable = DrawableCompat.wrap(originalDrawable).mutate() + DrawableCompat.setTint(drawable, getCompatColorAttr(colorAttr)) + } + return drawable +} \ 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..55211f70a --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/extension/CoroutineExt.kt @@ -0,0 +1,19 @@ +package com.mxt.anitrend.extension + +import kotlinx.coroutines.CoroutineExceptionHandler +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +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..e3513aecc --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/extension/KoinExt.kt @@ -0,0 +1,52 @@ +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") +} + +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/extension/SupportExt.kt b/app/src/main/java/com/mxt/anitrend/extension/SupportExt.kt new file mode 100644 index 000000000..3a3565df6 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/extension/SupportExt.kt @@ -0,0 +1,57 @@ +package com.mxt.anitrend.extension + + + +/** + * No locks are used to synchronize an access to the [Lazy] instance value; if the instance is accessed from multiple threads, + * its behavior is undefined. + * + * This mode should not be used unless the [Lazy] instance is guaranteed never to be initialized from more than one thread. + */ +val LAZY_MODE_UNSAFE = LazyThreadSafetyMode.NONE + +/** + * Initializer function can be called several times on concurrent access to uninitialized [Lazy] instance value, + * but only the first returned value will be used as the value of [Lazy] instance. + */ +val LAZY_MODE_PUBLICATION = LazyThreadSafetyMode.PUBLICATION + +/** + * Locks are used to ensure that only a single thread can initialize the [Lazy] instance. + */ +val LAZY_MODE_SYNCHRONIZED = LazyThreadSafetyMode.SYNCHRONIZED + +/** + * Potentially useless but returns an empty string, the signature may change in future + * + * @see String.isNullOrBlank + */ +fun String.Companion.empty() = "" + + +/** + * Returns a copy of this strings having its first letter uppercase, or the original string, + * if it's empty or already starts with an upper case letter. + * + * @param exceptions words or characters to exclude during capitalization + */ +fun String?.capitalizeWords(exceptions: List? = null): String = when { + !this.isNullOrEmpty() -> { + val result = StringBuilder(length) + val words = split("_|\\s".toRegex()).dropLastWhile { it.isEmpty() } + for ((index, word) in words.withIndex()) { + when (word.isNotEmpty()) { + true -> { + if (!exceptions.isNullOrEmpty() && exceptions.contains(word)) result.append(word) + else result.append(word.capitalize()) + } + } + if (index != words.size - 1) + result.append(" ") + } + result.toString() + } + else -> String.empty() +} + + 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..622cf9f87 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/koin/AppModule.kt @@ -0,0 +1,106 @@ +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.presenter.widget.WidgetPresenter +import com.mxt.anitrend.util.ConfigurationUtil +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 + +object AppModule : KoinComponent { + val appModule = module { + single { + MyObjectBox.builder() + .androidContext(androidContext()) + .build() + } + + single { + AnalyticsLogging( + context = androidContext(), + settings = get() + ) + } + + factory { + Settings(androidContext()) + } + + factory { + ConfigurationUtil() + } + + 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()) + } + } + + @JvmStatic + fun get(`class`: Class): T = getKoin().get( + `class`::class, + null, + null + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/mxt/anitrend/model/api/converter/AniGraphConverter.kt b/app/src/main/java/com/mxt/anitrend/model/api/converter/AniGraphConverter.kt new file mode 100644 index 000000000..4bef608e1 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/model/api/converter/AniGraphConverter.kt @@ -0,0 +1,97 @@ +package com.mxt.anitrend.model.api.converter + +import android.content.Context +import com.google.gson.ExclusionStrategy +import com.google.gson.FieldAttributes +import com.google.gson.GsonBuilder +import com.mxt.anitrend.model.api.converter.request.AniRequestConverter +import com.mxt.anitrend.model.api.converter.response.AniGraphResponseConverter +import io.github.wax911.library.converter.GraphConverter +import io.github.wax911.library.model.request.QueryContainerBuilder +import okhttp3.RequestBody +import okhttp3.ResponseBody +import retrofit2.Converter +import retrofit2.Retrofit +import java.lang.reflect.Type + +class AniGraphConverter( + context: Context? +) : GraphConverter(context) { + + /** + * Response body converter delegates logic processing to a child class that handles + * wrapping and deserialization of the json response data. + * + * @param parameterAnnotations All the annotation applied to request parameters + * @param methodAnnotations All the annotation applied to the requesting method + * @param retrofit The retrofit object representing the response + * @param type The type of the parameter of the request + * + * @see AniRequestConverter + */ + override fun requestBodyConverter( + type: Type?, + parameterAnnotations: Array, + methodAnnotations: Array, + retrofit: Retrofit? + ): Converter? = + AniRequestConverter( + methodAnnotations = methodAnnotations, + graphProcessor = graphProcessor, + gson = gson + ) + + /** + * Response body converter delegates logic processing to a child class that handles + * wrapping and deserialization of the json response data. + * @see GraphResponseConverter + *

+ * + * + * @param annotations All the annotation applied to the requesting Call method + * @see retrofit2.Call + * + * @param retrofit The retrofit object representing the response + * @param type The generic type declared on the Call method + */ + override fun responseBodyConverter( + type: Type?, + annotations: Array, + retrofit: Retrofit + ): Converter? = + AniGraphResponseConverter(type, gson) + + companion object { + + /** + * Allows you to provide your own Gson configuration which will be used when serialize or + * deserialize response and request bodies. + * + * @param context any valid application context + */ + fun create(context: Context?) = + AniGraphConverter(context).apply { + gson = GsonBuilder() + .addSerializationExclusionStrategy(object : ExclusionStrategy { + /** + * @param clazz the class object that is under test + * @return true if the class should be ignored; otherwise false + */ + override fun shouldSkipClass(clazz: Class<*>?) = false + + /** + * @param f the field object that is under test + * @return true if the field should be ignored; otherwise false + */ + override fun shouldSkipField(f: FieldAttributes?): Boolean { + return f?.name?.equals("operationName") ?: false + || + f?.name?.equals("extensions") ?: false + } + }) + .enableComplexMapKeySerialization() + .setLenient() + .create() + } + } +} \ No newline at end of file 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 deleted file mode 100644 index 9cd776fb8..000000000 --- a/app/src/main/java/com/mxt/anitrend/model/api/converter/GraphQLConverter.java +++ /dev/null @@ -1,112 +0,0 @@ -package com.mxt.anitrend.model.api.converter; - -import android.content.Context; -import android.support.annotation.NonNull; -import android.util.Log; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.mxt.anitrend.base.custom.annotation.processor.GraphProcessor; -import com.mxt.anitrend.model.entity.container.attribute.GraphError; -import com.mxt.anitrend.model.entity.container.body.DataContainer; -import com.mxt.anitrend.model.entity.container.body.GraphContainer; -import com.mxt.anitrend.model.entity.container.request.QueryContainer; -import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Type; - -import okhttp3.MediaType; -import okhttp3.RequestBody; -import okhttp3.ResponseBody; -import retrofit2.Converter; -import retrofit2.Retrofit; - -/** - * Created by max on 2017/10/22. - * Body for GraphQL requests and responses - */ - -public final class GraphQLConverter extends Converter.Factory { - - private GraphProcessor graphProcessor; - - private final Gson gson = new GsonBuilder() - .enableComplexMapKeySerialization() - .serializeNulls() - .setLenient() - .create(); - - public static GraphQLConverter create(Context context) { - return new GraphQLConverter(context); - } - - private GraphQLConverter(Context context) { - this.graphProcessor = GraphProcessor.getInstance(context); - } - - @Override - public Converter> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) { - return new GraphResponseConverter<>(type); - } - - @Override - public Converter requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) { - return new GraphRequestConverter(methodAnnotations); - } - - /** - * GraphQL response body converter to unwrap nested object results, - * resulting in a smaller generic tree for requests - */ - private class GraphResponseConverter implements Converter { - private Type type; - - GraphResponseConverter(Type type) { - this.type = type; - } - - @Override - public T convert(@NonNull ResponseBody responseBody) { - T targetResult = null; - String jsonResponse = null; - try { - jsonResponse = responseBody.string(); - GraphContainer container = gson.fromJson(jsonResponse, type); - if(!container.isEmpty() && !container.getData().isEmpty()) { - DataContainer dataContainer = container.getData(); - targetResult = dataContainer.getResult(); - } else - for (GraphError error: container.getErrors()) - Log.e(this.toString(), error.toString()); - } catch (Exception ex) { - ex.printStackTrace(); - Log.e("GraphQLConverter", jsonResponse); - } finally { - responseBody.close(); - } - return targetResult; - } - } - - /** - * GraphQL request body converter and injector, uses method annotation for a given retrofit call - */ - private class GraphRequestConverter implements Converter { - private Annotation[] methodAnnotations; - - GraphRequestConverter(Annotation[] methodAnnotations) { - this.methodAnnotations = methodAnnotations; - } - - @Override - public RequestBody convert(@NonNull QueryContainerBuilder containerBuilder) { - QueryContainer queryContainer = containerBuilder - .setQuery(graphProcessor.getQuery(methodAnnotations)) - .build(); - String queryJson = gson.toJson(queryContainer); - Log.d("GraphRequestConverter", queryJson); - return RequestBody.create(MediaType.parse("application/graphql"), queryJson); - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/mxt/anitrend/model/api/converter/request/AniGraphRequestConverter.kt b/app/src/main/java/com/mxt/anitrend/model/api/converter/request/AniGraphRequestConverter.kt new file mode 100644 index 000000000..9ae64bd67 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/model/api/converter/request/AniGraphRequestConverter.kt @@ -0,0 +1,56 @@ +package com.mxt.anitrend.model.api.converter.request + +import com.google.gson.Gson +import com.mxt.anitrend.BuildConfig +import io.github.wax911.library.annotation.processor.GraphProcessor +import io.github.wax911.library.converter.GraphConverter +import io.github.wax911.library.converter.request.GraphRequestConverter +import io.github.wax911.library.model.request.QueryContainerBuilder +import okhttp3.MediaType +import okhttp3.RequestBody +import timber.log.Timber + +class AniRequestConverter( + methodAnnotations: Array, + graphProcessor: GraphProcessor, + gson: Gson +) : GraphRequestConverter(methodAnnotations, graphProcessor, gson) { + + /** + * Converter for the request body, gets the GraphQL query from the method annotation + * and constructs a GraphQL request body to send over the network. + *

+ * + * @param containerBuilder The constructed builder method of your query with variables + * @return Request body + */ + override fun convert(containerBuilder: QueryContainerBuilder): RequestBody { + val rawPayload = graphProcessor.getQuery(methodAnnotations) + + /*val requestPayload = if (BuildConfig.DEBUG) rawPayload + else GraphUtil.minify(rawPayload)*/ + + val queryContainer = containerBuilder + .setQuery(rawPayload) + .build() + + //val queryContainerModified = queryContainer.apply { + // variables.forEach { + // if (it.value == null) + // this.variables.remove(it.key) + // } + //} + + val queryJson = gson.toJson(queryContainer) + if (BuildConfig.DEBUG) + Timber.tag(TAG).i(queryJson) + + // Because anilist won't recognize application/graphql as a valid content type! + return RequestBody.create(MediaType.parse(GraphConverter.MimeType), queryJson) + //return RequestBody.create(null, queryJson) + } + + companion object { + private val TAG = AniRequestConverter::class.java.simpleName + } +} \ No newline at end of file diff --git a/app/src/main/java/com/mxt/anitrend/model/api/converter/response/AniGraphResponseConverter.kt b/app/src/main/java/com/mxt/anitrend/model/api/converter/response/AniGraphResponseConverter.kt new file mode 100644 index 000000000..43568e7de --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/model/api/converter/response/AniGraphResponseConverter.kt @@ -0,0 +1,51 @@ +package com.mxt.anitrend.model.api.converter.response + +import com.google.gson.Gson +import com.mxt.anitrend.model.entity.container.body.AniListContainer +import io.github.wax911.library.converter.response.GraphResponseConverter +import okhttp3.ResponseBody +import timber.log.Timber +import java.lang.reflect.Type + +class AniGraphResponseConverter( + type: Type?, + gson: Gson +) : GraphResponseConverter(type, gson) { + + /** + * Converter contains logic on how to handle responses, since GraphQL responses follow + * the JsonAPI spec it makes sense to wrap our base query response data and errors response + * in here, the logic remains open to the implementation + *

+ * + * @param responseBody The retrofit response body received from the network + * @return The type declared in the Call of the request + */ + override fun convert(responseBody: ResponseBody): T? { + var targetResult: T? = null + var jsonResponse: String? = null + try { + responseBody.use { + jsonResponse = it.string() + } + val container = gson.fromJson>( + jsonResponse, type + ) + if (container?.data != null) { + val dataContainer = container.data + targetResult = dataContainer.result + } else + container?.errors?.forEach { + Timber.tag(TAG).e(it.message) + } + } catch (ex: Exception) { + ex.printStackTrace() + Timber.tag(TAG).e(ex, jsonResponse?:"Json response is null") + } + return targetResult + } + + companion object { + private val TAG = AniGraphResponseConverter::class.java.simpleName + } +} \ No newline at end of file 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..1f4e11ff4 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 @@ -1,17 +1,13 @@ package com.mxt.anitrend.model.api.interceptor import android.content.Context -import android.util.Log - import com.mxt.anitrend.BuildConfig import com.mxt.anitrend.base.custom.async.WebTokenRequest -import com.mxt.anitrend.util.ApplicationPref - -import java.io.IOException - +import com.mxt.anitrend.util.Settings import okhttp3.Interceptor -import okhttp3.Request import okhttp3.Response +import timber.log.Timber +import java.io.IOException /** * Created by max on 2017/06/14. @@ -21,7 +17,7 @@ import okhttp3.Response class AuthInterceptor(context: Context) : Interceptor { private val applicationPref by lazy { - ApplicationPref(context) + Settings(context) } @Throws(IOException::class) @@ -33,7 +29,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/interceptor/CacheInterceptor.kt b/app/src/main/java/com/mxt/anitrend/model/api/interceptor/CacheInterceptor.kt index a68943ed5..3346c6045 100644 --- a/app/src/main/java/com/mxt/anitrend/model/api/interceptor/CacheInterceptor.kt +++ b/app/src/main/java/com/mxt/anitrend/model/api/interceptor/CacheInterceptor.kt @@ -1,16 +1,12 @@ package com.mxt.anitrend.model.api.interceptor import android.content.Context - import com.mxt.anitrend.util.CompatUtil - -import java.io.IOException -import java.util.concurrent.TimeUnit - import okhttp3.CacheControl import okhttp3.Interceptor -import okhttp3.Request import okhttp3.Response +import java.io.IOException +import java.util.concurrent.TimeUnit /** * Created by max on 2017/06/14. diff --git a/app/src/main/java/com/mxt/anitrend/model/api/interceptor/NetworkCacheInterceptor.kt b/app/src/main/java/com/mxt/anitrend/model/api/interceptor/NetworkCacheInterceptor.kt index 5fda99720..3b6220037 100644 --- a/app/src/main/java/com/mxt/anitrend/model/api/interceptor/NetworkCacheInterceptor.kt +++ b/app/src/main/java/com/mxt/anitrend/model/api/interceptor/NetworkCacheInterceptor.kt @@ -1,15 +1,12 @@ package com.mxt.anitrend.model.api.interceptor import android.content.Context - import com.mxt.anitrend.util.CompatUtil - -import java.io.IOException -import java.util.concurrent.TimeUnit - import okhttp3.CacheControl import okhttp3.Interceptor import okhttp3.Response +import java.io.IOException +import java.util.concurrent.TimeUnit /** * Created by max on 2017/07/17. 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..dbdcef35a 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,16 +1,15 @@ package com.mxt.anitrend.model.api.retro; import android.content.Context; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.mxt.anitrend.BuildConfig; -import com.mxt.anitrend.base.custom.annotation.processor.GraphProcessor; import com.mxt.anitrend.base.custom.async.WebTokenRequest; -import com.mxt.anitrend.model.api.converter.GraphQLConverter; +import com.mxt.anitrend.model.api.converter.AniGraphConverter; import com.mxt.anitrend.model.api.interceptor.AuthInterceptor; import com.mxt.anitrend.model.api.interceptor.CacheInterceptor; import com.mxt.anitrend.model.api.interceptor.NetworkCacheInterceptor; @@ -20,8 +19,8 @@ import com.mxt.anitrend.model.api.retro.crunchy.EpisodeModel; import com.mxt.anitrend.model.entity.anilist.WebToken; import com.mxt.anitrend.util.CompatUtil; -import com.mxt.anitrend.util.ErrorUtil; import com.mxt.anitrend.util.KeyUtil; +import com.mxt.anitrend.util.graphql.AniGraphErrorUtilKt; import java.util.concurrent.TimeUnit; @@ -33,6 +32,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. @@ -90,13 +90,12 @@ private static OkHttpClient.Builder createHttpClient(@Nullable Interceptor inter */ public static S createService(@NonNull Class serviceClass, Context context) { WebTokenRequest.getToken(context); - 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)) + .addConverterFactory(AniGraphConverter.Companion.create(context)) .baseUrl(BuildConfig.API_LINK) .build(); } @@ -106,7 +105,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 +116,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 +126,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 +136,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,9 +146,10 @@ public static RepositoryModel createRepositoryService() { Response response = refreshTokenCall.execute(); if(!response.isSuccessful()) - Log.e("requestCodeTokenSync", ErrorUtil.INSTANCE.getError(response)); + Timber.tag("requestCodeTokenSync").w(AniGraphErrorUtilKt.apiError(response)); return response.body(); } catch (Exception ex) { + Timber.tag("requestCodeTokenSync").e(ex); ex.printStackTrace(); return null; } diff --git a/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/AuthModel.java b/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/AuthModel.java deleted file mode 100644 index 07987781a..000000000 --- a/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/AuthModel.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.mxt.anitrend.model.api.retro.anilist; - -import com.mxt.anitrend.model.entity.anilist.WebToken; - -import retrofit2.Call; -import retrofit2.http.Field; -import retrofit2.http.FormUrlEncoded; -import retrofit2.http.POST; - -/** - * Created by max on 2017/10/14. - * Authentication endpoints - */ - -public interface AuthModel { - - /** - * If the resource owner accepts the client, they will be redirected to the client’s redirected uri. - * A code parameter will be included in the redirect uri, this is not the access token, - * but instead the authorization code which will be exchanged for the access token in the next step. - * - * @param code Authorization code from previous request - */ - @FormUrlEncoded - @POST("token") - Call getAuthRequest(@Field("grant_type") String grant_type, - @Field("client_id") String client_id, - @Field("client_secret") String client_secret, - @Field("redirect_uri") String redirect_uri, - @Field("code") String code); -} diff --git a/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/AuthModel.kt b/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/AuthModel.kt new file mode 100644 index 000000000..a809823f0 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/AuthModel.kt @@ -0,0 +1,31 @@ +package com.mxt.anitrend.model.api.retro.anilist + +import com.mxt.anitrend.model.entity.anilist.WebToken + +import retrofit2.Call +import retrofit2.http.Field +import retrofit2.http.FormUrlEncoded +import retrofit2.http.POST + +/** + * Created by max on 2017/10/14. + * Authentication endpoints + */ + +interface AuthModel { + + /** + * If the resource owner accepts the client, they will be redirected to the client’s redirected uri. + * A code parameter will be included in the redirect uri, this is not the access token, + * but instead the authorization code which will be exchanged for the access token in the next step. + * + * @param code Authorization code from previous request + */ + @FormUrlEncoded + @POST("token") + fun getAuthRequest(@Field("grant_type") grant_type: String, + @Field("client_id") client_id: String, + @Field("client_secret") client_secret: String, + @Field("redirect_uri") redirect_uri: String, + @Field("code") code: String): Call +} diff --git a/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/BaseModel.java b/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/BaseModel.java deleted file mode 100644 index 8eb1021c2..000000000 --- a/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/BaseModel.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.mxt.anitrend.model.api.retro.anilist; - -import com.mxt.anitrend.base.custom.annotation.GraphQuery; -import com.mxt.anitrend.model.entity.anilist.MediaTag; -import com.mxt.anitrend.model.entity.base.UserBase; -import com.mxt.anitrend.model.entity.container.body.GraphContainer; -import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder; - -import java.util.List; - -import okhttp3.ResponseBody; -import retrofit2.Call; -import retrofit2.http.Body; -import retrofit2.http.Headers; -import retrofit2.http.POST; - -/** - * Created by max on 2018/03/20. - */ - -public interface BaseModel { - - @POST("/") - @GraphQuery("Genres") - @Headers("Content-Type: application/json") - Call>> getGenres(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("Tags") - @Headers("Content-Type: application/json") - Call>> getTags(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("ToggleLike") - @Headers("Content-Type: application/json") - Call>> toggleLike(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("ToggleFavourite") - @Headers("Content-Type: application/json") - Call toggleFavourite(@Body QueryContainerBuilder request); -} diff --git a/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/BaseModel.kt b/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/BaseModel.kt new file mode 100644 index 000000000..c2d959548 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/BaseModel.kt @@ -0,0 +1,39 @@ +package com.mxt.anitrend.model.api.retro.anilist + +import com.mxt.anitrend.model.entity.anilist.MediaTag +import com.mxt.anitrend.model.entity.base.UserBase +import com.mxt.anitrend.model.entity.container.body.AniListContainer +import io.github.wax911.library.annotation.GraphQuery +import io.github.wax911.library.model.request.QueryContainerBuilder +import okhttp3.ResponseBody +import retrofit2.Call +import retrofit2.http.Body +import retrofit2.http.Headers +import retrofit2.http.POST + +/** + * Created by max on 2018/03/20. + */ + +interface BaseModel { + + @POST("/") + @GraphQuery("Genres") + @Headers("Content-Type: application/json") + fun getGenres(@Body request: QueryContainerBuilder?): Call>> + + @POST("/") + @GraphQuery("Tags") + @Headers("Content-Type: application/json") + fun getTags(@Body request: QueryContainerBuilder?): Call>> + + @POST("/") + @GraphQuery("ToggleLike") + @Headers("Content-Type: application/json") + fun toggleLike(@Body request: QueryContainerBuilder?): Call>> + + @POST("/") + @GraphQuery("ToggleFavourite") + @Headers("Content-Type: application/json") + fun toggleFavourite(@Body request: QueryContainerBuilder?): Call +} diff --git a/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/BrowseModel.java b/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/BrowseModel.java deleted file mode 100644 index 084fea786..000000000 --- a/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/BrowseModel.java +++ /dev/null @@ -1,85 +0,0 @@ -package com.mxt.anitrend.model.api.retro.anilist; - -import com.mxt.anitrend.base.custom.annotation.GraphQuery; -import com.mxt.anitrend.model.entity.anilist.MediaList; -import com.mxt.anitrend.model.entity.anilist.MediaListCollection; -import com.mxt.anitrend.model.entity.anilist.Review; -import com.mxt.anitrend.model.entity.anilist.meta.DeleteState; -import com.mxt.anitrend.model.entity.base.MediaBase; -import com.mxt.anitrend.model.entity.container.body.GraphContainer; -import com.mxt.anitrend.model.entity.container.body.PageContainer; -import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder; - -import java.util.List; - -import retrofit2.Call; -import retrofit2.http.Body; -import retrofit2.http.Headers; -import retrofit2.http.POST; - -/** - * Created by max on 2018/03/20. - */ - -public interface BrowseModel { - - @POST("/") - @GraphQuery("MediaListCollection") - @Headers("Content-Type: application/json") - Call>> getMediaListCollection(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("MediaBrowse") - @Headers("Content-Type: application/json") - Call>> getMediaBrowse(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("ReviewBrowse") - @Headers("Content-Type: application/json") - Call>> getReviewBrowse(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("MediaListBrowse") - @Headers("Content-Type: application/json") - Call>> getMediaListBrowse(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("MediaList") - @Headers("Content-Type: application/json") - Call> getMediaList(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("MediaWithList") - @Headers("Content-Type: application/json") - Call> getMediaWithList(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("DeleteMediaListEntry") - @Headers("Content-Type: application/json") - Call> deleteMediaListEntry(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("DeleteReview") - @Headers("Content-Type: application/json") - Call> deleteReview(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("SaveMediaListEntry") - @Headers("Content-Type: application/json") - Call> saveMediaListEntry(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("UpdateMediaListEntries") - @Headers("Content-Type: application/json") - Call>> updateMediaListEntries(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("RateReview") - @Headers("Content-Type: application/json") - Call> rateReview(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("SaveReview") - @Headers("Content-Type: application/json") - Call> saveReview(@Body QueryContainerBuilder request); -} diff --git a/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/BrowseModel.kt b/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/BrowseModel.kt new file mode 100644 index 000000000..7076728d9 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/BrowseModel.kt @@ -0,0 +1,82 @@ +package com.mxt.anitrend.model.api.retro.anilist + +import com.mxt.anitrend.model.entity.anilist.MediaList +import com.mxt.anitrend.model.entity.anilist.MediaListCollection +import com.mxt.anitrend.model.entity.anilist.Review +import com.mxt.anitrend.model.entity.anilist.meta.DeleteState +import com.mxt.anitrend.model.entity.base.MediaBase +import com.mxt.anitrend.model.entity.container.body.AniListContainer +import com.mxt.anitrend.model.entity.container.body.PageContainer +import io.github.wax911.library.annotation.GraphQuery +import io.github.wax911.library.model.request.QueryContainerBuilder +import retrofit2.Call +import retrofit2.http.Body +import retrofit2.http.Headers +import retrofit2.http.POST + +/** + * Created by max on 2018/03/20. + */ + +interface BrowseModel { + + @POST("/") + @GraphQuery("MediaListCollection") + @Headers("Content-Type: application/json") + fun getMediaListCollection(@Body request: QueryContainerBuilder?): Call>> + + @POST("/") + @GraphQuery("MediaBrowse") + @Headers("Content-Type: application/json") + fun getMediaBrowse(@Body request: QueryContainerBuilder?): Call>> + + @POST("/") + @GraphQuery("ReviewBrowse") + @Headers("Content-Type: application/json") + fun getReviewBrowse(@Body request: QueryContainerBuilder?): Call>> + + @POST("/") + @GraphQuery("MediaListBrowse") + @Headers("Content-Type: application/json") + fun getMediaListBrowse(@Body request: QueryContainerBuilder?): Call>> + + @POST("/") + @GraphQuery("MediaList") + @Headers("Content-Type: application/json") + fun getMediaList(@Body request: QueryContainerBuilder?): Call> + + @POST("/") + @GraphQuery("MediaWithList") + @Headers("Content-Type: application/json") + fun getMediaWithList(@Body request: QueryContainerBuilder?): Call> + + @POST("/") + @GraphQuery("DeleteMediaListEntry") + @Headers("Content-Type: application/json") + fun deleteMediaListEntry(@Body request: QueryContainerBuilder?): Call> + + @POST("/") + @GraphQuery("DeleteReview") + @Headers("Content-Type: application/json") + fun deleteReview(@Body request: QueryContainerBuilder?): Call> + + @POST("/") + @GraphQuery("SaveMediaListEntry") + @Headers("Content-Type: application/json") + fun saveMediaListEntry(@Body request: QueryContainerBuilder?): Call> + + @POST("/") + @GraphQuery("UpdateMediaListEntries") + @Headers("Content-Type: application/json") + fun updateMediaListEntries(@Body request: QueryContainerBuilder?): Call>> + + @POST("/") + @GraphQuery("RateReview") + @Headers("Content-Type: application/json") + fun rateReview(@Body request: QueryContainerBuilder?): Call> + + @POST("/") + @GraphQuery("SaveReview") + @Headers("Content-Type: application/json") + fun saveReview(@Body request: QueryContainerBuilder?): Call> +} diff --git a/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/CharacterModel.java b/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/CharacterModel.java deleted file mode 100644 index 4d936211c..000000000 --- a/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/CharacterModel.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.mxt.anitrend.model.api.retro.anilist; - -import com.mxt.anitrend.base.custom.annotation.GraphQuery; -import com.mxt.anitrend.model.entity.anilist.MediaCharacter; -import com.mxt.anitrend.model.entity.anilist.edge.MediaEdge; -import com.mxt.anitrend.model.entity.base.CharacterBase; -import com.mxt.anitrend.model.entity.base.MediaBase; -import com.mxt.anitrend.model.entity.container.body.ConnectionContainer; -import com.mxt.anitrend.model.entity.container.body.EdgeContainer; -import com.mxt.anitrend.model.entity.container.body.GraphContainer; -import com.mxt.anitrend.model.entity.container.body.PageContainer; -import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder; - -import retrofit2.Call; -import retrofit2.http.Body; -import retrofit2.http.Headers; -import retrofit2.http.POST; - -/** - * Created by max on 2018/03/20. - * Character relation queries - */ - -public interface CharacterModel { - - @POST("/") - @GraphQuery("CharacterBase") - @Headers("Content-Type: application/json") - Call>getCharacterBase(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("CharacterOverview") - @Headers("Content-Type: application/json") - Call> getCharacterOverview(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("CharacterMedia") - @Headers("Content-Type: application/json") - Call>>> getCharacterMedia(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("CharacterActors") - @Headers("Content-Type: application/json") - Call>>> getCharacterActors(@Body QueryContainerBuilder request); -} diff --git a/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/CharacterModel.kt b/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/CharacterModel.kt new file mode 100644 index 000000000..f6f86b138 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/CharacterModel.kt @@ -0,0 +1,44 @@ +package com.mxt.anitrend.model.api.retro.anilist + +import com.mxt.anitrend.model.entity.anilist.MediaCharacter +import com.mxt.anitrend.model.entity.anilist.edge.MediaEdge +import com.mxt.anitrend.model.entity.base.CharacterBase +import com.mxt.anitrend.model.entity.base.MediaBase +import com.mxt.anitrend.model.entity.container.body.AniListContainer +import com.mxt.anitrend.model.entity.container.body.ConnectionContainer +import com.mxt.anitrend.model.entity.container.body.EdgeContainer +import com.mxt.anitrend.model.entity.container.body.PageContainer +import io.github.wax911.library.annotation.GraphQuery +import io.github.wax911.library.model.request.QueryContainerBuilder +import retrofit2.Call +import retrofit2.http.Body +import retrofit2.http.Headers +import retrofit2.http.POST + +/** + * Created by max on 2018/03/20. + * Character relation queries + */ + +interface CharacterModel { + + @POST("/") + @GraphQuery("CharacterBase") + @Headers("Content-Type: application/json") + fun getCharacterBase(@Body request: QueryContainerBuilder?): Call> + + @POST("/") + @GraphQuery("CharacterOverview") + @Headers("Content-Type: application/json") + fun getCharacterOverview(@Body request: QueryContainerBuilder?): Call> + + @POST("/") + @GraphQuery("CharacterMedia") + @Headers("Content-Type: application/json") + fun getCharacterMedia(@Body request: QueryContainerBuilder?): Call>>> + + @POST("/") + @GraphQuery("CharacterActors") + @Headers("Content-Type: application/json") + fun getCharacterActors(@Body request: QueryContainerBuilder?): Call>>> +} diff --git a/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/FeedModel.java b/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/FeedModel.java deleted file mode 100644 index 841f68eac..000000000 --- a/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/FeedModel.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.mxt.anitrend.model.api.retro.anilist; - -import com.mxt.anitrend.base.custom.annotation.GraphQuery; -import com.mxt.anitrend.model.entity.anilist.FeedList; -import com.mxt.anitrend.model.entity.anilist.FeedReply; -import com.mxt.anitrend.model.entity.anilist.meta.DeleteState; -import com.mxt.anitrend.model.entity.container.body.GraphContainer; -import com.mxt.anitrend.model.entity.container.body.PageContainer; -import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder; - -import retrofit2.Call; -import retrofit2.http.Body; -import retrofit2.http.Headers; -import retrofit2.http.POST; - -/** - * Created by max on 2018/03/20. - * Feed model queries - */ - -public interface FeedModel { - - @POST("/") - @GraphQuery("FeedList") - @Headers("Content-Type: application/json") - Call>> getFeedList(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("FeedListReply") - @Headers("Content-Type: application/json") - Call> getFeedListReply(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("FeedMessage") - @Headers("Content-Type: application/json") - Call>> getFeedMessage(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("SaveTextActivity") - @Headers("Content-Type: application/json") - Call> saveTextActivity(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("SaveMessageActivity") - @Headers("Content-Type: application/json") - Call> saveMessageActivity(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("SaveActivityReply") - @Headers("Content-Type: application/json") - Call> saveActivityReply(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("DeleteActivity") - @Headers("Content-Type: application/json") - Call> deleteActivity(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("DeleteActivityReply") - @Headers("Content-Type: application/json") - Call> deleteActivityReply(@Body QueryContainerBuilder request); -} diff --git a/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/FeedModel.kt b/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/FeedModel.kt new file mode 100644 index 000000000..f8ae2aac4 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/FeedModel.kt @@ -0,0 +1,61 @@ +package com.mxt.anitrend.model.api.retro.anilist + +import com.mxt.anitrend.model.entity.anilist.FeedList +import com.mxt.anitrend.model.entity.anilist.FeedReply +import com.mxt.anitrend.model.entity.anilist.meta.DeleteState +import com.mxt.anitrend.model.entity.container.body.AniListContainer +import com.mxt.anitrend.model.entity.container.body.PageContainer +import io.github.wax911.library.annotation.GraphQuery +import io.github.wax911.library.model.request.QueryContainerBuilder +import retrofit2.Call +import retrofit2.http.Body +import retrofit2.http.Headers +import retrofit2.http.POST + +/** + * Created by max on 2018/03/20. + * Feed model queries + */ + +interface FeedModel { + + @POST("/") + @GraphQuery("FeedList") + @Headers("Content-Type: application/json") + fun getFeedList(@Body request: QueryContainerBuilder?): Call>> + + @POST("/") + @GraphQuery("FeedListReply") + @Headers("Content-Type: application/json") + fun getFeedListReply(@Body request: QueryContainerBuilder?): Call> + + @POST("/") + @GraphQuery("FeedMessage") + @Headers("Content-Type: application/json") + fun getFeedMessage(@Body request: QueryContainerBuilder?): Call>> + + @POST("/") + @GraphQuery("SaveTextActivity") + @Headers("Content-Type: application/json") + fun saveTextActivity(@Body request: QueryContainerBuilder?): Call> + + @POST("/") + @GraphQuery("SaveMessageActivity") + @Headers("Content-Type: application/json") + fun saveMessageActivity(@Body request: QueryContainerBuilder?): Call> + + @POST("/") + @GraphQuery("SaveActivityReply") + @Headers("Content-Type: application/json") + fun saveActivityReply(@Body request: QueryContainerBuilder?): Call> + + @POST("/") + @GraphQuery("DeleteActivity") + @Headers("Content-Type: application/json") + fun deleteActivity(@Body request: QueryContainerBuilder?): Call> + + @POST("/") + @GraphQuery("DeleteActivityReply") + @Headers("Content-Type: application/json") + fun deleteActivityReply(@Body request: QueryContainerBuilder?): Call> +} diff --git a/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/MediaModel.java b/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/MediaModel.java deleted file mode 100644 index c006e77a8..000000000 --- a/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/MediaModel.java +++ /dev/null @@ -1,70 +0,0 @@ -package com.mxt.anitrend.model.api.retro.anilist; - -import com.mxt.anitrend.base.custom.annotation.GraphQuery; -import com.mxt.anitrend.model.entity.anilist.ExternalLink; -import com.mxt.anitrend.model.entity.anilist.FeedList; -import com.mxt.anitrend.model.entity.anilist.Media; -import com.mxt.anitrend.model.entity.anilist.edge.CharacterEdge; -import com.mxt.anitrend.model.entity.anilist.edge.MediaEdge; -import com.mxt.anitrend.model.entity.anilist.edge.StaffEdge; -import com.mxt.anitrend.model.entity.base.MediaBase; -import com.mxt.anitrend.model.entity.container.body.ConnectionContainer; -import com.mxt.anitrend.model.entity.container.body.EdgeContainer; -import com.mxt.anitrend.model.entity.container.body.GraphContainer; -import com.mxt.anitrend.model.entity.container.body.PageContainer; -import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder; - -import java.util.List; - -import retrofit2.Call; -import retrofit2.http.Body; -import retrofit2.http.Headers; -import retrofit2.http.POST; - -/** - * Created by max on 2018/03/20. - * Series queries - */ - -public interface MediaModel { - - @POST("/") - @GraphQuery("MediaBase") - @Headers("Content-Type: application/json") - Call> getMediaBase(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("MediaOverview") - @Headers("Content-Type: application/json") - Call> getMediaOverview(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("MediaRelations") - @Headers("Content-Type: application/json") - Call>>> getMediaRelations(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("MediaStats") - @Headers("Content-Type: application/json") - Call> getMediaStats(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("MediaEpisodes") - @Headers("Content-Type: application/json") - Call>>> getMediaEpisodes(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("MediaCharacters") - @Headers("Content-Type: application/json") - Call>>> getMediaCharacters(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("MediaStaff") - @Headers("Content-Type: application/json") - Call>>> getMediaStaff(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("MediaSocial") - @Headers("Content-Type: application/json") - Call>> getMediaSocial(@Body QueryContainerBuilder request); -} diff --git a/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/MediaModel.kt b/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/MediaModel.kt new file mode 100644 index 000000000..f76789119 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/MediaModel.kt @@ -0,0 +1,67 @@ +package com.mxt.anitrend.model.api.retro.anilist + +import com.mxt.anitrend.model.entity.anilist.ExternalLink +import com.mxt.anitrend.model.entity.anilist.FeedList +import com.mxt.anitrend.model.entity.anilist.Media +import com.mxt.anitrend.model.entity.anilist.edge.CharacterEdge +import com.mxt.anitrend.model.entity.anilist.edge.MediaEdge +import com.mxt.anitrend.model.entity.anilist.edge.StaffEdge +import com.mxt.anitrend.model.entity.base.MediaBase +import com.mxt.anitrend.model.entity.container.body.AniListContainer +import com.mxt.anitrend.model.entity.container.body.ConnectionContainer +import com.mxt.anitrend.model.entity.container.body.EdgeContainer +import com.mxt.anitrend.model.entity.container.body.PageContainer +import io.github.wax911.library.annotation.GraphQuery +import io.github.wax911.library.model.request.QueryContainerBuilder +import retrofit2.Call +import retrofit2.http.Body +import retrofit2.http.Headers +import retrofit2.http.POST + +/** + * Created by max on 2018/03/20. + * Series queries + */ + +interface MediaModel { + + @POST("/") + @GraphQuery("MediaBase") + @Headers("Content-Type: application/json") + fun getMediaBase(@Body request: QueryContainerBuilder?): Call> + + @POST("/") + @GraphQuery("MediaOverview") + @Headers("Content-Type: application/json") + fun getMediaOverview(@Body request: QueryContainerBuilder?): Call> + + @POST("/") + @GraphQuery("MediaRelations") + @Headers("Content-Type: application/json") + fun getMediaRelations(@Body request: QueryContainerBuilder?): Call>>> + + @POST("/") + @GraphQuery("MediaStats") + @Headers("Content-Type: application/json") + fun getMediaStats(@Body request: QueryContainerBuilder?): Call> + + @POST("/") + @GraphQuery("MediaEpisodes") + @Headers("Content-Type: application/json") + fun getMediaEpisodes(@Body request: QueryContainerBuilder?): Call>>> + + @POST("/") + @GraphQuery("MediaCharacters") + @Headers("Content-Type: application/json") + fun getMediaCharacters(@Body request: QueryContainerBuilder?): Call>>> + + @POST("/") + @GraphQuery("MediaStaff") + @Headers("Content-Type: application/json") + fun getMediaStaff(@Body request: QueryContainerBuilder?): Call>>> + + @POST("/") + @GraphQuery("MediaSocial") + @Headers("Content-Type: application/json") + fun getMediaSocial(@Body request: QueryContainerBuilder?): Call>> +} diff --git a/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/SearchModel.java b/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/SearchModel.java deleted file mode 100644 index 16f00ce09..000000000 --- a/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/SearchModel.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.mxt.anitrend.model.api.retro.anilist; - -import com.mxt.anitrend.base.custom.annotation.GraphQuery; -import com.mxt.anitrend.model.entity.base.CharacterBase; -import com.mxt.anitrend.model.entity.base.MediaBase; -import com.mxt.anitrend.model.entity.base.StaffBase; -import com.mxt.anitrend.model.entity.base.StudioBase; -import com.mxt.anitrend.model.entity.base.UserBase; -import com.mxt.anitrend.model.entity.container.body.GraphContainer; -import com.mxt.anitrend.model.entity.container.body.PageContainer; -import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder; - -import retrofit2.Call; -import retrofit2.http.Body; -import retrofit2.http.Headers; -import retrofit2.http.POST; - -/** - * Created by max on 2018/03/20. - * Search queries - */ - -public interface SearchModel { - - @POST("/") - @GraphQuery("MediaSearch") - @Headers("Content-Type: application/json") - Call>> getMediaSearch(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("StudioSearch") - @Headers("Content-Type: application/json") - Call>> getStudioSearch(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("StaffSearch") - @Headers("Content-Type: application/json") - Call>> getStaffSearch(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("CharacterSearch") - @Headers("Content-Type: application/json") - Call>> getCharacterSearch(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("UserSearch") - @Headers("Content-Type: application/json") - Call>> getUserSearch(@Body QueryContainerBuilder request); -} diff --git a/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/SearchModel.kt b/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/SearchModel.kt new file mode 100644 index 000000000..1d03d3526 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/SearchModel.kt @@ -0,0 +1,44 @@ +package com.mxt.anitrend.model.api.retro.anilist + +import com.mxt.anitrend.model.entity.base.* +import com.mxt.anitrend.model.entity.container.body.AniListContainer +import com.mxt.anitrend.model.entity.container.body.PageContainer +import io.github.wax911.library.annotation.GraphQuery +import io.github.wax911.library.model.request.QueryContainerBuilder +import retrofit2.Call +import retrofit2.http.Body +import retrofit2.http.Headers +import retrofit2.http.POST + +/** + * Created by max on 2018/03/20. + * Search queries + */ + +interface SearchModel { + + @POST("/") + @GraphQuery("MediaSearch") + @Headers("Content-Type: application/json") + fun getMediaSearch(@Body request: QueryContainerBuilder?): Call>> + + @POST("/") + @GraphQuery("StudioSearch") + @Headers("Content-Type: application/json") + fun getStudioSearch(@Body request: QueryContainerBuilder?): Call>> + + @POST("/") + @GraphQuery("StaffSearch") + @Headers("Content-Type: application/json") + fun getStaffSearch(@Body request: QueryContainerBuilder?): Call>> + + @POST("/") + @GraphQuery("CharacterSearch") + @Headers("Content-Type: application/json") + fun getCharacterSearch(@Body request: QueryContainerBuilder?): Call>> + + @POST("/") + @GraphQuery("UserSearch") + @Headers("Content-Type: application/json") + fun getUserSearch(@Body request: QueryContainerBuilder?): Call>> +} diff --git a/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/StaffModel.java b/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/StaffModel.java deleted file mode 100644 index df9cc7865..000000000 --- a/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/StaffModel.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.mxt.anitrend.model.api.retro.anilist; - -import com.mxt.anitrend.base.custom.annotation.GraphQuery; -import com.mxt.anitrend.model.entity.anilist.edge.MediaEdge; -import com.mxt.anitrend.model.entity.base.MediaBase; -import com.mxt.anitrend.model.entity.base.StaffBase; -import com.mxt.anitrend.model.entity.container.body.ConnectionContainer; -import com.mxt.anitrend.model.entity.container.body.EdgeContainer; -import com.mxt.anitrend.model.entity.container.body.GraphContainer; -import com.mxt.anitrend.model.entity.container.body.PageContainer; -import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder; - -import retrofit2.Call; -import retrofit2.http.Body; -import retrofit2.http.Headers; -import retrofit2.http.POST; - -/** - * Created by max on 2018/03/20. - * Staff queries - */ - -public interface StaffModel { - - @POST("/") - @GraphQuery("StaffBase") - @Headers("Content-Type: application/json") - Call> getStaffBase(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("StaffOverview") - @Headers("Content-Type: application/json") - Call> getStaffOverview(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("StaffMedia") - @Headers("Content-Type: application/json") - Call>>> getStaffMedia(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("StaffRoles") - @Headers("Content-Type: application/json") - Call>>> getStaffRoles(@Body QueryContainerBuilder request); -} diff --git a/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/StaffModel.kt b/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/StaffModel.kt new file mode 100644 index 000000000..bf89c61c9 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/StaffModel.kt @@ -0,0 +1,43 @@ +package com.mxt.anitrend.model.api.retro.anilist + +import com.mxt.anitrend.model.entity.anilist.edge.MediaEdge +import com.mxt.anitrend.model.entity.base.MediaBase +import com.mxt.anitrend.model.entity.base.StaffBase +import com.mxt.anitrend.model.entity.container.body.AniListContainer +import com.mxt.anitrend.model.entity.container.body.ConnectionContainer +import com.mxt.anitrend.model.entity.container.body.EdgeContainer +import com.mxt.anitrend.model.entity.container.body.PageContainer +import io.github.wax911.library.annotation.GraphQuery +import io.github.wax911.library.model.request.QueryContainerBuilder +import retrofit2.Call +import retrofit2.http.Body +import retrofit2.http.Headers +import retrofit2.http.POST + +/** + * Created by max on 2018/03/20. + * Staff queries + */ + +interface StaffModel { + + @POST("/") + @GraphQuery("StaffBase") + @Headers("Content-Type: application/json") + fun getStaffBase(@Body request: QueryContainerBuilder?): Call> + + @POST("/") + @GraphQuery("StaffOverview") + @Headers("Content-Type: application/json") + fun getStaffOverview(@Body request: QueryContainerBuilder?): Call> + + @POST("/") + @GraphQuery("StaffMedia") + @Headers("Content-Type: application/json") + fun getStaffMedia(@Body request: QueryContainerBuilder?): Call>>> + + @POST("/") + @GraphQuery("StaffRoles") + @Headers("Content-Type: application/json") + fun getStaffRoles(@Body request: QueryContainerBuilder?): Call>>> +} diff --git a/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/StudioModel.java b/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/StudioModel.java deleted file mode 100644 index 3151dcda6..000000000 --- a/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/StudioModel.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.mxt.anitrend.model.api.retro.anilist; - -import com.mxt.anitrend.base.custom.annotation.GraphQuery; -import com.mxt.anitrend.model.entity.base.MediaBase; -import com.mxt.anitrend.model.entity.base.StudioBase; -import com.mxt.anitrend.model.entity.container.body.ConnectionContainer; -import com.mxt.anitrend.model.entity.container.body.GraphContainer; -import com.mxt.anitrend.model.entity.container.body.PageContainer; -import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder; - -import retrofit2.Call; -import retrofit2.http.Body; -import retrofit2.http.Headers; -import retrofit2.http.POST; - -/** - * Created by max on 2018/03/20. - * Studio queries - */ - -public interface StudioModel { - - @POST("/") - @GraphQuery("StudioBase") - @Headers("Content-Type: application/json") - Call> getStudioBase(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("StudioMedia") - @Headers("Content-Type: application/json") - Call>>> getStudioMedia(@Body QueryContainerBuilder request); -} diff --git a/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/StudioModel.kt b/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/StudioModel.kt new file mode 100644 index 000000000..530747ab6 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/StudioModel.kt @@ -0,0 +1,31 @@ +package com.mxt.anitrend.model.api.retro.anilist + +import com.mxt.anitrend.model.entity.base.MediaBase +import com.mxt.anitrend.model.entity.base.StudioBase +import com.mxt.anitrend.model.entity.container.body.AniListContainer +import com.mxt.anitrend.model.entity.container.body.ConnectionContainer +import com.mxt.anitrend.model.entity.container.body.PageContainer +import io.github.wax911.library.annotation.GraphQuery +import io.github.wax911.library.model.request.QueryContainerBuilder +import retrofit2.Call +import retrofit2.http.Body +import retrofit2.http.Headers +import retrofit2.http.POST + +/** + * Created by max on 2018/03/20. + * Studio queries + */ + +interface StudioModel { + + @POST("/") + @GraphQuery("StudioBase") + @Headers("Content-Type: application/json") + fun getStudioBase(@Body request: QueryContainerBuilder?): Call> + + @POST("/") + @GraphQuery("StudioMedia") + @Headers("Content-Type: application/json") + fun getStudioMedia(@Body request: QueryContainerBuilder?): Call>>> +} 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 deleted file mode 100644 index 82e4f134c..000000000 --- a/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/UserModel.java +++ /dev/null @@ -1,95 +0,0 @@ -package com.mxt.anitrend.model.api.retro.anilist; - -import com.mxt.anitrend.base.custom.annotation.GraphQuery; -import com.mxt.anitrend.model.entity.anilist.Favourite; -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.base.UserBase; -import com.mxt.anitrend.model.entity.container.body.ConnectionContainer; -import com.mxt.anitrend.model.entity.container.body.GraphContainer; -import com.mxt.anitrend.model.entity.container.body.PageContainer; -import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder; - -import retrofit2.Call; -import retrofit2.http.Body; -import retrofit2.http.Headers; -import retrofit2.http.POST; - -/** - * Created by max on 2018/03/20. - * user models - */ - -public interface UserModel { - - @POST("/") - @GraphQuery("UserNotifications") - @Headers("Content-Type: application/json") - Call>> getUserNotifications(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("CurrentUser") - @Headers("Content-Type: application/json") - Call> getCurrentUser(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("UserBase") - @Headers("Content-Type: application/json") - Call> getUserBase(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("UserOverview") - @Headers("Content-Type: application/json") - Call> getUserOverview(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("UserStats") - @Headers("Content-Type: application/json") - Call>> getUserStats(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("UserFollowers") - @Headers("Content-Type: application/json") - Call>> getFollowers(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("UserFollowing") - @Headers("Content-Type: application/json") - Call>> getFollowing(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("UserFavouriteCount") - @Headers("Content-Type: application/json") - Call>> getFavouritesCount(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("AnimeFavourites") - @Headers("Content-Type: application/json") - Call>> getAnimeFavourites(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("MangaFavourites") - @Headers("Content-Type: application/json") - Call>> getMangaFavourites(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("CharacterFavourites") - @Headers("Content-Type: application/json") - Call>> getCharacterFavourites(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("StaffFavourites") - @Headers("Content-Type: application/json") - Call>> getStaffFavourites(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("StudioFavourites") - @Headers("Content-Type: application/json") - Call>> getStudioFavourites(@Body QueryContainerBuilder request); - - @POST("/") - @GraphQuery("ToggleFollow") - @Headers("Content-Type: application/json") - Call> toggleFollow(@Body QueryContainerBuilder request); -} diff --git a/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/UserModel.kt b/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/UserModel.kt new file mode 100644 index 000000000..cc377fc6a --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/model/api/retro/anilist/UserModel.kt @@ -0,0 +1,94 @@ +package com.mxt.anitrend.model.api.retro.anilist + +import com.mxt.anitrend.model.entity.anilist.Favourite +import com.mxt.anitrend.model.entity.anilist.Notification +import com.mxt.anitrend.model.entity.anilist.User +import com.mxt.anitrend.model.entity.anilist.user.UserStatisticTypes +import com.mxt.anitrend.model.entity.base.UserBase +import com.mxt.anitrend.model.entity.container.body.AniListContainer +import com.mxt.anitrend.model.entity.container.body.ConnectionContainer +import com.mxt.anitrend.model.entity.container.body.PageContainer +import io.github.wax911.library.annotation.GraphQuery +import io.github.wax911.library.model.request.QueryContainerBuilder +import retrofit2.Call +import retrofit2.http.Body +import retrofit2.http.Headers +import retrofit2.http.POST + +/** + * Created by max on 2018/03/20. + * user models + */ + +interface UserModel { + + @POST("/") + @GraphQuery("UserNotifications") + @Headers("Content-Type: application/json") + fun getUserNotifications(@Body request: QueryContainerBuilder?): Call>> + + @POST("/") + @GraphQuery("CurrentUser") + @Headers("Content-Type: application/json") + fun getCurrentUser(@Body request: QueryContainerBuilder?): Call> + + @POST("/") + @GraphQuery("UserBase") + @Headers("Content-Type: application/json") + fun getUserBase(@Body request: QueryContainerBuilder?): Call> + + @POST("/") + @GraphQuery("UserOverview") + @Headers("Content-Type: application/json") + fun getUserOverview(@Body request: QueryContainerBuilder?): Call> + + @POST("/") + @GraphQuery("UserStats") + @Headers("Content-Type: application/json") + fun getUserStats(@Body request: QueryContainerBuilder?): Call>> + + @POST("/") + @GraphQuery("UserFollowers") + @Headers("Content-Type: application/json") + fun getFollowers(@Body request: QueryContainerBuilder?): Call>> + + @POST("/") + @GraphQuery("UserFollowing") + @Headers("Content-Type: application/json") + fun getFollowing(@Body request: QueryContainerBuilder?): Call>> + + @POST("/") + @GraphQuery("UserFavouriteCount") + @Headers("Content-Type: application/json") + fun getFavouritesCount(@Body request: QueryContainerBuilder?): Call>> + + @POST("/") + @GraphQuery("AnimeFavourites") + @Headers("Content-Type: application/json") + fun getAnimeFavourites(@Body request: QueryContainerBuilder?): Call>> + + @POST("/") + @GraphQuery("MangaFavourites") + @Headers("Content-Type: application/json") + fun getMangaFavourites(@Body request: QueryContainerBuilder?): Call>> + + @POST("/") + @GraphQuery("CharacterFavourites") + @Headers("Content-Type: application/json") + fun getCharacterFavourites(@Body request: QueryContainerBuilder?): Call>> + + @POST("/") + @GraphQuery("StaffFavourites") + @Headers("Content-Type: application/json") + fun getStaffFavourites(@Body request: QueryContainerBuilder?): Call>> + + @POST("/") + @GraphQuery("StudioFavourites") + @Headers("Content-Type: application/json") + fun getStudioFavourites(@Body request: QueryContainerBuilder?): Call>> + + @POST("/") + @GraphQuery("ToggleFollow") + @Headers("Content-Type: application/json") + fun toggleFollow(@Body request: QueryContainerBuilder?): Call> +} diff --git a/app/src/main/java/com/mxt/anitrend/model/api/retro/base/GiphyModel.java b/app/src/main/java/com/mxt/anitrend/model/api/retro/base/GiphyModel.java deleted file mode 100644 index e54192768..000000000 --- a/app/src/main/java/com/mxt/anitrend/model/api/retro/base/GiphyModel.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.mxt.anitrend.model.api.retro.base; - -import com.mxt.anitrend.model.entity.giphy.GiphyContainer; - -import retrofit2.Call; -import retrofit2.http.GET; -import retrofit2.http.Query; - -/** - * Created by max on 2017/12/09. - * giphy request end point - */ - -public interface GiphyModel { - - @GET("search") - Call findGif(@Query("api_key") String api_key, @Query("q") String q, - @Query("limit") int limit, @Query("offset") int offset, - @Query("rating") String rating, @Query("lang") String lang); - - @GET("trending") - Call getTrending(@Query("api_key") String api_key, @Query("limit") int limit, - @Query("offset") int offset, @Query("rating") String rating); -} diff --git a/app/src/main/java/com/mxt/anitrend/model/api/retro/base/GiphyModel.kt b/app/src/main/java/com/mxt/anitrend/model/api/retro/base/GiphyModel.kt new file mode 100644 index 000000000..91c88be4f --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/model/api/retro/base/GiphyModel.kt @@ -0,0 +1,28 @@ +package com.mxt.anitrend.model.api.retro.base + +import com.mxt.anitrend.model.entity.giphy.GiphyContainer + +import retrofit2.Call +import retrofit2.http.GET +import retrofit2.http.Query + +/** + * Created by max on 2017/12/09. + * giphy request end point + */ + +interface GiphyModel { + + @GET("search") + fun findGif( + @Query("api_key") api_key: String, @Query("q") q: String?, + @Query("limit") limit: Int, @Query("offset") offset: Int?, + @Query("rating") rating: String, @Query("lang") lang: String? + ): Call + + @GET("trending") + fun getTrending( + @Query("api_key") api_key: String, @Query("limit") limit: Int?, + @Query("offset") offset: Int, @Query("rating") rating: String? + ): Call +} diff --git a/app/src/main/java/com/mxt/anitrend/model/api/retro/base/RepositoryModel.java b/app/src/main/java/com/mxt/anitrend/model/api/retro/base/RepositoryModel.java deleted file mode 100644 index e1454446f..000000000 --- a/app/src/main/java/com/mxt/anitrend/model/api/retro/base/RepositoryModel.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.mxt.anitrend.model.api.retro.base; - -import com.mxt.anitrend.model.entity.base.VersionBase; - -import retrofit2.Call; -import retrofit2.http.GET; -import retrofit2.http.Path; - -/** - * Created by max on 2017/04/16. - * Base request model - */ -public interface RepositoryModel { - - String DOWNLOAD_LINK = "https://github.com/AniTrend/anitrend-app/releases/download/%s/app-release.apk"; - - @GET("/AniTrend/anitrend-app/raw/{branch}/app/.meta/version.json") - Call checkVersion(@Path("branch") String branch); -} diff --git a/app/src/main/java/com/mxt/anitrend/model/api/retro/base/RepositoryModel.kt b/app/src/main/java/com/mxt/anitrend/model/api/retro/base/RepositoryModel.kt new file mode 100644 index 000000000..7ebc0f610 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/model/api/retro/base/RepositoryModel.kt @@ -0,0 +1,23 @@ +package com.mxt.anitrend.model.api.retro.base + +import com.mxt.anitrend.model.entity.base.VersionBase + +import retrofit2.Call +import retrofit2.http.GET +import retrofit2.http.Path + +/** + * Created by max on 2017/04/16. + * Base request model + */ +interface RepositoryModel { + + @GET("/AniTrend/anitrend-app/raw/{branch}/app/.meta/version.json") + fun checkVersion( + @Path("branch" + ) branch: String?): Call + + companion object { + const val DOWNLOAD_LINK = "https://github.com/AniTrend/anitrend-app/releases/download/%s/app-release.apk" + } +} diff --git a/app/src/main/java/com/mxt/anitrend/model/api/retro/crunchy/EpisodeModel.java b/app/src/main/java/com/mxt/anitrend/model/api/retro/crunchy/EpisodeModel.java deleted file mode 100644 index feb9cfd94..000000000 --- a/app/src/main/java/com/mxt/anitrend/model/api/retro/crunchy/EpisodeModel.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.mxt.anitrend.model.api.retro.crunchy; - -import com.mxt.anitrend.model.entity.crunchy.Rss; - -import retrofit2.Call; -import retrofit2.http.GET; -import retrofit2.http.Path; - -/** - * Created by max on 2017/10/22. - */ - -public interface EpisodeModel { - - @GET("/{path}") - Call getRSS(@Path("path") String link); - - @GET("crunchyroll/rss/anime/popular?format=xml") - Call getPopularFeed(); - - @GET("crunchyroll/rss/anime") - Call getLatestFeed(); -} diff --git a/app/src/main/java/com/mxt/anitrend/model/api/retro/crunchy/EpisodeModel.kt b/app/src/main/java/com/mxt/anitrend/model/api/retro/crunchy/EpisodeModel.kt new file mode 100644 index 000000000..0086fd056 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/model/api/retro/crunchy/EpisodeModel.kt @@ -0,0 +1,25 @@ +package com.mxt.anitrend.model.api.retro.crunchy + +import com.mxt.anitrend.model.entity.crunchy.Rss + +import retrofit2.Call +import retrofit2.http.GET +import retrofit2.http.Path + +/** + * Created by max on 2017/10/22. + */ + +interface EpisodeModel { + + @get:GET("crunchyroll/rss/anime/popular?format=xml") + val popularFeed: Call + + @get:GET("crunchyroll/rss/anime") + val latestFeed: Call + + @GET("/{path}") + fun getRSS( + @Path("path") link: String? + ): Call +} diff --git a/app/src/main/java/com/mxt/anitrend/model/entity/anilist/Media.java b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/Media.java index c874eb8f8..ed8bac787 100644 --- a/app/src/main/java/com/mxt/anitrend/model/entity/anilist/Media.java +++ b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/Media.java @@ -1,6 +1,7 @@ package com.mxt.anitrend.model.entity.anilist; import android.os.Parcel; + import com.annimon.stream.Stream; import com.mxt.anitrend.model.entity.anilist.meta.MediaStats; import com.mxt.anitrend.model.entity.anilist.meta.MediaTrailer; 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..077dd483d 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,8 @@ 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/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/ImageBase.java b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/meta/ImageBase.java deleted file mode 100644 index 71a4777ef..000000000 --- a/app/src/main/java/com/mxt/anitrend/model/entity/anilist/meta/ImageBase.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.mxt.anitrend.model.entity.anilist.meta; - -import android.os.Parcel; -import android.os.Parcelable; - -/** - * Created by max on 2018/03/20. - */ - -public class ImageBase implements Parcelable { - - private String large; - private String medium; - - protected ImageBase(Parcel in) { - large = in.readString(); - medium = in.readString(); - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeString(large); - dest.writeString(medium); - } - - @Override - public int describeContents() { - return 0; - } - - public static final Creator CREATOR = new Creator() { - @Override - public ImageBase createFromParcel(Parcel in) { - return new ImageBase(in); - } - - @Override - public ImageBase[] newArray(int size) { - return new ImageBase[size]; - } - }; - - public String getLarge() { - return large; - } - - public String getMedium() { - return medium; - } - - @Override - public String toString() { - return large; - } -} diff --git a/app/src/main/java/com/mxt/anitrend/model/entity/anilist/meta/ImageBase.kt b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/meta/ImageBase.kt new file mode 100644 index 000000000..d891e71cc --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/model/entity/anilist/meta/ImageBase.kt @@ -0,0 +1,14 @@ +package com.mxt.anitrend.model.entity.anilist.meta + +import android.os.Parcelable +import kotlinx.android.parcel.Parcelize + +/** + * Created by max on 2018/03/20. + */ +@Parcelize +class ImageBase( + val extraLarge: String?, + val large: String?, + val medium: String? +) : Parcelable 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..afc9aec69 --- /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 = 0, + val count: Int = 0, + val countries: List?, + val episodesWatched: Int = 0, + val formats: List?, + val genres: List?, + val lengths: List?, + val meanScore: Float = 0f, + val minutesWatched: Int = 0, + val releaseYears: List?, + val scores: List?, + val staff: List?, + val standardDeviation: Float = 0f, + val startYears: List?, + val statuses: List?, + val studios: List?, + val tags: List?, + val voiceActors: List?, + val volumesRead: Int = 0 +) \ 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..6ed1dc3c8 --- /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.MediaTag +import com.mxt.anitrend.model.entity.anilist.user.statistics.contract.IUserStatistic + +/** [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/base/MediaBase.java b/app/src/main/java/com/mxt/anitrend/model/entity/base/MediaBase.java index d97a6ac4a..f9e52f341 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,8 @@ 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..df10dae90 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,8 @@ 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/attribute/GraphError.java b/app/src/main/java/com/mxt/anitrend/model/entity/container/attribute/GraphError.java deleted file mode 100644 index 106ad69ba..000000000 --- a/app/src/main/java/com/mxt/anitrend/model/entity/container/attribute/GraphError.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.mxt.anitrend.model.entity.container.attribute; - -import java.util.List; -import java.util.Map; - -public class GraphError { - - private String message; - private int status; - private List> locations; - - public String getMessage() { - return message; - } - - public int getStatus() { - return status; - } - - public List> getLocations() { - return locations; - } - - @Override - public String toString() { - return "message='" + message + '\'' + ", status=" + status + ", locations=" + locations; - } -} diff --git a/app/src/main/java/com/mxt/anitrend/model/entity/container/body/AniListContainer.kt b/app/src/main/java/com/mxt/anitrend/model/entity/container/body/AniListContainer.kt new file mode 100644 index 000000000..e6180d17a --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/model/entity/container/body/AniListContainer.kt @@ -0,0 +1,8 @@ +package com.mxt.anitrend.model.entity.container.body + +import io.github.wax911.library.model.attribute.GraphError + +data class AniListContainer( + val data: DataContainer?, + val errors: List? +) 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; diff --git a/app/src/main/java/com/mxt/anitrend/model/entity/container/body/DataContainer.java b/app/src/main/java/com/mxt/anitrend/model/entity/container/body/DataContainer.java deleted file mode 100644 index a10cee8e4..000000000 --- a/app/src/main/java/com/mxt/anitrend/model/entity/container/body/DataContainer.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.mxt.anitrend.model.entity.container.body; - -import com.google.gson.annotations.SerializedName; - -public class DataContainer { - - @SerializedName(value = "Page", alternate = { - "MediaTagCollection", "GenreCollection", "MediaListCollection", - "Character", "Staff", "Studio", "User", "Media", "MediaList", - "Activity", "ActivityReply", "MediaTrends", "Viewer", "Deleted", - - "ToggleLike", "ToggleFavourite", "ToggleFollow", - - "SaveMediaListEntry", "UpdateMediaListEntries", "DeleteMediaListEntry", - - "RateReview", "SaveReview", "DeleteReview", - - "SaveTextActivity", "SaveMessageActivity", "SaveActivityReply", "DeleteActivity", - "DeleteActivityReply" - }) - private T result; - - public T getResult() { - return result; - } - - public boolean isEmpty() { - return result == null; - } -} \ No newline at end of file diff --git a/app/src/main/java/com/mxt/anitrend/model/entity/container/body/DataContainer.kt b/app/src/main/java/com/mxt/anitrend/model/entity/container/body/DataContainer.kt new file mode 100644 index 000000000..608dfaa23 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/model/entity/container/body/DataContainer.kt @@ -0,0 +1,27 @@ +package com.mxt.anitrend.model.entity.container.body + +import com.google.gson.annotations.SerializedName + +data class DataContainer( + @SerializedName( + value = "Page", + alternate = [ + "MediaTagCollection", "GenreCollection", "MediaListCollection", + + "Character", "Staff", "Studio", "User", "Media", "MediaList", + + "Activity", "ActivityReply", "MediaTrends", "Viewer", "Deleted", + + "ToggleLike", "ToggleFavourite", "ToggleFollow", + + "SaveMediaListEntry", "UpdateMediaListEntries", "DeleteMediaListEntry", + + "RateReview", "SaveReview", "DeleteReview", + + "SaveTextActivity", "SaveMessageActivity", "SaveActivityReply", + "DeleteActivity", "DeleteActivityReply" + ] + ) + val result: T? = null + +) \ No newline at end of file diff --git a/app/src/main/java/com/mxt/anitrend/model/entity/container/body/GraphContainer.java b/app/src/main/java/com/mxt/anitrend/model/entity/container/body/GraphContainer.java deleted file mode 100644 index 8c10202cc..000000000 --- a/app/src/main/java/com/mxt/anitrend/model/entity/container/body/GraphContainer.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.mxt.anitrend.model.entity.container.body; - -import com.mxt.anitrend.model.entity.container.attribute.GraphError; -import com.mxt.anitrend.util.CompatUtil; - -import java.util.List; - -public class GraphContainer { - - private DataContainer data; - private List errors; - - public DataContainer getData() { - return data; - } - - public List getErrors() { - return errors; - } - - public boolean isEmpty() { - return data == null && !CompatUtil.INSTANCE.isEmpty(errors); - } -} diff --git a/app/src/main/java/com/mxt/anitrend/model/entity/container/request/QueryContainer.java b/app/src/main/java/com/mxt/anitrend/model/entity/container/request/QueryContainer.java deleted file mode 100644 index 3482c55ee..000000000 --- a/app/src/main/java/com/mxt/anitrend/model/entity/container/request/QueryContainer.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.mxt.anitrend.model.entity.container.request; - -import android.os.Parcel; -import android.os.Parcelable; - -import com.mxt.anitrend.model.api.converter.GraphQLConverter; - -import java.util.Map; -import java.util.WeakHashMap; - -/** - * Actual query and variable container - * Use case can be found here: - * @see GraphQLConverter#requestBodyConverter - */ -public class QueryContainer implements Parcelable { - - protected String query; - protected Map variables; - - QueryContainer() { - variables = new WeakHashMap<>(); - } - - private QueryContainer(Parcel in) { - query = in.readString(); - variables = in.readHashMap(WeakHashMap.class.getClassLoader()); - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeString(query); - dest.writeMap(variables); - } - - @Override - public int describeContents() { - return 0; - } - - public static final Creator CREATOR = new Creator() { - @Override - public QueryContainer createFromParcel(Parcel in) { - return new QueryContainer(in); - } - - @Override - public QueryContainer[] newArray(int size) { - return new QueryContainer[size]; - } - }; - - protected void setQuery(String query) { - this.query = query; - } - - void putVariable(String key, Object value) { - variables.put(key, value); - } - - boolean containsVariable(String key) { - return variables != null && variables.containsKey(key); - } -} \ No newline at end of file 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 deleted file mode 100644 index 6b6b09f6b..000000000 --- a/app/src/main/java/com/mxt/anitrend/model/entity/container/request/QueryContainerBuilder.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.mxt.anitrend.model.entity.container.request; - -import android.os.Parcel; -import android.os.Parcelable; -import android.support.annotation.Nullable; - -import com.annimon.stream.Collectors; -import com.annimon.stream.Stream; - -import java.util.Map; - -/** - * Created by max on 2018/03/16. - * Query & Variable builder for graph requests - */ -public class QueryContainerBuilder implements Parcelable { - - private QueryContainer queryContainer; - - public QueryContainerBuilder() { - queryContainer = new QueryContainer(); - } - - protected QueryContainerBuilder(Parcel in) { - queryContainer = in.readParcelable(QueryContainer.class.getClassLoader()); - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeParcelable(queryContainer, flags); - } - - @Override - public int describeContents() { - return 0; - } - - public static final Creator CREATOR = new Creator() { - @Override - public QueryContainerBuilder createFromParcel(Parcel in) { - return new QueryContainerBuilder(in); - } - - @Override - public QueryContainerBuilder[] newArray(int size) { - return new QueryContainerBuilder[size]; - } - }; - - public QueryContainerBuilder setQuery(String query) { - this.queryContainer.setQuery(query); - return this; - } - - public QueryContainerBuilder putVariable(String key, Object value) { - queryContainer.putVariable(key, value); - return this; - } - - public @Nullable Object getVariable(String key) { - if(containsVariable(key)) - return queryContainer.variables.get(key); - return null; - } - - public boolean containsVariable(String key) { - return queryContainer.containsVariable(key); - } - - public QueryContainer build() { - queryContainer.variables = Stream.of(queryContainer.variables) - .filter(value -> value.getValue() != null) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - return queryContainer; - } -} 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 1a29716cf..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 android.support.v4.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..57255dc51 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/presenter/base/BasePresenter.kt @@ -0,0 +1,192 @@ +package com.mxt.anitrend.presenter.base + +import android.content.Context +import android.content.Intent +import androidx.annotation.IdRes +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.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.migration.MigrationUtil +import com.mxt.anitrend.util.migration.Migrations +import timber.log.Timber +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 + + @IdRes + fun getNavigationItem(): Int { + return when (settings.startupPage) { + "0" -> R.id.nav_home_feed + "1" -> R.id.nav_anime + "2" -> R.id.nav_manga + "3" -> R.id.nav_trending + "4" -> R.id.nav_airing + "5" -> R.id.nav_myanime + "6" -> R.id.nav_mymanga + "7" -> R.id.nav_hub + "8" -> R.id.nav_reviews + else -> R.id.nav_airing + } + } + + fun checkIfMigrationIsNeeded(): Boolean { + if (!settings.isFreshInstall) { + val migrationUtil = MigrationUtil.Builder() + .addMigration(Migrations.MIGRATION_101_108) + .addMigration(Migrations.MIGRATION_109_134) + .addMigration(Migrations.MIGRATION_135_136) + .build() + return migrationUtil.applyMigration() + } + return true + } + + 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 settings.isAuthenticated && database.currentUser != null && + userId != 0L && database.currentUser?.id == userId + } + + fun isCurrentUser(userName: String?): Boolean { + return settings.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 (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/presenter/fragment/MediaPresenter.java b/app/src/main/java/com/mxt/anitrend/presenter/fragment/MediaPresenter.java index 4489b2a85..149c5a056 100644 --- a/app/src/main/java/com/mxt/anitrend/presenter/fragment/MediaPresenter.java +++ b/app/src/main/java/com/mxt/anitrend/presenter/fragment/MediaPresenter.java @@ -20,8 +20,8 @@ import com.mxt.anitrend.model.entity.container.body.ConnectionContainer; import com.mxt.anitrend.presenter.base.BasePresenter; import com.mxt.anitrend.util.CompatUtil; -import com.mxt.anitrend.util.DateUtil; -import com.mxt.anitrend.util.MediaUtil; +import com.mxt.anitrend.util.date.DateUtil; +import com.mxt.anitrend.util.media.MediaUtil; import java.util.ArrayList; import java.util.Collections; diff --git a/app/src/main/java/com/mxt/anitrend/service/DownloaderService.kt b/app/src/main/java/com/mxt/anitrend/service/DownloaderService.kt index 45db53eb3..92bf7f1f8 100644 --- a/app/src/main/java/com/mxt/anitrend/service/DownloaderService.kt +++ b/app/src/main/java/com/mxt/anitrend/service/DownloaderService.kt @@ -5,12 +5,10 @@ import android.content.Context import android.net.Uri import android.os.Environment import android.webkit.MimeTypeMap - import com.mxt.anitrend.R import com.mxt.anitrend.model.api.retro.base.RepositoryModel import com.mxt.anitrend.model.entity.base.VersionBase - -import java.util.Locale +import java.util.* object DownloaderService { @@ -23,7 +21,6 @@ object DownloaderService { val downloadManager = context?.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager? val request = DownloadManager.Request(Uri.parse(downloadLink)) request.setTitle(String.format(Locale.getDefault(), "anitrend_v%s_rc_%d.apk", versionBase.version, versionBase.code)) - request.allowScanningByMediaScanner() val ext = MimeTypeMap.getFileExtensionFromUrl(RepositoryModel.DOWNLOAD_LINK) request.setMimeType(MimeTypeMap.getSingleton().getMimeTypeFromExtension(ext)) request.setDescription(context?.getString(R.string.text_downloading_update)) 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..a983ca9a0 100644 --- a/app/src/main/java/com/mxt/anitrend/service/JobDispatcherService.kt +++ b/app/src/main/java/com/mxt/anitrend/service/JobDispatcherService.kt @@ -1,33 +1,32 @@ 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 import com.mxt.anitrend.model.entity.anilist.User 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 com.mxt.anitrend.util.graphql.GraphUtil +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..3431128cc 100644 --- a/app/src/main/java/com/mxt/anitrend/service/TagGenreService.kt +++ b/app/src/main/java/com/mxt/anitrend/service/TagGenreService.kt @@ -2,21 +2,18 @@ package com.mxt.anitrend.service import android.app.IntentService import android.content.Intent -import android.util.Log - import com.annimon.stream.Stream -import com.google.firebase.analytics.FirebaseAnalytics import com.mxt.anitrend.base.interfaces.event.RetroCallback import com.mxt.anitrend.model.entity.anilist.Genre import com.mxt.anitrend.model.entity.anilist.MediaTag import com.mxt.anitrend.presenter.widget.WidgetPresenter import com.mxt.anitrend.util.CompatUtil -import com.mxt.anitrend.util.ErrorUtil -import com.mxt.anitrend.util.GraphUtil import com.mxt.anitrend.util.KeyUtil - +import com.mxt.anitrend.util.graphql.GraphUtil +import com.mxt.anitrend.util.graphql.apiError import retrofit2.Call import retrofit2.Response +import timber.log.Timber /** * Created by max on 2017/10/24. @@ -34,13 +31,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(response.apiError()) } override fun onFailure(call: Call>, throwable: Throwable) { - Log.e("fetchAllMediaTags", throwable.message) + Timber.tag("fetchAllMediaTags").e(throwable) throwable.printStackTrace() } }) @@ -56,17 +53,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(response.apiError()) } 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/ActionModeUtil.java b/app/src/main/java/com/mxt/anitrend/util/ActionModeUtil.java index 03a000336..97a895dd4 100644 --- a/app/src/main/java/com/mxt/anitrend/util/ActionModeUtil.java +++ b/app/src/main/java/com/mxt/anitrend/util/ActionModeUtil.java @@ -1,11 +1,12 @@ package com.mxt.anitrend.util; -import android.support.v4.content.ContextCompat; -import android.support.v7.widget.CardView; -import android.support.v7.widget.RecyclerView; import android.view.ActionMode; import android.widget.CheckBox; +import androidx.cardview.widget.CardView; +import androidx.core.content.ContextCompat; +import androidx.recyclerview.widget.RecyclerView; + import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.recycler.RecyclerViewHolder; import com.mxt.anitrend.base.interfaces.event.ActionModeListener; 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 370635114..000000000 --- a/app/src/main/java/com/mxt/anitrend/util/AnalyticsUtil.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.mxt.anitrend.util; - -import android.support.annotation.NonNull; -import android.support.v4.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 { - - 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); - } - } - - public static void reportException(@NonNull String tag, @NonNull String message) { - Crashlytics.log(0, tag, message); - } - - public static void clearSession() { - Crashlytics.setUserIdentifier(""); - } - - public static void setCrashAnalyticsUser(FragmentActivity fragmentActivity, String userName) { - if(fragmentActivity != null) { - App app = ((App) fragmentActivity.getApplicationContext()); - if (app.getFabric() != null) - Crashlytics.setUserIdentifier(userName); - } - } -} 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 6c89988b9..000000000 --- a/app/src/main/java/com/mxt/anitrend/util/ApplicationPref.kt +++ /dev/null @@ -1,297 +0,0 @@ -package com.mxt.anitrend.util - -import android.content.Context -import android.content.SharedPreferences -import android.preference.PreferenceManager -import android.support.annotation.IdRes -import android.support.annotation.StyleRes - -import com.mxt.anitrend.BuildConfig -import com.mxt.anitrend.R -import com.mxt.anitrend.util.ApplicationPref.Companion._isLightTheme - -import java.util.Locale - -/** - * Created by max on 2017/09/16. - * Application preferences - */ - -class ApplicationPref(private val context: Context) { - - /** Base Application Values */ - private val _versionCode = "_versionCode" - private val _freshInstall = "_freshInstall" - private val _isAuthenticated = "_isAuthenticated" - - val sharedPreferences: SharedPreferences by lazy { - PreferenceManager.getDefaultSharedPreferences(context) - } - - var isAuthenticated: Boolean - get() = sharedPreferences.getBoolean(_isAuthenticated, false) - set(authenticated) { - val editor = sharedPreferences.edit() - editor.putBoolean(_isAuthenticated, authenticated) - editor.apply() - } - - val theme: Int - @StyleRes get() = sharedPreferences.getInt(_isLightTheme, R.style.AppThemeLight) - - val isBlackThemeEnabled: Boolean - get() = sharedPreferences.getBoolean(context.getString(R.string.pref_key_black_theme), false) - - // Returns the IDs of the startup page - val startupPage: Int - @IdRes get() { - when (sharedPreferences.getString(context.getString(R.string.pref_key_startup_page), "4")) { - "0" -> return R.id.nav_home_feed - "1" -> return R.id.nav_anime - "2" -> return R.id.nav_manga - "3" -> return R.id.nav_trending - "4" -> return R.id.nav_airing - "5" -> return R.id.nav_myanime - "6" -> return R.id.nav_mymanga - "7" -> return R.id.nav_hub - "8" -> return R.id.nav_reviews - } - return R.id.nav_airing - } - - val isFreshInstall: Boolean - get() = sharedPreferences.getBoolean(_freshInstall, true) - - val userLanguage: String? - get() = sharedPreferences.getString(context.getString(R.string.pref_key_selected_Language), Locale.getDefault().language) - - //Returns amount of time in seconds - val syncTime: Int - get() = Integer.valueOf(sharedPreferences.getString(context.getString(R.string.pref_key_sync_frequency), "15")!!) - - val isNotificationEnabled: Boolean - get() = sharedPreferences.getBoolean(context.getString(R.string.pref_key_new_message_notifications), true) - - val notificationsSound: String? - get() = sharedPreferences.getString(context.getString(R.string.pref_key_ringtone), "DEFAULT_SOUND") - - val isCrashReportsEnabled: Boolean? - get() = sharedPreferences.getBoolean(context.getString(R.string.pref_key_crash_reports), false) - - val isUsageAnalyticsEnabled: Boolean? - get() = sharedPreferences.getBoolean(context.getString(R.string.pref_key_crash_reports), false) - - val seasonYear: Int - get() = sharedPreferences.getInt(KeyUtil.arg_seasonYear, DateUtil.getCurrentYear(0)) - - - val sortOrder: String? - @KeyUtil.SortOrderType get() = sharedPreferences.getString(_sortOrder, KeyUtil.DESC) - - - var mediaStatus: String? - @KeyUtil.MediaStatus get() = sharedPreferences.getString(_mediaStatus, null) - set(@KeyUtil.MediaStatus mediaStatus) { - val editor = sharedPreferences.edit() - editor.putString(_mediaStatus, mediaStatus) - editor.apply() - } - - - var mediaFormat: String? - @KeyUtil.MediaFormat get() = sharedPreferences.getString(_mediaFormat, null) - set(@KeyUtil.MediaFormat mediaFormat) { - val editor = sharedPreferences.edit() - editor.putString(_mediaFormat, mediaFormat) - editor.apply() - } - - var animeFormat: String? - @KeyUtil.AnimeFormat get() = sharedPreferences.getString(_animeFormat, null) - set(@KeyUtil.AnimeFormat animeFormat) { - val editor = sharedPreferences.edit() - editor.putString(_animeFormat, animeFormat) - editor.apply() - } - - var mangaFormat: String? - @KeyUtil.MangaFormat get() = sharedPreferences.getString(_mangaFormat, null) - set(@KeyUtil.MangaFormat mangaFormat) { - val editor = sharedPreferences.edit() - editor.putString(_mangaFormat, mangaFormat) - editor.apply() - } - - - var mediaSource: String? - @KeyUtil.MediaSource get() = sharedPreferences.getString(_mediaSource, null) - set(@KeyUtil.MediaSource mediaSource) { - val editor = sharedPreferences.edit() - editor.putString(_mediaSource, mediaSource) - editor.apply() - } - - - var airingSort: String? - @KeyUtil.AiringSort get() = sharedPreferences.getString(_airingSort, KeyUtil.EPISODE) - set(@KeyUtil.AiringSort airingSort) { - val editor = sharedPreferences.edit() - editor.putString(_airingSort, airingSort) - editor.apply() - } - - - var characterSort: String? - @KeyUtil.CharacterSort get() = sharedPreferences.getString(_characterSort, KeyUtil.ROLE) - set(@KeyUtil.CharacterSort characterSort) { - val editor = sharedPreferences.edit() - editor.putString(_characterSort, characterSort) - editor.apply() - } - - - var mediaListSort: String? - @KeyUtil.MediaListSort get() = sharedPreferences.getString(_mediaListSort, KeyUtil.PROGRESS) - set(@KeyUtil.MediaListSort mediaListSort) { - val editor = sharedPreferences.edit() - editor.putString(_mediaListSort, mediaListSort) - editor.apply() - } - - - var mediaSort: String? - @KeyUtil.MediaSort get() = sharedPreferences.getString(_mediaSort, KeyUtil.POPULARITY) - set(@KeyUtil.MediaSort mediaSort) { - val editor = sharedPreferences.edit() - editor.putString(_mediaSort, mediaSort) - editor.apply() - } - - var mediaTrendSort: String? - @KeyUtil.MediaTrendSort get() = sharedPreferences.getString(_mediaTrendSort, KeyUtil.TRENDING) - set(@KeyUtil.MediaTrendSort mediaTrendSort) { - val editor = sharedPreferences.edit() - editor.putString(_mediaTrendSort, mediaTrendSort) - editor.apply() - } - - - var reviewSort: String? - @KeyUtil.ReviewSort get() = sharedPreferences.getString(_reviewSort, KeyUtil.ID) - set(@KeyUtil.ReviewSort reviewSort) { - val editor = sharedPreferences.edit() - editor.putString(_reviewSort, reviewSort) - editor.apply() - } - - - var staffSort: String? - @KeyUtil.StaffSort get() = sharedPreferences.getString(_staffSort, KeyUtil.ROLE) - set(@KeyUtil.StaffSort staffSort) { - val editor = sharedPreferences.edit() - editor.putString(_staffSort, staffSort) - editor.apply() - } - - var updateChannel: String? - @KeyUtil.Channel get() = sharedPreferences.getString(_updateChannel, KeyUtil.STABLE) - set(@KeyUtil.Channel channel) { - val editor = sharedPreferences.edit() - editor.putString(_updateChannel, channel) - editor.apply() - } - - val isUpdated: Boolean - get() = sharedPreferences.getInt(_versionCode, 1) < BuildConfig.VERSION_CODE - - var selectedGenres: Map? - get() { - val selected = sharedPreferences.getString(_genreFilter, null) - return GenreTagUtil().convertToEntity(selected) - } - set(selectedIndices) { - val selected = GenreTagUtil() - .convertToJson(selectedIndices) - val editor = sharedPreferences.edit() - editor.putString(_genreFilter, selected) - editor.apply() - } - - var selectedTags: Map? - get() { - val selected = sharedPreferences.getString(_tagFilter, null) - return GenreTagUtil().convertToEntity(selected) - } - set(selectedIndices) { - val selected = GenreTagUtil() - .convertToJson(selectedIndices) - val editor = sharedPreferences.edit() - editor.putString(_tagFilter, selected) - editor.apply() - } - - fun toggleTheme() { - val editor = sharedPreferences.edit() - editor.putInt(_isLightTheme, if (theme == R.style.AppThemeLight) R.style.AppThemeDark else R.style.AppThemeLight) - editor.apply() - } - - fun setFreshInstall() { - val editor = sharedPreferences.edit() - editor.putBoolean(_freshInstall, false) - editor.apply() - } - - fun saveSeasonYear(year: Int) { - val editor = sharedPreferences.edit() - editor.putInt(KeyUtil.arg_seasonYear, year) - editor.apply() - } - - - fun shouldShowTipFor(@KeyUtil.TapTargetType tipType: String): Boolean { - return sharedPreferences.getBoolean(tipType, true) - } - - fun disableTipFor(@KeyUtil.TapTargetType tipType: String) { - val editor = sharedPreferences.edit() - editor.putBoolean(tipType, false) - editor.apply() - } - - fun saveSortOrder(@KeyUtil.SortOrderType sortOrder: String) { - val editor = sharedPreferences.edit() - editor.putString(_sortOrder, sortOrder) - editor.apply() - } - - fun setUpdated() { - val editor = sharedPreferences.edit() - editor.putInt(_versionCode, BuildConfig.VERSION_CODE) - editor.apply() - } - - companion object { - - /** Application Base Options */ - const val _isLightTheme = "_isLightTheme" - const val _updateChannel = "_updateChannel" - - /** Api Keys */ - private const val _genreFilter = "_genreFilter" - private const val _tagFilter = "_tagFilter" - private const val _sortOrder = "_sortOrder" - private const val _mediaStatus = "_mediaStatus" - private const val _mediaFormat = "_mediaFormat" - private const val _animeFormat = "_animeFormat" - private const val _mangaFormat = "_mangaFormat" - private const val _mediaSource = "_mediaSource" - private const val _airingSort = "_airingSort" - private const val _characterSort = "_characterSort" - const val _mediaListSort = "_mediaListSort" - private const val _mediaSort = "_mediaSort" - private const val _mediaTrendSort = "_mediaTrendSort" - private const val _reviewSort = "_reviewSort" - private const val _staffSort = "_staffSort" - } -} diff --git a/app/src/main/java/com/mxt/anitrend/util/CenterSnapUtil.kt b/app/src/main/java/com/mxt/anitrend/util/CenterSnapUtil.kt index 7f93b74d1..dd55d37ee 100644 --- a/app/src/main/java/com/mxt/anitrend/util/CenterSnapUtil.kt +++ b/app/src/main/java/com/mxt/anitrend/util/CenterSnapUtil.kt @@ -1,9 +1,8 @@ package com.mxt.anitrend.util -import android.support.v7.widget.PagerSnapHelper -import android.support.v7.widget.RecyclerView import android.view.View - +import androidx.recyclerview.widget.PagerSnapHelper +import androidx.recyclerview.widget.RecyclerView 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..4c9284cd5 100644 --- a/app/src/main/java/com/mxt/anitrend/util/ChartUtil.kt +++ b/app/src/main/java/com/mxt/anitrend/util/ChartUtil.kt @@ -1,13 +1,13 @@ package com.mxt.anitrend.util import android.content.Context - import com.github.mikephil.charting.charts.BarLineChartBase import com.github.mikephil.charting.components.AxisBase import com.github.mikephil.charting.components.XAxis import com.github.mikephil.charting.components.YAxis -import com.github.mikephil.charting.formatter.IAxisValueFormatter +import com.github.mikephil.charting.formatter.ValueFormatter import com.mxt.anitrend.R +import com.mxt.anitrend.extension.getCompatColorAttr /** * Created by max on 2018/02/24. @@ -15,7 +15,7 @@ import com.mxt.anitrend.R class ChartUtil { - class StepXAxisFormatter : IAxisValueFormatter { + class StepXAxisFormatter : ValueFormatter() { private lateinit var dataModel: List private lateinit var chartBase: BarLineChartBase<*> @@ -46,18 +46,19 @@ class ChartUtil { } fun build(context: Context) { - val xAxis = chartBase.xAxis - xAxis.position = XAxis.XAxisPosition.BOTTOM - xAxis.setDrawGridLines(false) - xAxis.granularity = 1f - if (dataModel.size <= 10) - xAxis.labelCount = dataModel.size - xAxis.textColor = CompatUtil.getColorFromAttr(context, R.attr.titleColor) - xAxis.valueFormatter = this + with (chartBase.xAxis) { + position = XAxis.XAxisPosition.BOTTOM + setDrawGridLines(false) + granularity = 1f + if (dataModel.size <= 10) + labelCount = dataModel.size + textColor = context.getCompatColorAttr(R.attr.titleColor) + valueFormatter = this@StepXAxisFormatter + } } } - class StepYAxisFormatter : IAxisValueFormatter { + class StepYAxisFormatter : ValueFormatter() { private lateinit var chartBase: BarLineChartBase<*> @@ -81,18 +82,18 @@ class ChartUtil { } fun build(context: Context) { - chartBase.legend.textColor = CompatUtil.getColorFromAttr(context, R.attr.titleColor) - - val leftAxis = chartBase.axisLeft - leftAxis.setLabelCount(5, false) - leftAxis.spaceTop = 15f - leftAxis.axisMinimum = 0f - leftAxis.disableGridDashedLine() - leftAxis.disableAxisLineDashedLine() - leftAxis.setPosition(YAxis.YAxisLabelPosition.OUTSIDE_CHART) - leftAxis.textColor = CompatUtil.getColorFromAttr(context, R.attr.titleColor) - leftAxis.valueFormatter = this - + chartBase.legend.textColor = context.getCompatColorAttr(R.attr.titleColor) + + with (chartBase.axisLeft) { + setLabelCount(5, false) + spaceTop = 15f + axisMinimum = 0f + disableGridDashedLine() + disableAxisLineDashedLine() + setPosition(YAxis.YAxisLabelPosition.OUTSIDE_CHART) + textColor = context.getCompatColorAttr(R.attr.titleColor) + valueFormatter = this@StepYAxisFormatter + } chartBase.axisRight.isEnabled = false } } 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..99b101df2 100644 --- a/app/src/main/java/com/mxt/anitrend/util/CompatUtil.kt +++ b/app/src/main/java/com/mxt/anitrend/util/CompatUtil.kt @@ -9,29 +9,33 @@ import android.graphics.Point import android.graphics.drawable.Drawable import android.net.ConnectivityManager import android.net.NetworkInfo -import android.support.annotation.* -import android.support.v4.app.ActivityManagerCompat -import android.support.v4.app.ActivityOptionsCompat -import android.support.v4.app.FragmentActivity -import android.support.v4.content.ContextCompat -import android.support.v4.graphics.drawable.DrawableCompat -import android.support.v4.view.ViewCompat -import android.support.v7.content.res.AppCompatResources -import android.text.TextUtils import android.view.LayoutInflater import android.view.View import android.view.WindowManager import android.view.inputmethod.InputMethodManager import android.widget.Toast +import androidx.annotation.* +import androidx.appcompat.content.res.AppCompatResources +import androidx.core.app.ActivityManagerCompat +import androidx.core.app.ActivityOptionsCompat +import androidx.core.content.ContextCompat +import androidx.core.graphics.drawable.DrawableCompat +import androidx.core.view.ViewCompat +import androidx.fragment.app.FragmentActivity import com.annimon.stream.IntPair import com.annimon.stream.Optional import com.annimon.stream.Stream import com.mxt.anitrend.R import com.mxt.anitrend.base.custom.view.container.CustomSwipeRefreshLayout +import com.mxt.anitrend.extension.getCompatColor +import com.mxt.anitrend.extension.getCompatColorAttr +import com.mxt.anitrend.util.collection.ComparatorUtil 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. @@ -41,11 +45,19 @@ object CompatUtil { private const val CACHE_LIMIT = 1024 * 1024 * 250 + @Deprecated( + message = "Use extension functions present in [AppExt]", + replaceWith = ReplaceWith( + expression = "activity.hideKeyboard()", + imports = ["com.mxt.extension.AppExt.hideKeyboard"]), + level = DeprecationLevel.ERROR + ) fun hideKeyboard(activity: FragmentActivity?) { val inputMethodManager = activity?.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager? 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 @@ -69,7 +81,8 @@ object CompatUtil { intent.putExtra(KeyUtil.arg_model, imageUri) startSharedImageTransition(activity, view, intent, R.string.transition_image_preview) } else { - NotifyUtil.makeText(activity, errorMessage, Toast.LENGTH_SHORT).show() + if (activity != null) + NotifyUtil.makeText(activity, errorMessage, Toast.LENGTH_SHORT).show() } } @@ -87,6 +100,13 @@ object CompatUtil { * @return Drawable * @see Drawable */ + @Deprecated( + message = "Use extension functions present in [ContextExt]", + replaceWith = ReplaceWith( + expression = "context.getCompatDrawable(resource)", + imports = ["com.mxt.extension.getCompatDrawable"]), + level = DeprecationLevel.ERROR + ) fun getDrawable(context: Context, @DrawableRes resource: Int): Drawable? { return AppCompatResources.getDrawable(context, resource) } @@ -108,6 +128,13 @@ object CompatUtil { * @return Drawable * @see Drawable */ + @Deprecated( + message = "Use extension functions present in [ContextExt]", + replaceWith = ReplaceWith( + expression = "context.getCompatTintedDrawable(resource)", + imports = ["com.mxt.extension.getCompatTintedDrawable"]), + level = DeprecationLevel.ERROR + ) fun getTintedDrawable(context: Context, @DrawableRes resource: Int): Drawable { val drawable = DrawableCompat.wrap(Objects.requireNonNull(AppCompatResources.getDrawable(context, resource))).mutate() DrawableCompat.setTint(drawable, getColorFromAttr(context, R.attr.titleColor)) @@ -132,10 +159,18 @@ object CompatUtil { * @return Drawable * @see Drawable */ + + @Deprecated( + message = "Use extension functions present in [ContextExt]", + replaceWith = ReplaceWith( + expression = "context.getCompatDrawable(resource, tint)", + imports = ["com.mxt.extension.getCompatDrawable"]), + level = DeprecationLevel.WARNING + ) fun getDrawable(context: Context, @DrawableRes resource: Int, @ColorRes tint: Int): Drawable { val drawable = DrawableCompat.wrap(Objects.requireNonNull(AppCompatResources.getDrawable(context, resource))).mutate() if (tint != 0) - DrawableCompat.setTint(drawable, getColor(context, tint)) + DrawableCompat.setTint(drawable, context.getCompatColor(tint)) return drawable } @@ -157,6 +192,13 @@ object CompatUtil { * @return Drawable * @see Drawable */ + @Deprecated( + message = "Use extension functions present in [ContextExt]", + replaceWith = ReplaceWith( + expression = "context.getCompatTintedDrawable(resource)", + imports = ["com.mxt.extension.getCompatTintedDrawable"]), + level = DeprecationLevel.WARNING + ) fun getDrawableTintAttr(context: Context, @DrawableRes resource: Int, @AttrRes attribute: Int): Drawable { val drawable = DrawableCompat.wrap(Objects.requireNonNull(AppCompatResources.getDrawable(context, resource))).mutate() DrawableCompat.setTint(drawable, getColorFromAttr(context, attribute)) @@ -174,6 +216,13 @@ object CompatUtil { * * @return Color Integer */ + @Deprecated( + message = "Use extension functions present in [ContextExt]", + replaceWith = ReplaceWith( + expression = "context.getCompatColorAttr(attr)", + imports = ["com.mxt.extension.getCompatColorAttr"]), + level = DeprecationLevel.WARNING + ) @ColorInt fun getColorFromAttr(context: Context, @AttrRes attribute: Int): Int { val colorAttribute = context.obtainStyledAttributes(intArrayOf(attribute)) @@ -230,31 +279,23 @@ 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(@KeyUtil.ApplicationTheme theme: String?): Boolean { + return theme == null || theme == KeyUtil.THEME_LIGHT } - fun isLightTheme(context: Context): Boolean { - return ApplicationPref(context).theme == R.style.AppThemeLight + fun isLightTheme(context: Context?): Boolean { + return if (context != null) + isLightTheme(Settings(context).theme) + else + true } fun dipToPx(dpValue: Float): Int { @@ -269,7 +310,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 +321,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 } @@ -293,10 +334,26 @@ object CompatUtil { return screenWidth >= widthDp } + + @Deprecated( + message = "Use extension functions present in [ContextExt]", + replaceWith = ReplaceWith( + expression = "context.getCompatColor(color)", + imports = ["com.mxt.extension.getCompatColor"]), + level = DeprecationLevel.WARNING + ) fun getColor(context: Context, @ColorRes color: Int): Int { return ContextCompat.getColor(context, color) } + + @Deprecated( + message = "Use extension functions present in [ContextExt]", + replaceWith = ReplaceWith( + expression = "context.getLayoutInflater()", + imports = ["com.mxt.extension.getLayoutInflater"]), + level = DeprecationLevel.WARNING + ) fun getLayoutInflater(context: Context): LayoutInflater { return context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater } @@ -347,8 +404,8 @@ object CompatUtil { fun configureSwipeRefreshLayout(swipeRefreshLayout: CustomSwipeRefreshLayout, fragmentActivity: FragmentActivity?) { fragmentActivity?.also { swipeRefreshLayout.setDragTriggerDistance(CustomSwipeRefreshLayout.DIRECTION_BOTTOM, getNavigationBarHeight(it.resources) + dipToPx(16f)) - swipeRefreshLayout.setProgressBackgroundColorSchemeColor(getColorFromAttr(it, R.attr.rootColor)) - swipeRefreshLayout.setColorSchemeColors(getColorFromAttr(it, R.attr.contentColor)) + swipeRefreshLayout.setProgressBackgroundColorSchemeColor(it.getCompatColorAttr(R.attr.rootColor)) + swipeRefreshLayout.setColorSchemeColors(it.getCompatColorAttr(R.attr.contentColor)) swipeRefreshLayout.visibility = View.GONE swipeRefreshLayout.setPermitRefresh(true) swipeRefreshLayout.setPermitLoad(false) @@ -371,9 +428,7 @@ object CompatUtil { * @return list of the array */ @SafeVarargs - fun constructListFrom(vararg array: T): List = - Arrays.asList(*array) - + fun constructListFrom(vararg array: T): List = listOf(*array) /** * Gets the index of any type of collection guaranteed that an equals override for the class diff --git a/app/src/main/java/com/mxt/anitrend/util/ConfigurationUtil.kt b/app/src/main/java/com/mxt/anitrend/util/ConfigurationUtil.kt new file mode 100644 index 000000000..24508dbbf --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/util/ConfigurationUtil.kt @@ -0,0 +1,47 @@ +package com.mxt.anitrend.util + +import androidx.annotation.StyleRes +import com.mxt.anitrend.R +import com.mxt.anitrend.base.custom.activity.ActivityBase +import com.mxt.anitrend.extension.applyConfiguredTheme +import org.koin.core.KoinComponent +import org.koin.core.inject + +class ConfigurationUtil : KoinComponent { + + private val settings by inject() + + @KeyUtil.ApplicationTheme + private lateinit var currentTheme: String + private lateinit var currentLocale: String + + /** + * Applies appropriate theme and locale startup + */ + fun onCreateAttach(base: ActivityBase<*, *>) { + currentTheme = settings.theme + currentLocale = settings.userLanguage + @StyleRes val theme = when (currentTheme) { + KeyUtil.THEME_DARK -> R.style.AppThemeDark + KeyUtil.THEME_BLACK -> R.style.AppThemeBlack + else -> R.style.AppThemeLight + } + base.setTheme(theme) + } + + /** + * Checks if the previously set theme is the same as the current when the activity resumes it's state + */ + fun onResumeAttach(base: ActivityBase<*, *>) { + if (currentTheme != settings.theme || currentLocale != settings.userLanguage) { + with (base) { + applyConfiguredTheme() + val currentIntent = intent + finish() + overridePendingTransition(0, 0) + startActivity(currentIntent) + overridePendingTransition(0, 0) + } + } + } +} \ No newline at end of file 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..4edb59aaf 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 android.text.InputType; import android.text.SpannedString; import android.text.TextUtils; import android.widget.EditText; import android.widget.Toast; +import androidx.annotation.IdRes; +import androidx.annotation.StringRes; +import androidx.fragment.app.FragmentActivity; + import com.afollestad.materialdialogs.MaterialDialog; import com.afollestad.materialdialogs.Theme; import com.mxt.anitrend.BuildConfig; @@ -18,6 +20,8 @@ import com.mxt.anitrend.base.custom.view.text.RichMarkdownTextView; import com.mxt.anitrend.base.custom.view.text.SingleLineTextView; import com.mxt.anitrend.binding.RichMarkdownExtensionsKt; +import com.mxt.anitrend.extension.ContextExtKt; +import com.mxt.anitrend.util.markdown.MarkDownUtil; import java.io.IOException; import java.io.InputStream; @@ -53,7 +57,7 @@ public static void createDialogAttachMedia(@IdRes int action, final EditText edi editor.getEditableText().insert(start, MarkDownUtil.INSTANCE.convertLink(editText.getText().toString())); dialog.dismiss(); } else { - NotifyUtil.makeText(context, R.string.input_empty_warning, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(context, R.string.input_empty_warning, Toast.LENGTH_SHORT).show(); } } break; @@ -78,7 +82,7 @@ public static void createDialogAttachMedia(@IdRes int action, final EditText edi editor.getEditableText().insert(start, MarkDownUtil.INSTANCE.convertImage(editText.getText().toString())); dialog.dismiss(); } else { - NotifyUtil.makeText(context, R.string.input_empty_warning, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(context, R.string.input_empty_warning, Toast.LENGTH_SHORT).show(); } } break; @@ -103,7 +107,7 @@ public static void createDialogAttachMedia(@IdRes int action, final EditText edi editor.getEditableText().insert(start, MarkDownUtil.INSTANCE.convertYoutube(editText.getText().toString())); dialog.dismiss(); } else { - NotifyUtil.makeText(context, R.string.input_empty_warning, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(context, R.string.input_empty_warning, Toast.LENGTH_SHORT).show(); } } break; @@ -128,7 +132,7 @@ public static void createDialogAttachMedia(@IdRes int action, final EditText edi editor.getEditableText().insert(start, MarkDownUtil.INSTANCE.convertVideo(editText.getText().toString())); dialog.dismiss(); } else { - NotifyUtil.makeText(context, R.string.input_empty_warning, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(context, R.string.input_empty_warning, Toast.LENGTH_SHORT).show(); } } break; @@ -197,8 +201,8 @@ public static void createTagMessage(Context context, String title, String conten .content(MarkDownUtil.INSTANCE.convert(content)) .autoDismiss(true).onAny(singleButtonCallback); - if (isSpoiler) builder.icon(CompatUtil.INSTANCE.getDrawable(context, R.drawable.ic_spoiler_tag)); - else builder.icon(CompatUtil.INSTANCE.getDrawable(context, R.drawable.ic_loyalty_white_24dp)); + if (isSpoiler) builder.icon(ContextExtKt.getCompatDrawable(context, R.drawable.ic_spoiler_tag)); + else builder.icon(ContextExtKt.getCompatDrawable(context, R.drawable.ic_loyalty_white_24dp)); builder.show(); } @@ -243,9 +247,9 @@ 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) { + 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 deleted file mode 100644 index 2cc74fb45..000000000 --- a/app/src/main/java/com/mxt/anitrend/util/ErrorUtil.kt +++ /dev/null @@ -1,69 +0,0 @@ -package com.mxt.anitrend.util - -import android.util.Log -import com.google.gson.reflect.TypeToken -import com.mxt.anitrend.model.api.retro.WebFactory -import com.mxt.anitrend.model.entity.container.body.GraphContainer -import retrofit2.Response - -/** - * Created by max on 2017/06/15. - * ResponseError utility class - */ - -object ErrorUtil { - - private const val HTTP_LIMIT_REACHED = 429 - - private const val TAG = "ErrorUtil" - private const val Retry_After = "Retry-After" - private const val RateLimit_Limit = "X-RateLimit-Limit" - private const val RateLimit_Remaining = "X-RateLimit-Remaining" - - /** - * Converts the response error response into an object. - * - * @return The error object, or null if an exception was encountered - * @see Error - */ - fun getError(response: Response<*>?): String { - try { - if (response != null) { - val headers = response.headers() - val responseBody = response.errorBody() - val message = responseBody?.string() - var error = getGraphQLError(message) - if (response.code() != HTTP_LIMIT_REACHED) { - if (responseBody != null && !message.isNullOrBlank()) - if (!error.isNullOrBlank()) - return error - } else { - error = String.format("%s of %s requests remaining, please retry after %s seconds", - headers.get(RateLimit_Remaining), headers.get(RateLimit_Limit), headers.get(Retry_After)) - return error - } - } - } catch (ex: Exception) { - ex.printStackTrace() - return "Unexpected error encountered" - } - - return "Unable to provide information regarding error!" - } - - private fun getGraphQLError(errorJson: String?): String? { - return errorJson?.let { - Log.e(TAG, it) - val tokenType = object : TypeToken>() {}.type - val graphContainer = WebFactory.gson.fromJson>(it, tokenType) - val errors = graphContainer.errors - if (!CompatUtil.isEmpty(errors)) { - val builder = StringBuilder() - for (error in errors) - builder.append(error.toString()) - return@let builder.toString() - } - null - } - } -} diff --git a/app/src/main/java/com/mxt/anitrend/util/IntentBundleUtil.kt b/app/src/main/java/com/mxt/anitrend/util/IntentBundleUtil.kt index 98c41d853..85bd730fa 100644 --- a/app/src/main/java/com/mxt/anitrend/util/IntentBundleUtil.kt +++ b/app/src/main/java/com/mxt/anitrend/util/IntentBundleUtil.kt @@ -3,11 +3,10 @@ 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 android.text.TextUtils - +import androidx.core.app.ShareCompat +import androidx.fragment.app.FragmentActivity +import com.mxt.anitrend.util.markdown.RegexUtil import java.util.regex.Matcher /** @@ -19,7 +18,7 @@ class IntentBundleUtil(private val intent: Intent) { var sharedIntent: ShareCompat.IntentReader? = null - private val deepLinkMatcher: Matcher? by lazy { + private val deepLinkMatcher: Matcher? by lazy(LazyThreadSafetyMode.NONE) { RegexUtil.findIntentKeys(intentData?.path) } @@ -27,8 +26,8 @@ class IntentBundleUtil(private val intent: Intent) { private val intentData: Uri? = intent.data - private fun hasDepth(key: String): Array? { - return if (key.contains("/")) + private fun hasDepth(key: String?): Array? { + return if (key?.contains("/") == true) key.split("/".toRegex()) .dropLastWhile { it.isEmpty() @@ -42,19 +41,19 @@ class IntentBundleUtil(private val intent: Intent) { val groupLimit = it.groupCount() var lastKey = it.group(groupLimit) - val splitKeys: Array? = hasDepth(lastKey) + val splitKeys = hasDepth(lastKey) when (type) { KeyUtil.DEEP_LINK_ACTIVITY -> { if (splitKeys != null) intent.putExtra(KeyUtil.arg_id, splitKeys[0].toLong()) else - intent.putExtra(KeyUtil.arg_id, lastKey.toLong()) + intent.putExtra(KeyUtil.arg_id, lastKey?.toLong()) } KeyUtil.DEEP_LINK_USER -> when { - TextUtils.isDigitsOnly(lastKey) -> intent.putExtra(KeyUtil.arg_id, lastKey.toLong()) + TextUtils.isDigitsOnly(lastKey) -> intent.putExtra(KeyUtil.arg_id, lastKey?.toLong()) else -> { - if (lastKey.contains("/")) + if (lastKey?.contains("/") == true) lastKey = lastKey.replace("/", "") intent.putExtra(KeyUtil.arg_userName, lastKey) } @@ -63,35 +62,35 @@ class IntentBundleUtil(private val intent: Intent) { if (splitKeys != null) intent.putExtra(KeyUtil.arg_id, splitKeys[0].toLong()) else - intent.putExtra(KeyUtil.arg_id, lastKey.toLong()) + intent.putExtra(KeyUtil.arg_id, lastKey?.toLong()) intent.putExtra(KeyUtil.arg_mediaType, KeyUtil.MANGA) } KeyUtil.DEEP_LINK_ANIME -> { if (splitKeys != null) intent.putExtra(KeyUtil.arg_id, splitKeys[0].toLong()) else - intent.putExtra(KeyUtil.arg_id, lastKey.toLong()) + intent.putExtra(KeyUtil.arg_id, lastKey?.toLong()) intent.putExtra(KeyUtil.arg_mediaType, KeyUtil.ANIME) } KeyUtil.DEEP_LINK_CHARACTER -> if (splitKeys != null) intent.putExtra(KeyUtil.arg_id, splitKeys[0].toLong()) else - intent.putExtra(KeyUtil.arg_id, lastKey.toLong()) + intent.putExtra(KeyUtil.arg_id, lastKey?.toLong()) KeyUtil.DEEP_LINK_ACTOR -> if (splitKeys != null) intent.putExtra(KeyUtil.arg_id, splitKeys[0].toLong()) else - intent.putExtra(KeyUtil.arg_id, lastKey.toLong()) + intent.putExtra(KeyUtil.arg_id, lastKey?.toLong()) KeyUtil.DEEP_LINK_STAFF -> if (splitKeys != null) intent.putExtra(KeyUtil.arg_id, splitKeys[0].toLong()) else - intent.putExtra(KeyUtil.arg_id, lastKey.toLong()) + intent.putExtra(KeyUtil.arg_id, lastKey?.toLong()) KeyUtil.DEEP_LINK_STUDIO -> if (splitKeys != null) intent.putExtra(KeyUtil.arg_id, splitKeys[0].toLong()) else - intent.putExtra(KeyUtil.arg_id, lastKey.toLong()) + intent.putExtra(KeyUtil.arg_id, lastKey?.toLong()) } } } 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..37bfad52d 100644 --- a/app/src/main/java/com/mxt/anitrend/util/JobSchedulerUtil.kt +++ b/app/src/main/java/com/mxt/anitrend/util/JobSchedulerUtil.kt @@ -2,6 +2,7 @@ package com.mxt.anitrend.util import android.content.Context import androidx.work.* +import com.mxt.anitrend.extension.appContext import com.mxt.anitrend.service.JobDispatcherService @@ -25,7 +26,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) @@ -36,7 +37,7 @@ object JobSchedulerUtil { .setConstraints(constraints) .build() - WorkManager.getInstance() + WorkManager.getInstance(context) .enqueueUniquePeriodicWork(KeyUtil.WorkNotificationId, ExistingPeriodicWorkPolicy.REPLACE, periodicWorkRequest) } @@ -45,7 +46,7 @@ object JobSchedulerUtil { /** * Cancels any scheduled jobs. */ - fun cancelJob() { - WorkManager.getInstance().cancelUniqueWork(KeyUtil.WorkNotificationId) + fun cancelJob(context: Context = appContext) { + WorkManager.getInstance(context).cancelUniqueWork(KeyUtil.WorkNotificationId) } } 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..9b3de6da9 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. @@ -29,7 +29,10 @@ public interface KeyUtil { String WorkAuthenticatorId = "one_notification_sync"; + String THEME_LIGHT = "light", THEME_DARK = "dark", THEME_BLACK = "black"; + @StringDef({THEME_LIGHT, THEME_DARK, THEME_BLACK}) + @interface ApplicationTheme {} // ------------------------------------------------------------------------------------ // GraphQL Variable Params Keys diff --git a/app/src/main/java/com/mxt/anitrend/util/MediaListUtil.java b/app/src/main/java/com/mxt/anitrend/util/MediaListUtil.java deleted file mode 100644 index 77b976ee2..000000000 --- a/app/src/main/java/com/mxt/anitrend/util/MediaListUtil.java +++ /dev/null @@ -1,85 +0,0 @@ -package com.mxt.anitrend.util; - -import android.os.Bundle; -import android.support.annotation.NonNull; - -import com.annimon.stream.Stream; -import com.mxt.anitrend.base.custom.view.widget.AutoIncrementWidget; -import com.mxt.anitrend.base.custom.view.widget.CustomSeriesManageBase; -import com.mxt.anitrend.model.entity.anilist.MediaList; -import com.mxt.anitrend.model.entity.anilist.meta.CustomList; -import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder; - -import java.util.List; -import java.util.Locale; - -public class MediaListUtil { - - /** - * Creates query variables for updating the status of the current users lists, use cases - * @see CustomSeriesManageBase#persistChanges() - * @see AutoIncrementWidget#updateModelState() - * - * @param model the current media list item - */ - public static Bundle getMediaListParams(@NonNull MediaList model, @KeyUtil.ScoreFormat String scoreFormat) { - QueryContainerBuilder queryContainer = GraphUtil.INSTANCE.getDefaultQuery(false) - .putVariable(KeyUtil.arg_scoreFormat, scoreFormat); - - if (model.getId() > 0) - queryContainer.putVariable(KeyUtil.arg_id, model.getId()); - queryContainer.putVariable(KeyUtil.arg_mediaId, model.getMediaId()); - queryContainer.putVariable(KeyUtil.arg_listStatus, model.getStatus()); - queryContainer.putVariable(KeyUtil.arg_listScore, model.getScore()); - queryContainer.putVariable(KeyUtil.arg_listNotes, model.getNotes()); - queryContainer.putVariable(KeyUtil.arg_listPrivate, model.isHidden()); - queryContainer.putVariable(KeyUtil.arg_listPriority, model.getPriority()); - queryContainer.putVariable(KeyUtil.arg_listHiddenFromStatusLists, model.isHiddenFromStatusLists()); - queryContainer.putVariable(KeyUtil.arg_startedAt, model.getStartedAt()); - queryContainer.putVariable(KeyUtil.arg_completedAt, model.getCompletedAt()); - - if (model.getAdvancedScores() != null) - queryContainer.putVariable(KeyUtil.arg_listAdvancedScore, model.getAdvancedScores()); - - if (!CompatUtil.INSTANCE.isEmpty(model.getCustomLists())) { - List enabledCustomLists = Stream.of(model.getCustomLists()) - .filter(CustomList::isEnabled) - .map(CustomList::getName) - .toList(); - queryContainer.putVariable(KeyUtil.arg_listCustom, enabledCustomLists); - } - - queryContainer.putVariable(KeyUtil.arg_listRepeat, model.getRepeat()); - queryContainer.putVariable(KeyUtil.arg_listProgress, model.getProgress()); - queryContainer.putVariable(KeyUtil.arg_listProgressVolumes, model.getProgressVolumes()); - - Bundle bundle = new Bundle(); - bundle.putParcelable(KeyUtil.arg_graph_params, queryContainer); - return bundle; - } - - /** - * Checks if the sorting should be done on titles - */ - public static boolean isTitleSort(@KeyUtil.MediaListSort String mediaSort) { - return CompatUtil.INSTANCE.equals(mediaSort, KeyUtil.TITLE); - } - - /** - * Checks if the current list items progress can be incremented beyond what it is currently at - */ - public static boolean isProgressUpdatable(MediaList mediaList) { - return mediaList.getMedia().getNextAiringEpisode() != null && - mediaList.getMedia().getNextAiringEpisode().getEpisode() - - mediaList.getProgress() >= 1; - } - - /** - * Filters by the given search term - */ - public static boolean isFilterMatch(MediaList model, String filter) { - return model.getMedia().getTitle().getEnglish().toLowerCase(Locale.getDefault()).contains(filter) || - model.getMedia().getTitle().getRomaji().toLowerCase(Locale.getDefault()).contains(filter) || - model.getMedia().getTitle().getOriginal().toLowerCase(Locale.getDefault()).contains(filter); - } -} 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..d0949f6a1 100644 --- a/app/src/main/java/com/mxt/anitrend/util/NotificationUtil.kt +++ b/app/src/main/java/com/mxt/anitrend/util/NotificationUtil.kt @@ -6,34 +6,27 @@ import android.app.PendingIntent import android.content.Context import android.content.Intent import android.graphics.Color -import android.net.Uri import android.os.Build -import android.support.v4.app.NotificationCompat -import android.support.v4.app.NotificationCompat.PRIORITY_DEFAULT -import android.support.v4.app.NotificationCompat.PRIORITY_HIGH +import androidx.core.app.NotificationCompat +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 +41,10 @@ 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())) .setAutoCancel(true) .setPriority(PRIORITY_HIGH) @@ -95,7 +83,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/NotifyUtil.java b/app/src/main/java/com/mxt/anitrend/util/NotifyUtil.java deleted file mode 100644 index 92e6a4868..000000000 --- a/app/src/main/java/com/mxt/anitrend/util/NotifyUtil.java +++ /dev/null @@ -1,182 +0,0 @@ -package com.mxt.anitrend.util; - -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 android.util.TypedValue; -import android.view.Gravity; -import android.view.View; -import android.widget.TextView; -import android.widget.Toast; - -import com.mxt.anitrend.R; -import com.mxt.anitrend.databinding.CustomAuthToastBinding; -import com.mxt.anitrend.databinding.CustomToastBinding; -import com.mxt.anitrend.model.entity.anilist.User; -import com.tapadoo.alerter.Alerter; - -/** - * Created by max on 2017/11/04. - * Utilities for notifications - */ - -public class NotifyUtil { - - /** - * Create an alert using the activity base - */ - public static void createAlerter(FragmentActivity activity, String title, String text, @DrawableRes int icon, - @ColorRes int backgroundColor, @KeyUtil.AlerterDuration long duration) { - Alerter.create(activity).setTitle(title).setText(text) - .setIcon(CompatUtil.INSTANCE.getDrawable(activity, icon, R.color.white)) - .setProgressColorInt(CompatUtil.INSTANCE.getColor(activity, R.color.white)) - .setBackgroundColorRes(backgroundColor) - .enableIconPulse(true).enableSwipeToDismiss() - .enableVibration(true).setDuration(duration == 0 ? KeyUtil.DURATION_SHORT : duration) - .enableProgress(duration != 0) - .show(); - } - - /** - * Create an alert using the activity base - */ - public static void createAlerter(FragmentActivity activity, @StringRes int title, @StringRes int text, @DrawableRes int icon, - @ColorRes int backgroundColor, @KeyUtil.AlerterDuration long duration) { - Alerter.create(activity).setTitle(title).setText(text) - .setIcon(CompatUtil.INSTANCE.getDrawable(activity, icon, R.color.white)) - .setProgressColorInt(CompatUtil.INSTANCE.getColor(activity, R.color.white)) - .setBackgroundColorRes(backgroundColor) - .enableIconPulse(true).enableSwipeToDismiss() - .enableVibration(true).setDuration(duration == 0 ? KeyUtil.DURATION_SHORT : duration) - .enableProgress(duration != 0) - .show(); - } - - /** - * Create an alert using the activity base - */ - public static void createAlerter(FragmentActivity activity, String title, String text, @DrawableRes int icon, @ColorRes int backgroundColor) { - Alerter.create(activity).setTitle(title).setText(text) - .setIcon(CompatUtil.INSTANCE.getDrawable(activity, icon, R.color.white)) - .setBackgroundColorRes(backgroundColor) - .enableIconPulse(true).enableSwipeToDismiss() - .enableVibration(true).setDuration(KeyUtil.DURATION_SHORT) - .show(); - } - - /** - * Create an alert using the activity base - */ - public static void createAlerter(FragmentActivity activity, @StringRes int title, @StringRes int text, @DrawableRes int icon, @ColorRes int backgroundColor) { - Alerter.create(activity).setTitle(title).setText(text) - .setIcon(CompatUtil.INSTANCE.getDrawable(activity, icon, R.color.white)) - .setBackgroundColorRes(backgroundColor) - .enableIconPulse(true).enableSwipeToDismiss() - .enableVibration(true).setDuration(KeyUtil.DURATION_SHORT) - .show(); - } - - /** - * Create an alert using the activity base - */ - public static void createAlerter(FragmentActivity activity, @StringRes int title, @StringRes int text, @DrawableRes int icon, @ColorRes int backgroundColor, View.OnClickListener clickListener) { - Alerter.create(activity).setTitle(title).setText(text) - .setIcon(CompatUtil.INSTANCE.getDrawable(activity, icon, R.color.white)) - .setBackgroundColorRes(backgroundColor) - .enableIconPulse(true).enableSwipeToDismiss() - .enableVibration(true).setDuration(KeyUtil.DURATION_SHORT) - .setOnClickListener(clickListener) - .show(); - } - - /** - * Create a custom toast - */ - public static void createLoginToast(FragmentActivity context, User user) { - Toast notification = new Toast(context); - CustomAuthToastBinding binding = CustomAuthToastBinding.inflate(CompatUtil.INSTANCE.getLayoutInflater(context)); - binding.setModel(user); - notification.setView(binding.getRoot()); - notification.setGravity(Gravity.BOTTOM | Gravity.FILL_HORIZONTAL, 0, 0); - notification.setDuration(Toast.LENGTH_LONG); - notification.show(); - } - - public static Toast makeText(Context context, @StringRes int stringRes, @DrawableRes int drawableRes, int duration) { - Toast toast = new Toast(context); - CustomToastBinding binding = CustomToastBinding.inflate(CompatUtil.INSTANCE.getLayoutInflater(context)); - binding.toastText.setText(context.getString(stringRes)); - binding.toastIcon.setImageDrawable(CompatUtil.INSTANCE.getTintedDrawable(context, drawableRes)); - toast.setView(binding.getRoot()); - toast.setGravity(Gravity.BOTTOM | Gravity.FILL_HORIZONTAL, 0, CompatUtil.INSTANCE.dipToPx(32)); - toast.setDuration(duration); - return toast; - } - - public static Toast makeText(Context context, @StringRes int stringRes, int duration) { - Toast toast = new Toast(context); - CustomToastBinding binding = CustomToastBinding.inflate(CompatUtil.INSTANCE.getLayoutInflater(context)); - binding.toastText.setText(context.getString(stringRes)); - binding.toastIcon.setImageDrawable(CompatUtil.INSTANCE.getTintedDrawable(context, R.drawable.ic_new_releases_white_24dp)); - toast.setView(binding.getRoot()); - toast.setGravity(Gravity.BOTTOM | Gravity.FILL_HORIZONTAL, 0, CompatUtil.INSTANCE.dipToPx(32)); - toast.setDuration(duration); - return toast; - } - - public static Toast makeText(Context context, String stringRes, @DrawableRes int drawableRes, int duration) { - Toast toast = new Toast(context); - CustomToastBinding binding = CustomToastBinding.inflate(CompatUtil.INSTANCE.getLayoutInflater(context)); - binding.toastText.setText(stringRes); - binding.toastIcon.setImageDrawable(CompatUtil.INSTANCE.getTintedDrawable(context, drawableRes)); - toast.setView(binding.getRoot()); - toast.setGravity(Gravity.BOTTOM | Gravity.FILL_HORIZONTAL, 0, CompatUtil.INSTANCE.dipToPx(32)); - toast.setDuration(duration); - return toast; - } - - public static Toast makeText(Context context, String stringRes, int duration) { - Toast toast = new Toast(context); - CustomToastBinding binding = CustomToastBinding.inflate(CompatUtil.INSTANCE.getLayoutInflater(context)); - binding.toastText.setText(stringRes); - binding.toastIcon.setImageDrawable(CompatUtil.INSTANCE.getTintedDrawable(context, R.drawable.ic_new_releases_white_24dp)); - toast.setView(binding.getRoot()); - toast.setGravity(Gravity.BOTTOM | Gravity.FILL_HORIZONTAL, 0, CompatUtil.INSTANCE.dipToPx(32)); - toast.setDuration(duration); - return toast; - } - - 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); - mainTextView.setTextColor(CompatUtil.INSTANCE.getColorFromAttr(parent.getContext(), R.attr.titleColor)); - actionTextView.setTextColor(CompatUtil.INSTANCE.getColorFromAttr(parent.getContext(), R.attr.colorAccent)); - actionTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12); - return snackbar; - } - - 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); - mainTextView.setTextColor(CompatUtil.INSTANCE.getColorFromAttr(parent.getContext(), R.attr.titleColor)); - actionTextView.setTextColor(CompatUtil.INSTANCE.getColorFromAttr(parent.getContext(), R.attr.colorAccent)); - actionTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12); - return snackbar; - } - - public static ProgressDialog createProgressDialog(Context context, @StringRes int stringRes) { - ProgressDialog progressDialog = new ProgressDialog(context); - progressDialog.setMessage(context.getString(stringRes)); - return progressDialog; - } -} diff --git a/app/src/main/java/com/mxt/anitrend/util/NotifyUtil.kt b/app/src/main/java/com/mxt/anitrend/util/NotifyUtil.kt new file mode 100644 index 000000000..5fc1b17a7 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/util/NotifyUtil.kt @@ -0,0 +1,185 @@ +package com.mxt.anitrend.util + +import android.app.ProgressDialog +import android.content.Context +import android.util.TypedValue +import android.view.Gravity +import android.view.View +import android.widget.TextView +import android.widget.Toast + +import androidx.annotation.ColorRes +import androidx.annotation.DrawableRes +import androidx.annotation.StringRes +import androidx.fragment.app.FragmentActivity + +import com.google.android.material.snackbar.Snackbar +import com.mxt.anitrend.R +import com.mxt.anitrend.databinding.CustomAuthToastBinding +import com.mxt.anitrend.databinding.CustomToastBinding +import com.mxt.anitrend.extension.* +import com.mxt.anitrend.model.entity.anilist.User +import com.tapadoo.alerter.Alerter + +/** + * Created by max on 2017/11/04. + * Utilities for notifications + */ + +object NotifyUtil { + + /** + * Create an alert using the activity base + */ + fun createAlerter(activity: FragmentActivity, title: String, text: String, @DrawableRes icon: Int, + @ColorRes backgroundColor: Int, @KeyUtil.AlerterDuration duration: Long) { + Alerter.create(activity).setTitle(title).setText(text) + .setIcon(activity.getCompatDrawable(icon, R.color.white)!!) + .setProgressColorInt(activity.getCompatColor(R.color.white)) + .setBackgroundColorRes(backgroundColor) + .enableIconPulse(true).enableSwipeToDismiss() + .enableVibration(true).setDuration(if (duration == 0L) KeyUtil.DURATION_SHORT else duration) + .enableProgress(duration != 0L) + .show() + } + + /** + * Create an alert using the activity base + */ + fun createAlerter(activity: FragmentActivity, @StringRes title: Int, @StringRes text: Int, @DrawableRes icon: Int, + @ColorRes backgroundColor: Int, @KeyUtil.AlerterDuration duration: Long) { + Alerter.create(activity).setTitle(title).setText(text) + .setIcon(activity.getCompatDrawable(icon, R.color.white)!!) + .setProgressColorInt(activity.getCompatColor(R.color.white)) + .setBackgroundColorRes(backgroundColor) + .enableIconPulse(true).enableSwipeToDismiss() + .enableVibration(true).setDuration(if (duration == 0L) KeyUtil.DURATION_SHORT else duration) + .enableProgress(duration != 0L) + .show() + } + + /** + * Create an alert using the activity base + */ + fun createAlerter(activity: FragmentActivity, title: String, text: String, @DrawableRes icon: Int, @ColorRes backgroundColor: Int) { + Alerter.create(activity).setTitle(title).setText(text) + .setIcon(activity.getCompatDrawable(icon, R.color.white)!!) + .setBackgroundColorRes(backgroundColor) + .enableIconPulse(true).enableSwipeToDismiss() + .enableVibration(true).setDuration(KeyUtil.DURATION_SHORT) + .show() + } + + /** + * Create an alert using the activity base + */ + fun createAlerter(activity: FragmentActivity, @StringRes title: Int, @StringRes text: Int, @DrawableRes icon: Int, @ColorRes backgroundColor: Int) { + Alerter.create(activity).setTitle(title).setText(text) + .setIcon(activity.getCompatDrawable(icon, R.color.white)!!) + .setBackgroundColorRes(backgroundColor) + .enableIconPulse(true).enableSwipeToDismiss() + .enableVibration(true).setDuration(KeyUtil.DURATION_SHORT) + .show() + } + + /** + * Create an alert using the activity base + */ + fun createAlerter(activity: FragmentActivity, @StringRes title: Int, @StringRes text: Int, @DrawableRes icon: Int, @ColorRes backgroundColor: Int, clickListener: View.OnClickListener) { + Alerter.create(activity).setTitle(title).setText(text) + .setIcon(activity.getCompatDrawable(icon, R.color.white)!!) + .setBackgroundColorRes(backgroundColor) + .enableIconPulse(true).enableSwipeToDismiss() + .enableVibration(true).setDuration(KeyUtil.DURATION_SHORT) + .setOnClickListener(clickListener) + .show() + } + + /** + * Create a custom toast + */ + fun createLoginToast(context: FragmentActivity, user: User) { + val notification = Toast(context) + val binding = CustomAuthToastBinding.inflate(context.layoutInflater) + binding.model = user + notification.view = binding.root + notification.setGravity(Gravity.BOTTOM or Gravity.FILL_HORIZONTAL, 0, 0) + notification.duration = Toast.LENGTH_LONG + notification.show() + } + + fun makeText(context: Context, @StringRes stringRes: Int, @DrawableRes drawableRes: Int, duration: Int): Toast { + val toast = Toast(context) + val binding = CustomToastBinding.inflate(context.getLayoutInflater()) + binding.toastText.text = context.getString(stringRes) + binding.toastIcon.setImageDrawable(context.getCompatTintedDrawable(drawableRes)) + toast.view = binding.root + toast.setGravity(Gravity.BOTTOM or Gravity.FILL_HORIZONTAL, 0, CompatUtil.dipToPx(32f)) + toast.duration = duration + return toast + } + + fun makeText(context: Context, @StringRes stringRes: Int, duration: Int): Toast { + val toast = Toast(context) + val binding = CustomToastBinding.inflate(context.getLayoutInflater()) + binding.toastText.text = context.getString(stringRes) + binding.toastIcon.setImageDrawable(context.getCompatTintedDrawable(R.drawable.ic_new_releases_white_24dp)) + toast.view = binding.root + toast.setGravity(Gravity.BOTTOM or Gravity.FILL_HORIZONTAL, 0, CompatUtil.dipToPx(32f)) + toast.duration = duration + return toast + } + + fun makeText(context: Context, stringRes: String, @DrawableRes drawableRes: Int, duration: Int): Toast { + val toast = Toast(context) + val binding = CustomToastBinding.inflate(context.getLayoutInflater()) + binding.toastText.text = stringRes + binding.toastIcon.setImageDrawable(context.getCompatTintedDrawable(drawableRes)) + toast.view = binding.root + toast.setGravity(Gravity.BOTTOM or Gravity.FILL_HORIZONTAL, 0, CompatUtil.dipToPx(32f)) + toast.duration = duration + return toast + } + + fun makeText(context: Context, stringRes: String, duration: Int): Toast { + val toast = Toast(context) + val binding = CustomToastBinding.inflate(context.getLayoutInflater()) + binding.toastText.text = stringRes + binding.toastIcon.setImageDrawable(context.getCompatTintedDrawable(R.drawable.ic_new_releases_white_24dp)) + toast.view = binding.root + toast.setGravity(Gravity.BOTTOM or Gravity.FILL_HORIZONTAL, 0, CompatUtil.dipToPx(32f)) + toast.duration = duration + return toast + } + + fun make(parent: View, stringRes: String, duration: Int): Snackbar { + val snackbar = Snackbar.make(parent, stringRes, duration) + val snackBarContainer = snackbar.view + snackBarContainer.setBackgroundColor(parent.context.getCompatColorAttr(R.attr.colorPrimaryDark)) + val mainTextView = snackBarContainer.findViewById(R.id.snackbar_text) + val actionTextView = snackBarContainer.findViewById(R.id.snackbar_action) + mainTextView.setTextColor(parent.context.getCompatColorAttr(R.attr.titleColor)) + actionTextView.setTextColor(parent.context.getCompatColorAttr(R.attr.colorAccent)) + actionTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12f) + return snackbar + } + + fun make(parent: View, @StringRes stringRes: Int, duration: Int): Snackbar { + val snackbar = Snackbar.make(parent, stringRes, duration) + val snackBarContainer = snackbar.view + snackBarContainer.setBackgroundColor(parent.context.getCompatColorAttr(R.attr.colorPrimaryDark)) + val mainTextView = snackBarContainer.findViewById(R.id.snackbar_text) + val actionTextView = snackBarContainer.findViewById(R.id.snackbar_action) + mainTextView.setTextColor(parent.context.getCompatColorAttr(R.attr.titleColor)) + actionTextView.setTextColor(parent.context.getCompatColorAttr(R.attr.colorAccent)) + actionTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12f) + return snackbar + } + + @Suppress("DEPRECATION") + fun createProgressDialog(context: Context, @StringRes stringRes: Int): ProgressDialog { + val progressDialog = ProgressDialog(context) + progressDialog.setMessage(context.getString(stringRes)) + return progressDialog + } +} 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..c329eab0f --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/util/Settings.kt @@ -0,0 +1,379 @@ +package com.mxt.anitrend.util + +import android.content.Context +import android.content.SharedPreferences +import androidx.core.content.edit +import androidx.preference.PreferenceManager +import com.mxt.anitrend.BuildConfig +import com.mxt.anitrend.R +import com.mxt.anitrend.util.collection.GenreTagUtil +import com.mxt.anitrend.util.date.DateUtil +import java.util.* + +/** + * 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() + } + } + + @get:KeyUtil.ApplicationTheme + @set:KeyUtil.ApplicationTheme + var theme: String = KeyUtil.THEME_LIGHT + get() = sharedPreferences.getString(context.getString(R.string.pref_key_app_theme), KeyUtil.THEME_LIGHT) ?: KeyUtil.THEME_LIGHT + set(value) { + field = value + sharedPreferences.edit { + putString(context.getString(R.string.pref_key_app_theme), value) + apply() + } + } + + // Returns the IDs of the startup page + val startupPage: String? + get() = sharedPreferences.getString( + context.getString(R.string.pref_key_startup_page), "3") + + 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() = 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() = 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 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() = 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() = 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 = 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 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 _updateChannel = "_updateChannel" + const val _appTheme = "application_theme" + + /** 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/ShortcutUtil.java b/app/src/main/java/com/mxt/anitrend/util/ShortcutUtil.java index f1bcd187d..4dbdc14b7 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,9 @@ 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..dd304be51 100644 --- a/app/src/main/java/com/mxt/anitrend/util/TapTargetUtil.java +++ b/app/src/main/java/com/mxt/anitrend/util/TapTargetUtil.java @@ -1,13 +1,14 @@ 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 android.view.View; +import androidx.annotation.IdRes; +import androidx.annotation.Nullable; +import androidx.annotation.StringRes; +import androidx.core.graphics.ColorUtils; +import androidx.fragment.app.FragmentActivity; +import androidx.interpolator.view.animation.FastOutSlowInInterpolator; + import com.annimon.stream.Stream; import com.mxt.anitrend.R; 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..4956b02f1 100644 --- a/app/src/main/java/com/mxt/anitrend/util/TutorialUtil.java +++ b/app/src/main/java/com/mxt/anitrend/util/TutorialUtil.java @@ -1,16 +1,17 @@ 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 android.util.Log; import android.view.View; +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 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/ComparatorUtil.java b/app/src/main/java/com/mxt/anitrend/util/collection/ComparatorUtil.java similarity index 89% rename from app/src/main/java/com/mxt/anitrend/util/ComparatorUtil.java rename to app/src/main/java/com/mxt/anitrend/util/collection/ComparatorUtil.java index e3a791910..095a35ea3 100644 --- a/app/src/main/java/com/mxt/anitrend/util/ComparatorUtil.java +++ b/app/src/main/java/com/mxt/anitrend/util/collection/ComparatorUtil.java @@ -1,4 +1,4 @@ -package com.mxt.anitrend.util; +package com.mxt.anitrend.util.collection; import java.util.Comparator; import java.util.HashMap; diff --git a/app/src/main/java/com/mxt/anitrend/util/EpisodeUtil.kt b/app/src/main/java/com/mxt/anitrend/util/collection/EpisodeUtil.kt similarity index 96% rename from app/src/main/java/com/mxt/anitrend/util/EpisodeUtil.kt rename to app/src/main/java/com/mxt/anitrend/util/collection/EpisodeUtil.kt index 02d4c4b7c..56b38aebd 100644 --- a/app/src/main/java/com/mxt/anitrend/util/EpisodeUtil.kt +++ b/app/src/main/java/com/mxt/anitrend/util/collection/EpisodeUtil.kt @@ -1,4 +1,4 @@ -package com.mxt.anitrend.util +package com.mxt.anitrend.util.collection import com.mxt.anitrend.model.entity.anilist.ExternalLink diff --git a/app/src/main/java/com/mxt/anitrend/util/GenreTagUtil.java b/app/src/main/java/com/mxt/anitrend/util/collection/GenreTagUtil.java similarity index 95% rename from app/src/main/java/com/mxt/anitrend/util/GenreTagUtil.java rename to app/src/main/java/com/mxt/anitrend/util/collection/GenreTagUtil.java index 2e410b71b..e93e5e06b 100644 --- a/app/src/main/java/com/mxt/anitrend/util/GenreTagUtil.java +++ b/app/src/main/java/com/mxt/anitrend/util/collection/GenreTagUtil.java @@ -1,8 +1,8 @@ -package com.mxt.anitrend.util; +package com.mxt.anitrend.util.collection; -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/GroupingUtil.kt b/app/src/main/java/com/mxt/anitrend/util/collection/GroupingUtil.kt similarity index 93% rename from app/src/main/java/com/mxt/anitrend/util/GroupingUtil.kt rename to app/src/main/java/com/mxt/anitrend/util/collection/GroupingUtil.kt index 9d7771ed6..e72f46da4 100644 --- a/app/src/main/java/com/mxt/anitrend/util/GroupingUtil.kt +++ b/app/src/main/java/com/mxt/anitrend/util/collection/GroupingUtil.kt @@ -1,10 +1,6 @@ -package com.mxt.anitrend.util +package com.mxt.anitrend.util.collection -import android.text.TextUtils - -import com.annimon.stream.Collectors import com.annimon.stream.Stream -import com.annimon.stream.function.Function import com.mxt.anitrend.model.entity.anilist.edge.CharacterEdge import com.mxt.anitrend.model.entity.anilist.edge.MediaEdge import com.mxt.anitrend.model.entity.anilist.edge.StaffEdge @@ -13,9 +9,10 @@ import com.mxt.anitrend.model.entity.base.StaffBase import com.mxt.anitrend.model.entity.container.body.EdgeContainer import com.mxt.anitrend.model.entity.group.RecyclerHeaderItem import com.mxt.anitrend.model.entity.group.RecyclerItem +import com.mxt.anitrend.util.CompatUtil +import com.mxt.anitrend.util.KeyUtil import com.mxt.anitrend.view.fragment.group.CharacterActorsFragment - -import java.util.ArrayList +import java.util.* /** * Created by max on 2018/02/18. @@ -130,7 +127,12 @@ object GroupingUtil { val recyclerHeaderItem = RecyclerHeaderItem(edge.relationType) if (!entityMap.contains(recyclerHeaderItem)) { val totalItems = Stream.of(edges).map { it.relationType } - .filter { role -> CompatUtil.equals(role, edge.relationType) } + .filter { role -> + CompatUtil.equals( + role, + edge.relationType + ) + } .count() recyclerHeaderItem.size = totalItems.toInt() entityMap.add(recyclerHeaderItem) @@ -205,7 +207,12 @@ object GroupingUtil { val recyclerHeaderItem = RecyclerHeaderItem(edge.staffRole) if (!entityMap.contains(recyclerHeaderItem)) { val totalItems = Stream.of(edges).map { it.staffRole } - .filter { role -> CompatUtil.equals(role, edge.staffRole) } + .filter { role -> + CompatUtil.equals( + role, + edge.staffRole + ) + } .count() recyclerHeaderItem.size = totalItems.toInt() entityMap.add(recyclerHeaderItem) diff --git a/app/src/main/java/com/mxt/anitrend/util/DateUtil.kt b/app/src/main/java/com/mxt/anitrend/util/date/DateUtil.kt similarity index 86% rename from app/src/main/java/com/mxt/anitrend/util/DateUtil.kt rename to app/src/main/java/com/mxt/anitrend/util/date/DateUtil.kt index ec926bf89..03dc1baeb 100644 --- a/app/src/main/java/com/mxt/anitrend/util/DateUtil.kt +++ b/app/src/main/java/com/mxt/anitrend/util/date/DateUtil.kt @@ -1,19 +1,16 @@ -package com.mxt.anitrend.util +package com.mxt.anitrend.util.date -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 import com.mxt.anitrend.model.entity.anilist.meta.FuzzyDate - +import com.mxt.anitrend.util.CompatUtil +import com.mxt.anitrend.util.KeyUtil import org.ocpsoft.prettytime.PrettyTime - import java.text.ParseException import java.text.SimpleDateFormat -import java.util.Calendar -import java.util.Date -import java.util.GregorianCalendar -import java.util.Locale +import java.util.* import java.util.concurrent.TimeUnit /** @@ -25,11 +22,18 @@ object DateUtil { private val seasons by lazy { arrayOf( - KeyUtil.WINTER, KeyUtil.WINTER, - KeyUtil.SPRING, KeyUtil.SPRING, KeyUtil.SPRING, - KeyUtil.SUMMER, KeyUtil.SUMMER, KeyUtil.SUMMER, - KeyUtil.FALL, KeyUtil.FALL, KeyUtil.FALL, - KeyUtil.WINTER + KeyUtil.WINTER, + KeyUtil.WINTER, + KeyUtil.SPRING, + KeyUtil.SPRING, + KeyUtil.SPRING, + KeyUtil.SUMMER, + KeyUtil.SUMMER, + KeyUtil.SUMMER, + KeyUtil.FALL, + KeyUtil.FALL, + KeyUtil.FALL, + KeyUtil.WINTER ) } @@ -57,7 +61,8 @@ object DateUtil { val menuSelect: Int @IntRange(from = 0, to = 4) get() { val season = seasons[Calendar.getInstance().get(Calendar.MONTH)] - return CompatUtil.constructListFrom(*KeyUtil.MediaSeason).indexOf(season) + return CompatUtil.constructListFrom(*KeyUtil.MediaSeason) + .indexOf(season) } /** @@ -84,7 +89,10 @@ object DateUtil { * Get the current fuzzy date */ val currentDate: FuzzyDate - get() = FuzzyDate(date, month + 1, year) + get() = FuzzyDate( + date, month + 1, + year + ) fun getMediaSeason(fuzzyDate: FuzzyDate): String { @@ -92,10 +100,14 @@ object DateUtil { try { val converted = format.parse(fuzzyDate.toString()) val calendar = GregorianCalendar(Locale.getDefault()) - calendar.time = converted - + if (converted != null) + calendar.time = converted return String.format(Locale.getDefault(), "%s %d", - CompatUtil.capitalizeWords(seasons[calendar.get(Calendar.MONTH)]), + CompatUtil.capitalizeWords( + seasons[calendar.get( + Calendar.MONTH + )] + ), calendar.get(Calendar.YEAR)) } catch (e: ParseException) { @@ -146,7 +158,8 @@ object DateUtil { if (fuzzyDate != null && fuzzyDate.isValidDate) { val simpleDateFormat = SimpleDateFormat(dateInputFormat, Locale.getDefault()) val converted = simpleDateFormat.parse(fuzzyDate.toString()) - return SimpleDateFormat(dateOutputFormat, Locale.getDefault()).format(converted) + if (converted != null) + return SimpleDateFormat(dateOutputFormat, Locale.getDefault()).format(converted) } } catch (ex: Exception) { ex.printStackTrace() @@ -162,7 +175,7 @@ object DateUtil { private fun isNewerDate(fuzzyDate: FuzzyDate): Boolean { val format = SimpleDateFormat(dateInputFormat, Locale.getDefault()) val converted = format.parse(fuzzyDate.toString()) - return converted.time > System.currentTimeMillis() + return (converted?.time ?: 0) > System.currentTimeMillis() } /** @@ -231,7 +244,9 @@ object DateUtil { * @param endDelta End difference plus or minus the current year */ fun getYearRanges(start: Int, endDelta: Int): List { - return IntStream.rangeClosed(start, getCurrentYear(endDelta)) + return IntStream.rangeClosed(start, + getCurrentYear(endDelta) + ) .boxed().collect(Collectors.toList()) } diff --git a/app/src/main/java/com/mxt/anitrend/util/graphql/AniGraphErrorUtil.kt b/app/src/main/java/com/mxt/anitrend/util/graphql/AniGraphErrorUtil.kt new file mode 100644 index 000000000..6469c34ff --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/util/graphql/AniGraphErrorUtil.kt @@ -0,0 +1,43 @@ +package com.mxt.anitrend.util.graphql + +import io.github.wax911.library.util.getError +import retrofit2.Response +import timber.log.Timber + +/** + * Created by max on 2017/06/15. + * ResponseError utility class + */ + +private const val HTTP_LIMIT_REACHED = 429 + +private const val TAG = "ErrorUtil" +private const val Retry_After = "Retry-After" +private const val RateLimit_Limit = "X-RateLimit-Limit" +private const val RateLimit_Remaining = "X-RateLimit-Remaining" + +/** + * Converts the response error response into an object. + * + * @return The error object, or null if an exception was encountered + * @see Error + */ +fun Response<*>?.apiError(): String { + try { + if (this != null) { + val headers = headers() + val errors = getError() + return if (code() != HTTP_LIMIT_REACHED) { + errors?.firstOrNull()?.message ?: "Unable to provide information regarding error!" + } else + "${headers.get(RateLimit_Remaining)} of ${headers.get(RateLimit_Limit)} requests remaining, please retry after ${headers.get(Retry_After)} seconds" + } + } catch (ex: Exception) { + ex.printStackTrace() + Timber.tag(TAG).e(ex) + return "Unexpected error encountered" + } + + return "Unable to provide information regarding error!" +} + diff --git a/app/src/main/java/com/mxt/anitrend/util/GraphUtil.kt b/app/src/main/java/com/mxt/anitrend/util/graphql/GraphUtil.kt similarity index 81% rename from app/src/main/java/com/mxt/anitrend/util/GraphUtil.kt rename to app/src/main/java/com/mxt/anitrend/util/graphql/GraphUtil.kt index d300c7968..e21b33398 100644 --- a/app/src/main/java/com/mxt/anitrend/util/GraphUtil.kt +++ b/app/src/main/java/com/mxt/anitrend/util/graphql/GraphUtil.kt @@ -1,17 +1,20 @@ -package com.mxt.anitrend.util +package com.mxt.anitrend.util.graphql import com.annimon.stream.Stream import com.mxt.anitrend.model.entity.anilist.FeedList import com.mxt.anitrend.model.entity.anilist.Notification -import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder import com.mxt.anitrend.presenter.base.BasePresenter +import com.mxt.anitrend.util.CompatUtil +import com.mxt.anitrend.util.KeyUtil +import com.mxt.anitrend.util.Settings +import io.github.wax911.library.model.request.QueryContainerBuilder +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 @@ -21,6 +24,7 @@ object GraphUtil { val queryContainer = QueryContainerBuilder() if (includePaging) queryContainer.putVariable(KeyUtil.arg_page_limit, KeyUtil.PAGING_LIMIT) + return queryContainer } @@ -28,8 +32,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._appTheme) && + !CompatUtil.equals(preferenceKey, Settings._updateChannel) } /** diff --git a/app/src/main/java/com/mxt/anitrend/util/LocaleUtil.kt b/app/src/main/java/com/mxt/anitrend/util/locale/LocaleUtil.kt similarity index 64% rename from app/src/main/java/com/mxt/anitrend/util/LocaleUtil.kt rename to app/src/main/java/com/mxt/anitrend/util/locale/LocaleUtil.kt index 056c69442..a2fdd9d95 100644 --- a/app/src/main/java/com/mxt/anitrend/util/LocaleUtil.kt +++ b/app/src/main/java/com/mxt/anitrend/util/locale/LocaleUtil.kt @@ -1,11 +1,10 @@ -package com.mxt.anitrend.util +package com.mxt.anitrend.util.locale import android.annotation.TargetApi import android.content.Context import android.os.Build -import com.mxt.anitrend.App - -import java.util.Locale +import com.mxt.anitrend.util.Settings +import java.util.* /** * This class is used to change the application locale. @@ -14,18 +13,20 @@ import java.util.Locale */ object LocaleUtil { - fun onAttach(context: Context, applicationPref: ApplicationPref): Context { - val language = applicationPref.userLanguage + fun onAttach(context: Context): Context { + val language = Settings(context).userLanguage 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 +36,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 diff --git a/app/src/main/java/com/mxt/anitrend/util/MarkDownUtil.kt b/app/src/main/java/com/mxt/anitrend/util/markdown/MarkDownUtil.kt similarity index 50% rename from app/src/main/java/com/mxt/anitrend/util/MarkDownUtil.kt rename to app/src/main/java/com/mxt/anitrend/util/markdown/MarkDownUtil.kt index 5fcf27e96..3e0fff5ca 100644 --- a/app/src/main/java/com/mxt/anitrend/util/MarkDownUtil.kt +++ b/app/src/main/java/com/mxt/anitrend/util/markdown/MarkDownUtil.kt @@ -1,13 +1,11 @@ -package com.mxt.anitrend.util +package com.mxt.anitrend.util.markdown -import android.content.Context import android.os.Build -import android.support.v7.widget.AppCompatTextView import android.text.Html 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. @@ -33,7 +31,11 @@ object MarkDownUtil { fun convert(input: String?): Spanned { var result = when(input.isNullOrBlank()) { true -> fromMD("No content available") - else -> fromMD(RegexUtil.findUserTags(input)) + else -> fromMD( + RegexUtil.findUserTags( + input + ) + ) } try { @@ -42,37 +44,21 @@ 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 } - fun convert(input: String?, context: Context, source: AppCompatTextView): Spanned { - var result: SpannableStringBuilder - result = when { - input.isNullOrBlank() -> fromMD("No content available") - else -> fromMD(RegexUtil.findUserTags(input)) - } - // result = fromMD(RegexUtil.findUserTags(input), context, source); - - try { - if (result.isNotEmpty()) - while (result[result.length - 1] == '\n') - result = result.delete(result.length - 1, result.length) - } catch (e: Exception) { - e.printStackTrace() - Log.e("convert(input...)", e.message) - } - - return result - } - - fun convertLink(text: String) = RegexUtil.createLinkStandard(text) + fun convertLink(text: String) = + RegexUtil.createLinkStandard(text) - fun convertImage(text: String) = RegexUtil.createImageStandard(text) + fun convertImage(text: String) = + RegexUtil.createImageStandard(text) - fun convertYoutube(text: String) = RegexUtil.createYoutubeStandard(text) + fun convertYoutube(text: String) = + RegexUtil.createYoutubeStandard(text) - fun convertVideo(text: String) = RegexUtil.createWebMStandard(text) + fun convertVideo(text: String) = + RegexUtil.createWebMStandard(text) } diff --git a/app/src/main/java/com/mxt/anitrend/util/RegexUtil.kt b/app/src/main/java/com/mxt/anitrend/util/markdown/RegexUtil.kt similarity index 91% rename from app/src/main/java/com/mxt/anitrend/util/RegexUtil.kt rename to app/src/main/java/com/mxt/anitrend/util/markdown/RegexUtil.kt index ebbe7f53b..b896d7f76 100644 --- a/app/src/main/java/com/mxt/anitrend/util/RegexUtil.kt +++ b/app/src/main/java/com/mxt/anitrend/util/markdown/RegexUtil.kt @@ -1,7 +1,4 @@ -package com.mxt.anitrend.util - -import android.text.TextUtils -import com.github.rjeschke.txtmark.Processor +package com.mxt.anitrend.util.markdown import java.util.regex.Matcher import java.util.regex.Pattern @@ -68,7 +65,7 @@ object RegexUtil { while (matcher.find()) { val match = matcher.group() val replacement = String.format( - USER_URL_LINK, match, + USER_URL_LINK, match, match.replace("@", "") ) if (newText?.contains(replacement, ignoreCase = false) == true) @@ -94,14 +91,16 @@ object RegexUtil { */ fun buildYoutube(id: String): String { return if (!id.contains("youtube")) { - if (id.contains(YoutubeShort)) Youtube + id.replace(YoutubeShort, "") else Youtube + id + if (id.contains(YoutubeShort)) Youtube + id.replace( + YoutubeShort, "") else Youtube + id } else id } fun createYoutubeStandard(link: String): String { if (!link.contains("youtube")) if (link.contains(YoutubeShort)) - return String.format("%s(%s)", KEY_YOU, link.replace(YoutubeShort, "")) + return String.format("%s(%s)", + KEY_YOU, link.replace(YoutubeShort, "")) return String.format("%s(%s)", KEY_YOU, link) } @@ -125,7 +124,7 @@ object RegexUtil { */ fun getYoutubeThumb(link: String): String { val matcher = Pattern.compile(PATTERN_YOUTUBE_EXTRACT).matcher(link) - val temp: String + val temp: String? if (matcher.find()) temp = matcher.group(matcher.groupCount()) @@ -137,8 +136,10 @@ object RegexUtil { fun removeTags(value: String?): String? { return when (value.isNullOrBlank()) { true -> null - else -> findImages(findMedia(value) - .replaceAll("")) + else -> findImages( + findMedia(value) + .replaceAll("") + ) .replaceAll("") .replace("!~","") .replace("~!","") @@ -162,8 +163,8 @@ object RegexUtil { val match = matcher.group() // the full match e.g. img%(http://git.raw.sample.jpg) val tag = matcher.group(gc - 1) // returns the first match group tag of the regex match img|IMG|Img val media = matcher.group(gc) // contains the second match group e.g. (http://git.raw.sample.jpg) brackets included - val mediaWithoutBrackets = media.removeSurrounding("(", ")") - substitute = when (tag.toLowerCase()) { + val mediaWithoutBrackets = media?.removeSurrounding("(", ")") + substitute = when (tag?.toLowerCase()) { KEY_IMG -> substitute.replace(match, "![image]$media") KEY_WEB -> diff --git a/app/src/main/java/com/mxt/anitrend/util/MediaActionUtil.java b/app/src/main/java/com/mxt/anitrend/util/media/MediaActionUtil.java similarity index 83% rename from app/src/main/java/com/mxt/anitrend/util/MediaActionUtil.java rename to app/src/main/java/com/mxt/anitrend/util/media/MediaActionUtil.java index e6c571442..39ac45042 100644 --- a/app/src/main/java/com/mxt/anitrend/util/MediaActionUtil.java +++ b/app/src/main/java/com/mxt/anitrend/util/media/MediaActionUtil.java @@ -1,23 +1,28 @@ -package com.mxt.anitrend.util; +package com.mxt.anitrend.util.media; import android.app.ProgressDialog; -import android.arch.lifecycle.Lifecycle; import android.content.SharedPreferences; -import android.support.annotation.NonNull; -import android.support.v4.app.FragmentActivity; -import android.util.Log; import android.widget.Toast; +import androidx.annotation.NonNull; +import androidx.fragment.app.FragmentActivity; +import androidx.lifecycle.Lifecycle; + import com.mxt.anitrend.R; import com.mxt.anitrend.base.interfaces.event.LifecycleListener; import com.mxt.anitrend.base.interfaces.event.RetroCallback; import com.mxt.anitrend.model.entity.anilist.meta.MediaListOptions; import com.mxt.anitrend.model.entity.base.MediaBase; -import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder; import com.mxt.anitrend.presenter.widget.WidgetPresenter; +import com.mxt.anitrend.util.KeyUtil; +import com.mxt.anitrend.util.NotifyUtil; +import com.mxt.anitrend.util.graphql.AniGraphErrorUtilKt; +import com.mxt.anitrend.util.graphql.GraphUtil; +import io.github.wax911.library.model.request.QueryContainerBuilder; import retrofit2.Call; import retrofit2.Response; +import timber.log.Timber; /** * Created by max on 2018/01/05. @@ -34,6 +39,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; @@ -64,7 +70,7 @@ private void dismissProgress() { } public void startSeriesAction() { - progressDialog = NotifyUtil.createProgressDialog(context, R.string.text_checking_collection); + progressDialog = NotifyUtil.INSTANCE.createProgressDialog(context, R.string.text_checking_collection); progressDialog.show(); actionPicker(); } @@ -74,7 +80,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,8 +100,8 @@ public void onResponse(@NonNull Call call, @NonNull Response call, @NonNull Response call, @NonNull Throwable throwable) { if (lifecycle != null && lifecycle.getCurrentState().isAtLeast(Lifecycle.State.STARTED)) { dismissProgress(); + Timber.tag(TAG).e(throwable); throwable.printStackTrace(); - NotifyUtil.makeText(context, R.string.text_error_request, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(context, R.string.text_error_request, Toast.LENGTH_SHORT).show(); } } diff --git a/app/src/main/java/com/mxt/anitrend/util/MediaBrowseUtil.java b/app/src/main/java/com/mxt/anitrend/util/media/MediaBrowseUtil.java similarity index 98% rename from app/src/main/java/com/mxt/anitrend/util/MediaBrowseUtil.java rename to app/src/main/java/com/mxt/anitrend/util/media/MediaBrowseUtil.java index f55c31233..ad21aedc9 100644 --- a/app/src/main/java/com/mxt/anitrend/util/MediaBrowseUtil.java +++ b/app/src/main/java/com/mxt/anitrend/util/media/MediaBrowseUtil.java @@ -1,4 +1,4 @@ -package com.mxt.anitrend.util; +package com.mxt.anitrend.util.media; import android.os.Parcel; import android.os.Parcelable; diff --git a/app/src/main/java/com/mxt/anitrend/util/MediaDialogUtil.java b/app/src/main/java/com/mxt/anitrend/util/media/MediaDialogUtil.java similarity index 78% rename from app/src/main/java/com/mxt/anitrend/util/MediaDialogUtil.java rename to app/src/main/java/com/mxt/anitrend/util/media/MediaDialogUtil.java index 8dc850ba9..43a39445e 100644 --- a/app/src/main/java/com/mxt/anitrend/util/MediaDialogUtil.java +++ b/app/src/main/java/com/mxt/anitrend/util/media/MediaDialogUtil.java @@ -1,13 +1,13 @@ -package com.mxt.anitrend.util; +package com.mxt.anitrend.util.media; import android.app.ProgressDialog; import android.content.Context; import android.os.Bundle; -import android.support.annotation.NonNull; import android.text.Html; -import android.util.Log; import android.widget.Toast; +import androidx.annotation.NonNull; + import com.afollestad.materialdialogs.MaterialDialog; import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.consumer.BaseConsumer; @@ -19,9 +19,15 @@ import com.mxt.anitrend.model.entity.anilist.meta.DeleteState; import com.mxt.anitrend.model.entity.base.MediaBase; import com.mxt.anitrend.presenter.widget.WidgetPresenter; +import com.mxt.anitrend.util.CompatUtil; +import com.mxt.anitrend.util.DialogUtil; +import com.mxt.anitrend.util.KeyUtil; +import com.mxt.anitrend.util.NotifyUtil; +import com.mxt.anitrend.util.graphql.AniGraphErrorUtilKt; import retrofit2.Call; import retrofit2.Response; +import timber.log.Timber; /** * Created by max on 2018/01/20. @@ -30,6 +36,8 @@ final class MediaDialogUtil extends DialogUtil { + private static final String TAG = MediaDialogUtil.class.getSimpleName(); + /** * General series managing template dialog builder which sets the text and icon based on the criteria, * new or old series entries. @@ -71,7 +79,7 @@ static void createSeriesManage(Context context, @NonNull MediaBase mediaBase) { private static void onDialogPositive(Context context, CustomSeriesManageBase seriesManageBase, MaterialDialog dialog) { dialog.dismiss(); - ProgressDialog progressDialog = NotifyUtil.createProgressDialog(context, R.string.text_processing_request); + ProgressDialog progressDialog = NotifyUtil.INSTANCE.createProgressDialog(context, R.string.text_processing_request); progressDialog.show(); WidgetPresenter presenter = new WidgetPresenter<>(context); @@ -90,14 +98,14 @@ public void onResponse(@NonNull Call 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(); + NotifyUtil.INSTANCE.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)); - NotifyUtil.makeText(context, context.getString(R.string.text_error_request), R.drawable.ic_warning_white_18dp, Toast.LENGTH_SHORT).show(); + Timber.tag(TAG).w(AniGraphErrorUtilKt.apiError(response)); + NotifyUtil.INSTANCE.makeText(context, context.getString(R.string.text_error_request), R.drawable.ic_warning_white_18dp, Toast.LENGTH_SHORT).show(); } } catch (Exception e) { + Timber.tag(TAG).w(e); e.printStackTrace(); - Log.e(this.toString(), e.getLocalizedMessage()); } } @@ -106,10 +114,10 @@ public void onFailure(@NonNull Call call, @NonNull Throwable throwabl throwable.printStackTrace(); try { progressDialog.dismiss(); - NotifyUtil.makeText(context, context.getString(R.string.text_error_request), R.drawable.ic_warning_white_18dp, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(context, context.getString(R.string.text_error_request), R.drawable.ic_warning_white_18dp, Toast.LENGTH_SHORT).show(); } catch (Exception e) { + Timber.tag(TAG).e(e); e.printStackTrace(); - Log.e(this.toString(), e.getLocalizedMessage()); } } }); @@ -124,7 +132,7 @@ public void onFailure(@NonNull Call call, @NonNull Throwable throwabl private static void onDialogNegative(Context context, CustomSeriesManageBase seriesManageBase, MaterialDialog dialog) { dialog.dismiss(); - ProgressDialog progressDialog = NotifyUtil.createProgressDialog(context, R.string.text_processing_request); + ProgressDialog progressDialog = NotifyUtil.INSTANCE.createProgressDialog(context, R.string.text_processing_request); progressDialog.show(); seriesManageBase.persistChanges(); @@ -144,14 +152,15 @@ public void onResponse(@NonNull Call call, @NonNull Response(requestType, seriesManageBase.getModel()), false); - NotifyUtil.makeText(context, context.getString(R.string.text_changes_saved), R.drawable.ic_check_circle_white_24dp, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.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)); - NotifyUtil.makeText(context, context.getString(R.string.text_error_request), R.drawable.ic_warning_white_18dp, Toast.LENGTH_SHORT).show(); + Timber.tag(TAG).w(AniGraphErrorUtilKt.apiError(response)); + NotifyUtil.INSTANCE.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); } } @@ -160,9 +169,10 @@ public void onFailure(@NonNull Call call, @NonNull Throwable throwa throwable.printStackTrace(); try { progressDialog.dismiss(); - NotifyUtil.makeText(context, context.getString(R.string.text_error_request), R.drawable.ic_warning_white_18dp, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.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/media/MediaListUtil.kt b/app/src/main/java/com/mxt/anitrend/util/media/MediaListUtil.kt new file mode 100644 index 000000000..661082702 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/util/media/MediaListUtil.kt @@ -0,0 +1,82 @@ +package com.mxt.anitrend.util.media + +import android.os.Bundle +import com.annimon.stream.Stream +import com.mxt.anitrend.base.custom.view.widget.AutoIncrementWidget +import com.mxt.anitrend.base.custom.view.widget.CustomSeriesManageBase +import com.mxt.anitrend.model.entity.anilist.MediaList +import com.mxt.anitrend.util.CompatUtil +import com.mxt.anitrend.util.KeyUtil +import com.mxt.anitrend.util.graphql.GraphUtil +import java.util.* + +object MediaListUtil { + + /** + * Creates query variables for updating the status of the current users lists, use cases + * @see CustomSeriesManageBase.persistChanges + * @see AutoIncrementWidget.updateModelState + * @param model the current media list item + */ + fun getMediaListParams(model: MediaList, @KeyUtil.ScoreFormat scoreFormat: String): Bundle { + val queryContainer = GraphUtil.getDefaultQuery(false) + .putVariable(KeyUtil.arg_scoreFormat, scoreFormat) + + if (model.id > 0) + queryContainer.putVariable(KeyUtil.arg_id, model.id) + queryContainer.putVariable(KeyUtil.arg_mediaId, model.mediaId) + queryContainer.putVariable(KeyUtil.arg_listStatus, model.status) + queryContainer.putVariable(KeyUtil.arg_listScore, model.score) + queryContainer.putVariable(KeyUtil.arg_listNotes, model.notes) + queryContainer.putVariable(KeyUtil.arg_listPrivate, model.isHidden) + queryContainer.putVariable(KeyUtil.arg_listPriority, model.priority) + queryContainer.putVariable(KeyUtil.arg_listHiddenFromStatusLists, model.isHiddenFromStatusLists) + queryContainer.putVariable(KeyUtil.arg_startedAt, model.startedAt) + queryContainer.putVariable(KeyUtil.arg_completedAt, model.completedAt) + + if (model.advancedScores != null) + queryContainer.putVariable(KeyUtil.arg_listAdvancedScore, model.advancedScores) + + if (!CompatUtil.isEmpty(model.customLists)) { + val enabledCustomLists = Stream.of(model.customLists) + .filter { it.isEnabled } + .map { it.name } + .toList() + queryContainer.putVariable(KeyUtil.arg_listCustom, enabledCustomLists) + } + + queryContainer.putVariable(KeyUtil.arg_listRepeat, model.repeat) + queryContainer.putVariable(KeyUtil.arg_listProgress, model.progress) + queryContainer.putVariable(KeyUtil.arg_listProgressVolumes, model.progressVolumes) + + val bundle = Bundle() + bundle.putParcelable(KeyUtil.arg_graph_params, queryContainer) + return bundle + } + + /** + * Checks if the sorting should be done on titles + */ + fun isTitleSort(@KeyUtil.MediaListSort mediaSort: String): Boolean { + return CompatUtil.equals( + mediaSort, + KeyUtil.TITLE + ) + } + + /** + * Checks if the current list items progress can be incremented beyond what it is currently at + */ + fun isProgressUpdatable(mediaList: MediaList): Boolean { + return mediaList.media.nextAiringEpisode != null && mediaList.media.nextAiringEpisode!!.episode - mediaList.progress >= 1 + } + + /** + * Filters by the given search term + */ + fun isFilterMatch(model: MediaList, filter: String): Boolean { + return model.media.title.english.toLowerCase(Locale.getDefault()).contains(filter) || + model.media.title.romaji.toLowerCase(Locale.getDefault()).contains(filter) || + model.media.title.original.toLowerCase(Locale.getDefault()).contains(filter) + } +} diff --git a/app/src/main/java/com/mxt/anitrend/util/MediaUtil.java b/app/src/main/java/com/mxt/anitrend/util/media/MediaUtil.java similarity index 95% rename from app/src/main/java/com/mxt/anitrend/util/MediaUtil.java rename to app/src/main/java/com/mxt/anitrend/util/media/MediaUtil.java index 9013a53ac..d01f5cdf3 100644 --- a/app/src/main/java/com/mxt/anitrend/util/MediaUtil.java +++ b/app/src/main/java/com/mxt/anitrend/util/media/MediaUtil.java @@ -1,9 +1,11 @@ -package com.mxt.anitrend.util; +package com.mxt.anitrend.util.media; import com.annimon.stream.Stream; import com.mxt.anitrend.model.entity.anilist.MediaList; import com.mxt.anitrend.model.entity.anilist.meta.MediaTrend; import com.mxt.anitrend.model.entity.base.MediaBase; +import com.mxt.anitrend.util.CompatUtil; +import com.mxt.anitrend.util.KeyUtil; import java.util.Collections; import java.util.List; 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..3dd00a346 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/util/migration/Migration.kt @@ -0,0 +1,41 @@ +package com.mxt.anitrend.util.migration + +import com.mxt.anitrend.util.Settings + +/** + * 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(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 new file mode 100644 index 000000000..72bd7ed2d --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/util/migration/MigrationUtil.kt @@ -0,0 +1,76 @@ +package com.mxt.anitrend.util.migration + +import androidx.annotation.VisibleForTesting +import com.mxt.anitrend.BuildConfig +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 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 (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 { + strategies.forEach { strategy -> + strategy.applyMigration(settings) + } + true + } catch (ex: Exception) { + Timber.tag(TAG).e(ex) + ex.printStackTrace() + false + } + } + Timber.tag(TAG).d("No migrations to run for this version of the application") + return true + } + + class Builder { + private val migrations: MutableList = ArrayList() + + fun addMigration(migration: Migration): Builder { + if (!migrations.contains(migration)) + 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..4d2e943b7 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/util/migration/Migrations.kt @@ -0,0 +1,57 @@ +package com.mxt.anitrend.util.migration + +import android.os.Build +import androidx.core.content.edit +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.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_101_108 = object : Migration(101, 108) { + override fun applyMigration(settings: Settings) { + Timber.i("Applying test migration from 101 - 109") + settings.sharedPreferences.edit { + clear() + apply() + } + DatabaseHelper().invalidateBoxStores() + JobSchedulerUtil.cancelJob() + } + } + + val MIGRATION_109_134 = object : Migration(109, 134) { + override fun applyMigration(settings: Settings) { + Timber.i("Applying migration from 109 - 134") + settings.sharedPreferences.edit { + clear() + apply() + } + DatabaseHelper().invalidateBoxStores() + JobSchedulerUtil.cancelJob() + WebFactory.invalidate() + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) + ShortcutUtil.removeAllDynamicShortcuts(appContext) + supportAnalytics.resetAnalyticsData() + } + } + + val MIGRATION_135_136 = object : Migration(135, 136) { + override fun applyMigration(settings: Settings) { + Timber.i("No incremental migrations for 135 - 136") + settings.sharedPreferences.edit { + clear() + apply() + } + } + } +} \ 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 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..e620ea058 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,8 +1,7 @@ package com.mxt.anitrend.view.activity.base import android.os.Bundle -import android.support.v7.widget.Toolbar -import butterknife.ButterKnife +import androidx.appcompat.widget.Toolbar import com.mxt.anitrend.R import com.mxt.anitrend.base.custom.activity.ActivityBase import com.mxt.anitrend.presenter.base.BasePresenter 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 deleted file mode 100644 index a208025ab..000000000 --- a/app/src/main/java/com/mxt/anitrend/view/activity/base/AppCompatPreferenceActivity.java +++ /dev/null @@ -1,127 +0,0 @@ -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 android.view.MenuInflater; -import android.view.View; -import android.view.ViewGroup; - -import com.mxt.anitrend.R; -import com.mxt.anitrend.util.ApplicationPref; -import com.mxt.anitrend.util.CompatUtil; - -/** - * A {@link android.preference.PreferenceActivity} which implements and proxies the necessary calls - * to be used with AppCompat. - */ -public abstract class AppCompatPreferenceActivity extends PreferenceActivity { - - private AppCompatDelegate mDelegate; - - protected ApplicationPref applicationPref; - - protected void configureActivity() { - @StyleRes int style = applicationPref.getTheme(); - if(!CompatUtil.INSTANCE.isLightTheme(style) && applicationPref.isBlackThemeEnabled()) - setTheme(R.style.AppThemeBlack); - else - setTheme(style); - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - getDelegate().installViewFactory(); - getDelegate().onCreate(savedInstanceState); - applicationPref = new ApplicationPref(this); - configureActivity(); - super.onCreate(savedInstanceState); - } - - @Override - protected void onPostCreate(Bundle savedInstanceState) { - super.onPostCreate(savedInstanceState); - getDelegate().onPostCreate(savedInstanceState); - } - - public ActionBar getSupportActionBar() { - return getDelegate().getSupportActionBar(); - } - - public void setSupportActionBar(@Nullable Toolbar toolbar) { - getDelegate().setSupportActionBar(toolbar); - } - - @Override - public MenuInflater getMenuInflater() { - return getDelegate().getMenuInflater(); - } - - @Override - public void setContentView(@LayoutRes int layoutResID) { - getDelegate().setContentView(layoutResID); - } - - @Override - public void setContentView(View view) { - getDelegate().setContentView(view); - } - - @Override - public void setContentView(View view, ViewGroup.LayoutParams params) { - getDelegate().setContentView(view, params); - } - - @Override - public void addContentView(View view, ViewGroup.LayoutParams params) { - getDelegate().addContentView(view, params); - } - - @Override - protected void onPostResume() { - super.onPostResume(); - getDelegate().onPostResume(); - } - - @Override - protected void onTitleChanged(CharSequence title, int color) { - super.onTitleChanged(title, color); - getDelegate().setTitle(title); - } - - @Override - public void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - getDelegate().onConfigurationChanged(newConfig); - } - - @Override - protected void onStop() { - super.onStop(); - getDelegate().onStop(); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - getDelegate().onDestroy(); - } - - public void invalidateOptionsMenu() { - getDelegate().invalidateOptionsMenu(); - } - - private AppCompatDelegate getDelegate() { - if (mDelegate == null) { - mDelegate = AppCompatDelegate.create(this, null); - } - return mDelegate; - } -} 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..2e940de24 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,13 +2,14 @@ import android.graphics.drawable.Drawable; import android.os.Bundle; -import android.support.annotation.Nullable; import android.text.TextUtils; import android.view.View; import android.view.Window; import android.view.WindowManager; import android.widget.Toast; +import androidx.annotation.Nullable; + import com.bumptech.glide.Glide; import com.bumptech.glide.load.DataSource; import com.bumptech.glide.load.engine.GlideException; @@ -56,7 +57,7 @@ protected void onPostCreate(@Nullable Bundle savedInstanceState) { Glide.with(this).load(getIntent().getStringExtra(KeyUtil.arg_model)) .listener(this).into(previewImage); else - NotifyUtil.makeText(this, R.string.layout_empty_response, R.drawable.ic_warning_white_18dp, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(this, R.string.layout_empty_response, R.drawable.ic_warning_white_18dp, Toast.LENGTH_SHORT).show(); onActivityReady(); } 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..3f4471f71 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,12 +6,7 @@ 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 android.text.TextUtils; -import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.Window; @@ -19,6 +14,11 @@ import android.view.animation.DecelerateInterpolator; import android.widget.Toast; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.widget.Toolbar; +import androidx.core.app.ActivityCompat; + import com.bumptech.glide.Glide; import com.github.chrisbanes.photoview.PhotoView; import com.mxt.anitrend.R; @@ -30,6 +30,7 @@ import butterknife.BindView; import butterknife.ButterKnife; +import timber.log.Timber; /** * Created by max on 2017/11/14. @@ -69,7 +70,7 @@ protected void onPostCreate(@Nullable Bundle savedInstanceState) { mImageUri = getIntent().getStringExtra(KeyUtil.arg_model); Glide.with(this).load(mImageUri).into(mImageView); } else - NotifyUtil.makeText(this, R.string.layout_empty_response, R.drawable.ic_warning_white_18dp, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(this, R.string.layout_empty_response, R.drawable.ic_warning_white_18dp, Toast.LENGTH_SHORT).show(); } @Override @@ -93,7 +94,7 @@ else if(ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permi ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_PERMISSION); break; case NEGATIVE: - NotifyUtil.makeText(this, R.string.canceled_by_user, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(this, R.string.canceled_by_user, Toast.LENGTH_SHORT).show(); break; } }); @@ -113,8 +114,8 @@ else if(ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permi intent.setData(Uri.parse(mImageUri)); startActivity(intent); } catch (Exception e) { - Log.e(toString(), e.getLocalizedMessage()); - NotifyUtil.makeText(this, R.string.text_unknown_error, Toast.LENGTH_SHORT).show(); + Timber.tag(TAG).e(e.getLocalizedMessage()); + NotifyUtil.INSTANCE.makeText(this, R.string.text_unknown_error, Toast.LENGTH_SHORT).show(); } return true; } @@ -151,10 +152,10 @@ private void downloadAttachment() { DownloadManager dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE); if (dm != null) { dm.enqueue(r); - NotifyUtil.createAlerter(this, R.string.title_download_info, R.string.text_download_info, + NotifyUtil.INSTANCE.createAlerter(this, R.string.title_download_info, R.string.text_download_info, R.drawable.ic_cloud_download_white_24dp, R.color.colorStateGreen, KeyUtil.DURATION_SHORT); } else - NotifyUtil.createAlerter(this, R.string.title_download_info, R.string.text_unknown_error, + NotifyUtil.INSTANCE.createAlerter(this, R.string.title_download_info, R.string.text_unknown_error, R.drawable.ic_cloud_download_white_24dp, R.color.colorStateRed, KeyUtil.DURATION_SHORT); } 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..37e5e8ce4 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/view/activity/base/LoggingActivity.kt @@ -0,0 +1,161 @@ +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.presenter.base.BasePresenter +import com.mxt.anitrend.util.KeyUtil +import com.mxt.anitrend.util.NotifyUtil +import com.nguyenhoanglam.progresslayout.ProgressLayout +import kotlinx.coroutines.* +import java.io.File +import java.io.FileWriter +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 applicationVersionTextView: 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) + applicationVersionTextView.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 (!progressLayout.isLoading) { + progressLayout.showLoading() + if (requestPermissionIfMissing(Manifest.permission.WRITE_EXTERNAL_STORAGE)) { + async (Dispatchers.IO) { + val root = File( + Environment.getExternalStoragePublicDirectory( + Environment.DIRECTORY_DOWNLOADS + ), + "AniTrend Logcat.txt" + ) + FileWriter(root).use { + it.write(log.toString()) + } + withContext(Dispatchers.Main) { + progressLayout.showContent() + NotifyUtil.makeText(applicationContext, R.string.bug_report_saved, Toast.LENGTH_SHORT).show() + } + }.invokeOnCompletion { + it?.printStackTrace() + } + } + } else { + NotifyUtil.createAlerter(this, + R.string.title_activity_logging, + R.string.busy_please_wait, + R.drawable.ic_bug_report_grey_600_24dp, + R.color.colorStateBlue, + KeyUtil.DURATION_SHORT + ) + } + } + 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() + } + + private fun printLog(logHistory: String) { + updateUI() + reportLogTextView.text = logHistory + } + + override fun makeRequest() { + async (Dispatchers.IO) { + val process = Runtime.getRuntime().exec("logcat -d -v threadtime com.mxt.anitrend:*") + InputStreamReader(process.inputStream).use { inputStream -> + log.append(inputStream.readText()) + .append("\n") + } + val logHistory = log.toString() + withContext(Dispatchers.Main) { + printLog(logHistory) + } + }.invokeOnCompletion { + it?.printStackTrace() + } + } + + 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 b2d0992d8..000000000 --- a/app/src/main/java/com/mxt/anitrend/view/activity/base/ReportActivity.java +++ /dev/null @@ -1,80 +0,0 @@ -package com.mxt.anitrend.view.activity.base; - -import android.Manifest; -import android.content.Context; -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 android.support.annotation.Nullable; -import android.widget.Button; -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 deleted file mode 100644 index 040581d28..000000000 --- a/app/src/main/java/com/mxt/anitrend/view/activity/base/SettingsActivity.java +++ /dev/null @@ -1,354 +0,0 @@ -package com.mxt.anitrend.view.activity.base; - - -import android.annotation.TargetApi; -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.content.res.Configuration; -import android.media.Ringtone; -import android.media.RingtoneManager; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.preference.ListPreference; -import android.preference.Preference; -import android.preference.PreferenceActivity; -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 android.text.TextUtils; -import android.view.MenuItem; -import android.widget.Toast; - -import com.mxt.anitrend.R; -import com.mxt.anitrend.util.CompatUtil; -import com.mxt.anitrend.util.JobSchedulerUtil; - -import java.util.List; - -/** - * A {@link PreferenceActivity} that presents a set of application settings. On - * handset devices, settings are presented as a single list. On tablets, - * settings are split by category, with category headers shown to the left of - * the list of settings. - *

- * See - * Android Design: Settings for design guidelines and the Settings - * API Guide for more information on developing a Settings UI. - */ -public class SettingsActivity extends AppCompatPreferenceActivity { - - private SharedPreferences.OnSharedPreferenceChangeListener onSharedPreferenceChangeListener = (sharedPreferences, key) -> { - if (CompatUtil.INSTANCE.equals(key, getString(R.string.pref_key_crash_reports)) || CompatUtil.INSTANCE.equals(key, getString(R.string.pref_key_usage_analytics)) || - CompatUtil.INSTANCE.equals(key, getString(R.string.pref_key_selected_Language)) || CompatUtil.INSTANCE.equals(key, getString(R.string.pref_key_black_theme))) { - // Change the application theme if the current theme is not in dark mode - if (CompatUtil.INSTANCE.equals(key, getString(R.string.pref_key_black_theme))) - if(CompatUtil.INSTANCE.isLightTheme(getApplicationContext())) - applicationPref.toggleTheme(); - Toast.makeText(getApplicationContext(), R.string.text_application_restart_required, Toast.LENGTH_LONG).show(); - } else if (CompatUtil.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()) - JobSchedulerUtil.INSTANCE.scheduleJob(getApplicationContext()); - else - JobSchedulerUtil.INSTANCE.cancelJob(); - } - }; - - /** - * A preference value change listener that updates the preference's summary - * to reflect its new value. - */ - private static Preference.OnPreferenceChangeListener sBindPreferenceSummaryToValueListener = (preference, value) -> { - - String stringValue = value.toString(); - - if (preference instanceof ListPreference) { - // For list preferences, look up the correct display value in - // the preference's 'entries' list. - ListPreference listPreference = (ListPreference) preference; - int index = listPreference.findIndexOfValue(stringValue); - - // Set the summary to reflect the new value. - preference.setSummary( - index >= 0 - ? listPreference.getEntries()[index] - : null); - - } else if (preference instanceof RingtonePreference) { - // For ringtone preferences, look up the correct display value - // using RingtoneManager. - if (TextUtils.isEmpty(stringValue)) { - // Empty values correspond to 'silent' (no ringtone). - preference.setSummary(R.string.pref_ringtone_silent); - } else { - Ringtone ringtone = RingtoneManager.getRingtone( - preference.getContext(), Uri.parse(stringValue)); - - if (ringtone == null) { - // Clear the summary if there was a lookup error. - preference.setSummary(null); - } else { - // Set the summary to reflect the new ringtone display - // name. - String name = ringtone.getTitle(preference.getContext()); - preference.setSummary(name); - } - } - - } else { - // For all other preferences, set the summary to the value's - // simple string representation. - preference.setSummary(stringValue); - } - return true; - }; - - /** - * Helper method to determine if the device has an extra-large screen. For - * example, 10" tablets are extra-large. - */ - private static boolean isXLargeTablet(Context context) { - return (context.getResources().getConfiguration().screenLayout - & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_XLARGE; - } - - /** - * Binds a preference's summary to its value. More specifically, when the - * preference's value is changed, its summary (line of text below the - * preference title) is updated to reflect the value. The summary is also - * immediately updated upon calling this method. The exact display format is - * dependent on the type of preference. - * - * @see #sBindPreferenceSummaryToValueListener - */ - private static void bindPreferenceSummaryToValue(Preference preference) { - // Set the listener to watch for value changes. - preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener); - - // Trigger the listener immediately with the preference's - // current value. - sBindPreferenceSummaryToValueListener.onPreferenceChange(preference, PreferenceManager - .getDefaultSharedPreferences(preference.getContext()) - .getString(preference.getKey(), "")); - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setupActionBar(); - } - - /** - * Set up the {@link android.app.ActionBar}, if the API is available. - */ - private void setupActionBar() { - ActionBar actionBar = getSupportActionBar(); - if (actionBar != null) { - // Show the Up button in the action bar. - actionBar.setDisplayHomeAsUpEnabled(true); - } - } - - @Override - public boolean onMenuItemSelected(int featureId, MenuItem item) { - int id = item.getItemId(); - if (id == android.R.id.home) { - if (!super.onMenuItemSelected(featureId, item)) { - NavUtils.navigateUpFromSameTask(this); - } - return true; - } - return super.onMenuItemSelected(featureId, item); - } - - /** - * {@inheritDoc} - */ - @Override - public boolean onIsMultiPane() { - return isXLargeTablet(this); - } - - /** - * {@inheritDoc} - */ - @Override - @TargetApi(Build.VERSION_CODES.HONEYCOMB) - public void onBuildHeaders(List

target) { - loadHeadersFromResource(R.xml.pref_headers, target); - } - - /** - * This method stops fragment injection in malicious applications. - * Make sure to deny any unknown fragments here. - */ - protected boolean isValidFragment(String fragmentName) { - return PreferenceFragment.class.getName().equals(fragmentName) - || CustomizePreferenceFragment.class.getName().equals(fragmentName) - || GeneralPreferenceFragment.class.getName().equals(fragmentName) - || DataSyncPreferenceFragment.class.getName().equals(fragmentName) - || PrivacyPreferenceFragment.class.getName().equals(fragmentName) - || NotificationPreferenceFragment.class.getName().equals(fragmentName); - } - - @TargetApi(Build.VERSION_CODES.HONEYCOMB) - public static class CustomizePreferenceFragment extends PreferenceFragment { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - addPreferencesFromResource(R.xml.pref_customize); - setHasOptionsMenu(true); - - // Bind the summaries of EditText/List/Dialog/Ringtone preferences - // to their values. When their values change, their summaries are - // updated to reflect the new value, per the Android Design - // guidelines. - // bindPreferenceSummaryToValue(findPreference(getString(R.string.pref_key_amoled_theme))); - bindPreferenceSummaryToValue(findPreference(getString(R.string.pref_key_selected_Language))); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - int id = item.getItemId(); - if (id == android.R.id.home) { - startActivity(new Intent(getActivity(), SettingsActivity.class)); - return true; - } - return super.onOptionsItemSelected(item); - } - } - - @TargetApi(Build.VERSION_CODES.HONEYCOMB) - public static class GeneralPreferenceFragment extends PreferenceFragment { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - addPreferencesFromResource(R.xml.pref_general); - setHasOptionsMenu(true); - - // Bind the summaries of EditText/List/Dialog/Ringtone preferences - // to their values. When their values change, their summaries are - // updated to reflect the new value, per the Android Design - // guidelines. - bindPreferenceSummaryToValue(findPreference(getString(R.string.pref_key_startup_page))); - bindPreferenceSummaryToValue(findPreference(getString(R.string.pref_key_update_channel))); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - int id = item.getItemId(); - if (id == android.R.id.home) { - startActivity(new Intent(getActivity(), SettingsActivity.class)); - return true; - } - return super.onOptionsItemSelected(item); - } - } - - @TargetApi(Build.VERSION_CODES.HONEYCOMB) - public static class NotificationPreferenceFragment extends PreferenceFragment { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - addPreferencesFromResource(R.xml.pref_notification); - setHasOptionsMenu(true); - - // Bind the summaries of EditText/List/Dialog/Ringtone preferences - // to their values. When their values change, their summaries are - // updated to reflect the new value, per the Android Design - // guidelines. - bindPreferenceSummaryToValue(findPreference(getString(R.string.pref_key_ringtone))); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - int id = item.getItemId(); - if (id == android.R.id.home) { - startActivity(new Intent(getActivity(), SettingsActivity.class)); - return true; - } - return super.onOptionsItemSelected(item); - } - } - - @TargetApi(Build.VERSION_CODES.HONEYCOMB) - public static class DataSyncPreferenceFragment extends PreferenceFragment { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - addPreferencesFromResource(R.xml.pref_data_sync); - setHasOptionsMenu(true); - - // Bind the summaries of EditText/List/Dialog/Ringtone preferences - // to their values. When their values change, their summaries are - // updated to reflect the new value, per the Android Design - // guidelines. - bindPreferenceSummaryToValue(findPreference(getString(R.string.pref_key_sync_frequency))); - } - - - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - int id = item.getItemId(); - if (id == android.R.id.home) { - Intent intent = new Intent(getActivity(), SettingsActivity.class); - intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - startActivity(intent); - return true; - } - return super.onOptionsItemSelected(item); - } - } - - @TargetApi(Build.VERSION_CODES.HONEYCOMB) - public static class PrivacyPreferenceFragment extends PreferenceFragment { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - addPreferencesFromResource(R.xml.pref_privacy); - setHasOptionsMenu(true); - - // Bind the summaries of EditText/List/Dialog/Ringtone preferences - // to their values. When their values change, their summaries are - // updated to reflect the new value, per the Android Design - // guidelines. - // bindPreferenceSummaryToValue(findPreference(getString(R.string.pref_key_crash_reports))); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - int id = item.getItemId(); - if (id == android.R.id.home) { - Intent intent = new Intent(getActivity(), SettingsActivity.class); - intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - startActivity(intent); - return true; - } - return super.onOptionsItemSelected(item); - } - } - - @Override - protected void onPostResume() { - super.onPostResume(); - if (applicationPref != null) - applicationPref.getSharedPreferences() - .registerOnSharedPreferenceChangeListener(onSharedPreferenceChangeListener); - } - - @Override - protected void onPause() { - if (applicationPref != null) - applicationPref.getSharedPreferences() - .unregisterOnSharedPreferenceChangeListener(onSharedPreferenceChangeListener); - super.onPause(); - } -} diff --git a/app/src/main/java/com/mxt/anitrend/view/activity/base/SettingsActivity.kt b/app/src/main/java/com/mxt/anitrend/view/activity/base/SettingsActivity.kt new file mode 100644 index 000000000..94e6b5ab8 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/view/activity/base/SettingsActivity.kt @@ -0,0 +1,129 @@ +package com.mxt.anitrend.view.activity.base + +import android.content.SharedPreferences +import android.os.Bundle +import android.widget.Toast +import androidx.appcompat.widget.Toolbar +import androidx.fragment.app.FragmentActivity +import androidx.preference.PreferenceFragmentCompat +import butterknife.BindView +import butterknife.ButterKnife +import com.mxt.anitrend.R +import com.mxt.anitrend.base.custom.activity.ActivityBase +import com.mxt.anitrend.extension.applyConfiguredTheme +import com.mxt.anitrend.presenter.base.BasePresenter +import com.mxt.anitrend.util.DialogUtil +import com.mxt.anitrend.util.JobSchedulerUtil +import com.mxt.anitrend.util.NotifyUtil +import com.mxt.anitrend.util.Settings +import org.koin.android.ext.android.inject +import timber.log.Timber + +class SettingsActivity : ActivityBase() { + + @BindView(R.id.toolbar) + lateinit var toolbar: Toolbar + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.settings_activity) + ButterKnife.bind(this) + setSupportActionBar(toolbar) + } + + override fun onPostCreate(savedInstanceState: Bundle?) { + super.onPostCreate(savedInstanceState) + onActivityReady() + } + + /** + * Make decisions, check for permissions or fire background threads from this method + * N.B. Must be called after onPostCreate + */ + override fun onActivityReady() { + supportActionBar?.setDisplayHomeAsUpEnabled(true) + updateUI() + } + + override fun updateUI() { + supportFragmentManager + .beginTransaction() + .replace(R.id.settings, SettingsFragment()) + .commit() + + } + + override fun makeRequest() { + + } + + class SettingsFragment : PreferenceFragmentCompat(), SharedPreferences.OnSharedPreferenceChangeListener { + + private val settings by inject() + + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { + setPreferencesFromResource(R.xml.root_preferences, rootKey) + } + + /** + * Called when the fragment is visible to the user and actively running. + * This is generally + * tied to [Activity.onResume] of the containing + * Activity's lifecycle. + */ + override fun onResume() { + super.onResume() + settings.sharedPreferences.registerOnSharedPreferenceChangeListener(this) + } + + /** + * Called when the Fragment is no longer resumed. This is generally + * tied to [Activity.onPause] of the containing + * Activity's lifecycle. + */ + override fun onPause() { + settings.sharedPreferences.unregisterOnSharedPreferenceChangeListener(this) + super.onPause() + } + + private fun requireRestartNotice(fragmentActivity: FragmentActivity) { + DialogUtil.createDefaultDialog(fragmentActivity) + .autoDismiss(true) + .positiveText(R.string.Ok) + .content(R.string.text_application_restart_required) + .show() + } + + override fun onSharedPreferenceChanged(preferences: SharedPreferences?, key: String?) { + activity?.apply { + when (key) { + getString(R.string.pref_key_crash_reports), + getString(R.string.pref_key_usage_analytics), + getString(R.string.pref_key_selected_language)-> { + requireRestartNotice(this) + } + getString(R.string.pref_key_startup_page) -> { + if (!settings.isAuthenticated) + NotifyUtil.makeText(this, R.string.info_login_req, Toast.LENGTH_SHORT).show() + else + requireRestartNotice(this) + } + getString(R.string.pref_key_app_theme) -> { + applyConfiguredTheme() + } + getString(R.string.pref_key_sync_frequency) -> { + JobSchedulerUtil.cancelJob(this) + JobSchedulerUtil.scheduleJob(this) + } + getString(R.string.pref_key_new_message_notifications) -> { + if (settings.isNotificationEnabled) + JobSchedulerUtil.scheduleJob(this) + else + JobSchedulerUtil.cancelJob(this) + } + else -> Timber.i("$key not registered in this sharedPreferenceChange listener") + } + } + } + } +} \ No newline at end of file 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..06c7e328a 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,18 +1,19 @@ package com.mxt.anitrend.view.activity.base; -import android.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 android.view.View; import android.widget.Spinner; import android.widget.Toast; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.widget.AppCompatImageView; +import androidx.core.app.ShareCompat; +import androidx.databinding.DataBindingUtil; + import com.annimon.stream.IntPair; +import com.google.android.material.bottomsheet.BottomSheetBehavior; +import com.google.android.material.textfield.TextInputEditText; import com.mxt.anitrend.R; import com.mxt.anitrend.adapter.spinner.IconArrayAdapter; import com.mxt.anitrend.base.custom.activity.ActivityBase; @@ -22,14 +23,16 @@ import com.mxt.anitrend.base.interfaces.event.BottomSheetListener; import com.mxt.anitrend.base.interfaces.event.ItemClickListener; import com.mxt.anitrend.databinding.ActivityShareContentBinding; +import com.mxt.anitrend.extension.AppExtKt; +import com.mxt.anitrend.extension.KoinExt; 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.CompatUtil; 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.util.Settings; +import com.mxt.anitrend.util.markdown.MarkDownUtil; import com.mxt.anitrend.view.sheet.BottomSheetGiphy; import org.greenrobot.eventbus.EventBus; @@ -99,8 +102,12 @@ public void onSlide(@NonNull View bottomSheet, float slideOffset) { */ @Override protected void configureActivity() { - setTheme(new ApplicationPref(this).getTheme() == R.style.AppThemeLight ? - R.style.AppThemeLight_Translucent: R.style.AppThemeDark_Translucent); + Settings settings = KoinExt.get(Settings.class); + setTheme( + CompatUtil.INSTANCE.isLightTheme(settings.getTheme()) ? + R.style.AppThemeLight_Translucent : + R.style.AppThemeDark_Translucent + ); } @Override @@ -192,7 +199,7 @@ public void onStateExpanded() { @Override @Subscribe(threadMode = ThreadMode.MAIN_ORDERED) public void onModelChanged(BaseConsumer consumer) { if(consumer.getRequestMode() == KeyUtil.MUT_SAVE_TEXT_FEED) { - NotifyUtil.makeText(this, R.string.text_compose_success, R.drawable.ic_insert_emoticon_white_24dp, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(this, R.string.text_compose_success, R.drawable.ic_insert_emoticon_white_24dp, Toast.LENGTH_SHORT).show(); bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); } } @@ -239,7 +246,7 @@ public void onItemClick(View target, IntPair data) { mBottomSheet.show(getSupportFragmentManager(), mBottomSheet.getTag()); break; case R.id.widget_flipper: - CompatUtil.INSTANCE.hideKeyboard(this); + AppExtKt.hideKeyboard(this); break; default: DialogUtil.createDialogAttachMedia(target.getId(), binding.composerWidget.getEditor(), this); diff --git a/app/src/main/java/com/mxt/anitrend/view/activity/base/VideoPlayerActivity.java b/app/src/main/java/com/mxt/anitrend/view/activity/base/VideoPlayerActivity.java index 8d29ec56d..cb7e87c61 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,12 +3,13 @@ import android.os.Build; import android.os.Bundle; import android.os.PersistableBundle; -import android.support.annotation.Nullable; import android.view.View; import android.view.Window; import android.view.WindowManager; import android.widget.Toast; +import androidx.annotation.Nullable; + import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.activity.ActivityBase; import com.mxt.anitrend.presenter.base.BasePresenter; @@ -38,7 +39,7 @@ protected void onCreate(Bundle savedInstanceState) { contentLink = getIntent().getStringExtra(KeyUtil.arg_model); onActivityReady(); } else { - NotifyUtil.makeText(this, R.string.text_error_request, R.drawable.ic_warning_white_18dp, Toast.LENGTH_LONG).show(); + NotifyUtil.INSTANCE.makeText(this, R.string.text_error_request, R.drawable.ic_warning_white_18dp, Toast.LENGTH_LONG).show(); } } @@ -62,7 +63,7 @@ public void onBackPressed() { e.printStackTrace(); } if(Jzvd.backPress()) { - NotifyUtil.makeText(this, R.string.text_confirm_exit, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(this, R.string.text_confirm_exit, Toast.LENGTH_SHORT).show(); return; } super.onBackPressed(); @@ -75,7 +76,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 +98,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..c88f3e725 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,10 +3,11 @@ import android.content.Intent; import android.os.Build; import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v4.content.ContextCompat; import android.view.View; +import androidx.annotation.Nullable; +import androidx.core.content.ContextCompat; + import com.codemybrainsout.onboarder.AhoyOnboarderActivity; import com.codemybrainsout.onboarder.AhoyOnboarderCard; import com.mxt.anitrend.R; @@ -47,10 +48,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 +63,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)) )); } 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..9a616f9e0 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,30 +2,31 @@ 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 android.view.Menu; import android.view.MenuItem; import android.widget.Toast; +import androidx.annotation.Nullable; +import androidx.appcompat.widget.Toolbar; +import androidx.coordinatorlayout.widget.CoordinatorLayout; +import androidx.viewpager.widget.ViewPager; + import com.mxt.anitrend.R; import com.mxt.anitrend.adapter.pager.detail.CharacterPageAdapter; import com.mxt.anitrend.base.custom.activity.ActivityBase; import com.mxt.anitrend.base.custom.view.widget.FavouriteToolbarWidget; import com.mxt.anitrend.model.entity.base.CharacterBase; -import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder; import com.mxt.anitrend.presenter.base.BasePresenter; -import com.mxt.anitrend.util.GraphUtil; import com.mxt.anitrend.util.KeyUtil; import com.mxt.anitrend.util.NotifyUtil; +import com.mxt.anitrend.util.graphql.GraphUtil; import com.ogaclejapan.smarttablayout.SmartTabLayout; import java.util.Locale; import butterknife.BindView; import butterknife.ButterKnife; +import io.github.wax911.library.model.request.QueryContainerBuilder; /** * Created by max on 2017/12/14. @@ -64,7 +65,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) { @@ -90,7 +91,7 @@ public boolean onOptionsItemSelected(MenuItem item) { break; } } else - NotifyUtil.makeText(getApplicationContext(), R.string.text_activity_loading, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(getApplicationContext(), R.string.text_activity_loading, Toast.LENGTH_SHORT).show(); return super.onOptionsItemSelected(item); } 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..e51a17289 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,11 @@ 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.appcompat.widget.Toolbar; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentTransaction; 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..41ab8aaeb 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,11 @@ 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.appcompat.widget.Toolbar; +import androidx.coordinatorlayout.widget.CoordinatorLayout; +import androidx.viewpager.widget.ViewPager; 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..36e3ee233 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,16 +1,17 @@ package com.mxt.anitrend.view.activity.detail; import android.content.Intent; -import android.databinding.DataBindingUtil; import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v4.view.ViewPager; -import android.support.v7.widget.Toolbar; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Toast; +import androidx.annotation.Nullable; +import androidx.appcompat.widget.Toolbar; +import androidx.databinding.DataBindingUtil; +import androidx.viewpager.widget.ViewPager; + import com.mxt.anitrend.R; import com.mxt.anitrend.adapter.pager.detail.AnimePageAdapter; import com.mxt.anitrend.adapter.pager.detail.MangaPageAdapter; @@ -20,22 +21,21 @@ import com.mxt.anitrend.base.custom.view.widget.FavouriteToolbarWidget; import com.mxt.anitrend.databinding.ActivitySeriesBinding; import com.mxt.anitrend.model.entity.base.MediaBase; -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.GraphUtil; import com.mxt.anitrend.util.KeyUtil; -import com.mxt.anitrend.util.MediaActionUtil; 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.mxt.anitrend.util.graphql.GraphUtil; +import com.mxt.anitrend.util.media.MediaActionUtil; import com.ogaclejapan.smarttablayout.SmartTabLayout; import java.util.Locale; import butterknife.BindView; import butterknife.ButterKnife; +import io.github.wax911.library.model.request.QueryContainerBuilder; import uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt; /** @@ -81,7 +81,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); @@ -116,7 +116,7 @@ public boolean onOptionsItemSelected(MenuItem item) { break; } } else - NotifyUtil.makeText(getApplicationContext(), R.string.text_activity_loading, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(getApplicationContext(), R.string.text_activity_loading, Toast.LENGTH_SHORT).show(); return super.onOptionsItemSelected(item); } @@ -135,7 +135,7 @@ protected void onActivityReady() { viewPager.setOffscreenPageLimit(offScreenLimit); smartTabLayout.setViewPager(viewPager); } else - NotifyUtil.createAlerter(this, R.string.text_error_request, R.string.text_unknown_error, R.drawable.ic_warning_white_18dp, R.color.colorStateRed); + NotifyUtil.INSTANCE.createAlerter(this, R.string.text_error_request, R.string.text_unknown_error, R.drawable.ic_warning_white_18dp, R.color.colorStateRed); } @Override @@ -154,11 +154,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/MediaBrowseActivity.java b/app/src/main/java/com/mxt/anitrend/view/activity/detail/MediaBrowseActivity.java index 6bb78a9d0..a0ddde3f0 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,19 +1,20 @@ 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 android.text.Spanned; +import androidx.annotation.Nullable; +import androidx.appcompat.widget.Toolbar; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentTransaction; + import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.activity.ActivityBase; import com.mxt.anitrend.model.entity.base.MediaBase; import com.mxt.anitrend.presenter.base.BasePresenter; import com.mxt.anitrend.presenter.fragment.MediaPresenter; import com.mxt.anitrend.util.KeyUtil; -import com.mxt.anitrend.util.MarkDownUtil; +import com.mxt.anitrend.util.markdown.MarkDownUtil; import com.mxt.anitrend.view.fragment.list.MediaBrowseFragment; import butterknife.BindView; 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..ef49b20f1 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,13 +1,14 @@ 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 android.view.Menu; import android.view.MenuItem; +import androidx.annotation.Nullable; +import androidx.appcompat.widget.Toolbar; +import androidx.coordinatorlayout.widget.CoordinatorLayout; +import androidx.viewpager.widget.ViewPager; + import com.mxt.anitrend.R; import com.mxt.anitrend.adapter.pager.index.MediaListPageAdapter; import com.mxt.anitrend.base.custom.activity.ActivityBase; 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..6880ecfc5 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,11 @@ 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.appcompat.widget.Toolbar; +import androidx.coordinatorlayout.widget.CoordinatorLayout; +import androidx.viewpager.widget.ViewPager; 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..3bb398303 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,11 @@ 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.appcompat.widget.Toolbar; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentTransaction; 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..509451570 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,35 +1,35 @@ package com.mxt.anitrend.view.activity.detail; import android.content.Intent; -import android.databinding.DataBindingUtil; import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v4.view.ViewPager; -import android.support.v7.widget.Toolbar; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Toast; +import androidx.annotation.Nullable; +import androidx.appcompat.widget.Toolbar; +import androidx.databinding.DataBindingUtil; +import androidx.viewpager.widget.ViewPager; + import com.mxt.anitrend.R; import com.mxt.anitrend.adapter.pager.detail.ProfilePageAdapter; import com.mxt.anitrend.base.custom.activity.ActivityBase; import com.mxt.anitrend.base.custom.view.image.WideImageView; import com.mxt.anitrend.databinding.ActivityProfileBinding; import com.mxt.anitrend.model.entity.base.UserBase; -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.GraphUtil; 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.util.graphql.GraphUtil; import com.mxt.anitrend.view.sheet.BottomSheetComposer; import com.ogaclejapan.smarttablayout.SmartTabLayout; import butterknife.BindView; import butterknife.ButterKnife; +import io.github.wax911.library.model.request.QueryContainerBuilder; /** * Created by max on 2017/11/14. @@ -108,7 +108,7 @@ public boolean onOptionsItemSelected(MenuItem item) { mBottomSheet.show(getSupportFragmentManager(), mBottomSheet.getTag()); } } else - NotifyUtil.makeText(this, R.string.text_activity_loading, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(this, R.string.text_activity_loading, Toast.LENGTH_SHORT).show(); return true; } return super.onOptionsItemSelected(item); @@ -121,7 +121,7 @@ public boolean onOptionsItemSelected(MenuItem item) { @Override protected void onActivityReady() { if(id == -1 && userName == null) - NotifyUtil.createAlerter(this, R.string.text_user_model, R.string.layout_empty_response, R.drawable.ic_warning_white_18dp, R.color.colorStateRed); + NotifyUtil.INSTANCE.createAlerter(this, R.string.text_user_model, R.string.layout_empty_response, R.drawable.ic_warning_white_18dp, R.color.colorStateRed); else makeRequest(); } @@ -135,14 +135,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); } @@ -172,7 +172,7 @@ public void onChanged(@Nullable UserBase model) { this.model = model; updateUI(); } else - NotifyUtil.createAlerter(this, R.string.text_user_model, R.string.layout_empty_response, R.drawable.ic_warning_white_18dp, R.color.colorStateRed); + NotifyUtil.INSTANCE.createAlerter(this, R.string.text_user_model, R.string.layout_empty_response, R.drawable.ic_warning_white_18dp, R.color.colorStateRed); } @Override 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..ef025c5ac 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,30 +2,31 @@ 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 android.view.Menu; import android.view.MenuItem; import android.widget.Toast; +import androidx.annotation.Nullable; +import androidx.appcompat.widget.Toolbar; +import androidx.coordinatorlayout.widget.CoordinatorLayout; +import androidx.viewpager.widget.ViewPager; + import com.mxt.anitrend.R; import com.mxt.anitrend.adapter.pager.detail.StaffPageAdapter; import com.mxt.anitrend.base.custom.activity.ActivityBase; import com.mxt.anitrend.base.custom.view.widget.FavouriteToolbarWidget; import com.mxt.anitrend.model.entity.base.StaffBase; -import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder; import com.mxt.anitrend.presenter.base.BasePresenter; -import com.mxt.anitrend.util.GraphUtil; import com.mxt.anitrend.util.KeyUtil; import com.mxt.anitrend.util.NotifyUtil; +import com.mxt.anitrend.util.graphql.GraphUtil; import com.ogaclejapan.smarttablayout.SmartTabLayout; import java.util.Locale; import butterknife.BindView; import butterknife.ButterKnife; +import io.github.wax911.library.model.request.QueryContainerBuilder; /** * Created by max on 2017/12/14. @@ -63,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) { @@ -89,7 +90,7 @@ public boolean onOptionsItemSelected(MenuItem item) { break; } } else - NotifyUtil.makeText(getApplicationContext(), R.string.text_activity_loading, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(getApplicationContext(), R.string.text_activity_loading, Toast.LENGTH_SHORT).show(); return super.onOptionsItemSelected(item); } 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..efd8c9ba2 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,29 +2,30 @@ 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 android.view.Menu; import android.view.MenuItem; import android.widget.Toast; +import androidx.annotation.Nullable; +import androidx.appcompat.widget.Toolbar; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentTransaction; + import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.activity.ActivityBase; import com.mxt.anitrend.base.custom.view.widget.FavouriteToolbarWidget; import com.mxt.anitrend.model.entity.base.StudioBase; -import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder; import com.mxt.anitrend.presenter.base.BasePresenter; -import com.mxt.anitrend.util.GraphUtil; import com.mxt.anitrend.util.KeyUtil; import com.mxt.anitrend.util.NotifyUtil; +import com.mxt.anitrend.util.graphql.GraphUtil; import com.mxt.anitrend.view.fragment.detail.StudioMediaFragment; import java.util.Locale; import butterknife.BindView; import butterknife.ButterKnife; +import io.github.wax911.library.model.request.QueryContainerBuilder; /** * Created by max on 2017/12/14. @@ -61,7 +62,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) { @@ -85,7 +86,7 @@ public boolean onOptionsItemSelected(MenuItem item) { break; } } else - NotifyUtil.makeText(getApplicationContext(), R.string.text_activity_loading, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(getApplicationContext(), R.string.text_activity_loading, Toast.LENGTH_SHORT).show(); return super.onOptionsItemSelected(item); } 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 d84aa1fc1..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 android.arch.lifecycle.Observer; -import android.content.Intent; -import android.databinding.DataBindingUtil; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.support.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().enqueue(authenticatorWorker); - WorkManager.getInstance().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..115b13863 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/view/activity/index/LoginActivity.kt @@ -0,0 +1,216 @@ +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.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.util.graphql.GraphUtil +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 (CompatUtil.isLightTheme(Settings(this).theme)) + 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) { + if (isAlive) { + WebTokenRequest.invalidateInstance(applicationContext) + NotifyUtil.createAlerter(this, getString(R.string.text_error_auth_login), + error, R.drawable.ic_warning_white_18dp, R.color.colorStateRed, KeyUtil.DURATION_LONG) + binding.widgetFlipper.showPrevious() + Timber.tag(TAG).e(error) + } + } + + override fun showEmpty(message: String) { + if (isAlive) { + WebTokenRequest.invalidateInstance(applicationContext) + NotifyUtil.createAlerter(this, getString(R.string.text_error_auth_login), + message, R.drawable.ic_warning_white_18dp, R.color.colorStateOrange, KeyUtil.DURATION_LONG) + binding.widgetFlipper.showPrevious() + Timber.tag(TAG).w(message) + } + } + + 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 deleted file mode 100644 index 3e999d692..000000000 --- a/app/src/main/java/com/mxt/anitrend/view/activity/index/MainActivity.java +++ /dev/null @@ -1,523 +0,0 @@ -package com.mxt.anitrend.view.activity.index; - -import android.Manifest; -import android.content.Intent; -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 android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.widget.TextView; -import android.widget.Toast; - -import com.mxt.anitrend.R; -import com.mxt.anitrend.adapter.pager.index.AiringPageAdapter; -import com.mxt.anitrend.adapter.pager.index.FeedPageAdapter; -import com.mxt.anitrend.adapter.pager.index.HubPageAdapter; -import com.mxt.anitrend.adapter.pager.index.MangaPageAdapter; -import com.mxt.anitrend.adapter.pager.index.MediaListPageAdapter; -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.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.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.MarkDownUtil; -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.SettingsActivity; -import com.mxt.anitrend.view.activity.detail.ProfileActivity; -import com.mxt.anitrend.view.sheet.BottomSheetMessage; -import com.ogaclejapan.smarttablayout.SmartTabLayout; - -import org.greenrobot.eventbus.EventBus; -import org.greenrobot.eventbus.Subscribe; -import org.greenrobot.eventbus.ThreadMode; - -import butterknife.BindView; -import butterknife.ButterKnife; - -import static android.content.pm.PackageManager.PERMISSION_DENIED; -import static android.content.pm.PackageManager.PERMISSION_GRANTED; - -/** - * Created by max on 2017/10/04. - * Base main_menu activity to show case template - */ - -public class MainActivity extends ActivityBase implements View.OnClickListener, - BaseConsumer.onRequestModelChange, NavigationView.OnNavigationItemSelectedListener { - - protected @BindView(R.id.toolbar) Toolbar mToolbar; - protected @BindView(R.id.page_container) ViewPager mViewPager; - protected @BindView(R.id.smart_tab) SmartTabLayout mNavigationTabStrip; - protected @BindView(R.id.coordinator) CoordinatorLayout coordinatorLayout; - protected @BindView(R.id.drawer_layout) DrawerLayout mDrawerLayout; - protected @BindView(R.id.nav_view) NavigationView mNavigationView; - - private ActionBarDrawerToggle mDrawerToggle; - - private @IdRes int redirectShortcut; - private @IdRes int selectedItem; - private @StringRes int selectedTitle; - - private int mPageIndex; - - private Menu menuItems; - - private MenuItem mHomeFeed, mAccountLogin, mSignOutProfile, mManageMenu; - - private HeaderImageView mHeaderView; - private TextView mUserName; - private AvatarIndicatorView mUserAvatar; - - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - ButterKnife.bind(this); - setSupportActionBar(mToolbar); - setPresenter(new BasePresenter(getApplicationContext())); - mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, mToolbar, - R.string.navigation_drawer_open, R.string.navigation_drawer_close); - if (savedInstanceState == null) - redirectShortcut = getIntent().getIntExtra(KeyUtil.arg_redirect, 0); - } - - @Override - protected void onPostCreate(@Nullable Bundle savedInstanceState) { - super.onPostCreate(savedInstanceState); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) - mNavigationView.setItemBackground( - CompatUtil.INSTANCE.getDrawable(this, R.drawable.nav_background)); - mNavigationView.setNavigationItemSelectedListener(this); - mViewPager.setOffscreenPageLimit(offScreenLimit); - mPageIndex = DateUtil.INSTANCE.getMenuSelect(); - menuItems = mNavigationView.getMenu(); - onActivityReady(); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.main_menu, menu); - MenuItem searchItem = menu.findItem(R.id.action_search); - if(mSearchView != null) - mSearchView.setMenuItem(searchItem); - return super.onCreateOptionsMenu(menu); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - Intent intent; - switch (item.getItemId()) { - case R.id.action_donate: - intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.patreon.com/wax911")); - startActivity(intent); - return true; - case R.id.action_about: - startActivity(new Intent(MainActivity.this, AboutActivity.class)); - return true; - case R.id.action_share: - intent = new Intent(); - intent.setAction(Intent.ACTION_SEND); - intent.putExtra(Intent.EXTRA_TEXT, getString(R.string.campaign_link)); - intent.setType("text/plain"); - startActivity(intent); - return true; - case R.id.action_settings: - startActivity(new Intent(MainActivity.this, SettingsActivity.class)); - return true; - case R.id.action_discord: - String invite = getString(R.string.link_anitrend_discord); - intent = new Intent(Intent.ACTION_VIEW, Uri.parse(invite)); - startActivity(intent); - return true; - case R.id.action_report: - startActivity(new Intent(MainActivity.this, ReportActivity.class)); - return true; - } - return super.onOptionsItemSelected(item); - } - - /** - * Make decisions, check for permissions or fire background threads from this method - * N.B. Must be called after onPostCreate - */ - @Override - protected void onActivityReady() { - if(selectedItem == 0) - selectedItem = getPresenter().getApplicationPref().isAuthenticated()? - (redirectShortcut == 0? getPresenter().getApplicationPref().getStartupPage() : redirectShortcut) - : (redirectShortcut == 0? R.id.nav_anime : redirectShortcut); - mNavigationView.setCheckedItem(selectedItem); - onNavigate(selectedItem); - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - outState.putInt(KeyUtil.arg_redirect, redirectShortcut); - outState.putInt(KeyUtil.key_navigation_selected, selectedItem); - outState.putInt(KeyUtil.key_navigation_title, selectedTitle); - super.onSaveInstanceState(outState); - } - - @Override - protected void onRestoreInstanceState(Bundle savedInstanceState) { - super.onRestoreInstanceState(savedInstanceState); - if(savedInstanceState != null) { - redirectShortcut = savedInstanceState.getInt(KeyUtil.arg_redirect); - selectedItem = savedInstanceState.getInt(KeyUtil.key_navigation_selected); - selectedTitle = savedInstanceState.getInt(KeyUtil.key_navigation_title); - } - } - - @Override - public void onBackPressed() { - if (mDrawerLayout.isDrawerOpen(GravityCompat.START)) { - mDrawerLayout.closeDrawer(GravityCompat.START); - return; - } super.onBackPressed(); - } - - @Override - protected void onPause() { - super.onPause(); - mDrawerLayout.removeDrawerListener(mDrawerToggle); - } - - /** - * 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 - * {@link #onResumeFragments()}. - */ - @Override - protected void onResume() { - super.onResume(); - if(!EventBus.getDefault().isRegistered(this)) - EventBus.getDefault().register(this); - mDrawerLayout.addDrawerListener(mDrawerToggle); - mDrawerToggle.syncState(); - updateUI(); - } - - @Override - public boolean onNavigationItemSelected(@NonNull MenuItem item) { - final @IdRes int menu = item.getItemId(); - if(selectedItem != menu) - onNavigate(menu); - if(menu != R.id.nav_light_theme && menu != R.id.nav_sign_in) - mDrawerLayout.closeDrawer(GravityCompat.START); - return true; - } - - private void onNavigate(@IdRes int menu) { - switch (menu) { - case R.id.nav_home_feed: - mToolbar.setTitle(getString(R.string.drawer_title_home)); - selectedItem = menu; - mViewPager.setAdapter(new FeedPageAdapter(getSupportFragmentManager(), getApplicationContext())); - mNavigationTabStrip.setViewPager(mViewPager); - break; - case R.id.nav_anime: - mToolbar.setTitle(getString(R.string.drawer_title_anime)); - selectedItem = menu; - mViewPager.setAdapter(new SeasonPageAdapter(getSupportFragmentManager(), getApplicationContext())); - mNavigationTabStrip.setViewPager(mViewPager); - mViewPager.setCurrentItem(mPageIndex, false); - break; - case R.id.nav_manga: - mToolbar.setTitle(getString(R.string.drawer_title_manga)); - selectedItem = menu; - mViewPager.setAdapter(new MangaPageAdapter(getSupportFragmentManager(), getApplicationContext())); - mNavigationTabStrip.setViewPager(mViewPager); - break; - case R.id.nav_trending: - mToolbar.setTitle(getString(R.string.drawer_title_trending)); - selectedItem = menu; - mViewPager.setAdapter(new TrendingPageAdapter(getSupportFragmentManager(), getApplicationContext())); - mNavigationTabStrip.setViewPager(mViewPager); - break; - case R.id.nav_airing: - mToolbar.setTitle(getString(R.string.drawer_title_airing)); - mViewPager.setAdapter(new AiringPageAdapter(getSupportFragmentManager(), getApplicationContext())); - mNavigationTabStrip.setViewPager(mViewPager); - selectedItem = menu; - break; - case R.id.nav_myanime: - Bundle animeParams = new Bundle(); - animeParams.putString(KeyUtil.arg_mediaType, KeyUtil.ANIME); - animeParams.putString(KeyUtil.arg_userName, getPresenter().getDatabase().getCurrentUser().getName()); - animeParams.putLong(KeyUtil.arg_id, getPresenter().getDatabase().getCurrentUser().getId()); - - MediaListPageAdapter animeListPageAdapter = new MediaListPageAdapter(getSupportFragmentManager(), getApplicationContext()); - animeListPageAdapter.setParams(animeParams); - - mToolbar.setTitle(getString(R.string.drawer_title_myanime)); - mViewPager.setAdapter(animeListPageAdapter); - mNavigationTabStrip.setViewPager(mViewPager); - selectedItem = menu; - break; - case R.id.nav_mymanga: - Bundle mangaParams = new Bundle(); - mangaParams.putString(KeyUtil.arg_mediaType, KeyUtil.MANGA); - mangaParams.putString(KeyUtil.arg_userName, getPresenter().getDatabase().getCurrentUser().getName()); - mangaParams.putLong(KeyUtil.arg_id, getPresenter().getDatabase().getCurrentUser().getId()); - - MediaListPageAdapter mangaListPageAdapter = new MediaListPageAdapter(getSupportFragmentManager(), getApplicationContext()); - mangaListPageAdapter.setParams(mangaParams); - - mToolbar.setTitle(getString(R.string.drawer_title_mymanga)); - mViewPager.setAdapter(mangaListPageAdapter); - mNavigationTabStrip.setViewPager(mViewPager); - selectedItem = menu; - break; - case R.id.nav_hub: - mToolbar.setTitle(getString(R.string.drawer_title_hub)); - mViewPager.setAdapter(new HubPageAdapter(getSupportFragmentManager(), getApplicationContext())); - mNavigationTabStrip.setViewPager(mViewPager); - selectedItem = menu; - break; - case R.id.nav_reviews: - mToolbar.setTitle(getString(R.string.drawer_title_reviews)); - selectedItem = menu; - mViewPager.setAdapter(new ReviewPageAdapter(getSupportFragmentManager(), getApplicationContext())); - mNavigationTabStrip.setViewPager(mViewPager); - break; - case R.id.nav_sign_in: - startActivity(new Intent(MainActivity.this, LoginActivity.class)); - break; - case R.id.nav_sign_out: - mBottomSheet = new BottomSheetMessage.Builder() - .setText(R.string.drawer_signout_text) - .setTitle(R.string.drawer_signout_title) - .setPositiveText(R.string.Yes) - .setNegativeText(R.string.No) - .buildWithCallback(new BottomSheetChoice() { - @Override - public void onPositiveButton() { - WebTokenRequest.invalidateInstance(getApplicationContext()); - Intent intent = new Intent(MainActivity.this, SplashActivity.class); - finish(); - startActivity(intent); - } - - @Override - public void onNegativeButton() { - - } - }); - showBottomSheet(); - break; - case R.id.nav_check_update: - switch (ContextCompat.checkSelfPermission(getApplicationContext(), android.Manifest.permission.WRITE_EXTERNAL_STORAGE)) { - case PERMISSION_GRANTED: - mBottomSheet = new BottomSheetMessage.Builder() - .setText(R.string.drawer_update_text) - .setTitle(R.string.drawer_update_title) - .setPositiveText(R.string.Yes) - .setNegativeText(R.string.No) - .buildWithCallback(new BottomSheetChoice() { - @Override - public void onPositiveButton() { - VersionBase versionBase = getPresenter().getDatabase().getRemoteVersion(); - if(versionBase != null && versionBase.isNewerVersion()) - DownloaderService.INSTANCE.downloadNewVersion(MainActivity.this, versionBase); - else - NotifyUtil.createAlerter(MainActivity.this, getString(R.string.title_update_infodadat), - getString(R.string.app_no_date), R.drawable.ic_cloud_done_white_24dp, R.color.colorStateGreen); - } - - @Override - public void onNegativeButton() { - - } - }); - showBottomSheet(); - break; - case PERMISSION_DENIED: - if(ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) - DialogUtil.createMessage(MainActivity.this, R.string.title_permission_write, R.string.text_permission_write, (dialog, which) -> { - switch (which) { - case POSITIVE: - ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_PERMISSION); - break; - case NEGATIVE: - NotifyUtil.makeText(MainActivity.this, R.string.canceled_by_user, Toast.LENGTH_SHORT).show(); - break; - } - }); - else - requestPermissionIfMissing(android.Manifest.permission.WRITE_EXTERNAL_STORAGE); - break; - } - break; - case R.id.nav_light_theme: - getPresenter().getApplicationPref().toggleTheme(); - recreate(); - break; - default: - break; - } - } - - /** - * Called for each of the requested permissions as they are granted - * - * @param permission the current permission granted - */ - @Override - protected void onPermissionGranted(@NonNull String permission) { - super.onPermissionGranted(permission); - try { - if (permission.equals(Manifest.permission.WRITE_EXTERNAL_STORAGE)) - onNavigate(R.id.nav_check_update); - } catch (Exception e) { - e.printStackTrace(); - } - } - - @Override - protected void updateUI() { - VersionBase versionBase = getPresenter().getDatabase().getRemoteVersion(); - View HeaderContainer = mNavigationView.getHeaderView(0); - - mHeaderView = HeaderContainer.findViewById(R.id.drawer_banner); - mUserAvatar = HeaderContainer.findViewById(R.id.drawer_avatar_indicator); - mUserName = HeaderContainer.findViewById(R.id.drawer_app_name); - - mHomeFeed = menuItems.findItem(R.id.nav_home_feed); - mAccountLogin = menuItems.findItem(R.id.nav_sign_in); - mSignOutProfile = menuItems.findItem(R.id.nav_sign_out); - mManageMenu = menuItems.findItem(R.id.nav_header_manage); - - HeaderContainer.findViewById(R.id.banner_clickable).setOnClickListener(this); - - if(getPresenter().getApplicationPref().isAuthenticated()) - setupUserItems(); - else - mHeaderView.setImageResource(R.drawable.reg_bg); - - if(versionBase != null && versionBase.isNewerVersion()) { - // If a new version of the application is available on GitHub - TextView mAppUpdateWidget = menuItems.findItem(R.id.nav_check_update).getActionView().findViewById(R.id.app_update_info); - mAppUpdateWidget.setText(getString(R.string.app_update, versionBase.getVersion())); - mAppUpdateWidget.setVisibility(View.VISIBLE); - } - checkNewInstallation(); - } - - @Override - protected void makeRequest() { - // nothing to request - } - - private void setupUserItems() { - User user; - if((user = getPresenter().getDatabase().getCurrentUser()) != null) { - mUserName.setText(user.getName()); - mUserAvatar.onInit(); - HeaderImageView.setImage(mHeaderView, user.getBannerImage()); - if (getPresenter().getApplicationPref().shouldShowTipFor(KeyUtil.KEY_LOGIN_TIP)) { - NotifyUtil.createLoginToast(MainActivity.this, user); - getPresenter().getApplicationPref().disableTipFor(KeyUtil.KEY_LOGIN_TIP); - mBottomSheet = new BottomSheetMessage.Builder() - .setText(R.string.login_message) - .setTitle(R.string.login_title) - .setNegativeText(R.string.Ok) - .build(); - showBottomSheet(); - } - AnalyticsUtil.setCrashAnalyticsUser(this, user.getName()); - } - - mAccountLogin.setVisible(false); - - mSignOutProfile.setVisible(true); - mManageMenu.setVisible(true); - mHomeFeed.setVisible(true); - } - - /** - * Checks to see if this instance is a new installation - */ - private void checkNewInstallation() { - if (getPresenter().getApplicationPref().isUpdated()) { - DialogUtil.createChangeLog(this); - getPresenter().getApplicationPref().setUpdated(); - } - if(getPresenter().getApplicationPref().isFreshInstall()) { - getPresenter().getApplicationPref().setFreshInstall(); - mBottomSheet = new BottomSheetMessage.Builder() - .setText(R.string.app_intro_guide) - .setTitle(R.string.app_intro_title) - .setNegativeText(R.string.Ok).build(); - showBottomSheet(); - } - } - - @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; - } - } - - @Override - protected void onDestroy() { - if(mUserAvatar != null) - mUserAvatar.onViewRecycled(); - super.onDestroy(); - } - - @Override @Subscribe(threadMode = ThreadMode.MAIN_ORDERED) - public void onModelChanged(BaseConsumer consumer) { - if(consumer.getRequestMode() == KeyUtil.USER_CURRENT_REQ && consumer.getChangeModel() != null && consumer.getChangeModel().getUnreadNotificationCount() > 0) - NotifyUtil.createAlerter(this, R.string.alerter_notification_title, R.string.alerter_notification_text, - R.drawable.ic_notifications_active_white_24dp, R.color.colorAccent); - } -} - diff --git a/app/src/main/java/com/mxt/anitrend/view/activity/index/MainActivity.kt b/app/src/main/java/com/mxt/anitrend/view/activity/index/MainActivity.kt new file mode 100644 index 000000000..c80c4555b --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/view/activity/index/MainActivity.kt @@ -0,0 +1,534 @@ +package com.mxt.anitrend.view.activity.index + +import android.Manifest +import android.content.Intent +import android.content.pm.PackageManager.PERMISSION_DENIED +import android.content.pm.PackageManager.PERMISSION_GRANTED +import android.net.Uri +import android.os.Build +import android.os.Bundle +import android.view.Menu +import android.view.MenuItem +import android.view.View +import android.widget.TextView +import android.widget.Toast +import androidx.annotation.IdRes +import androidx.annotation.StringRes +import androidx.appcompat.app.ActionBarDrawerToggle +import androidx.appcompat.widget.Toolbar +import androidx.coordinatorlayout.widget.CoordinatorLayout +import androidx.core.app.ActivityCompat +import androidx.core.content.ContextCompat +import androidx.core.view.GravityCompat +import androidx.drawerlayout.widget.DrawerLayout +import androidx.viewpager.widget.ViewPager +import butterknife.BindView +import butterknife.ButterKnife +import com.afollestad.materialdialogs.DialogAction +import com.google.android.material.navigation.NavigationView +import com.mxt.anitrend.R +import com.mxt.anitrend.adapter.pager.index.* +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.extension.LAZY_MODE_UNSAFE +import com.mxt.anitrend.extension.getCompatDrawable +import com.mxt.anitrend.extension.startNewActivity +import com.mxt.anitrend.model.entity.anilist.User +import com.mxt.anitrend.presenter.base.BasePresenter +import com.mxt.anitrend.service.DownloaderService +import com.mxt.anitrend.util.DialogUtil +import com.mxt.anitrend.util.KeyUtil +import com.mxt.anitrend.util.NotifyUtil +import com.mxt.anitrend.util.date.DateUtil +import com.mxt.anitrend.view.activity.base.AboutActivity +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 +import com.ogaclejapan.smarttablayout.SmartTabLayout +import org.greenrobot.eventbus.EventBus +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode + +/** + * Created by max on 2017/10/04. + * Base main_menu activity to show case template + */ + +class MainActivity : ActivityBase(), View.OnClickListener, + BaseConsumer.onRequestModelChange, NavigationView.OnNavigationItemSelectedListener { + + @BindView(R.id.toolbar) + lateinit var mToolbar: Toolbar + @BindView(R.id.page_container) + lateinit var mViewPager: ViewPager + @BindView(R.id.smart_tab) + lateinit var mNavigationTabStrip: SmartTabLayout + @BindView(R.id.coordinator) + lateinit var coordinatorLayout: CoordinatorLayout + @BindView(R.id.drawer_layout) + lateinit var mDrawerLayout: DrawerLayout + @BindView(R.id.nav_view) + lateinit var mNavigationView: NavigationView + + private val mDrawerToggle by lazy(LAZY_MODE_UNSAFE) { + ActionBarDrawerToggle(this@MainActivity, mDrawerLayout, mToolbar, + R.string.navigation_drawer_open, R.string.navigation_drawer_close + ) + } + + @IdRes + private var redirectShortcut: Int = 0 + @IdRes + private var selectedItem: Int = 0 + @StringRes + private var selectedTitle: Int = 0 + + private var mPageIndex: Int = 0 + + private lateinit var menuItems: Menu + + private lateinit var mHomeFeed: MenuItem + private lateinit var mAccountLogin: MenuItem + private lateinit var mSignOutProfile: MenuItem + private lateinit var mManageMenu: MenuItem + + private val headerContainer by lazy(LAZY_MODE_UNSAFE) { + mNavigationView.getHeaderView(0) + } + + private val mHeaderView by lazy(LAZY_MODE_UNSAFE) { + headerContainer.findViewById(R.id.drawer_banner) + } + private val mUserName by lazy(LAZY_MODE_UNSAFE) { + headerContainer.findViewById(R.id.drawer_app_name) + } + private val mUserAvatar by lazy(LAZY_MODE_UNSAFE) { + headerContainer.findViewById(R.id.drawer_avatar_indicator) + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_main) + ButterKnife.bind(this) + setSupportActionBar(mToolbar) + setPresenter(BasePresenter(applicationContext)) + if (savedInstanceState == null) + redirectShortcut = intent.getIntExtra(KeyUtil.arg_redirect, 0) + } + + override fun onPostCreate(savedInstanceState: Bundle?) { + super.onPostCreate(savedInstanceState) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) + mNavigationView.itemBackground = getCompatDrawable(R.drawable.nav_background) + mNavigationView.setNavigationItemSelectedListener(this) + mViewPager.offscreenPageLimit = offScreenLimit + mPageIndex = DateUtil.menuSelect + menuItems = mNavigationView.menu + onActivityReady() + } + + override fun onCreateOptionsMenu(menu: Menu): Boolean { + menuInflater.inflate(R.menu.main_menu, menu) + val searchItem = menu.findItem(R.id.action_search) + mSearchView?.setMenuItem(searchItem) + return super.onCreateOptionsMenu(menu) + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + val intent: Intent + when (item.itemId) { + R.id.action_donate -> { + intent = Intent(Intent.ACTION_VIEW, Uri.parse("https://www.patreon.com/wax911")) + startActivity(intent) + return true + } + R.id.action_about -> { + startActivity(Intent(this@MainActivity, AboutActivity::class.java)) + return true + } + R.id.action_share -> { + intent = Intent() + intent.action = Intent.ACTION_SEND + intent.putExtra(Intent.EXTRA_TEXT, getString(R.string.campaign_link)) + intent.type = "text/plain" + startActivity(intent) + return true + } + R.id.action_settings -> { + startActivity(Intent(this@MainActivity, SettingsActivity::class.java)) + return true + } + R.id.action_discord -> { + val invite = getString(R.string.link_anitrend_discord) + intent = Intent(Intent.ACTION_VIEW, Uri.parse(invite)) + startActivity(intent) + return true + } + R.id.action_report -> { + startActivity(Intent(this@MainActivity, LoggingActivity::class.java)) + return true + } + } + return super.onOptionsItemSelected(item) + } + + /** + * Make decisions, check for permissions or fire background threads from this method + * N.B. Must be called after onPostCreate + */ + override fun onActivityReady() { + if (selectedItem == 0) + selectedItem = if (presenter.settings.isAuthenticated) + if (redirectShortcut == 0) presenter.getNavigationItem() else redirectShortcut + else + if (redirectShortcut == 0) R.id.nav_anime else redirectShortcut + mNavigationView.setCheckedItem(selectedItem) + onNavigate(selectedItem) + } + + override fun onSaveInstanceState(outState: Bundle) { + outState.putInt(KeyUtil.arg_redirect, redirectShortcut) + outState.putInt(KeyUtil.key_navigation_selected, selectedItem) + outState.putInt(KeyUtil.key_navigation_title, selectedTitle) + super.onSaveInstanceState(outState) + } + + override fun onRestoreInstanceState(savedInstanceState: Bundle) { + super.onRestoreInstanceState(savedInstanceState) + redirectShortcut = savedInstanceState.getInt(KeyUtil.arg_redirect) + selectedItem = savedInstanceState.getInt(KeyUtil.key_navigation_selected) + selectedTitle = savedInstanceState.getInt(KeyUtil.key_navigation_title) + } + + override fun onBackPressed() { + if (mDrawerLayout.isDrawerOpen(GravityCompat.START)) { + mDrawerLayout.closeDrawer(GravityCompat.START) + return + } + super.onBackPressed() + } + + override fun onPause() { + super.onPause() + mDrawerLayout.removeDrawerListener(mDrawerToggle) + } + + /** + * 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() + if (!EventBus.getDefault().isRegistered(this)) + EventBus.getDefault().register(this) + mDrawerLayout.addDrawerListener(mDrawerToggle) + mDrawerToggle.syncState() + updateUI() + } + + override fun onNavigationItemSelected(item: MenuItem): Boolean { + @IdRes val menu = item.itemId + if (selectedItem != menu) + onNavigate(menu) + if (menu != R.id.nav_sign_in) + mDrawerLayout.closeDrawer(GravityCompat.START) + return true + } + + private fun onNavigate(@IdRes menu: Int) { + when (menu) { + R.id.nav_home_feed -> { + mToolbar.title = getString(R.string.drawer_title_home) + selectedItem = menu + mViewPager.adapter = FeedPageAdapter(supportFragmentManager, applicationContext) + mNavigationTabStrip.setViewPager(mViewPager) + } + R.id.nav_anime -> { + mToolbar.title = getString(R.string.drawer_title_anime) + selectedItem = menu + mViewPager.adapter = SeasonPageAdapter(supportFragmentManager, applicationContext) + mNavigationTabStrip.setViewPager(mViewPager) + mViewPager.setCurrentItem(mPageIndex, false) + } + R.id.nav_manga -> { + mToolbar.title = getString(R.string.drawer_title_manga) + selectedItem = menu + mViewPager.adapter = MangaPageAdapter(supportFragmentManager, applicationContext) + mNavigationTabStrip.setViewPager(mViewPager) + } + R.id.nav_trending -> { + mToolbar.title = getString(R.string.drawer_title_trending) + selectedItem = menu + mViewPager.adapter = + TrendingPageAdapter(supportFragmentManager, applicationContext) + mNavigationTabStrip.setViewPager(mViewPager) + } + R.id.nav_airing -> { + mToolbar.title = getString(R.string.drawer_title_airing) + mViewPager.adapter = AiringPageAdapter(supportFragmentManager, applicationContext) + mNavigationTabStrip.setViewPager(mViewPager) + selectedItem = menu + } + R.id.nav_myanime -> { + val animeParams = Bundle() + animeParams.putString(KeyUtil.arg_mediaType, KeyUtil.ANIME) + animeParams.putString(KeyUtil.arg_userName, presenter.database.currentUser?.name) + animeParams.putLong(KeyUtil.arg_id, presenter.database.currentUser?.id ?: 0) + + val animeListPageAdapter = + MediaListPageAdapter(supportFragmentManager, applicationContext) + animeListPageAdapter.params = animeParams + + mToolbar.title = getString(R.string.drawer_title_myanime) + mViewPager.adapter = animeListPageAdapter + mNavigationTabStrip.setViewPager(mViewPager) + selectedItem = menu + } + R.id.nav_mymanga -> { + val mangaParams = Bundle() + mangaParams.putString(KeyUtil.arg_mediaType, KeyUtil.MANGA) + mangaParams.putString(KeyUtil.arg_userName, presenter.database.currentUser?.name) + mangaParams.putLong(KeyUtil.arg_id, presenter.database.currentUser?.id ?: 0) + + val mangaListPageAdapter = + MediaListPageAdapter(supportFragmentManager, applicationContext) + mangaListPageAdapter.params = mangaParams + + mToolbar.title = getString(R.string.drawer_title_mymanga) + mViewPager.adapter = mangaListPageAdapter + mNavigationTabStrip.setViewPager(mViewPager) + selectedItem = menu + } + R.id.nav_hub -> { + mToolbar.title = getString(R.string.drawer_title_hub) + mViewPager.adapter = HubPageAdapter(supportFragmentManager, applicationContext) + mNavigationTabStrip.setViewPager(mViewPager) + selectedItem = menu + } + R.id.nav_reviews -> { + mToolbar.title = getString(R.string.drawer_title_reviews) + selectedItem = menu + mViewPager.adapter = ReviewPageAdapter(supportFragmentManager, applicationContext) + mNavigationTabStrip.setViewPager(mViewPager) + } + R.id.nav_sign_in -> startActivity(Intent(this@MainActivity, LoginActivity::class.java)) + R.id.nav_sign_out -> { + mBottomSheet = BottomSheetMessage.Builder() + .setText(R.string.drawer_signout_text) + .setTitle(R.string.drawer_signout_title) + .setPositiveText(R.string.Yes) + .setNegativeText(R.string.No) + .buildWithCallback(object : BottomSheetChoice { + override fun onPositiveButton() { + WebTokenRequest.invalidateInstance(applicationContext) + val intent = Intent(this@MainActivity, SplashActivity::class.java) + finish() + startActivity(intent) + } + + override fun onNegativeButton() { + + } + }) + showBottomSheet() + } + R.id.nav_check_update -> when (ContextCompat.checkSelfPermission( + applicationContext, + Manifest.permission.WRITE_EXTERNAL_STORAGE + )) { + PERMISSION_GRANTED -> { + mBottomSheet = BottomSheetMessage.Builder() + .setText(R.string.drawer_update_text) + .setTitle(R.string.drawer_update_title) + .setPositiveText(R.string.Yes) + .setNegativeText(R.string.No) + .buildWithCallback(object : BottomSheetChoice { + override fun onPositiveButton() { + val versionBase = presenter.database.remoteVersion + if (versionBase != null && versionBase.isNewerVersion) + DownloaderService.downloadNewVersion( + this@MainActivity, + versionBase + ) + else + NotifyUtil.createAlerter( + this@MainActivity, + getString(R.string.title_update_infodadat), + getString(R.string.app_no_date), + R.drawable.ic_cloud_done_white_24dp, + R.color.colorStateGreen + ) + } + + override fun onNegativeButton() { + + } + }) + showBottomSheet() + } + PERMISSION_DENIED -> if (ActivityCompat.shouldShowRequestPermissionRationale( + this@MainActivity, + Manifest.permission.WRITE_EXTERNAL_STORAGE + ) + ) + DialogUtil.createMessage( + this@MainActivity, + R.string.title_permission_write, + R.string.text_permission_write + ) { _, which -> + when (which) { + DialogAction.POSITIVE -> ActivityCompat.requestPermissions( + this, + arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), + REQUEST_PERMISSION + ) + DialogAction.NEGATIVE -> NotifyUtil.makeText( + this@MainActivity, + R.string.canceled_by_user, + Toast.LENGTH_SHORT + ).show() + else -> {} + } + } + else + requestPermissionIfMissing(Manifest.permission.WRITE_EXTERNAL_STORAGE) + } + else -> { } + } + } + + /** + * Called for each of the requested permissions as they are granted + * + * @param permission the current permission granted + */ + override fun onPermissionGranted(permission: String) { + super.onPermissionGranted(permission) + try { + if (permission == Manifest.permission.WRITE_EXTERNAL_STORAGE) + onNavigate(R.id.nav_check_update) + } catch (e: Exception) { + e.printStackTrace() + } + + } + + override fun updateUI() { + val versionBase = presenter.database.remoteVersion + headerContainer + .findViewById(R.id.banner_clickable).setOnClickListener(this) + + mHomeFeed = menuItems.findItem(R.id.nav_home_feed) + mAccountLogin = menuItems.findItem(R.id.nav_sign_in) + mSignOutProfile = menuItems.findItem(R.id.nav_sign_out) + mManageMenu = menuItems.findItem(R.id.nav_header_manage) + + if (presenter.settings.isAuthenticated) + setupUserItems() + else + mHeaderView.setImageResource(R.drawable.reg_bg) + + if (versionBase != null && versionBase.isNewerVersion) { + // If a new version of the application is available on GitHub + val mAppUpdateWidget = menuItems.findItem(R.id.nav_check_update) + .actionView.findViewById(R.id.app_update_info) + mAppUpdateWidget.text = getString(R.string.app_update, versionBase.version) + mAppUpdateWidget.visibility = View.VISIBLE + } + checkNewInstallation() + } + + override fun makeRequest() { + // nothing to request + } + + private fun setupUserItems() { + presenter.database.currentUser?.apply { + mUserName.text = name + mUserAvatar.onInit() + HeaderImageView.setImage(mHeaderView, bannerImage) + if (presenter.settings.shouldShowTipFor(KeyUtil.KEY_LOGIN_TIP)) { + NotifyUtil.createLoginToast(this@MainActivity, this) + presenter.settings.disableTipFor(KeyUtil.KEY_LOGIN_TIP) + mBottomSheet = BottomSheetMessage.Builder() + .setText(R.string.login_message) + .setTitle(R.string.login_title) + .setNegativeText(R.string.Ok) + .build() + showBottomSheet() + } + KoinExt.get(ISupportAnalytics::class.java).setCrashAnalyticUser(name) + } + mAccountLogin.isVisible = false + + mSignOutProfile.isVisible = true + mManageMenu.isVisible = true + mHomeFeed.isVisible = true + } + + /** + * Checks to see if this instance is a new installation + */ + private fun checkNewInstallation() { + if (presenter.settings.isUpdated) { + DialogUtil.createChangeLog(this) + presenter.settings.setUpdated() + } + if (presenter.settings.isFreshInstall) { + presenter.settings.isFreshInstall = false + mBottomSheet = BottomSheetMessage.Builder() + .setText(R.string.app_intro_guide) + .setTitle(R.string.app_intro_title) + .setNegativeText(R.string.Ok).build() + showBottomSheet() + } + } + + override fun onClick(view: View) { + if (view.id == R.id.banner_clickable) { + if (presenter.settings.isAuthenticated) { + val user = presenter.database.currentUser + if (user != null) { + startNewActivity( + Bundle().apply { + putString(KeyUtil.arg_userName, presenter.database.currentUser?.name) + } + ) + } else + NotifyUtil.makeText( + applicationContext, + R.string.text_error_login, + Toast.LENGTH_SHORT + ).show() + } else + onNavigate(R.id.nav_sign_in) + } + } + + override fun onDestroy() { + mUserAvatar.onViewRecycled() + super.onDestroy() + } + + @Subscribe(threadMode = ThreadMode.MAIN_ORDERED) + override fun onModelChanged(consumer: BaseConsumer) { + if (consumer.requestMode == KeyUtil.USER_CURRENT_REQ && consumer.changeModel != null && consumer.changeModel.unreadNotificationCount > 0) + NotifyUtil.createAlerter( + this, R.string.alerter_notification_title, R.string.alerter_notification_text, + R.drawable.ic_notifications_active_white_24dp, R.color.colorAccent + ) + } +} + 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..ce9b88b2a 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,11 @@ 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.appcompat.widget.Toolbar; +import androidx.coordinatorlayout.widget.CoordinatorLayout; +import androidx.viewpager.widget.ViewPager; 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 deleted file mode 100644 index a091a8bc7..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 android.support.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..e4e4bc917 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/view/activity/index/SplashActivity.kt @@ -0,0 +1,113 @@ +package com.mxt.anitrend.view.activity.index + +import android.content.Intent +import android.os.Bundle +import butterknife.BindView +import butterknife.ButterKnife +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.extension.getCompatTintedDrawable +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.DialogUtil +import com.mxt.anitrend.util.KeyUtil +import com.mxt.anitrend.util.date.DateUtil +import com.mxt.anitrend.view.activity.base.WelcomeActivity + +/** + * 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()) { + val freshInstall = presenter.settings.isFreshInstall + val intent = Intent( + this@SplashActivity, + if (freshInstall) + WelcomeActivity::class.java + else + MainActivity::class.java + ) + startActivity(intent) + finish() + } else { + val drawable = getCompatTintedDrawable(R.drawable.ic_system_update_grey_600_24dp) + val dialog = DialogUtil.createDefaultDialog(this) + .autoDismiss(false) + .positiveText(R.string.Ok) + .title(R.string.title_migration_failed) + .content(R.string.text_migration_failed) + .onAny { dialog, _ -> + dialog.dismiss() + finish() + } + if (drawable != null) + dialog.icon(drawable) + dialog.show() + } + } + } + + 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.settings.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.remoteVersion = model + updateUI() + } + + override fun showError(error: String) { + updateUI() + } + + override fun showEmpty(message: String) { + 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 8220cf054..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 android.support.v7.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 ffe3272d9..93055b18f 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,13 +2,14 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.widget.Toast; +import androidx.annotation.Nullable; + import com.afollestad.materialdialogs.DialogAction; import com.annimon.stream.IntPair; import com.mxt.anitrend.R; @@ -17,20 +18,21 @@ import com.mxt.anitrend.model.entity.anilist.Review; import com.mxt.anitrend.model.entity.base.MediaBase; 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.CompatUtil; import com.mxt.anitrend.util.DialogUtil; -import com.mxt.anitrend.util.GraphUtil; import com.mxt.anitrend.util.KeyUtil; -import com.mxt.anitrend.util.MediaActionUtil; import com.mxt.anitrend.util.NotifyUtil; +import com.mxt.anitrend.util.Settings; +import com.mxt.anitrend.util.graphql.GraphUtil; +import com.mxt.anitrend.util.media.MediaActionUtil; import com.mxt.anitrend.view.activity.detail.MediaActivity; import com.mxt.anitrend.view.sheet.BottomReviewReader; import java.util.Collections; +import io.github.wax911.library.model.request.QueryContainerBuilder; + /** * Created by max on 2017/10/30. * Media review browse @@ -81,18 +83,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 +114,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,12 +177,12 @@ 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(); } else - NotifyUtil.makeText(getContext(), R.string.info_login_req, R.drawable.ic_group_add_grey_600_18dp, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(getContext(), R.string.info_login_req, R.drawable.ic_group_add_grey_600_18dp, Toast.LENGTH_SHORT).show(); break; } } diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/CharacterOverviewFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/CharacterOverviewFragment.java index 914c2b83f..14b30746b 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,26 +1,25 @@ 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.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.fragment.FragmentBase; import com.mxt.anitrend.databinding.FragmentCharacterOverviewBinding; import com.mxt.anitrend.model.entity.anilist.MediaCharacter; -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.GraphUtil; import com.mxt.anitrend.util.KeyUtil; -import com.mxt.anitrend.view.activity.base.ImagePreviewActivity; +import com.mxt.anitrend.util.graphql.GraphUtil; import butterknife.ButterKnife; import butterknife.OnClick; +import io.github.wax911.library.model.request.QueryContainerBuilder; /** * Created by max on 2018/01/30. 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..d58d6951e 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,13 +2,14 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.widget.Toast; +import androidx.annotation.Nullable; + import com.annimon.stream.IntPair; import com.annimon.stream.Optional; import com.mxt.anitrend.R; @@ -17,18 +18,18 @@ import com.mxt.anitrend.base.custom.consumer.BaseConsumer; import com.mxt.anitrend.base.custom.fragment.FragmentBaseComment; import com.mxt.anitrend.base.interfaces.event.ItemClickListener; +import com.mxt.anitrend.extension.AppExtKt; import com.mxt.anitrend.model.entity.anilist.FeedList; import com.mxt.anitrend.model.entity.anilist.FeedReply; import com.mxt.anitrend.model.entity.base.MediaBase; import com.mxt.anitrend.model.entity.base.UserBase; -import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder; import com.mxt.anitrend.presenter.widget.WidgetPresenter; 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.MediaActionUtil; import com.mxt.anitrend.util.NotifyUtil; +import com.mxt.anitrend.util.graphql.GraphUtil; +import com.mxt.anitrend.util.media.MediaActionUtil; import com.mxt.anitrend.view.activity.detail.MediaActivity; import com.mxt.anitrend.view.activity.detail.ProfileActivity; import com.mxt.anitrend.view.sheet.BottomSheetGiphy; @@ -41,6 +42,8 @@ import java.util.Collections; import java.util.List; +import io.github.wax911.library.model.request.QueryContainerBuilder; + /** * Created by max on 2017/11/16. * Comment fragment @@ -97,7 +100,7 @@ public boolean onOptionsItemSelected(MenuItem item) { break; } } else - NotifyUtil.makeText(getContext(), R.string.text_activity_loading, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(getContext(), R.string.text_activity_loading, Toast.LENGTH_SHORT).show(); return super.onOptionsItemSelected(item); } @@ -125,7 +128,7 @@ public void onItemClick(View target, IntPair data) { showBottomSheet(); break; case R.id.widget_flipper: - CompatUtil.INSTANCE.hideKeyboard(getActivity()); + AppExtKt.hideKeyboard(getActivity()); break; default: DialogUtil.createDialogAttachMedia(target.getId(), composerWidget.getEditor(), getContext()); @@ -202,7 +205,7 @@ public void onItemClick(View target, IntPair data) { .build(); showBottomSheet(); } else - NotifyUtil.makeText(getActivity(), R.string.text_no_likes, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(getActivity(), R.string.text_no_likes, Toast.LENGTH_SHORT).show(); break; case R.id.user_avatar: intent = new Intent(getActivity(), ProfileActivity.class); @@ -229,12 +232,12 @@ 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(); } else - NotifyUtil.makeText(getContext(), R.string.info_login_req, R.drawable.ic_group_add_grey_600_18dp, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(getContext(), R.string.info_login_req, R.drawable.ic_group_add_grey_600_18dp, Toast.LENGTH_SHORT).show(); break; } } @@ -293,7 +296,7 @@ public void onChanged(@Nullable FeedList content) { feedList = content; initExtraComponents(); } else - NotifyUtil.createAlerter(getActivity(), R.string.text_error_request, R.string.layout_empty_response, + NotifyUtil.INSTANCE.createAlerter(getActivity(), R.string.text_error_request, R.string.layout_empty_response, R.drawable.ic_warning_white_18dp, R.color.colorStateOrange); } @@ -331,7 +334,7 @@ public void onItemClick(View target, IntPair data) { .build(); showBottomSheet(); } else - NotifyUtil.makeText(getActivity(), R.string.text_no_likes, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(getActivity(), R.string.text_no_likes, Toast.LENGTH_SHORT).show(); break; case R.id.user_avatar: intent = new Intent(getActivity(), ProfileActivity.class); 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..1f99a70bb 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,12 +1,14 @@ package com.mxt.anitrend.view.fragment.detail; import android.os.Bundle; -import android.support.annotation.Nullable; -import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder; +import androidx.annotation.Nullable; + import com.mxt.anitrend.util.KeyUtil; import com.mxt.anitrend.view.fragment.list.FeedListFragment; +import io.github.wax911.library.model.request.QueryContainerBuilder; + /** * Created by max on 2018/03/24. * Media feed list fragment for media types, both anime and manga 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..1898b93fd --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/MediaOverviewFragment.kt @@ -0,0 +1,242 @@ +package com.mxt.anitrend.view.fragment.detail + +import android.content.Intent +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.recyclerview.widget.StaggeredGridLayoutManager +import butterknife.ButterKnife +import com.afollestad.materialdialogs.DialogAction +import com.annimon.stream.IntPair +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.extension.getCompatDrawable +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.presenter.fragment.MediaPresenter +import com.mxt.anitrend.util.CompatUtil +import com.mxt.anitrend.util.DialogUtil +import com.mxt.anitrend.util.KeyUtil +import com.mxt.anitrend.util.graphql.GraphUtil +import com.mxt.anitrend.util.media.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 + +/** + * Created by max on 2017/12/31. + */ + +class MediaOverviewFragment : FragmentBase() { + + private var binding: FragmentSeriesOverviewBinding? = 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) ?: 0 + 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) + + 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 + } + + 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")) { + 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 + 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) + .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(context?.getCompatDrawable(R.drawable.ic_emoji_sweat), + getString(R.string.layout_empty_response), getString(R.string.try_again)) { _ -> + binding?.stateLayout?.showLoading() + makeRequest() + } + } + + /** + * Called when a view has been clicked. + * + * @param v The view that was clicked. + */ + override fun onClick(v: View) { + val intent: Intent + when (v.id) { + R.id.series_image -> CompatUtil.imagePreview(activity, v, model?.coverImage?.extraLarge, 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 -> { + model?.tags?.also { + tagAdapter?.onItemRangeChanged(it) + 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/detail/MediaStaffFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/MediaStaffFragment.java index 6d67fab70..f8c8dfe92 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,9 +2,10 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; import android.view.View; +import androidx.annotation.Nullable; + import com.annimon.stream.IntPair; import com.mxt.anitrend.R; import com.mxt.anitrend.adapter.recycler.group.GroupStaffRoleAdapter; @@ -13,17 +14,18 @@ import com.mxt.anitrend.model.entity.base.StaffBase; import com.mxt.anitrend.model.entity.container.body.ConnectionContainer; import com.mxt.anitrend.model.entity.container.body.EdgeContainer; -import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder; import com.mxt.anitrend.model.entity.group.RecyclerItem; import com.mxt.anitrend.presenter.fragment.MediaPresenter; import com.mxt.anitrend.util.CompatUtil; -import com.mxt.anitrend.util.GraphUtil; -import com.mxt.anitrend.util.GroupingUtil; import com.mxt.anitrend.util.KeyUtil; +import com.mxt.anitrend.util.collection.GroupingUtil; +import com.mxt.anitrend.util.graphql.GraphUtil; import com.mxt.anitrend.view.activity.detail.StaffActivity; import java.util.Collections; +import io.github.wax911.library.model.request.QueryContainerBuilder; + /** * Created by max on 2018/01/18. */ 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..a166dc536 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,13 +4,14 @@ 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 android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.StaggeredGridLayoutManager; + import com.annimon.stream.IntPair; import com.annimon.stream.Stream; import com.github.mikephil.charting.components.Legend; @@ -31,20 +32,20 @@ import com.mxt.anitrend.model.entity.anilist.Media; import com.mxt.anitrend.model.entity.anilist.MediaRank; import com.mxt.anitrend.model.entity.anilist.meta.ScoreDistribution; -import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder; import com.mxt.anitrend.presenter.fragment.MediaPresenter; import com.mxt.anitrend.util.ChartUtil; import com.mxt.anitrend.util.CompatUtil; -import com.mxt.anitrend.util.GraphUtil; import com.mxt.anitrend.util.KeyUtil; -import com.mxt.anitrend.util.MediaBrowseUtil; -import com.mxt.anitrend.util.MediaUtil; +import com.mxt.anitrend.util.graphql.GraphUtil; +import com.mxt.anitrend.util.media.MediaBrowseUtil; +import com.mxt.anitrend.util.media.MediaUtil; import com.mxt.anitrend.view.activity.detail.MediaBrowseActivity; import java.util.List; import java.util.Locale; import butterknife.ButterKnife; +import io.github.wax911.library.model.request.QueryContainerBuilder; /** * Created by max on 2017/12/28. 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..055ee0c6b 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,16 +2,17 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; import android.view.View; +import androidx.annotation.Nullable; + import com.annimon.stream.IntPair; import com.mxt.anitrend.R; import com.mxt.anitrend.adapter.recycler.index.FeedAdapter; import com.mxt.anitrend.model.entity.anilist.FeedList; import com.mxt.anitrend.util.CompatUtil; -import com.mxt.anitrend.util.GraphUtil; import com.mxt.anitrend.util.KeyUtil; +import com.mxt.anitrend.util.graphql.GraphUtil; import com.mxt.anitrend.view.activity.detail.ProfileActivity; import com.mxt.anitrend.view.fragment.list.FeedListFragment; import com.mxt.anitrend.view.sheet.BottomSheetComposer; 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..73ddec60e 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 @@ -7,7 +7,6 @@ import android.view.MenuInflater import android.view.MenuItem import android.view.View import android.widget.Toast - import com.annimon.stream.IntPair import com.annimon.stream.Stream import com.mxt.anitrend.R @@ -15,24 +14,20 @@ 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 -import com.mxt.anitrend.util.GraphUtil import com.mxt.anitrend.util.KeyUtil -import com.mxt.anitrend.util.MediaActionUtil import com.mxt.anitrend.util.NotifyUtil +import com.mxt.anitrend.util.graphql.GraphUtil +import com.mxt.anitrend.util.media.MediaActionUtil 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 +54,17 @@ 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() - .build().execute { this.markAllNotificationsAsRead() } - } else - NotifyUtil.makeText(context, R.string.text_activity_loading, Toast.LENGTH_SHORT) + ThreadPool.execute { markAllNotificationsAsRead() } + } else context?.also { + NotifyUtil.makeText(it, 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)) + } + } } /** @@ -189,23 +185,23 @@ class NotificationFragment : FragmentBaseList { intent = Intent(activity, CommentActivity::class.java) intent.putExtra(KeyUtil.arg_id, data.second.activityId) - CompatUtil.startRevealAnim(activity, target, intent) + startActivity(intent) } KeyUtil.FOLLOWING -> { intent = Intent(activity, ProfileActivity::class.java) intent.putExtra(KeyUtil.arg_id, data.second.user.id) - CompatUtil.startRevealAnim(activity, target, intent) + startActivity(intent) } KeyUtil.ACTIVITY_MENTION -> { intent = Intent(activity, CommentActivity::class.java) intent.putExtra(KeyUtil.arg_id, data.second.activityId) - CompatUtil.startRevealAnim(activity, target, intent) + startActivity(intent) } KeyUtil.THREAD_COMMENT_MENTION -> DialogUtil.createMessage(context, data.second.user.name, data.second.context) KeyUtil.THREAD_SUBSCRIBED -> DialogUtil.createMessage(context, data.second.user.name, data.second.context) @@ -215,22 +211,22 @@ class NotificationFragment : FragmentBaseList { intent = Intent(activity, CommentActivity::class.java) intent.putExtra(KeyUtil.arg_id, data.second.activityId) - CompatUtil.startRevealAnim(activity, target, intent) + startActivity(intent) } KeyUtil.ACTIVITY_REPLY, KeyUtil.ACTIVITY_REPLY_SUBSCRIBED -> { intent = Intent(activity, CommentActivity::class.java) intent.putExtra(KeyUtil.arg_id, data.second.activityId) - CompatUtil.startRevealAnim(activity, target, intent) + startActivity(intent) } KeyUtil.ACTIVITY_REPLY_LIKE -> { intent = Intent(activity, CommentActivity::class.java) intent.putExtra(KeyUtil.arg_id, data.second.activityId) - CompatUtil.startRevealAnim(activity, target, intent) + startActivity(intent) } KeyUtil.THREAD_LIKE -> DialogUtil.createMessage(context, data.second.user.name, data.second.context) @@ -249,12 +245,14 @@ 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() } else - NotifyUtil.makeText(context, R.string.info_login_req, R.drawable.ic_group_add_grey_600_18dp, Toast.LENGTH_SHORT).show() + context?.also { + NotifyUtil.makeText(it, R.string.info_login_req, R.drawable.ic_group_add_grey_600_18dp, Toast.LENGTH_SHORT).show() + } } } 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..73abfffc8 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,10 +2,11 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; import android.view.View; import android.widget.Toast; +import androidx.annotation.Nullable; + import com.annimon.stream.IntPair; import com.mxt.anitrend.R; import com.mxt.anitrend.adapter.recycler.index.ReviewAdapter; @@ -13,19 +14,20 @@ import com.mxt.anitrend.model.entity.anilist.Review; import com.mxt.anitrend.model.entity.base.MediaBase; 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.GraphUtil; import com.mxt.anitrend.util.KeyUtil; -import com.mxt.anitrend.util.MediaActionUtil; import com.mxt.anitrend.util.NotifyUtil; +import com.mxt.anitrend.util.graphql.GraphUtil; +import com.mxt.anitrend.util.media.MediaActionUtil; import com.mxt.anitrend.view.activity.detail.MediaActivity; import com.mxt.anitrend.view.activity.detail.ProfileActivity; import com.mxt.anitrend.view.sheet.BottomReviewReader; import java.util.Collections; +import io.github.wax911.library.model.request.QueryContainerBuilder; + /** * Created by max on 2017/12/28. * Reviews for a given series @@ -117,13 +119,13 @@ 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()); CompatUtil.INSTANCE.startRevealAnim(getActivity(), target, intent); } else - NotifyUtil.makeText(getActivity(), R.string.info_login_req, R.drawable.ic_warning_white_18dp, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(getActivity(), R.string.info_login_req, R.drawable.ic_warning_white_18dp, Toast.LENGTH_SHORT).show(); break; case R.id.review_read_more: mBottomSheet = new BottomReviewReader.Builder() @@ -146,12 +148,12 @@ 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(); } else - NotifyUtil.makeText(getContext(), R.string.info_login_req, R.drawable.ic_group_add_grey_600_18dp, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(getContext(), R.string.info_login_req, R.drawable.ic_group_add_grey_600_18dp, Toast.LENGTH_SHORT).show(); break; } } diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/StaffOverviewFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/StaffOverviewFragment.java index 237ca6b38..e49051fb6 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,26 +1,25 @@ 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.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.fragment.FragmentBase; import com.mxt.anitrend.databinding.FragmentStaffOverviewBinding; import com.mxt.anitrend.model.entity.base.StaffBase; -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.GraphUtil; import com.mxt.anitrend.util.KeyUtil; -import com.mxt.anitrend.view.activity.base.ImagePreviewActivity; +import com.mxt.anitrend.util.graphql.GraphUtil; import butterknife.ButterKnife; import butterknife.OnClick; +import io.github.wax911.library.model.request.QueryContainerBuilder; /** * Created by max on 2018/01/30. 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..f308b6be7 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,13 +2,14 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.widget.Toast; +import androidx.annotation.Nullable; + import com.afollestad.materialdialogs.DialogAction; import com.annimon.stream.IntPair; import com.mxt.anitrend.R; @@ -17,19 +18,20 @@ import com.mxt.anitrend.model.entity.base.MediaBase; import com.mxt.anitrend.model.entity.container.body.ConnectionContainer; 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.CompatUtil; import com.mxt.anitrend.util.DialogUtil; -import com.mxt.anitrend.util.GraphUtil; import com.mxt.anitrend.util.KeyUtil; -import com.mxt.anitrend.util.MediaActionUtil; import com.mxt.anitrend.util.NotifyUtil; +import com.mxt.anitrend.util.Settings; +import com.mxt.anitrend.util.graphql.GraphUtil; +import com.mxt.anitrend.util.media.MediaActionUtil; import com.mxt.anitrend.view.activity.detail.MediaActivity; import java.util.Collections; +import io.github.wax911.library.model.request.QueryContainerBuilder; + /** * Created by max on 2018/03/25. * StudioMediaFragment @@ -73,18 +75,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 +101,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,12 +158,12 @@ 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(); } else - NotifyUtil.makeText(getContext(), R.string.info_login_req, R.drawable.ic_group_add_grey_600_18dp, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(getContext(), R.string.info_login_req, R.drawable.ic_group_add_grey_600_18dp, Toast.LENGTH_SHORT).show(); break; } } 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..a1447a553 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,12 +1,14 @@ package com.mxt.anitrend.view.fragment.detail; import android.os.Bundle; -import android.support.annotation.Nullable; -import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder; +import androidx.annotation.Nullable; + import com.mxt.anitrend.util.KeyUtil; import com.mxt.anitrend.view.fragment.list.FeedListFragment; +import io.github.wax911.library.model.request.QueryContainerBuilder; + /** * Created by max on 2017/11/26. * user profile targeted feeds @@ -43,7 +45,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) @@ -51,7 +53,7 @@ public void makeRequest() { else queryContainer.putVariable(KeyUtil.arg_userName, userName); - if (queryContainer.containsVariable(KeyUtil.arg_userId) || queryContainer.containsVariable(KeyUtil.arg_userName)) + if (queryContainer.containsKey(KeyUtil.arg_userId) || queryContainer.containsKey(KeyUtil.arg_userName)) super.makeRequest(); } 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 deleted file mode 100644 index 6f2a20817..000000000 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/UserOverviewFragment.java +++ /dev/null @@ -1,201 +0,0 @@ -package com.mxt.anitrend.view.fragment.detail; - -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.Toast; - -import com.annimon.stream.Stream; -import com.mxt.anitrend.R; -import com.mxt.anitrend.base.custom.fragment.FragmentBase; -import com.mxt.anitrend.databinding.FragmentUserAboutBinding; -import com.mxt.anitrend.model.entity.anilist.User; -import com.mxt.anitrend.model.entity.base.StatsRing; -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.GraphUtil; -import com.mxt.anitrend.util.KeyUtil; -import com.mxt.anitrend.util.NotifyUtil; - -import java.util.ArrayList; -import java.util.List; - -import butterknife.ButterKnife; -import butterknife.OnClick; - -/** - * Created by max on 2017/11/27. - * about user fragment for the profile - */ - -public class UserOverviewFragment extends FragmentBase { - - private FragmentUserAboutBinding binding; - private User model; - - private long userId; - private String userName; - - public static UserOverviewFragment newInstance(Bundle args) { - UserOverviewFragment fragment = new UserOverviewFragment(); - fragment.setArguments(args); - return fragment; - } - - @Override - public void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - if (getArguments() != null) { - if (getArguments().containsKey(KeyUtil.arg_id)) - userId = getArguments().getLong(KeyUtil.arg_id); - else - userName = getArguments().getString(KeyUtil.arg_userName); - } - isMenuDisabled = true; - setPresenter(new BasePresenter(getContext())); - setViewModel(true); - } - - /** - * Called to have the fragment instantiate its user interface view. - * This is optional, and non-graphical fragments can return null (which - * is the default implementation). This will be called between - * {@link #onCreate(Bundle)} and {@link #onActivityCreated(Bundle)}. - *

- *

If you return a View from here, you will later be called in - * {@link #onDestroyView} when the view is being released. - * - * @param inflater The LayoutInflater object that can be used to inflate - * any views in the fragment, - * @param container If non-null, this is the parent view that the fragment's - * UI should be attached to. The fragment should not add the view itself, - * but this can be used to generate the LayoutParams of the view. - * @param savedInstanceState If non-null, this fragment is being re-constructed - * from a previous saved state as given here. - * @return Return the View for the fragment's UI, or null. - */ - @Nullable @Override - public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - binding = FragmentUserAboutBinding.inflate(inflater, container, false); - unbinder = ButterKnife.bind(this, binding.getRoot()); - binding.stateLayout.showLoading(); - 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() { - binding.setModel(model); - binding.stateLayout.showContent(); - binding.widgetStatus.setTextData(model.getAbout()); - - binding.userFollowStateWidget.setUserModel(model); - binding.userAboutPanelWidget.setFragmentActivity(getActivity()); - binding.userAboutPanelWidget.setUserId(model.getId(), getLifecycle()); - showRingStats(); - } - - /** - * All new or updated network requests should be handled in this method - */ - @Override - public void makeRequest() { - QueryContainerBuilder queryContainer = GraphUtil.INSTANCE.getDefaultQuery(false) - .putVariable(KeyUtil.arg_userName, userName); - if(userId > 0) - queryContainer.putVariable(KeyUtil.arg_id, userId); - getViewModel().getParams().putParcelable(KeyUtil.arg_graph_params, queryContainer); - getViewModel().requestData(KeyUtil.USER_OVERVIEW_REQ, getContext()); - } - - /** - * Called when the model state is changed. - * - * @param model The new data - */ - @Override - public void onChanged(@Nullable User 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 the view previously created by {@link #onCreateView} has - * been detached from the fragment. The next time the fragment needs - * to be displayed, a new view will be created. This is called - * after {@link #onStop()} and before {@link #onDestroy()}. It is called - * regardless of whether {@link #onCreateView} returned a - * non-null view. Internally it is called after the view's state has - * been saved but before it has been removed from its parent. - */ - @Override - public void onDestroyView() { - if(binding != null) - binding.userAboutPanelWidget.onViewRecycled(); - super.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())); - }).limit(5).toList(); - } - - return userGenreStats; - } - - private void showRingStats() { - List ringList = generateStatsData(); - if(ringList.size() > 1) { - binding.userStats.setDrawBg(CompatUtil.INSTANCE.isLightTheme(getContext()), CompatUtil.INSTANCE.getColorFromAttr(getContext(), R.attr.subtitleColor)); - binding.userStats.setData(ringList, 500); - } - } - - /** - * Called when a view has been clicked. - * - * @param view The view that was clicked. - */ - @Override @OnClick({R.id.user_avatar, R.id.user_stats_container}) - public void onClick(View view) { - switch (view.getId()) { - case R.id.user_avatar: - CompatUtil.INSTANCE.imagePreview(getActivity(), view, model.getAvatar().getLarge(), R.string.image_preview_error_user_avatar); - break; - case R.id.user_stats_container: - List ringList = generateStatsData(); - if(ringList.size() > 1) { - binding.userStats.setDrawBg(CompatUtil.INSTANCE.isLightTheme(getContext()), CompatUtil.INSTANCE.getColorFromAttr(getContext(), R.attr.subtitleColor)); - binding.userStats.setData(ringList, 500); - } - else - NotifyUtil.makeText(getActivity(), R.string.text_error_request, Toast.LENGTH_SHORT).show(); - break; - } - } -} diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/detail/UserOverviewFragment.kt b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/UserOverviewFragment.kt new file mode 100644 index 000000000..b80d16ce2 --- /dev/null +++ b/app/src/main/java/com/mxt/anitrend/view/fragment/detail/UserOverviewFragment.kt @@ -0,0 +1,200 @@ +package com.mxt.anitrend.view.fragment.detail + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Toast +import butterknife.ButterKnife +import butterknife.OnClick +import com.annimon.stream.Stream +import com.mxt.anitrend.R +import com.mxt.anitrend.base.custom.fragment.FragmentBase +import com.mxt.anitrend.databinding.FragmentUserAboutBinding +import com.mxt.anitrend.extension.empty +import com.mxt.anitrend.extension.extras +import com.mxt.anitrend.extension.getCompatColorAttr +import com.mxt.anitrend.extension.getCompatDrawable +import com.mxt.anitrend.model.entity.anilist.User +import com.mxt.anitrend.model.entity.base.StatsRing +import com.mxt.anitrend.presenter.base.BasePresenter +import com.mxt.anitrend.util.CompatUtil +import com.mxt.anitrend.util.KeyUtil +import com.mxt.anitrend.util.NotifyUtil +import com.mxt.anitrend.util.graphql.GraphUtil +import java.util.* + +/** + * Created by max on 2017/11/27. + * about user fragment for the profile + */ + +class UserOverviewFragment : FragmentBase() { + + private lateinit var binding: FragmentUserAboutBinding + private var model: User? = null + + private val userId by extras(KeyUtil.arg_id, 0) + private val userName by extras(KeyUtil.arg_userName, String.empty()) + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + isMenuDisabled = true + setPresenter(BasePresenter(context)) + setViewModel(true) + } + + /** + * Called to have the fragment instantiate its user interface view. + * This is optional, and non-graphical fragments can return null (which + * is the default implementation). This will be called between + * [.onCreate] and [.onActivityCreated]. + * + * + * + * If you return a View from here, you will later be called in + * [.onDestroyView] when the view is being released. + * + * @param inflater The LayoutInflater object that can be used to inflate + * any views in the fragment, + * @param container If non-null, this is the parent view that the fragment's + * UI should be attached to. The fragment should not add the view itself, + * but this can be used to generate the LayoutParams of the view. + * @param savedInstanceState If non-null, this fragment is being re-constructed + * from a previous saved state as given here. + * @return Return the View for the fragment's UI, or null. + */ + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + binding = FragmentUserAboutBinding.inflate(inflater, container, false) + unbinder = ButterKnife.bind(this, binding.root) + binding.stateLayout.showLoading() + return binding.root + } + + override fun onStart() { + super.onStart() + makeRequest() + } + + /** + * Is automatically called in the @onStart Method if overridden in list implementation + */ + override fun updateUI() { + model?.apply { + binding.model = this + binding.stateLayout.showContent() + binding.widgetStatus.setTextData(about) + + binding.userFollowStateWidget.setUserModel(model) + binding.userAboutPanelWidget.setFragmentActivity(activity) + binding.userAboutPanelWidget.setUserId(id, lifecycle) + showRingStats() + } + } + + /** + * All new or updated network requests should be handled in this method + */ + override fun makeRequest() { + val queryContainer = GraphUtil.getDefaultQuery(false) + if (!userName.isBlank()) + queryContainer.putVariable(KeyUtil.arg_userName, userName) + if (userId > 0) + queryContainer.putVariable(KeyUtil.arg_id, userId) + getViewModel().params.putParcelable(KeyUtil.arg_graph_params, queryContainer) + context?.apply { + getViewModel().requestData(KeyUtil.USER_OVERVIEW_REQ, this) + } + } + + /** + * Called when the model state is changed. + * + * @param model The new data + */ + override fun onChanged(model: User?) { + if (model != null) { + this.model = model + updateUI() + } else + binding.stateLayout.showError(context?.getCompatDrawable(R.drawable.ic_emoji_sweat), + getString(R.string.layout_empty_response), getString(R.string.try_again)) { view -> + binding.stateLayout.showLoading() + makeRequest() + } + } + + /** + * Called when the view previously created by [.onCreateView] has + * been detached from the fragment. The next time the fragment needs + * to be displayed, a new view will be created. This is called + * after [.onStop] and before [.onDestroy]. It is called + * *regardless* of whether [.onCreateView] returned a + * non-null view. Internally it is called after the view's state has + * been saved but before it has been removed from its parent. + */ + override fun onDestroyView() { + binding.userAboutPanelWidget.onViewRecycled() + super.onDestroyView() + } + + private fun generateStatsData(): List { + var userGenreStats: List = ArrayList() + if (model?.statistics != null && model?.statistics?.anime?.genres != null && !CompatUtil.isEmpty(model?.statistics?.anime?.genres)) { + val highestValue = Stream.of(model?.statistics?.anime?.genres) + .max { o1, o2 -> if (o1.count > o2.count) 1 else 0 } + .get().count + + userGenreStats = Stream.of(model?.statistics?.anime?.genres) + .sortBy { s -> -s.count }.map { genreStats -> + val percentage = genreStats.count.toFloat() / highestValue.toFloat() * 100f + StatsRing(percentage.toInt(), genreStats.genre, genreStats.count.toString()) + }.limit(5).toList() + } + + return userGenreStats + } + + private fun showRingStats() { + context?.apply { + val ringList = generateStatsData() + if (ringList.size > 1) { + binding.userStats.setDrawBg(CompatUtil.isLightTheme(this), getCompatColorAttr(R.attr.subtitleColor)) + binding.userStats.setData(ringList, 500) + } + } + } + + /** + * Called when a view has been clicked. + * + * @param view The view that was clicked. + */ + @OnClick(R.id.user_avatar, R.id.user_stats_container) + override fun onClick(view: View) { + when (view.id) { + R.id.user_avatar -> CompatUtil.imagePreview(activity, view, model?.avatar?.large, R.string.image_preview_error_user_avatar) + R.id.user_stats_container -> { + val ringList = generateStatsData() + if (ringList.size > 1) { + context?.apply { + binding.userStats.setDrawBg(CompatUtil.isLightTheme(this), getCompatColorAttr(R.attr.subtitleColor)) + binding.userStats.setData(ringList, 500) + } + } else + activity?.apply { + NotifyUtil.makeText(this, R.string.text_error_request, Toast.LENGTH_SHORT).show() + } + } + } + } + + companion object { + + fun newInstance(args: Bundle): UserOverviewFragment { + val fragment = UserOverviewFragment() + fragment.arguments = args + return fragment + } + } +} 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..58488e14b 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,9 +2,10 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; import android.view.View; +import androidx.annotation.Nullable; + import com.annimon.stream.IntPair; import com.mxt.anitrend.R; import com.mxt.anitrend.adapter.recycler.group.GroupCharacterAdapter; @@ -13,17 +14,18 @@ import com.mxt.anitrend.model.entity.base.CharacterBase; import com.mxt.anitrend.model.entity.container.body.ConnectionContainer; import com.mxt.anitrend.model.entity.container.body.PageContainer; -import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder; import com.mxt.anitrend.model.entity.group.RecyclerItem; import com.mxt.anitrend.presenter.base.BasePresenter; import com.mxt.anitrend.util.CompatUtil; -import com.mxt.anitrend.util.GraphUtil; -import com.mxt.anitrend.util.GroupingUtil; import com.mxt.anitrend.util.KeyUtil; +import com.mxt.anitrend.util.collection.GroupingUtil; +import com.mxt.anitrend.util.graphql.GraphUtil; import com.mxt.anitrend.view.activity.detail.CharacterActivity; import java.util.Collections; +import io.github.wax911.library.model.request.QueryContainerBuilder; + /** * Created by max on 2018/03/25. * CharacterFavouriteFragment 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..2cdc9b374 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,10 +2,11 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; import android.view.View; import android.widget.Toast; +import androidx.annotation.Nullable; + import com.annimon.stream.IntPair; import com.mxt.anitrend.R; import com.mxt.anitrend.adapter.recycler.index.MediaAdapter; @@ -14,17 +15,18 @@ import com.mxt.anitrend.model.entity.base.MediaBase; import com.mxt.anitrend.model.entity.container.body.ConnectionContainer; 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.GraphUtil; import com.mxt.anitrend.util.KeyUtil; -import com.mxt.anitrend.util.MediaActionUtil; import com.mxt.anitrend.util.NotifyUtil; +import com.mxt.anitrend.util.graphql.GraphUtil; +import com.mxt.anitrend.util.media.MediaActionUtil; import com.mxt.anitrend.view.activity.detail.MediaActivity; import java.util.Collections; +import io.github.wax911.library.model.request.QueryContainerBuilder; + /** * Created by max on 2018/03/25. * MediaFavouriteFragment @@ -122,12 +124,12 @@ 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(); } else - NotifyUtil.makeText(getContext(), R.string.info_login_req, R.drawable.ic_group_add_grey_600_18dp, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(getContext(), R.string.info_login_req, R.drawable.ic_group_add_grey_600_18dp, Toast.LENGTH_SHORT).show(); break; } } diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/favourite/StaffFavouriteFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/favourite/StaffFavouriteFragment.java index d93242e89..f039579c0 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,9 +2,10 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; import android.view.View; +import androidx.annotation.Nullable; + import com.annimon.stream.IntPair; import com.mxt.anitrend.R; import com.mxt.anitrend.adapter.recycler.index.StaffAdapter; @@ -13,15 +14,16 @@ import com.mxt.anitrend.model.entity.base.StaffBase; import com.mxt.anitrend.model.entity.container.body.ConnectionContainer; 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.GraphUtil; import com.mxt.anitrend.util.KeyUtil; +import com.mxt.anitrend.util.graphql.GraphUtil; import com.mxt.anitrend.view.activity.detail.StaffActivity; import java.util.Collections; +import io.github.wax911.library.model.request.QueryContainerBuilder; + /** * Created by max on 2018/03/25. * StaffFavouriteFragment 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..ec97f7c7d 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,9 +2,10 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; import android.view.View; +import androidx.annotation.Nullable; + import com.annimon.stream.IntPair; import com.mxt.anitrend.R; import com.mxt.anitrend.adapter.recycler.index.StudioAdapter; @@ -13,14 +14,15 @@ import com.mxt.anitrend.model.entity.base.StudioBase; import com.mxt.anitrend.model.entity.container.body.ConnectionContainer; 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.GraphUtil; import com.mxt.anitrend.util.KeyUtil; +import com.mxt.anitrend.util.graphql.GraphUtil; import com.mxt.anitrend.view.activity.detail.StudioActivity; import java.util.Collections; +import io.github.wax911.library.model.request.QueryContainerBuilder; + /** * Created by max on 2018/03/25. * StudioFavouriteFragment 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..c8d82005d 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,10 +2,11 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; import android.view.View; import android.widget.Toast; +import androidx.annotation.Nullable; + import com.annimon.stream.IntPair; import com.mxt.anitrend.R; import com.mxt.anitrend.adapter.recycler.group.GroupActorAdapter; @@ -16,20 +17,21 @@ import com.mxt.anitrend.model.entity.base.StaffBase; import com.mxt.anitrend.model.entity.container.body.ConnectionContainer; import com.mxt.anitrend.model.entity.container.body.EdgeContainer; -import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder; import com.mxt.anitrend.model.entity.group.RecyclerItem; import com.mxt.anitrend.presenter.fragment.MediaPresenter; import com.mxt.anitrend.util.CompatUtil; -import com.mxt.anitrend.util.GraphUtil; -import com.mxt.anitrend.util.GroupingUtil; import com.mxt.anitrend.util.KeyUtil; -import com.mxt.anitrend.util.MediaActionUtil; import com.mxt.anitrend.util.NotifyUtil; +import com.mxt.anitrend.util.collection.GroupingUtil; +import com.mxt.anitrend.util.graphql.GraphUtil; +import com.mxt.anitrend.util.media.MediaActionUtil; import com.mxt.anitrend.view.activity.detail.MediaActivity; import com.mxt.anitrend.view.activity.detail.StaffActivity; import java.util.Collections; +import io.github.wax911.library.model.request.QueryContainerBuilder; + /** * Created by max on 2018/03/23. * Character actors with their respective media @@ -88,12 +90,12 @@ 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(); } else - NotifyUtil.makeText(getContext(), R.string.info_login_req, R.drawable.ic_group_add_grey_600_18dp, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(getContext(), R.string.info_login_req, R.drawable.ic_group_add_grey_600_18dp, Toast.LENGTH_SHORT).show(); break; } } diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/group/MediaCharacterFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/group/MediaCharacterFragment.java index ee1cdbc79..332592437 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,9 +2,10 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; import android.view.View; +import androidx.annotation.Nullable; + import com.annimon.stream.IntPair; import com.mxt.anitrend.R; import com.mxt.anitrend.adapter.recycler.group.GroupCharacterAdapter; @@ -13,17 +14,18 @@ import com.mxt.anitrend.model.entity.base.CharacterBase; import com.mxt.anitrend.model.entity.container.body.ConnectionContainer; import com.mxt.anitrend.model.entity.container.body.EdgeContainer; -import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder; import com.mxt.anitrend.model.entity.group.RecyclerItem; import com.mxt.anitrend.presenter.fragment.MediaPresenter; import com.mxt.anitrend.util.CompatUtil; -import com.mxt.anitrend.util.GraphUtil; -import com.mxt.anitrend.util.GroupingUtil; import com.mxt.anitrend.util.KeyUtil; +import com.mxt.anitrend.util.collection.GroupingUtil; +import com.mxt.anitrend.util.graphql.GraphUtil; import com.mxt.anitrend.view.activity.detail.CharacterActivity; import java.util.Collections; +import io.github.wax911.library.model.request.QueryContainerBuilder; + /** * Created by max on 2018/01/18. */ 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..417d26327 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,10 +2,11 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; import android.view.View; import android.widget.Toast; +import androidx.annotation.Nullable; + import com.annimon.stream.IntPair; import com.mxt.anitrend.R; import com.mxt.anitrend.adapter.recycler.group.GroupSeriesAdapter; @@ -13,19 +14,20 @@ import com.mxt.anitrend.model.entity.base.MediaBase; import com.mxt.anitrend.model.entity.container.body.ConnectionContainer; import com.mxt.anitrend.model.entity.container.body.PageContainer; -import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder; import com.mxt.anitrend.model.entity.group.RecyclerItem; import com.mxt.anitrend.presenter.fragment.MediaPresenter; import com.mxt.anitrend.util.CompatUtil; -import com.mxt.anitrend.util.GraphUtil; -import com.mxt.anitrend.util.GroupingUtil; import com.mxt.anitrend.util.KeyUtil; -import com.mxt.anitrend.util.MediaActionUtil; import com.mxt.anitrend.util.NotifyUtil; +import com.mxt.anitrend.util.collection.GroupingUtil; +import com.mxt.anitrend.util.graphql.GraphUtil; +import com.mxt.anitrend.util.media.MediaActionUtil; import com.mxt.anitrend.view.activity.detail.MediaActivity; import java.util.Collections; +import io.github.wax911.library.model.request.QueryContainerBuilder; + /** * Created by max on 2018/01/27. * Shared fragment between media for staff and character @@ -136,12 +138,12 @@ 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(); } else - NotifyUtil.makeText(getContext(), R.string.info_login_req, R.drawable.ic_group_add_grey_600_18dp, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(getContext(), R.string.info_login_req, R.drawable.ic_group_add_grey_600_18dp, Toast.LENGTH_SHORT).show(); break; } } diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/group/MediaRelationFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/group/MediaRelationFragment.java index 0c6ec052f..e536ccb82 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,10 +2,11 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; import android.view.View; import android.widget.Toast; +import androidx.annotation.Nullable; + import com.annimon.stream.IntPair; import com.mxt.anitrend.R; import com.mxt.anitrend.adapter.recycler.group.GroupSeriesAdapter; @@ -14,19 +15,20 @@ import com.mxt.anitrend.model.entity.base.MediaBase; import com.mxt.anitrend.model.entity.container.body.ConnectionContainer; import com.mxt.anitrend.model.entity.container.body.EdgeContainer; -import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder; import com.mxt.anitrend.model.entity.group.RecyclerItem; import com.mxt.anitrend.presenter.fragment.MediaPresenter; import com.mxt.anitrend.util.CompatUtil; -import com.mxt.anitrend.util.GraphUtil; -import com.mxt.anitrend.util.GroupingUtil; import com.mxt.anitrend.util.KeyUtil; -import com.mxt.anitrend.util.MediaActionUtil; import com.mxt.anitrend.util.NotifyUtil; +import com.mxt.anitrend.util.collection.GroupingUtil; +import com.mxt.anitrend.util.graphql.GraphUtil; +import com.mxt.anitrend.util.media.MediaActionUtil; import com.mxt.anitrend.view.activity.detail.MediaActivity; import java.util.Collections; +import io.github.wax911.library.model.request.QueryContainerBuilder; + /** * Created by max on 2018/01/05. * MediaRelationFragment @@ -129,12 +131,12 @@ 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(); } else - NotifyUtil.makeText(getContext(), R.string.info_login_req, R.drawable.ic_group_add_grey_600_18dp, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(getContext(), R.string.info_login_req, R.drawable.ic_group_add_grey_600_18dp, Toast.LENGTH_SHORT).show(); break; } } diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/group/MediaStaffRoleFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/group/MediaStaffRoleFragment.java index 43492635b..ccae0275e 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,10 +2,11 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; import android.view.View; import android.widget.Toast; +import androidx.annotation.Nullable; + import com.annimon.stream.IntPair; import com.mxt.anitrend.R; import com.mxt.anitrend.adapter.recycler.group.GroupSeriesAdapter; @@ -14,19 +15,20 @@ import com.mxt.anitrend.model.entity.base.MediaBase; import com.mxt.anitrend.model.entity.container.body.ConnectionContainer; import com.mxt.anitrend.model.entity.container.body.EdgeContainer; -import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder; import com.mxt.anitrend.model.entity.group.RecyclerItem; import com.mxt.anitrend.presenter.fragment.MediaPresenter; import com.mxt.anitrend.util.CompatUtil; -import com.mxt.anitrend.util.GraphUtil; -import com.mxt.anitrend.util.GroupingUtil; import com.mxt.anitrend.util.KeyUtil; -import com.mxt.anitrend.util.MediaActionUtil; import com.mxt.anitrend.util.NotifyUtil; +import com.mxt.anitrend.util.collection.GroupingUtil; +import com.mxt.anitrend.util.graphql.GraphUtil; +import com.mxt.anitrend.util.media.MediaActionUtil; import com.mxt.anitrend.view.activity.detail.MediaActivity; import java.util.Collections; +import io.github.wax911.library.model.request.QueryContainerBuilder; + /** * Created by max on 2018/01/30. * MediaStaffRoleFragment @@ -127,12 +129,12 @@ 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(); } else - NotifyUtil.makeText(getContext(), R.string.info_login_req, R.drawable.ic_group_add_grey_600_18dp, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(getContext(), R.string.info_login_req, R.drawable.ic_group_add_grey_600_18dp, Toast.LENGTH_SHORT).show(); break; } } diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/list/AiringListFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/list/AiringListFragment.java index dfcb779bf..01e38cefb 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,8 @@ 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; @@ -11,9 +12,9 @@ import com.mxt.anitrend.model.entity.base.UserBase; import com.mxt.anitrend.model.entity.container.body.PageContainer; import com.mxt.anitrend.util.CompatUtil; -import com.mxt.anitrend.util.GraphUtil; import com.mxt.anitrend.util.KeyUtil; -import com.mxt.anitrend.util.MediaListUtil; +import com.mxt.anitrend.util.graphql.GraphUtil; +import com.mxt.anitrend.util.media.MediaListUtil; import java.util.Collections; import java.util.List; @@ -60,7 +61,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.INSTANCE.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 8b21c177d..d313e7d07 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,13 +2,14 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; import android.view.ActionMode; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Toast; +import androidx.annotation.Nullable; + import com.annimon.stream.IntPair; import com.annimon.stream.Optional; import com.mxt.anitrend.R; @@ -19,14 +20,13 @@ import com.mxt.anitrend.model.entity.base.MediaBase; import com.mxt.anitrend.model.entity.base.UserBase; 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.GraphUtil; import com.mxt.anitrend.util.KeyUtil; -import com.mxt.anitrend.util.MediaActionUtil; import com.mxt.anitrend.util.NotifyUtil; import com.mxt.anitrend.util.TapTargetUtil; +import com.mxt.anitrend.util.graphql.GraphUtil; +import com.mxt.anitrend.util.media.MediaActionUtil; import com.mxt.anitrend.view.activity.detail.CommentActivity; import com.mxt.anitrend.view.activity.detail.MediaActivity; import com.mxt.anitrend.view.activity.detail.ProfileActivity; @@ -39,6 +39,7 @@ import java.util.Collections; import java.util.List; +import io.github.wax911.library.model.request.QueryContainerBuilder; import uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt; /** @@ -96,11 +97,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(); @@ -217,7 +218,7 @@ public void onItemClick(View target, IntPair data) { .build(); showBottomSheet(); } else - NotifyUtil.makeText(getActivity(), R.string.text_no_likes, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(getActivity(), R.string.text_no_likes, Toast.LENGTH_SHORT).show(); break; case R.id.user_avatar: if(data.getSecond().getUser() != null) { @@ -241,12 +242,12 @@ 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(); } else - NotifyUtil.makeText(getContext(), R.string.info_login_req, R.drawable.ic_group_add_grey_600_18dp, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(getContext(), R.string.info_login_req, R.drawable.ic_group_add_grey_600_18dp, Toast.LENGTH_SHORT).show(); break; } } diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/list/MediaBrowseFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/list/MediaBrowseFragment.java index 234087766..d36e0e25c 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,13 +2,14 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.widget.Toast; +import androidx.annotation.Nullable; + import com.afollestad.materialdialogs.DialogAction; import com.annimon.stream.IntPair; import com.annimon.stream.Stream; @@ -19,17 +20,16 @@ import com.mxt.anitrend.model.entity.anilist.MediaTag; import com.mxt.anitrend.model.entity.base.MediaBase; 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.CompatUtil; -import com.mxt.anitrend.util.DateUtil; import com.mxt.anitrend.util.DialogUtil; -import com.mxt.anitrend.util.GenreTagUtil; import com.mxt.anitrend.util.KeyUtil; -import com.mxt.anitrend.util.MediaActionUtil; -import com.mxt.anitrend.util.MediaBrowseUtil; import com.mxt.anitrend.util.NotifyUtil; +import com.mxt.anitrend.util.Settings; +import com.mxt.anitrend.util.collection.GenreTagUtil; +import com.mxt.anitrend.util.date.DateUtil; +import com.mxt.anitrend.util.media.MediaActionUtil; +import com.mxt.anitrend.util.media.MediaBrowseUtil; import com.mxt.anitrend.view.activity.detail.MediaActivity; import java.util.Collections; @@ -38,6 +38,8 @@ import java.util.Map; import java.util.WeakHashMap; +import io.github.wax911.library.model.request.QueryContainerBuilder; + /** * Created by max on 2018/02/03. * Multi purpose media browse fragment @@ -103,28 +105,28 @@ 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: List genres = getPresenter().getDatabase().getGenreCollection(); if(CompatUtil.INSTANCE.isEmpty(genres)) { - NotifyUtil.makeText(getContext(), R.string.app_splash_loading, R.drawable.ic_warning_white_18dp, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(getContext(), R.string.app_splash_loading, R.drawable.ic_warning_white_18dp, Toast.LENGTH_SHORT).show(); getPresenter().checkGenresAndTags(getActivity()); } else { Map genresIndexMap = getPresenter() - .getApplicationPref().getSelectedGenres(); + .getSettings().getSelectedGenres(); Integer[] selectedGenres = Stream.of(genresIndexMap) .map(Map.Entry::getKey) @@ -137,11 +139,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; } @@ -151,11 +153,11 @@ public boolean onOptionsItemSelected(MenuItem item) { case R.id.action_tag: List tagList = getPresenter().getDatabase().getMediaTags(); if(CompatUtil.INSTANCE.isEmpty(tagList)) { - NotifyUtil.makeText(getContext(), R.string.app_splash_loading, R.drawable.ic_warning_white_18dp, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(getContext(), R.string.app_splash_loading, R.drawable.ic_warning_white_18dp, Toast.LENGTH_SHORT).show(); getPresenter().checkGenresAndTags(getActivity()); } else { Map tagsIndexMap = getPresenter() - .getApplicationPref().getSelectedTags(); + .getSettings().getSelectedTags(); Integer[] selectedTags = Stream.of(tagsIndexMap) .map(Map.Entry::getKey) @@ -168,11 +170,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 +184,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 +226,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,12 +295,12 @@ 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(); } else - NotifyUtil.makeText(getContext(), R.string.info_login_req, R.drawable.ic_group_add_grey_600_18dp, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(getContext(), R.string.info_login_req, R.drawable.ic_group_add_grey_600_18dp, Toast.LENGTH_SHORT).show(); break; } } 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..de38b2787 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,11 +1,13 @@ package com.mxt.anitrend.view.fragment.list; import android.os.Bundle; -import android.support.annotation.Nullable; -import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder; +import androidx.annotation.Nullable; + import com.mxt.anitrend.util.KeyUtil; +import io.github.wax911.library.model.request.QueryContainerBuilder; + public class MediaLatestList extends MediaBrowseFragment { public static MediaLatestList newInstance(Bundle params, QueryContainerBuilder queryContainer) { 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..f2ac2e634 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,14 +4,15 @@ import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.widget.Toast; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import com.afollestad.materialdialogs.DialogAction; import com.annimon.stream.IntPair; import com.annimon.stream.Optional; @@ -27,17 +28,16 @@ import com.mxt.anitrend.model.entity.base.MediaBase; import com.mxt.anitrend.model.entity.base.MediaListCollectionBase; 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.CompatUtil; import com.mxt.anitrend.util.DialogUtil; -import com.mxt.anitrend.util.GraphUtil; import com.mxt.anitrend.util.KeyUtil; -import com.mxt.anitrend.util.MediaActionUtil; -import com.mxt.anitrend.util.MediaListUtil; -import com.mxt.anitrend.util.MediaUtil; import com.mxt.anitrend.util.NotifyUtil; +import com.mxt.anitrend.util.Settings; +import com.mxt.anitrend.util.graphql.GraphUtil; +import com.mxt.anitrend.util.media.MediaActionUtil; +import com.mxt.anitrend.util.media.MediaListUtil; +import com.mxt.anitrend.util.media.MediaUtil; import com.mxt.anitrend.view.activity.detail.MediaActivity; import org.greenrobot.eventbus.Subscribe; @@ -46,6 +46,8 @@ import java.util.Collections; import java.util.List; +import io.github.wax911.library.model.request.QueryContainerBuilder; + /** * Created by max on 2017/12/18. * media list fragment @@ -107,18 +109,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 +155,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.INSTANCE.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 +169,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.INSTANCE.isTitleSort(mediaListSort)) { swipeRefreshLayout.setRefreshing(true); sortMediaListByTitle(mAdapter.getData()); } @@ -213,7 +215,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.INSTANCE.isTitleSort(getPresenter().getSettings().getMediaListSort())) sortMediaListByTitle(mediaListCollection.getEntries()); else onPostProcessed(mediaListCollection.getEntries()); @@ -262,18 +264,18 @@ 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(); } else - NotifyUtil.makeText(getContext(), R.string.info_login_req, R.drawable.ic_group_add_grey_600_18dp, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(getContext(), R.string.info_login_req, R.drawable.ic_group_add_grey_600_18dp, Toast.LENGTH_SHORT).show(); break; } } 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..12edd3154 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,11 +7,11 @@ import com.afollestad.materialdialogs.DialogAction; import com.mxt.anitrend.R; -import com.mxt.anitrend.util.ApplicationPref; 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.Settings; +import com.mxt.anitrend.util.graphql.GraphUtil; /** * Created by max on 2017/11/04. @@ -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 eb5e09df4..54b5101b9 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,11 +1,11 @@ package com.mxt.anitrend.view.fragment.list; -import android.arch.lifecycle.Lifecycle; import android.os.Bundle; import android.os.Parcelable; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.lifecycle.Lifecycle; import com.mxt.anitrend.BuildConfig; import com.mxt.anitrend.R; @@ -14,18 +14,19 @@ import com.mxt.anitrend.base.interfaces.event.RetroCallback; import com.mxt.anitrend.model.entity.anilist.ExternalLink; 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; -import com.mxt.anitrend.util.EpisodeUtil; -import com.mxt.anitrend.util.ErrorUtil; -import com.mxt.anitrend.util.GraphUtil; import com.mxt.anitrend.util.KeyUtil; +import com.mxt.anitrend.util.collection.EpisodeUtil; +import com.mxt.anitrend.util.graphql.AniGraphErrorUtilKt; +import com.mxt.anitrend.util.graphql.GraphUtil; import java.util.ArrayList; import java.util.List; +import io.github.wax911.library.model.request.QueryContainerBuilder; 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,15 +123,15 @@ public void onResponse(@NonNull Call>> ca makeRequest(); } } else - Log.e(TAG, ErrorUtil.INSTANCE.getError(response)); + Timber.tag(TAG).w(AniGraphErrorUtilKt.apiError(response)); } } @Override public void onFailure(@NonNull Call>> call, @NonNull Throwable throwable) { - if(isAlive() && getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED)) { + if(isAlive()) { + Timber.tag(TAG).w(throwable); throwable.printStackTrace(); - Log.e(TAG, throwable.getMessage()); } } } 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..a639fc003 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,26 +2,28 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; import android.view.View; +import androidx.annotation.Nullable; + import com.annimon.stream.IntPair; import com.mxt.anitrend.R; import com.mxt.anitrend.adapter.recycler.group.GroupCharacterAdapter; import com.mxt.anitrend.base.custom.fragment.FragmentBaseList; import com.mxt.anitrend.model.entity.base.CharacterBase; import com.mxt.anitrend.model.entity.container.body.PageContainer; -import com.mxt.anitrend.model.entity.container.request.QueryContainerBuilder; import com.mxt.anitrend.model.entity.group.RecyclerItem; import com.mxt.anitrend.presenter.base.BasePresenter; import com.mxt.anitrend.util.CompatUtil; -import com.mxt.anitrend.util.GraphUtil; -import com.mxt.anitrend.util.GroupingUtil; import com.mxt.anitrend.util.KeyUtil; +import com.mxt.anitrend.util.collection.GroupingUtil; +import com.mxt.anitrend.util.graphql.GraphUtil; import com.mxt.anitrend.view.activity.detail.CharacterActivity; import java.util.Collections; +import io.github.wax911.library.model.request.QueryContainerBuilder; + /** * Created by max on 2017/12/20. */ 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..37e9768ab 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,27 +2,29 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; import android.view.View; import android.widget.Toast; +import androidx.annotation.Nullable; + import com.annimon.stream.IntPair; import com.mxt.anitrend.R; import com.mxt.anitrend.adapter.recycler.index.MediaAdapter; import com.mxt.anitrend.base.custom.fragment.FragmentBaseList; import com.mxt.anitrend.model.entity.base.MediaBase; 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.GraphUtil; import com.mxt.anitrend.util.KeyUtil; -import com.mxt.anitrend.util.MediaActionUtil; import com.mxt.anitrend.util.NotifyUtil; +import com.mxt.anitrend.util.graphql.GraphUtil; +import com.mxt.anitrend.util.media.MediaActionUtil; import com.mxt.anitrend.view.activity.detail.MediaActivity; import java.util.Collections; +import io.github.wax911.library.model.request.QueryContainerBuilder; + /** * Created by max on 2017/12/20. * series searching fragment @@ -131,12 +133,12 @@ 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(); } else - NotifyUtil.makeText(getContext(), R.string.info_login_req, R.drawable.ic_group_add_grey_600_18dp, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(getContext(), R.string.info_login_req, R.drawable.ic_group_add_grey_600_18dp, Toast.LENGTH_SHORT).show(); break; } } diff --git a/app/src/main/java/com/mxt/anitrend/view/fragment/search/StaffSearchFragment.java b/app/src/main/java/com/mxt/anitrend/view/fragment/search/StaffSearchFragment.java index bf1f54487..9a65c70a2 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,24 +2,26 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; import android.view.View; +import androidx.annotation.Nullable; + import com.annimon.stream.IntPair; import com.mxt.anitrend.R; import com.mxt.anitrend.adapter.recycler.index.StaffAdapter; import com.mxt.anitrend.base.custom.fragment.FragmentBaseList; import com.mxt.anitrend.model.entity.base.StaffBase; 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.GraphUtil; import com.mxt.anitrend.util.KeyUtil; +import com.mxt.anitrend.util.graphql.GraphUtil; import com.mxt.anitrend.view.activity.detail.StaffActivity; import java.util.Collections; +import io.github.wax911.library.model.request.QueryContainerBuilder; + /** * Created by max on 2017/12/20. */ 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..ef8c24a55 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,23 +2,25 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; import android.view.View; +import androidx.annotation.Nullable; + import com.annimon.stream.IntPair; import com.mxt.anitrend.R; import com.mxt.anitrend.adapter.recycler.index.StudioAdapter; import com.mxt.anitrend.base.custom.fragment.FragmentBaseList; import com.mxt.anitrend.model.entity.base.StudioBase; 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.GraphUtil; import com.mxt.anitrend.util.KeyUtil; +import com.mxt.anitrend.util.graphql.GraphUtil; import com.mxt.anitrend.view.activity.detail.StudioActivity; import java.util.Collections; +import io.github.wax911.library.model.request.QueryContainerBuilder; + /** * Created by max on 2017/12/20. * studio search fragment 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..d6217dd8a 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,24 +2,26 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; import android.view.View; +import androidx.annotation.Nullable; + import com.annimon.stream.IntPair; import com.mxt.anitrend.R; import com.mxt.anitrend.adapter.recycler.index.UserAdapter; import com.mxt.anitrend.base.custom.fragment.FragmentBaseList; import com.mxt.anitrend.model.entity.base.UserBase; 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.GraphUtil; import com.mxt.anitrend.util.KeyUtil; +import com.mxt.anitrend.util.graphql.GraphUtil; import com.mxt.anitrend.view.activity.detail.ProfileActivity; import java.util.Collections; +import io.github.wax911.library.model.request.QueryContainerBuilder; + /** * Created by max on 2017/12/20. */ 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..a6191da20 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,13 +4,14 @@ import android.content.Intent; import android.net.Uri; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Toast; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import com.bumptech.glide.Glide; import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions; import com.bumptech.glide.request.RequestOptions; @@ -21,7 +22,7 @@ import com.mxt.anitrend.presenter.base.BasePresenter; import com.mxt.anitrend.util.KeyUtil; import com.mxt.anitrend.util.NotifyUtil; -import com.mxt.anitrend.util.RegexUtil; +import com.mxt.anitrend.util.markdown.RegexUtil; import butterknife.ButterKnife; @@ -106,7 +107,7 @@ public void makeRequest() { startActivity(intent); } catch (ActivityNotFoundException e) { e.printStackTrace(); - NotifyUtil.makeText(getContext(), R.string.init_youtube_missing, Toast.LENGTH_SHORT).show(); + NotifyUtil.INSTANCE.makeText(getContext(), R.string.init_youtube_missing, Toast.LENGTH_SHORT).show(); } }); updateUI(); 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 2164e83a1..000000000 --- a/app/src/main/java/com/mxt/anitrend/view/fragment/youtube/YoutubePlayerFragment.kt +++ /dev/null @@ -1,75 +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 - - 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) - } - } - - override fun onDestroyView() { - youTubePlayer?.release() - super.onDestroyView() - } - - override fun onInitializationSuccess( - provider: YouTubePlayer.Provider, - youTubePlayer: YouTubePlayer, - wasRestored: Boolean - ) { - try { - if (lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)) { - this@YoutubePlayerFragment.youTubePlayer = youTubePlayer - if (!wasRestored) - this@YoutubePlayerFragment.youTubePlayer?.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..dcff3a1e5 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,9 @@ 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..c4b8948c7 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,19 +3,20 @@ import android.annotation.SuppressLint; import android.app.Dialog; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.view.View; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import com.annimon.stream.IntPair; import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.consumer.BaseConsumer; import com.mxt.anitrend.base.custom.sheet.BottomSheetBase; import com.mxt.anitrend.base.custom.view.editor.ComposerWidget; import com.mxt.anitrend.base.interfaces.event.ItemClickListener; +import com.mxt.anitrend.extension.AppExtKt; import com.mxt.anitrend.model.entity.anilist.FeedList; import com.mxt.anitrend.model.entity.base.UserBase; -import com.mxt.anitrend.util.CompatUtil; import com.mxt.anitrend.util.DialogUtil; import com.mxt.anitrend.util.KeyUtil; import com.mxt.anitrend.util.NotifyUtil; @@ -110,7 +111,7 @@ public void onStart() { @SuppressLint("SwitchIntDef") @Override @Subscribe(threadMode = ThreadMode.MAIN_ORDERED) public void onModelChanged(BaseConsumer consumer) { - NotifyUtil.createAlerter(getActivity(), R.string.text_post_information, R.string.completed_success, R.drawable.ic_insert_emoticon_white_24dp, R.color.colorStateGreen); + NotifyUtil.INSTANCE.createAlerter(getActivity(), R.string.text_post_information, R.string.completed_success, R.drawable.ic_insert_emoticon_white_24dp, R.color.colorStateGreen); closeDialog(); } @@ -146,7 +147,7 @@ public void onItemClick(View target, IntPair data) { mBottomSheet.show(getActivity().getSupportFragmentManager(), mBottomSheet.getTag()); break; case R.id.widget_flipper: - CompatUtil.INSTANCE.hideKeyboard(getActivity()); + AppExtKt.hideKeyboard(getActivity()); break; default: DialogUtil.createDialogAttachMedia(target.getId(), composerWidget.getEditor(), getContext()); diff --git a/app/src/main/java/com/mxt/anitrend/view/sheet/BottomSheetGiphy.java b/app/src/main/java/com/mxt/anitrend/view/sheet/BottomSheetGiphy.java index 06bf1cc6c..aad4fa0b2 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,14 +3,15 @@ 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 android.text.TextUtils; import android.view.View; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.StaggeredGridLayoutManager; + import com.annimon.stream.IntPair; +import com.google.android.material.bottomsheet.BottomSheetBehavior; import com.miguelcatalan.materialsearchview.MaterialSearchView; import com.mxt.anitrend.R; import com.mxt.anitrend.adapter.recycler.detail.GiphyAdapter; @@ -81,10 +82,10 @@ protected void updateUI() { searchView.setOnSearchViewListener(this); searchView.setOnQueryTextListener(this); injectAdapter(); - if(presenter.getApplicationPref().shouldShowTipFor(KeyUtil.KEY_GIPHY_TIP)) { - NotifyUtil.createAlerter(getActivity(), R.string.title_new_feature, R.string.text_giphy_feature, + if(presenter.getSettings().shouldShowTipFor(KeyUtil.KEY_GIPHY_TIP)) { + NotifyUtil.INSTANCE.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/view/sheet/BottomSheetListUsers.java b/app/src/main/java/com/mxt/anitrend/view/sheet/BottomSheetListUsers.java index 6821278c0..d6ac6534d 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,15 +1,16 @@ package com.mxt.anitrend.view.sheet; import android.app.Dialog; -import android.arch.lifecycle.Observer; -import android.arch.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 android.view.View; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.lifecycle.Observer; +import androidx.lifecycle.ViewModelProviders; +import androidx.recyclerview.widget.StaggeredGridLayoutManager; + import com.annimon.stream.IntPair; import com.mxt.anitrend.R; import com.mxt.anitrend.adapter.recycler.index.UserAdapter; @@ -23,11 +24,10 @@ import com.mxt.anitrend.databinding.BottomSheetListBinding; import com.mxt.anitrend.model.entity.base.UserBase; 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.GraphUtil; import com.mxt.anitrend.util.KeyUtil; +import com.mxt.anitrend.util.graphql.GraphUtil; import com.mxt.anitrend.view.activity.detail.ProfileActivity; import com.nguyenhoanglam.progresslayout.ProgressLayout; @@ -36,6 +36,7 @@ import butterknife.BindView; import butterknife.ButterKnife; +import io.github.wax911.library.model.request.QueryContainerBuilder; public class BottomSheetListUsers extends BottomSheetBase> implements ItemClickListener, Observer>, RecyclerLoadListener, CustomSwipeRefreshLayout.OnRefreshAndLoadListener { 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..8306838db 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,11 +2,12 @@ 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 android.view.View; +import androidx.annotation.NonNull; +import androidx.annotation.StringRes; +import androidx.appcompat.widget.AppCompatButton; + import com.mxt.anitrend.R; import com.mxt.anitrend.base.custom.sheet.BottomSheetBase; import com.mxt.anitrend.base.custom.view.text.RichMarkdownTextView; 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..57f70a6e6 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,14 +4,15 @@ 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 android.text.TextUtils; import android.view.View; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.StaggeredGridLayoutManager; + import com.annimon.stream.IntPair; +import com.google.android.material.bottomsheet.BottomSheetBehavior; import com.miguelcatalan.materialsearchview.MaterialSearchView; import com.mxt.anitrend.R; import com.mxt.anitrend.adapter.recycler.index.UserAdapter; 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..be2c6cdef 100644 --- a/app/src/main/java/com/mxt/anitrend/worker/AuthenticatorWorker.kt +++ b/app/src/main/java/com/mxt/anitrend/worker/AuthenticatorWorker.kt @@ -3,26 +3,24 @@ package com.mxt.anitrend.worker import android.content.Context import android.net.Uri import android.text.TextUtils -import android.util.Log - +import androidx.work.Data +import androidx.work.ListenableWorker +import androidx.work.Worker +import androidx.work.WorkerParameters import com.mxt.anitrend.BuildConfig import com.mxt.anitrend.base.custom.async.WebTokenRequest import com.mxt.anitrend.presenter.base.BasePresenter import com.mxt.anitrend.util.KeyUtil - +import org.koin.core.KoinComponent +import org.koin.core.inject +import timber.log.Timber import java.util.concurrent.ExecutionException -import androidx.work.Data -import androidx.work.ListenableWorker -import androidx.work.Worker -import androidx.work.WorkerParameters +class AuthenticatorWorker(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams), KoinComponent { -class AuthenticatorWorker(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) { + private val presenter by inject() - private val presenter by lazy { - BasePresenter(context) - } - private val authenticatorUri: Uri by lazy { + private val authenticatorUri: Uri by lazy(LazyThreadSafetyMode.NONE) { Uri.parse(workerParams.inputData .getString(KeyUtil.arg_model)) } @@ -45,19 +43,19 @@ 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) - presenter.applicationPref.isAuthenticated = isSuccess + val isSuccess = WebTokenRequest.getToken(authorizationCode) + presenter.settings.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") + 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) @@ -72,6 +70,10 @@ 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) + } + + 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_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..a9137e034 100644 --- a/app/src/main/res/layout/activity_image_preview.xml +++ b/app/src/main/res/layout/activity_image_preview.xml @@ -1,7 +1,6 @@ - @@ -18,7 +17,7 @@ tools:ignore="UnusedAttribute" tools:src="@drawable/reg_bg" /> - - + - \ No newline at end of file + \ No newline at end of file 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_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..74a2f4b2d 100644 --- a/app/src/main/res/layout/activity_pager_generic.xml +++ b/app/src/main/res/layout/activity_pager_generic.xml @@ -1,13 +1,10 @@ - - @@ -16,8 +13,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_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 @@ - - - -