├── .gitignore ├── .gitlab-ci.yml ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── fabric.properties ├── keystore │ └── debug.keystore ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── ch │ │ └── redacted │ │ └── app │ │ ├── MainActivityTest.java │ │ ├── runner │ │ ├── RxAndroidJUnitRunner.java │ │ └── UnlockDeviceAndroidJUnitRunner.java │ │ └── util │ │ ├── RxIdlingExecutionHook.java │ │ └── RxIdlingResource.java │ ├── commonTest │ └── java │ │ └── ch │ │ └── redacted │ │ └── app │ │ └── test │ │ └── common │ │ ├── FailedMockApiService.java │ │ ├── TestComponentRule.java │ │ ├── TestDataFactory.java │ │ └── injection │ │ ├── component │ │ └── TestComponent.java │ │ └── module │ │ └── ApplicationTestModule.java │ ├── debug │ └── AndroidManifest.xml │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── ch │ │ │ └── redacted │ │ │ ├── REDApplication.java │ │ │ ├── data │ │ │ ├── DataManager.java │ │ │ ├── NotificationService.java │ │ │ ├── local │ │ │ │ ├── DrawerItem.java │ │ │ │ └── PreferencesHelper.java │ │ │ ├── model │ │ │ │ ├── Announcement.java │ │ │ │ ├── Artist.java │ │ │ │ ├── Collage.java │ │ │ │ ├── CollageSearch.java │ │ │ │ ├── Conversation.java │ │ │ │ ├── Conversations.java │ │ │ │ ├── ForumCategory.java │ │ │ │ ├── ForumThread.java │ │ │ │ ├── ForumView.java │ │ │ │ ├── Index.java │ │ │ │ ├── Profile.java │ │ │ │ ├── RanksCommunity.java │ │ │ │ ├── Recents.java │ │ │ │ ├── Request.java │ │ │ │ ├── RequestSearch.java │ │ │ │ ├── Subscription.java │ │ │ │ ├── ThreadPostBody.java │ │ │ │ ├── Top10.java │ │ │ │ ├── TorrentBookmark.java │ │ │ │ ├── TorrentComments.java │ │ │ │ ├── TorrentGroup.java │ │ │ │ ├── TorrentSearch.java │ │ │ │ └── UserSearch.java │ │ │ └── remote │ │ │ │ ├── ApiService.java │ │ │ │ ├── PyWhatAutoService.java │ │ │ │ ├── WhatManagerService.java │ │ │ │ └── interceptors │ │ │ │ ├── AddApiKeyInterceptor.java │ │ │ │ ├── AddCookiesInterceptor.java │ │ │ │ ├── AddWmCookiesInterceptor.java │ │ │ │ ├── ReceivedCookiesInterceptor.java │ │ │ │ └── ReceivedWmCookiesInterceptor.java │ │ │ ├── injection │ │ │ ├── ActivityContext.java │ │ │ ├── ApplicationContext.java │ │ │ ├── ConfigPersistent.java │ │ │ ├── PerActivity.java │ │ │ ├── PerFragment.java │ │ │ ├── component │ │ │ │ ├── ActivityComponent.java │ │ │ │ ├── ApplicationComponent.java │ │ │ │ ├── ConfigPersistentComponent.java │ │ │ │ └── FragmentComponent.java │ │ │ └── module │ │ │ │ ├── ActivityModule.java │ │ │ │ ├── ApplicationModule.java │ │ │ │ └── FragmentModule.java │ │ │ ├── ui │ │ │ ├── announcements │ │ │ │ ├── AnnouncementActivity.java │ │ │ │ ├── AnnouncementAdapter.java │ │ │ │ ├── AnnouncementMvpView.java │ │ │ │ └── AnnouncementPresenter.java │ │ │ ├── artist │ │ │ │ ├── ArtistActivity.java │ │ │ │ ├── ArtistMvpView.java │ │ │ │ ├── ArtistPresenter.java │ │ │ │ └── TorrentGroupAdapter.java │ │ │ ├── base │ │ │ │ ├── BaseActivity.java │ │ │ │ ├── BaseDrawerActivity.java │ │ │ │ ├── BaseFragment.java │ │ │ │ ├── BasePresenter.java │ │ │ │ ├── MvpView.java │ │ │ │ └── Presenter.java │ │ │ ├── bookmark │ │ │ │ ├── BookmarkActivity.java │ │ │ │ ├── BookmarkAdapter.java │ │ │ │ ├── BookmarkMvpView.java │ │ │ │ └── BookmarkPresenter.java │ │ │ ├── collage │ │ │ │ ├── CollageActivity.java │ │ │ │ ├── CollageAdapter.java │ │ │ │ ├── CollageMvpView.java │ │ │ │ └── CollagePresenter.java │ │ │ ├── comments │ │ │ │ └── CommentsAdapter.java │ │ │ ├── drawer │ │ │ │ ├── DrawerAdapter.java │ │ │ │ ├── DrawerMvpView.java │ │ │ │ └── DrawerPresenter.java │ │ │ ├── forum │ │ │ │ ├── category │ │ │ │ │ ├── CategoryActivity.java │ │ │ │ │ ├── CategoryAdapter.java │ │ │ │ │ ├── CategoryMvpView.java │ │ │ │ │ └── CategoryPresenter.java │ │ │ │ ├── thread │ │ │ │ │ ├── PostAdapter.java │ │ │ │ │ ├── ThreadActivity.java │ │ │ │ │ ├── ThreadMvpView.java │ │ │ │ │ └── ThreadPresenter.java │ │ │ │ └── threadList │ │ │ │ │ ├── ThreadListActivity.java │ │ │ │ │ ├── ThreadListAdapter.java │ │ │ │ │ ├── ThreadListMvpView.java │ │ │ │ │ └── ThreadListPresenter.java │ │ │ ├── inbox │ │ │ │ ├── ConversationAdapter.java │ │ │ │ ├── InboxActivity.java │ │ │ │ ├── InboxMvpView.java │ │ │ │ ├── InboxPresenter.java │ │ │ │ └── conversation │ │ │ │ │ ├── ConversationActivity.java │ │ │ │ │ ├── ConversationMvpView.java │ │ │ │ │ ├── ConversationPresenter.java │ │ │ │ │ └── MessageAdapter.java │ │ │ ├── login │ │ │ │ ├── LoginActivity.java │ │ │ │ ├── LoginMvpView.java │ │ │ │ └── LoginPresenter.java │ │ │ ├── profile │ │ │ │ ├── ProfileActivity.java │ │ │ │ ├── ProfileMvpView.java │ │ │ │ ├── ProfilePresenter.java │ │ │ │ └── RecentsAdapter.java │ │ │ ├── release │ │ │ │ ├── EndlessRecyclerViewScrollListener.java │ │ │ │ ├── ReleaseActivity.java │ │ │ │ ├── ReleaseMvpView.java │ │ │ │ ├── ReleasePresenter.java │ │ │ │ └── TorrentsAdapter.java │ │ │ ├── reply │ │ │ │ ├── ReplyActivity.java │ │ │ │ ├── ReplyMvpView.java │ │ │ │ └── ReplyPresenter.java │ │ │ ├── request │ │ │ │ ├── RequestActivity.java │ │ │ │ ├── RequestMvpView.java │ │ │ │ └── RequestPresenter.java │ │ │ ├── search │ │ │ │ ├── artist │ │ │ │ │ ├── ArtistSearchActivity.java │ │ │ │ │ ├── ArtistSearchMvpView.java │ │ │ │ │ └── ArtistSearchPresenter.java │ │ │ │ ├── collage │ │ │ │ │ ├── CollageSearchActivity.java │ │ │ │ │ ├── CollageSearchAdapter.java │ │ │ │ │ ├── CollageSearchMvpView.java │ │ │ │ │ └── CollageSearchPresenter.java │ │ │ │ ├── request │ │ │ │ │ ├── RequestSearchActivity.java │ │ │ │ │ ├── RequestSearchAdapter.java │ │ │ │ │ ├── RequestSearchMvpView.java │ │ │ │ │ └── RequestSearchPresenter.java │ │ │ │ ├── torrent │ │ │ │ │ ├── TorrentSearchActivity.java │ │ │ │ │ ├── TorrentSearchAdapter.java │ │ │ │ │ ├── TorrentSearchMvpView.java │ │ │ │ │ └── TorrentSearchPresenter.java │ │ │ │ └── user │ │ │ │ │ ├── UserSearchActivity.java │ │ │ │ │ ├── UserSearchAdapter.java │ │ │ │ │ ├── UserSearchMvpView.java │ │ │ │ │ └── UserSearchPresenter.java │ │ │ ├── settings │ │ │ │ ├── SettingsActivity.java │ │ │ │ └── SettingsFragment.java │ │ │ ├── subscriptions │ │ │ │ ├── SubscriptionAdapter.java │ │ │ │ ├── SubscriptionsActivity.java │ │ │ │ ├── SubscriptionsMvpView.java │ │ │ │ └── SubscriptionsPresenter.java │ │ │ ├── top10 │ │ │ │ ├── Top10Activity.java │ │ │ │ ├── Top10Adapter.java │ │ │ │ ├── Top10MvpView.java │ │ │ │ └── Top10Presenter.java │ │ │ └── view │ │ │ │ └── ForumNavigationView.java │ │ │ └── util │ │ │ ├── AndroidComponentUtil.java │ │ │ ├── Calculator.java │ │ │ ├── DialogFactory.java │ │ │ ├── Emoji.java │ │ │ ├── GenericFileProvider.java │ │ │ ├── GlideConfiguration.java │ │ │ ├── ImageHelper.java │ │ │ ├── NetworkUtil.java │ │ │ ├── ReleaseTypes.java │ │ │ ├── RxEventBus.java │ │ │ ├── SharedPrefsHelper.java │ │ │ └── Tags.java │ └── res │ │ ├── anim │ │ ├── common_fade_in.xml │ │ ├── common_fade_out.xml │ │ └── rotate.xml │ │ ├── color │ │ └── blue_link_text.xml │ │ ├── drawable-hdpi │ │ ├── drawer_shadow.9.png │ │ ├── ic_launcher.png │ │ ├── ic_locked.png │ │ └── no_artwork.png │ │ ├── drawable-mdpi │ │ ├── drawer_shadow.9.png │ │ ├── ic_launcher.png │ │ ├── ic_locked.png │ │ └── no_artwork.png │ │ ├── drawable-xhdpi │ │ ├── drawer_shadow.9.png │ │ ├── ic_launcher.png │ │ ├── ic_locked.png │ │ └── no_artwork.png │ │ ├── drawable-xxhdpi │ │ ├── drawer_shadow.9.png │ │ ├── ic_launcher.png │ │ ├── ic_locked.png │ │ └── no_artwork.png │ │ ├── drawable │ │ ├── circle.xml │ │ ├── default_avatar.png │ │ ├── ic_add_24dp.xml │ │ ├── ic_announcement_48px.xml │ │ ├── ic_archive_black_24px.xml │ │ ├── ic_arrow_downward_48px.xml │ │ ├── ic_arrow_upward_48px.xml │ │ ├── ic_artists_48px.xml │ │ ├── ic_barcode_48px.xml │ │ ├── ic_bookmark_24dp.xml │ │ ├── ic_bookmark_border_24dp.xml │ │ ├── ic_chevron_left_black_24px.xml │ │ ├── ic_chevron_right_black_24px.xml │ │ ├── ic_clear_24dp.xml │ │ ├── ic_content_copy_24dp.xml │ │ ├── ic_create_black_24px.xml │ │ ├── ic_delete_24dp.xml │ │ ├── ic_drafts_black_24px.xml │ │ ├── ic_expand_less_24dp.xml │ │ ├── ic_expand_more_24dp.xml │ │ ├── ic_face_black_24px.xml │ │ ├── ic_favorite_48px.xml │ │ ├── ic_file_download_24dp.xml │ │ ├── ic_file_download_black_24px.xml │ │ ├── ic_file_upload_black_24px.xml │ │ ├── ic_first_page_black_24px.xml │ │ ├── ic_forum_48px.xml │ │ ├── ic_forward_24dp.xml │ │ ├── ic_inbox_48dp.xml │ │ ├── ic_insert_chart_24dp.xml │ │ ├── ic_insert_chart_black_24px.xml │ │ ├── ic_last_page_black_24px.xml │ │ ├── ic_lock_24dp.xml │ │ ├── ic_mail_24dp.xml │ │ ├── ic_message_24px.xml │ │ ├── ic_not_interested_48px.xml │ │ ├── ic_notifications_active_48px.xml │ │ ├── ic_notifications_disabled_48px.xml │ │ ├── ic_notify_crash_reports.png │ │ ├── ic_profile_48px.xml │ │ ├── ic_redeem_48px.xml │ │ ├── ic_refresh_24dp.xml │ │ ├── ic_replay_48px.xml │ │ ├── ic_reply_24dp.xml │ │ ├── ic_report_48px.xml │ │ ├── ic_requests_48px.xml │ │ ├── ic_rippy.xml │ │ ├── ic_search_24dp.xml │ │ ├── ic_send_24dp.xml │ │ ├── ic_star_24dp.xml │ │ ├── ic_stars_48px.xml │ │ ├── ic_top_10_48px.xml │ │ ├── ic_torrents_48px.xml │ │ ├── ic_unarchive_black_24px.xml │ │ ├── ic_users_48px.xml │ │ ├── ic_visibility_24dp.xml │ │ ├── ic_visibility_off_24dp.xml │ │ ├── ic_warning_48px.xml │ │ ├── no_avatar.png │ │ ├── poll_selector.xml │ │ ├── pthlogo.png │ │ ├── redacted_logo_1.xml │ │ ├── redacted_logo_2.xml │ │ ├── redacted_logo_3.xml │ │ ├── search_border_line.xml │ │ ├── teal_background.png │ │ └── whatandroid_logo_beta.png │ │ ├── layout │ │ ├── activity_artist.xml │ │ ├── activity_artist_search.xml │ │ ├── activity_collage.xml │ │ ├── activity_collage_search.xml │ │ ├── activity_conversation.xml │ │ ├── activity_forum.xml │ │ ├── activity_list.xml │ │ ├── activity_login.xml │ │ ├── activity_messages.xml │ │ ├── activity_profile.xml │ │ ├── activity_release.xml │ │ ├── activity_request.xml │ │ ├── activity_request_search.xml │ │ ├── activity_settings.xml │ │ ├── activity_subscriptions.xml │ │ ├── activity_top_10.xml │ │ ├── activity_torrent_search.xml │ │ ├── activity_user_search.xml │ │ ├── artist_search_view.xml │ │ ├── collage_search_view.xml │ │ ├── compose_view.xml │ │ ├── description_view.xml │ │ ├── forum_navigation.xml │ │ ├── forum_view.xml │ │ ├── fragment_settings.xml │ │ ├── fragment_thread_list.xml │ │ ├── item_announcement.xml │ │ ├── item_artist.xml │ │ ├── item_category.xml │ │ ├── item_collage.xml │ │ ├── item_collage_search.xml │ │ ├── item_comment.xml │ │ ├── item_conversation.xml │ │ ├── item_forum.xml │ │ ├── item_forum_section.xml │ │ ├── item_group_header.xml │ │ ├── item_message.xml │ │ ├── item_post.xml │ │ ├── item_recent.xml │ │ ├── item_request.xml │ │ ├── item_subscribed_forum.xml │ │ ├── item_top10.xml │ │ ├── item_torrent.xml │ │ ├── item_torrent_bookmark.xml │ │ ├── item_torrent_group.xml │ │ ├── item_torrent_search.xml │ │ ├── item_user.xml │ │ ├── profile_ranks_view.xml │ │ ├── reply_view.xml │ │ ├── request_search_view.xml │ │ ├── swarm_activity_view.xml │ │ ├── torrent_search_view.xml │ │ ├── user_search_view.xml │ │ ├── view_drawer.xml │ │ ├── view_drawer_item.xml │ │ ├── view_profile_info.xml │ │ └── view_profile_torrents.xml │ │ ├── menu │ │ ├── bottom_navigation_inbox.xml │ │ ├── bottom_navigation_main.xml │ │ ├── bottom_navigation_subscriptions.xml │ │ ├── reply_menu.xml │ │ └── send_message_menu.xml │ │ ├── transition │ │ └── shared_element_transation.xml │ │ ├── values │ │ ├── arrays.xml │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── font_awesome.xml │ │ ├── plurals.xml │ │ ├── strings.xml │ │ ├── styles.xml │ │ └── tags.xml │ │ ├── xml-v25 │ │ └── shortcuts.xml │ │ └── xml │ │ ├── preferences.xml │ │ └── provider_paths.xml │ └── test │ └── java │ └── ch │ └── redacted │ └── app │ ├── DataManagerTest.java │ ├── ForumPresenterTest.java │ ├── LoginPresenterTest.java │ ├── ThreadListPresenterTest.java │ ├── Top10PresenterTest.java │ ├── UserSearchSearchPresenterTest.java │ └── util │ ├── DefaultConfig.java │ ├── RxEventBusTest.java │ └── RxSchedulersOverrideRule.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── licenses └── RIBOT └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /local.properties 3 | /.idea/workspace.xml 4 | .DS_Store 5 | /build 6 | .idea/ 7 | *iml 8 | *.iml 9 | */build -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | image: openjdk:8-jdk 2 | 3 | variables: 4 | ANDROID_COMPILE_SDK: "25" 5 | ANDROID_BUILD_TOOLS: "25.0.2" 6 | ANDROID_SDK_TOOLS: "25.2.3" 7 | 8 | before_script: 9 | - apt-get --quiet update --yes 10 | - apt-get --quiet install --yes wget tar unzip lib32stdc++6 lib32z1 11 | - wget --quiet --output-document=android-sdk.zip https://dl.google.com/android/repository/tools_r${ANDROID_SDK_TOOLS}-linux.zip 12 | - unzip android-sdk.zip -d ./android-sdk-linux 13 | - echo y | android-sdk-linux/tools/android --silent update sdk --no-ui --all --filter android-${ANDROID_COMPILE_SDK} 14 | - echo y | android-sdk-linux/tools/android --silent update sdk --no-ui --all --filter platform-tools 15 | - echo y | android-sdk-linux/tools/android --silent update sdk --no-ui --all --filter build-tools-${ANDROID_BUILD_TOOLS} 16 | - echo y | android-sdk-linux/tools/android --silent update sdk --no-ui --all --filter extra-android-m2repository 17 | - echo y | android-sdk-linux/tools/android --silent update sdk --no-ui --all --filter extra-google-google_play_services 18 | - echo y | android-sdk-linux/tools/android --silent update sdk --no-ui --all --filter extra-google-m2repository 19 | - export ANDROID_HOME=$PWD/android-sdk-linux 20 | - export PATH=$PATH:$PWD/android-sdk-linux/platform-tools/ 21 | - mkdir "android-sdk-linux/licenses" || true 22 | - echo -e "\n8933bad161af4178b1185d1a37fbf41ea5269c55" > "android-sdk-linux/licenses/android-sdk-license" 23 | - echo -e "\n84831b9409646a918e30573bab4c9c91346d8abd" > "android-sdk-linux/licenses/android-sdk-preview-license" 24 | - chmod +x ./gradlew 25 | 26 | stages: 27 | - build 28 | - test 29 | 30 | build: 31 | stage: build 32 | script: 33 | - ./gradlew assembleDebug 34 | artifacts: 35 | paths: 36 | - app/build/outputs/apk/app-debug.apk 37 | 38 | unitTests: 39 | stage: test 40 | script: 41 | - ./gradlew test -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Stuxo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # REDAndroid 2 | 3 | ## An android app for Redacted 4 | This app includes most site features, but some are still in progress 5 | 6 | The app may work with a default setup of Gazelle, however some changes have been made to the api to support certain features. These should not be breaking, or easy to remove/update. Just change the url to point to your site and enjoy. 7 | 8 | Licensed under the MIT License, see LICENSE for full terms. 9 | 10 | Releases 11 | - 12 | Releases can be found in the [releases](https://github.com/stuxo/REDAndroid/releases) page. 13 | 14 | Contributing 15 | - 16 | Pull requests are welcome, if you have any questions, open a ticket here, or find me elsewhere. 17 | Contact [sxo](https://github.com/stuxo) through GitHub, or the site. 18 | 19 | Architecture 20 | - 21 | This app is based on the MVP architecture used by [Ribot](https://github.com/ribot/android-boilerplate) 22 | 23 | Thanks 24 | - 25 | * Thank you for all the work on the original What.CD app from GWindow, Twinklebear and Dr4g0n over [here](https://github.com/Gwindow/WhatAndroid). 26 | * Thank you to all the testers, past and future. 27 | * Thank you to all contributers, past and future. 28 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | *iml 3 | *.iml 4 | .idea -------------------------------------------------------------------------------- /app/fabric.properties: -------------------------------------------------------------------------------- 1 | apiSecret=changeMeToYourRealApiSecret 2 | apiKey=changeMeToYourRealApiKey -------------------------------------------------------------------------------- /app/keystore/debug.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stuxo/REDAndroid/2df211a1872709808e4023448e1611b56eff10b2/app/keystore/debug.keystore -------------------------------------------------------------------------------- /app/src/androidTest/java/ch/redacted/app/MainActivityTest.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.app; 2 | 3 | import android.support.test.InstrumentationRegistry; 4 | import android.support.test.rule.ActivityTestRule; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import ch.redacted.app.test.common.TestComponentRule; 8 | import ch.redacted.ui.login.LoginActivity; 9 | import org.junit.Rule; 10 | import org.junit.Test; 11 | import org.junit.rules.RuleChain; 12 | import org.junit.rules.TestRule; 13 | import org.junit.runner.RunWith; 14 | 15 | import static android.support.test.espresso.Espresso.onView; 16 | import static android.support.test.espresso.assertion.ViewAssertions.matches; 17 | import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; 18 | import static android.support.test.espresso.matcher.ViewMatchers.withText; 19 | 20 | @RunWith(AndroidJUnit4.class) 21 | public class MainActivityTest { 22 | 23 | public final TestComponentRule component = 24 | new TestComponentRule(InstrumentationRegistry.getTargetContext()); 25 | public final ActivityTestRule main = 26 | new ActivityTestRule(LoginActivity.class, false, false) {}; 27 | 28 | // TestComponentRule needs to go first to make sure the Dagger ApplicationTestComponent is set 29 | // in the Application before any Activity is launched. 30 | @Rule 31 | public final TestRule chain = RuleChain.outerRule(component).around(main); 32 | 33 | @Test public void loginScreenShown() { 34 | 35 | main.launchActivity(null); 36 | 37 | String name = String.format("%s %s", "", ""); 38 | onView(withText(name)).check(matches(isDisplayed())); 39 | } 40 | } -------------------------------------------------------------------------------- /app/src/androidTest/java/ch/redacted/app/runner/RxAndroidJUnitRunner.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.app.runner; 2 | 3 | import android.os.Bundle; 4 | import android.support.test.espresso.Espresso; 5 | 6 | import ch.redacted.app.util.RxIdlingExecutionHook; 7 | import ch.redacted.app.util.RxIdlingResource; 8 | import rx.plugins.RxJavaPlugins; 9 | 10 | /** 11 | * Runner that registers a Espresso Indling resource that handles waiting for 12 | * RxJava Observables to finish. 13 | * WARNING - Using this runner will block the tests if the application uses long-lived hot 14 | * Observables such us event buses, etc. 15 | */ 16 | public class RxAndroidJUnitRunner extends UnlockDeviceAndroidJUnitRunner { 17 | 18 | @Override 19 | public void onCreate(Bundle arguments) { 20 | super.onCreate(arguments); 21 | RxIdlingResource rxIdlingResource = new RxIdlingResource(); 22 | RxJavaPlugins.getInstance() 23 | .registerObservableExecutionHook(new RxIdlingExecutionHook(rxIdlingResource)); 24 | Espresso.registerIdlingResources(rxIdlingResource); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/androidTest/java/ch/redacted/app/runner/UnlockDeviceAndroidJUnitRunner.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.app.runner; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.app.Application; 5 | import android.app.KeyguardManager; 6 | import android.os.PowerManager; 7 | import android.support.test.runner.AndroidJUnitRunner; 8 | 9 | import static android.content.Context.KEYGUARD_SERVICE; 10 | import static android.content.Context.POWER_SERVICE; 11 | import static android.os.PowerManager.ACQUIRE_CAUSES_WAKEUP; 12 | import static android.os.PowerManager.FULL_WAKE_LOCK; 13 | import static android.os.PowerManager.ON_AFTER_RELEASE; 14 | 15 | /** 16 | * Extension of AndroidJUnitRunner that adds some functionality to unblock the device screen 17 | * before starting the tests. 18 | */ 19 | public class UnlockDeviceAndroidJUnitRunner extends AndroidJUnitRunner { 20 | 21 | private PowerManager.WakeLock mWakeLock; 22 | 23 | @SuppressLint("MissingPermission") 24 | @Override 25 | public void onStart() { 26 | Application application = (Application) getTargetContext().getApplicationContext(); 27 | String simpleName = UnlockDeviceAndroidJUnitRunner.class.getSimpleName(); 28 | // Unlock the device so that the tests can input keystrokes. 29 | ((KeyguardManager) application.getSystemService(KEYGUARD_SERVICE)) 30 | .newKeyguardLock(simpleName) 31 | .disableKeyguard(); 32 | // Wake up the screen. 33 | PowerManager powerManager = ((PowerManager) application.getSystemService(POWER_SERVICE)); 34 | mWakeLock = powerManager.newWakeLock(FULL_WAKE_LOCK | ACQUIRE_CAUSES_WAKEUP | 35 | ON_AFTER_RELEASE, simpleName); 36 | mWakeLock.acquire(); 37 | super.onStart(); 38 | } 39 | 40 | @Override 41 | public void onDestroy() { 42 | super.onDestroy(); 43 | mWakeLock.release(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/src/androidTest/java/ch/redacted/app/util/RxIdlingExecutionHook.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.app.util; 2 | 3 | import rx.Observable; 4 | import rx.Subscription; 5 | import rx.plugins.RxJavaObservableExecutionHook; 6 | 7 | /** 8 | * RxJava Observable execution hook that handles updating the active subscription 9 | * count for a given Espresso RxIdlingResource. 10 | */ 11 | public class RxIdlingExecutionHook extends RxJavaObservableExecutionHook { 12 | 13 | private RxIdlingResource mRxIdlingResource; 14 | 15 | public RxIdlingExecutionHook(RxIdlingResource rxIdlingResource) { 16 | mRxIdlingResource = rxIdlingResource; 17 | } 18 | 19 | @Override 20 | public Observable.OnSubscribe onSubscribeStart( 21 | Observable observableInstance, Observable.OnSubscribe onSubscribe) { 22 | mRxIdlingResource.incrementActiveSubscriptionsCount(); 23 | return super.onSubscribeStart(observableInstance, onSubscribe); 24 | } 25 | 26 | @Override 27 | public Throwable onSubscribeError(Throwable e) { 28 | mRxIdlingResource.decrementActiveSubscriptionsCount(); 29 | return super.onSubscribeError(e); 30 | } 31 | 32 | @Override 33 | public Subscription onSubscribeReturn(Subscription subscription) { 34 | mRxIdlingResource.decrementActiveSubscriptionsCount(); 35 | return super.onSubscribeReturn(subscription); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/androidTest/java/ch/redacted/app/util/RxIdlingResource.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.app.util; 2 | 3 | import android.support.test.espresso.IdlingResource; 4 | 5 | import java.util.concurrent.atomic.AtomicInteger; 6 | 7 | import timber.log.Timber; 8 | 9 | /** 10 | * Espresso Idling resource that handles waiting for RxJava Observables executions. 11 | * This class must be used with RxIdlingExecutionHook. 12 | * Before registering this idling resource you must: 13 | * 1. Create an instance of RxIdlingExecutionHook by passing an instance of this class. 14 | * 2. Register RxIdlingExecutionHook with the RxJavaPlugins using registerObservableExecutionHook() 15 | * 3. Register this idle resource with Espresso using Espresso.registerIdlingResources() 16 | */ 17 | public class RxIdlingResource implements IdlingResource { 18 | 19 | private final AtomicInteger mActiveSubscriptionsCount = new AtomicInteger(0); 20 | private ResourceCallback mResourceCallback; 21 | 22 | @Override 23 | public String getName() { 24 | return getClass().getSimpleName(); 25 | } 26 | 27 | @Override 28 | public boolean isIdleNow() { 29 | return mActiveSubscriptionsCount.get() == 0; 30 | } 31 | 32 | @Override 33 | public void registerIdleTransitionCallback(ResourceCallback callback) { 34 | mResourceCallback = callback; 35 | } 36 | 37 | public void incrementActiveSubscriptionsCount() { 38 | int count = mActiveSubscriptionsCount.incrementAndGet(); 39 | Timber.i("Active subscriptions count increased to %d", count); 40 | } 41 | 42 | public void decrementActiveSubscriptionsCount() { 43 | int count = mActiveSubscriptionsCount.decrementAndGet(); 44 | Timber.i("Active subscriptions count decreased to %d", count); 45 | if (isIdleNow()) { 46 | Timber.i("There is no active subscriptions, transitioning to Idle"); 47 | mResourceCallback.onTransitionToIdle(); 48 | } 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /app/src/commonTest/java/ch/redacted/app/test/common/TestComponentRule.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.app.test.common; 2 | 3 | import android.content.Context; 4 | 5 | import ch.redacted.REDApplication; 6 | import ch.redacted.app.test.common.injection.module.ApplicationTestModule; 7 | import ch.redacted.app.test.common.injection.component.DaggerTestComponent; 8 | import ch.redacted.data.DataManager; 9 | import org.junit.rules.TestRule; 10 | import org.junit.runner.Description; 11 | import org.junit.runners.model.Statement; 12 | 13 | /** 14 | * Test rule that creates and sets a Dagger TestComponent into the application overriding the 15 | * existing application component. 16 | * Use this rule in your test case in order for the app to use mock dependencies. 17 | * It also exposes some of the dependencies so they can be easily accessed from the tests, e.g. to 18 | * stub mocks etc. 19 | */ 20 | public class TestComponentRule implements TestRule { 21 | 22 | private final ch.redacted.app.test.common.injection.component.TestComponent 23 | mTestComponent; 24 | private final Context mContext; 25 | 26 | public TestComponentRule(Context context) { 27 | mContext = context; 28 | REDApplication application = REDApplication.get(context); 29 | mTestComponent = DaggerTestComponent.builder() 30 | .applicationTestModule(new ApplicationTestModule(application)) 31 | .build(); 32 | } 33 | 34 | public Context getContext() { 35 | return mContext; 36 | } 37 | 38 | public DataManager getMockDataManager() { 39 | return mTestComponent.dataManager(); 40 | } 41 | 42 | @Override 43 | public Statement apply(final Statement base, Description description) { 44 | return new Statement() { 45 | @Override 46 | public void evaluate() throws Throwable { 47 | REDApplication application = REDApplication.get(mContext); 48 | application.setComponent(mTestComponent); 49 | base.evaluate(); 50 | application.setComponent(null); 51 | } 52 | }; 53 | } 54 | } -------------------------------------------------------------------------------- /app/src/commonTest/java/ch/redacted/app/test/common/injection/component/TestComponent.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.app.test.common.injection.component; 2 | 3 | import javax.inject.Singleton; 4 | 5 | import dagger.Component; 6 | import ch.redacted.app.test.common.injection.module.ApplicationTestModule; 7 | import ch.redacted.injection.component.ApplicationComponent; 8 | 9 | @Singleton 10 | @Component(modules = ApplicationTestModule.class) 11 | public interface TestComponent extends ApplicationComponent { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /app/src/commonTest/java/ch/redacted/app/test/common/injection/module/ApplicationTestModule.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.app.test.common.injection.module; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | 6 | import javax.inject.Singleton; 7 | 8 | import dagger.Module; 9 | import dagger.Provides; 10 | import ch.redacted.data.DataManager; 11 | import ch.redacted.data.remote.ApiService; 12 | import ch.redacted.data.remote.WhatManagerService; 13 | import ch.redacted.injection.ApplicationContext; 14 | 15 | import static org.mockito.Mockito.mock; 16 | 17 | /** 18 | * Provides application-level dependencies for an app running on a testing environment 19 | * This allows injecting mocks if necessary. 20 | */ 21 | @Module 22 | public class ApplicationTestModule { 23 | 24 | private final Application mApplication; 25 | 26 | public ApplicationTestModule(Application application) { 27 | mApplication = application; 28 | } 29 | 30 | @Provides 31 | Application provideApplication() { 32 | return mApplication; 33 | } 34 | 35 | @Provides 36 | @ApplicationContext 37 | Context provideContext() { 38 | return mApplication; 39 | } 40 | 41 | /************* MOCKS *************/ 42 | 43 | @Provides 44 | @Singleton DataManager provideDataManager() { 45 | return mock(DataManager.class); 46 | } 47 | 48 | @Provides 49 | @Singleton ApiService provideApiService() { 50 | return mock(ApiService.class); 51 | } 52 | 53 | @Provides 54 | @Singleton WhatManagerService provideWmService() { 55 | return mock(WhatManagerService.class); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/data/local/DrawerItem.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.data.local; 2 | 3 | /** 4 | * Created by hfatih on 1/5/2017. 5 | */ 6 | public enum DrawerItem { 7 | Announcements, 8 | Profile, 9 | Top10, 10 | Torrents, 11 | Requests, 12 | Collages, 13 | Forums, 14 | Users, 15 | Artists, 16 | Bookmarks, 17 | Inbox, 18 | Subscriptions 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/data/model/CollageSearch.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.data.model; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | 5 | import java.util.List; 6 | 7 | public class CollageSearch { 8 | @SerializedName("status") 9 | public String status; 10 | 11 | @SerializedName("response") 12 | public List response; 13 | 14 | public static class Response { 15 | @SerializedName("id") 16 | public int id; 17 | 18 | @SerializedName("name") 19 | public String name; 20 | 21 | @SerializedName("creatorID") 22 | public int creatorID; 23 | 24 | @SerializedName("collageCategoryID") 25 | public int collageCategoryID; 26 | 27 | @SerializedName("collageCategoryName") 28 | public String collageCategoryName; 29 | 30 | @SerializedName("hasBookmarked") 31 | public Boolean hasBookmarked; 32 | 33 | @SerializedName("subscriberCount") 34 | public int subscriberCount; 35 | 36 | @SerializedName("lastUpdated") 37 | public String lastUpdated; 38 | 39 | @SerializedName("tagList") 40 | public String tagList; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/data/model/Conversation.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.data.model; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | 5 | import java.util.Date; 6 | import java.util.List; 7 | 8 | /** 9 | * Created by sxo on 24/05/17. 10 | */ 11 | 12 | public class Conversation { 13 | 14 | @SerializedName("status") 15 | public String status; 16 | @SerializedName("response") 17 | public Response response; 18 | 19 | public static class Messages { 20 | @SerializedName("messageId") 21 | public int messageId; 22 | @SerializedName("senderId") 23 | public int senderId; 24 | @SerializedName("senderName") 25 | public String senderName; 26 | @SerializedName("sentDate") 27 | public Date sentDate; 28 | @SerializedName("bbBody") 29 | public String bbBody; 30 | @SerializedName("body") 31 | public String body; 32 | } 33 | 34 | public static class Response { 35 | @SerializedName("convId") 36 | public int convId; 37 | @SerializedName("subject") 38 | public String subject; 39 | @SerializedName("sticky") 40 | public boolean sticky; 41 | @SerializedName("messages") 42 | public List messages; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/data/model/Conversations.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.data.model; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | 5 | import java.util.Date; 6 | import java.util.List; 7 | 8 | /** 9 | * Created by sxo on 22/01/17. 10 | */ 11 | 12 | public class Conversations { 13 | 14 | @SerializedName("status") 15 | public String status; 16 | @SerializedName("response") 17 | public Response response; 18 | 19 | public static class Messages { 20 | @SerializedName("convId") 21 | public int convId; 22 | @SerializedName("subject") 23 | public String subject; 24 | @SerializedName("unread") 25 | public boolean unread; 26 | @SerializedName("sticky") 27 | public boolean sticky; 28 | @SerializedName("forwardedId") 29 | public int forwardedId; 30 | @SerializedName("forwardedName") 31 | public String forwardedName; 32 | @SerializedName("senderId") 33 | public int senderId; 34 | @SerializedName("username") 35 | public String username; 36 | @SerializedName("donor") 37 | public boolean donor; 38 | @SerializedName("warned") 39 | public boolean warned; 40 | @SerializedName("enabled") 41 | public boolean enabled; 42 | @SerializedName("date") 43 | public Date date; 44 | } 45 | 46 | public static class Response { 47 | @SerializedName("currentPage") 48 | public int currentPage; 49 | @SerializedName("pages") 50 | public int pages; 51 | @SerializedName("messages") 52 | public List messages; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/data/model/ForumCategory.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.data.model; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * Created by sxo on 24/12/16. 9 | */ 10 | 11 | public class ForumCategory { 12 | 13 | @SerializedName("status") 14 | public String status; 15 | @SerializedName("response") 16 | public Response response; 17 | 18 | public static class Forums { 19 | @SerializedName("forumId") 20 | public int forumId; 21 | @SerializedName("forumName") 22 | public String forumName; 23 | @SerializedName("forumDescription") 24 | public String forumDescription; 25 | @SerializedName("numTopics") 26 | public int numTopics; 27 | @SerializedName("numPosts") 28 | public int numPosts; 29 | @SerializedName("lastPostId") 30 | public int lastPostId; 31 | @SerializedName("lastAuthorId") 32 | public int lastAuthorId; 33 | @SerializedName("lastPostAuthorName") 34 | public String lastPostAuthorName; 35 | @SerializedName("lastTopicId") 36 | public int lastTopicId; 37 | @SerializedName("lastTime") 38 | public String lastTime; 39 | @SerializedName("lastTopic") 40 | public String lastTopic; 41 | @SerializedName("read") 42 | public boolean read; 43 | @SerializedName("locked") 44 | public boolean locked; 45 | @SerializedName("sticky") 46 | public boolean sticky; 47 | } 48 | 49 | public static class Categories { 50 | @SerializedName("categoryID") 51 | public int categoryID; 52 | @SerializedName("categoryName") 53 | public String categoryName; 54 | @SerializedName("forums") 55 | public List forums; 56 | } 57 | 58 | public static class Response { 59 | @SerializedName("categories") 60 | public List categories; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/data/model/ForumView.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.data.model; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | 5 | import java.util.Date; 6 | import java.util.List; 7 | 8 | /** 9 | * Created by sxo on 24/12/16. 10 | */ 11 | 12 | public class ForumView 13 | { 14 | @SerializedName("status") 15 | public String status; 16 | @SerializedName("response") 17 | public Response response; 18 | 19 | public static class SpecificRules { 20 | } 21 | 22 | public static class Threads { 23 | @SerializedName("topicId") 24 | public int topicId; 25 | @SerializedName("title") 26 | public String title; 27 | @SerializedName("authorId") 28 | public int authorId; 29 | @SerializedName("authorName") 30 | public String authorName; 31 | @SerializedName("locked") 32 | public boolean locked; 33 | @SerializedName("sticky") 34 | public boolean sticky; 35 | @SerializedName("postCount") 36 | public int postCount; 37 | @SerializedName("lastID") 38 | public int lastID; 39 | @SerializedName("lastTime") 40 | public Date lastTime; 41 | @SerializedName("lastAuthorId") 42 | public int lastAuthorId; 43 | @SerializedName("lastAuthorName") 44 | public String lastAuthorName; 45 | @SerializedName("lastReadPage") 46 | public int lastReadPage; 47 | @SerializedName("lastReadPostId") 48 | public int lastReadPostId; 49 | @SerializedName("read") 50 | public boolean read; 51 | } 52 | 53 | public static class Response { 54 | @SerializedName("forumName") 55 | public String forumName; 56 | @SerializedName("specificRules") 57 | public List specificRules; 58 | @SerializedName("currentPage") 59 | public int currentPage; 60 | @SerializedName("pages") 61 | public int pages; 62 | @SerializedName("threads") 63 | public List threads; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/data/model/Index.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.data.model; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | 5 | /** 6 | * Created by sxo on 20/12/16. 7 | */ 8 | 9 | public class Index { 10 | @SerializedName("status") 11 | public String status; 12 | @SerializedName("response") 13 | public Response response; 14 | 15 | public static class Notifications { 16 | @SerializedName("messages") 17 | public int messages; 18 | @SerializedName("notifications") 19 | public int notifications; 20 | @SerializedName("newAnnouncement") 21 | public boolean newAnnouncement; 22 | @SerializedName("newBlog") 23 | public boolean newBlog; 24 | @SerializedName("newSubscriptions") 25 | public boolean newSubscriptions; 26 | } 27 | 28 | public static class Userstats { 29 | @SerializedName("uploaded") 30 | public String uploaded; 31 | @SerializedName("downloaded") 32 | public String downloaded; 33 | @SerializedName("ratio") 34 | public double ratio; 35 | @SerializedName("requiredratio") 36 | public double requiredratio; 37 | @SerializedName("class") 38 | public String mclass; 39 | } 40 | 41 | public static class Response { 42 | @SerializedName("username") 43 | public String username; 44 | @SerializedName("id") 45 | public int id; 46 | @SerializedName("authkey") 47 | public String authkey; 48 | @SerializedName("passkey") 49 | public String passkey; 50 | @SerializedName("notifications") 51 | public Notifications notifications; 52 | @SerializedName("userstats") 53 | public Userstats userstats; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/data/model/RanksCommunity.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.data.model; 2 | 3 | /** 4 | * Created by sxo on 17/03/17. 5 | */ 6 | 7 | public class RanksCommunity { 8 | public RanksCommunity(Profile.Community community, Profile.Ranks ranks) { 9 | this.community = community; 10 | this.ranks = ranks; 11 | } 12 | 13 | public Profile.Community community; 14 | public Profile.Ranks ranks; 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/data/model/Recents.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.data.model; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | import java.util.List; 5 | 6 | public class Recents { 7 | 8 | public Response response; 9 | private String status; 10 | private String error; 11 | 12 | public class Response { 13 | public List snatches, uploads; 14 | } 15 | 16 | public class RecentTorrent { 17 | @SerializedName("ID") 18 | public int id; 19 | @SerializedName("Name") 20 | public String name; 21 | @SerializedName("WikiImage") 22 | public String wikiImage; 23 | List artists; 24 | 25 | //Returns the main artist 26 | public List getArtists(){ 27 | return artists.get(0).artists; 28 | } 29 | 30 | public class ArtistInfo { 31 | @SerializedName("1") 32 | public List artists; 33 | } 34 | } 35 | 36 | public class RecentArtist { 37 | public String id; 38 | public int artistID = -1; 39 | public String name; 40 | } 41 | } 42 | 43 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/data/model/Subscription.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.data.model; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | import java.util.List; 5 | 6 | /** 7 | * Created by sxo on 21/02/17. 8 | */ 9 | 10 | public class Subscription { 11 | 12 | @SerializedName("status") public String status; 13 | @SerializedName("response") public Response response; 14 | 15 | public static class Threads { 16 | @SerializedName("forumId") public int forumId; 17 | @SerializedName("forumName") public String forumName; 18 | @SerializedName("threadId") public int threadId; 19 | @SerializedName("threadTitle") public String threadTitle; 20 | @SerializedName("postId") public int postId; 21 | @SerializedName("lastPostId") public int lastPostId; 22 | @SerializedName("locked") public boolean locked; 23 | @SerializedName("new") public boolean mnew; 24 | } 25 | 26 | public static class Response { 27 | @SerializedName("threads") public List threads; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/data/model/ThreadPostBody.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.data.model; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | 5 | /** 6 | * Created by sxo on 16/01/17. 7 | */ 8 | public class ThreadPostBody { 9 | @SerializedName("forumid") 10 | private int forumId; 11 | @SerializedName("topicid") 12 | private int topicId; 13 | private String body; 14 | private String auth; 15 | 16 | public ThreadPostBody(int forumId, int topicId, String text, String auth) { 17 | this.forumId = forumId; 18 | this.topicId = topicId; 19 | this.body = text; 20 | this.auth = auth; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/data/model/Top10.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.data.model; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | import java.util.List; 5 | 6 | /** 7 | * Created by sxo on 5/01/17. 8 | */ 9 | 10 | public class Top10 { 11 | 12 | @SerializedName("status") public String status; 13 | @SerializedName("response") public List response; 14 | 15 | public static class Results { 16 | @SerializedName("torrentId") public int torrentId; 17 | @SerializedName("groupId") public int groupId; 18 | @SerializedName("artist") public String artist; 19 | @SerializedName("groupName") public String groupName; 20 | @SerializedName("groupCategory") public int groupCategory; 21 | @SerializedName("groupYear") public int groupYear; 22 | @SerializedName("remasterTitle") public String remasterTitle; 23 | @SerializedName("format") public String format; 24 | @SerializedName("encoding") public String encoding; 25 | @SerializedName("hasLog") public boolean hasLog; 26 | @SerializedName("hasCue") public boolean hasCue; 27 | @SerializedName("media") public String media; 28 | @SerializedName("scene") public boolean scene; 29 | @SerializedName("year") public int year; 30 | @SerializedName("tags") public List tags; 31 | @SerializedName("snatched") public int snatched; 32 | @SerializedName("seeders") public int seeders; 33 | @SerializedName("leechers") public int leechers; 34 | @SerializedName("data") public String data; 35 | @SerializedName("wikiImage") public String wikiImage; 36 | } 37 | 38 | public static class Response { 39 | @SerializedName("caption") public String caption; 40 | @SerializedName("tag") public String tag; 41 | @SerializedName("limit") public int limit; 42 | @SerializedName("results") public List results; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/data/model/TorrentComments.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.data.model; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | 5 | import java.util.Date; 6 | import java.util.List; 7 | 8 | /** 9 | * Created by sxo on 20/01/17. 10 | */ 11 | 12 | public class TorrentComments { 13 | 14 | @SerializedName("status") 15 | public String status; 16 | @SerializedName("response") 17 | public Response response; 18 | 19 | public static class Userinfo { 20 | @SerializedName("authorId") 21 | public int authorId; 22 | @SerializedName("authorName") 23 | public String authorName; 24 | @SerializedName("artist") 25 | public boolean artist; 26 | @SerializedName("donor") 27 | public boolean donor; 28 | @SerializedName("warned") 29 | public boolean warned; 30 | @SerializedName("avatar") 31 | public String avatar; 32 | @SerializedName("enabled") 33 | public boolean enabled; 34 | @SerializedName("userTitle") 35 | public String userTitle; 36 | } 37 | 38 | public static class Comments { 39 | @SerializedName("postId") 40 | public int postId; 41 | @SerializedName("addedTime") 42 | public Date addedTime; 43 | @SerializedName("bbBody") 44 | public String bbBody; 45 | @SerializedName("body") 46 | public String body; 47 | @SerializedName("editedUserId") 48 | public int editedUserId; 49 | @SerializedName("editedTime") 50 | public String editedTime; 51 | @SerializedName("editedUsername") 52 | public String editedUsername; 53 | @SerializedName("userinfo") 54 | public Userinfo userinfo; 55 | } 56 | 57 | public static class Response { 58 | @SerializedName("page") 59 | public int page; 60 | @SerializedName("pages") 61 | public int pages; 62 | @SerializedName("comments") 63 | public List comments; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/data/model/UserSearch.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.data.model; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * Created by sxo on 22/01/17. 9 | */ 10 | 11 | public class UserSearch { 12 | 13 | @SerializedName("status") 14 | public String status; 15 | @SerializedName("response") 16 | public Response response; 17 | 18 | public static class Results { 19 | @SerializedName("userId") 20 | public int userId; 21 | @SerializedName("username") 22 | public String username; 23 | @SerializedName("donor") 24 | public boolean donor; 25 | @SerializedName("warned") 26 | public boolean warned; 27 | @SerializedName("enabled") 28 | public boolean enabled; 29 | @SerializedName("class") 30 | public String mclass; 31 | } 32 | 33 | public static class Response { 34 | @SerializedName("currentPage") 35 | public int currentPage; 36 | @SerializedName("pages") 37 | public int pages; 38 | @SerializedName("results") 39 | public List results; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/data/remote/PyWhatAutoService.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.data.remote; 2 | 3 | import com.facebook.stetho.okhttp3.StethoInterceptor; 4 | import io.reactivex.Single; 5 | import okhttp3.OkHttpClient; 6 | import okhttp3.ResponseBody; 7 | import retrofit2.Response; 8 | import retrofit2.Retrofit; 9 | import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; 10 | import retrofit2.http.GET; 11 | import retrofit2.http.Query; 12 | 13 | /** 14 | * Created by sxo on 6/12/16. 15 | */ 16 | 17 | public interface PyWhatAutoService { 18 | 19 | @GET("/dl.pywa") 20 | Single> addTorrent(@Query("pass") String pass, @Query("site") String site, @Query("id") int id); 21 | 22 | /******** 23 | * Helper class that sets up a new services 24 | *******/ 25 | class Creator { 26 | 27 | public static PyWhatAutoService newPywaService(String url) { 28 | 29 | Retrofit retrofit = new Retrofit.Builder().client( 30 | new OkHttpClient.Builder().followRedirects(false) 31 | .addNetworkInterceptor(new StethoInterceptor()) 32 | .build()) 33 | .baseUrl(url) 34 | .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) 35 | .build(); 36 | return retrofit.create(PyWhatAutoService.class); 37 | } 38 | } 39 | } 40 | 41 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/data/remote/interceptors/AddApiKeyInterceptor.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.data.remote.interceptors; 2 | 3 | import android.content.Context; 4 | import android.util.Log; 5 | 6 | import java.io.IOException; 7 | import java.util.HashSet; 8 | 9 | import ch.redacted.REDApplication; 10 | import okhttp3.Interceptor; 11 | import okhttp3.Request; 12 | import okhttp3.Response; 13 | 14 | /** 15 | * This interceptor put all the Cookies in Preferences in the Request. 16 | * Your implementation on how to get the Preferences may ary, but this will work 99% of the time. 17 | */ 18 | public class AddApiKeyInterceptor implements Interceptor { 19 | private Context context; 20 | 21 | public AddApiKeyInterceptor(Context context) { 22 | this.context = context; 23 | } 24 | 25 | @Override 26 | public Response intercept(Chain chain) throws IOException { 27 | Request.Builder builder = chain.request().newBuilder(); 28 | String key = REDApplication.get(context).getComponent().preferencesHelper().getApiKey(); 29 | 30 | if (!key.isEmpty()){ 31 | builder.addHeader("Authorization", key); 32 | } 33 | 34 | return chain.proceed(builder.build()); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/data/remote/interceptors/AddCookiesInterceptor.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.data.remote.interceptors; 2 | 3 | import android.content.Context; 4 | import android.util.Log; 5 | 6 | import java.io.IOException; 7 | import java.util.HashSet; 8 | 9 | import ch.redacted.REDApplication; 10 | import okhttp3.Interceptor; 11 | import okhttp3.Request; 12 | import okhttp3.Response; 13 | 14 | /** 15 | * This interceptor put all the Cookies in Preferences in the Request. 16 | * Your implementation on how to get the Preferences may ary, but this will work 99% of the time. 17 | */ 18 | public class AddCookiesInterceptor implements Interceptor { 19 | private Context context; 20 | 21 | public AddCookiesInterceptor(Context context) { 22 | this.context = context; 23 | } 24 | 25 | @Override 26 | public Response intercept(Chain chain) throws IOException { 27 | Request.Builder builder = chain.request().newBuilder(); 28 | HashSet preferences = REDApplication.get(context).getComponent().preferencesHelper().getCookies(); 29 | for (String cookie : preferences) { 30 | if (!cookie.contains("deleted") && (!cookie.contains("redirect"))){ 31 | builder.addHeader("Cookie", cookie); 32 | Log.v("OkHttp", "Adding Header: " + cookie); // This is done so I know which headers are being added; this interceptor is used after the normal logging of OkHttp 33 | } 34 | } 35 | 36 | return chain.proceed(builder.build()); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/data/remote/interceptors/AddWmCookiesInterceptor.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.data.remote.interceptors; 2 | 3 | import android.content.Context; 4 | 5 | import java.io.IOException; 6 | 7 | import ch.redacted.REDApplication; 8 | import okhttp3.Interceptor; 9 | import okhttp3.Request; 10 | import okhttp3.Response; 11 | 12 | /** 13 | * This interceptor put all the Cookies in Preferences in the Request. 14 | * Your implementation on how to get the Preferences may ary, but this will work 99% of the time. 15 | */ 16 | public class AddWmCookiesInterceptor implements Interceptor { 17 | private Context context; 18 | 19 | public AddWmCookiesInterceptor(Context context) { 20 | this.context = context; 21 | } 22 | 23 | @Override 24 | public Response intercept(Chain chain) throws IOException { 25 | Request.Builder builder = chain.request().newBuilder(); 26 | String session = REDApplication.get(context).getComponent().preferencesHelper().getWmSession(); 27 | builder.addHeader("Cookie", session); 28 | 29 | return chain.proceed(builder.build()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/data/remote/interceptors/ReceivedCookiesInterceptor.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.data.remote.interceptors; 2 | 3 | import android.content.Context; 4 | 5 | import java.io.IOException; 6 | import java.util.HashSet; 7 | 8 | import ch.redacted.REDApplication; 9 | import okhttp3.Interceptor; 10 | import okhttp3.Response; 11 | 12 | public class ReceivedCookiesInterceptor implements Interceptor { 13 | private Context context; 14 | 15 | public ReceivedCookiesInterceptor(Context context) { 16 | this.context = context; 17 | } // AddCookiesInterceptor() 18 | 19 | @Override 20 | public Response intercept(Chain chain) throws IOException { 21 | Response originalResponse = chain.proceed(chain.request()); 22 | 23 | if (!originalResponse.headers("Set-Cookie").isEmpty()) { 24 | HashSet cookies = new HashSet<>(); 25 | 26 | for (String header : originalResponse.headers("Set-Cookie")) { 27 | if (!header.contains("deleted") && !header.contains("redirect")) { 28 | cookies.add(header); 29 | } 30 | } 31 | 32 | REDApplication.get(context).getComponent().preferencesHelper().putCookieSet(cookies); 33 | } 34 | 35 | return originalResponse; 36 | } 37 | } -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/data/remote/interceptors/ReceivedWmCookiesInterceptor.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.data.remote.interceptors; 2 | 3 | import android.content.Context; 4 | import java.io.IOException; 5 | 6 | import ch.redacted.REDApplication; 7 | import okhttp3.Interceptor; 8 | import okhttp3.Response; 9 | 10 | public class ReceivedWmCookiesInterceptor implements Interceptor { 11 | private Context context; 12 | 13 | public ReceivedWmCookiesInterceptor(Context context) { 14 | this.context = context; 15 | } // AddCookiesInterceptor() 16 | 17 | @Override 18 | public Response intercept(Chain chain) throws IOException { 19 | Response originalResponse = chain.proceed(chain.request()); 20 | 21 | if (!originalResponse.headers("Set-Cookie").isEmpty()) { 22 | String cookie = originalResponse.header("Set-Cookie"); 23 | REDApplication.get(context).getComponent().preferencesHelper().setWmSession(cookie); 24 | } 25 | 26 | return originalResponse; 27 | } 28 | } -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/injection/ActivityContext.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.injection; 2 | 3 | import java.lang.annotation.Retention; 4 | import java.lang.annotation.RetentionPolicy; 5 | 6 | import javax.inject.Qualifier; 7 | 8 | @Qualifier 9 | @Retention(RetentionPolicy.RUNTIME) 10 | public @interface ActivityContext { 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/injection/ApplicationContext.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.injection; 2 | 3 | import java.lang.annotation.Retention; 4 | import java.lang.annotation.RetentionPolicy; 5 | 6 | import javax.inject.Qualifier; 7 | 8 | @Qualifier 9 | @Retention(RetentionPolicy.RUNTIME) 10 | public @interface ApplicationContext { 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/injection/ConfigPersistent.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.injection; 2 | 3 | import java.lang.annotation.Retention; 4 | import java.lang.annotation.RetentionPolicy; 5 | 6 | import javax.inject.Scope; 7 | 8 | /** 9 | * A scoping annotation to permit dependencies conform to the life of the 10 | * {@link ConfigPersistentComponent} 11 | */ 12 | @Scope 13 | @Retention(RetentionPolicy.RUNTIME) 14 | public @interface ConfigPersistent { 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/injection/PerActivity.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.injection; 2 | 3 | import java.lang.annotation.Retention; 4 | import java.lang.annotation.RetentionPolicy; 5 | 6 | import javax.inject.Scope; 7 | 8 | /** 9 | * A scoping annotation to permit objects whose lifetime should 10 | * conform to the life of the Activity to be memorised in the 11 | * correct component. 12 | */ 13 | @Scope 14 | @Retention(RetentionPolicy.RUNTIME) 15 | public @interface PerActivity { 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/injection/PerFragment.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.injection; 2 | 3 | import java.lang.annotation.Retention; 4 | import java.lang.annotation.RetentionPolicy; 5 | 6 | import javax.inject.Scope; 7 | 8 | /** 9 | * A scoping annotation to permit objects whose lifetime should 10 | * conform to the life of the Fragment to be memorised in the 11 | * correct component. 12 | */ 13 | @Scope 14 | @Retention(RetentionPolicy.RUNTIME) 15 | public @interface PerFragment { 16 | } -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/injection/component/ApplicationComponent.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.injection.component; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | 6 | import javax.inject.Singleton; 7 | 8 | import dagger.Component; 9 | import ch.redacted.data.DataManager; 10 | import ch.redacted.data.local.PreferencesHelper; 11 | import ch.redacted.data.remote.ApiService; 12 | import ch.redacted.injection.ApplicationContext; 13 | import ch.redacted.injection.module.ApplicationModule; 14 | 15 | @Singleton 16 | @Component(modules = ApplicationModule.class) 17 | public interface ApplicationComponent { 18 | 19 | @ApplicationContext 20 | Context context(); 21 | Application application(); 22 | ApiService apiService(); 23 | PreferencesHelper preferencesHelper(); 24 | DataManager dataManager(); 25 | //RxEventBus eventBus(); 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/injection/component/ConfigPersistentComponent.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.injection.component; 2 | 3 | import dagger.Component; 4 | import ch.redacted.injection.ConfigPersistent; 5 | import ch.redacted.injection.module.ActivityModule; 6 | import ch.redacted.injection.module.FragmentModule; 7 | 8 | /** 9 | * A dagger component that will live during the lifecycle of an Activity but it won't 10 | * be destroy during configuration changes. Check {@link BaseActivity} to see how this components 11 | * survives configuration changes. 12 | * Use the {@link ConfigPersistent} scope to annotate dependencies that need to survive 13 | * configuration changes (for example Presenters). 14 | */ 15 | @ConfigPersistent 16 | @Component(dependencies = ApplicationComponent.class) 17 | public interface ConfigPersistentComponent { 18 | ActivityComponent activityComponent(ActivityModule activityModule); 19 | FragmentComponent fragmentComponent(FragmentModule fragmentModule); 20 | } -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/injection/component/FragmentComponent.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.injection.component; 2 | 3 | /** 4 | * Created by sxo on 27/12/16. 5 | */ 6 | 7 | import dagger.Subcomponent; 8 | import ch.redacted.injection.PerFragment; 9 | import ch.redacted.injection.module.FragmentModule; 10 | 11 | /** 12 | * This component inject dependencies to all Fragments across the application 13 | */ 14 | @PerFragment 15 | @Subcomponent(modules = FragmentModule.class) 16 | public interface FragmentComponent { 17 | } -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/injection/module/ActivityModule.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.injection.module; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | 6 | import dagger.Module; 7 | import dagger.Provides; 8 | import ch.redacted.injection.ActivityContext; 9 | 10 | @Module 11 | public class ActivityModule { 12 | 13 | private Activity mActivity; 14 | 15 | public ActivityModule(Activity activity) { 16 | mActivity = activity; 17 | } 18 | 19 | @Provides 20 | Activity provideActivity() { 21 | return mActivity; 22 | } 23 | 24 | @Provides 25 | @ActivityContext 26 | Context providesContext() { 27 | return mActivity; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/injection/module/ApplicationModule.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.injection.module; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | 6 | import javax.inject.Singleton; 7 | 8 | import dagger.Module; 9 | import dagger.Provides; 10 | import ch.redacted.data.remote.ApiService; 11 | import ch.redacted.injection.ApplicationContext; 12 | 13 | /** 14 | * Provide application-level dependencies. 15 | */ 16 | @Module 17 | public class ApplicationModule { 18 | protected final Application mApplication; 19 | 20 | public ApplicationModule(Application application) { 21 | mApplication = application; 22 | } 23 | 24 | @Provides 25 | Application provideApplication() { 26 | return mApplication; 27 | } 28 | 29 | @Provides 30 | @ApplicationContext 31 | Context provideContext() { 32 | return mApplication; 33 | } 34 | 35 | @Provides 36 | @Singleton 37 | ApiService provideApiService() { 38 | return ApiService.Creator.newApiService(mApplication); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/injection/module/FragmentModule.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.injection.module; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.support.v4.app.Fragment; 6 | 7 | import dagger.Module; 8 | import dagger.Provides; 9 | import ch.redacted.injection.ActivityContext; 10 | 11 | @Module 12 | public class FragmentModule { 13 | private Fragment mFragment; 14 | 15 | public FragmentModule(Fragment fragment) { 16 | mFragment = fragment; 17 | } 18 | 19 | @Provides 20 | Fragment providesFragment() { 21 | return mFragment; 22 | } 23 | 24 | @Provides 25 | Activity provideActivity() { 26 | return mFragment.getActivity(); 27 | } 28 | 29 | @Provides 30 | @ActivityContext 31 | Context providesContext() { 32 | return mFragment.getActivity(); 33 | } 34 | 35 | } -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/ui/announcements/AnnouncementMvpView.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.ui.announcements; 2 | 3 | import java.util.List; 4 | 5 | import ch.redacted.ui.base.MvpView; 6 | import ch.redacted.data.model.Announcement; 7 | 8 | public interface AnnouncementMvpView extends MvpView { 9 | 10 | void showAnnouncements(List announcements); 11 | 12 | void showAnnouncementsEmpty(); 13 | 14 | void showError(); 15 | 16 | void showProgress(boolean show); 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/ui/announcements/AnnouncementPresenter.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.ui.announcements; 2 | 3 | import io.reactivex.android.schedulers.AndroidSchedulers; 4 | import io.reactivex.disposables.CompositeDisposable; 5 | import io.reactivex.observers.DisposableSingleObserver; 6 | import io.reactivex.schedulers.Schedulers; 7 | import javax.inject.Inject; 8 | 9 | import ch.redacted.ui.base.BasePresenter; 10 | import ch.redacted.data.DataManager; 11 | import ch.redacted.data.model.Announcement; 12 | import ch.redacted.injection.ConfigPersistent; 13 | 14 | @ConfigPersistent public class AnnouncementPresenter extends BasePresenter { 15 | 16 | private final DataManager mDataManager; 17 | private CompositeDisposable mSubscription = new CompositeDisposable(); 18 | 19 | @Inject public AnnouncementPresenter(DataManager dataManager) { 20 | mDataManager = dataManager; 21 | } 22 | 23 | @Override public void attachView(AnnouncementMvpView mvpView) { 24 | super.attachView(mvpView); 25 | } 26 | 27 | @Override public void detachView() { 28 | super.detachView(); 29 | if (mSubscription != null) mSubscription.dispose(); 30 | } 31 | 32 | public void loadAnnouncements() { 33 | checkViewAttached(); 34 | getMvpView().showProgress(true); 35 | 36 | mSubscription.add(mDataManager.getAnnouncements() 37 | .observeOn(AndroidSchedulers.mainThread()) 38 | .subscribeOn(Schedulers.io()) 39 | .subscribeWith(new DisposableSingleObserver() { 40 | @Override 41 | public void onSuccess(Announcement announcements) { 42 | if (announcements.response.announcements.size() == 0){ 43 | getMvpView().showAnnouncementsEmpty(); 44 | getMvpView().showProgress(false); 45 | } else { 46 | getMvpView().showAnnouncements(announcements.response.announcements); 47 | getMvpView().showProgress(false); 48 | } 49 | } 50 | 51 | @Override 52 | public void onError(Throwable error) { 53 | getMvpView().showError(); 54 | error.printStackTrace(); 55 | getMvpView().showProgress(false); 56 | } 57 | })); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/ui/artist/ArtistMvpView.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.ui.artist; 2 | 3 | import java.util.List; 4 | 5 | import ch.redacted.data.model.Artist; 6 | import ch.redacted.ui.base.MvpView; 7 | 8 | public interface ArtistMvpView extends MvpView { 9 | 10 | void showArtist(Artist artist); 11 | 12 | void showLoadingProgress(boolean show); 13 | 14 | void showError(String message); 15 | 16 | void showBookmarked(boolean b); 17 | 18 | void showTorrents(List list); 19 | } -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/ui/base/BasePresenter.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.ui.base; 2 | 3 | /** 4 | * Base class that implements the Presenter interface and provides a base implementation for 5 | * attachView() and detachView(). It also handles keeping a reference to the mvpView that 6 | * can be accessed from the children classes by calling getMvpView(). 7 | */ 8 | public class BasePresenter implements Presenter { 9 | 10 | private T mMvpView; 11 | 12 | @Override 13 | public void attachView(T mvpView) { 14 | mMvpView = mvpView; 15 | } 16 | 17 | @Override 18 | public void detachView() { 19 | mMvpView = null; 20 | } 21 | 22 | public boolean isViewAttached() { 23 | return mMvpView != null; 24 | } 25 | 26 | public T getMvpView() { 27 | return mMvpView; 28 | } 29 | 30 | public void checkViewAttached() { 31 | if (!isViewAttached()) throw new MvpViewNotAttachedException(); 32 | } 33 | 34 | public static class MvpViewNotAttachedException extends RuntimeException { 35 | public MvpViewNotAttachedException() { 36 | super("Please call Presenter.attachView(MvpView) before" + 37 | " requesting data to the Presenter"); 38 | } 39 | } 40 | } 41 | 42 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/ui/base/MvpView.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.ui.base; 2 | 3 | 4 | /** 5 | * Base interface that any class that wants to act as a View in the MVP (Model View Presenter) 6 | * pattern must implement. Generally this interface will be extended by a more specific interface 7 | * that then usually will be implemented by an Activity or Fragment. 8 | */ 9 | public interface MvpView { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/ui/base/Presenter.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.ui.base; 2 | 3 | /** 4 | * Every presenter in the app must either implement this interface or extend BasePresenter 5 | * indicating the MvpView type that wants to be attached with. 6 | */ 7 | public interface Presenter { 8 | 9 | void attachView(V mvpView); 10 | 11 | void detachView(); 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/ui/bookmark/BookmarkMvpView.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.ui.bookmark; 2 | 3 | import java.util.List; 4 | 5 | import ch.redacted.data.model.TorrentBookmark; 6 | import ch.redacted.ui.base.MvpView; 7 | 8 | public interface BookmarkMvpView extends MvpView { 9 | 10 | void showBookmarks(List bookmark); 11 | 12 | // void showBookmarks(ArtistBookmark bookmark); 13 | 14 | void showBookmarksEmpty(); 15 | 16 | void showError(); 17 | 18 | void showProgress(boolean show); 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/ui/collage/CollageMvpView.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.ui.collage; 2 | 3 | import ch.redacted.data.model.Collage; 4 | import ch.redacted.ui.base.MvpView; 5 | 6 | public interface CollageMvpView extends MvpView { 7 | 8 | void showCollage(Collage collage); 9 | 10 | void showLoadingProgress(boolean show); 11 | 12 | void showError(String message); 13 | 14 | void showBookmarked(boolean b); 15 | 16 | void showProgress(boolean show); 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/ui/collage/CollagePresenter.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.ui.collage; 2 | 3 | import javax.inject.Inject; 4 | 5 | import ch.redacted.data.DataManager; 6 | import ch.redacted.data.model.Collage; 7 | import ch.redacted.ui.base.BasePresenter; 8 | import io.reactivex.android.schedulers.AndroidSchedulers; 9 | import io.reactivex.disposables.CompositeDisposable; 10 | import io.reactivex.observers.DisposableSingleObserver; 11 | import io.reactivex.schedulers.Schedulers; 12 | 13 | public class CollagePresenter extends BasePresenter { 14 | 15 | private final DataManager mDataManager; 16 | private CompositeDisposable mSubscription = new CompositeDisposable(); 17 | 18 | @Inject 19 | CollagePresenter(DataManager dataManager) { 20 | mDataManager = dataManager; 21 | } 22 | 23 | void loadCollage(int id) { 24 | checkViewAttached(); 25 | getMvpView().showLoadingProgress(true); 26 | 27 | mSubscription.add(mDataManager.getCollage(id) 28 | .observeOn(AndroidSchedulers.mainThread()) 29 | .subscribeOn(Schedulers.io()) 30 | .subscribeWith(new DisposableSingleObserver() { 31 | @Override 32 | public void onSuccess(Collage collage) { 33 | getMvpView().showCollage(collage); 34 | getMvpView().showProgress(false); 35 | } 36 | 37 | @Override 38 | public void onError(Throwable error) { 39 | getMvpView().showError(error.getMessage()); 40 | getMvpView().showProgress(false); 41 | } 42 | })); 43 | 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/ui/drawer/DrawerMvpView.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.ui.drawer; 2 | 3 | import ch.redacted.data.model.Profile; 4 | import ch.redacted.ui.base.MvpView; 5 | 6 | public interface DrawerMvpView extends MvpView { 7 | 8 | void showError(); 9 | 10 | void setupDrawer(); 11 | 12 | void showProgress(boolean show); 13 | 14 | void showProfileInfo(Profile profile); 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/ui/forum/category/CategoryMvpView.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.ui.forum.category; 2 | 3 | import java.util.List; 4 | 5 | import ch.redacted.ui.base.MvpView; 6 | 7 | public interface CategoryMvpView extends MvpView { 8 | 9 | void showCategories(List categories); 10 | 11 | void showCategoriesEmpty(); 12 | 13 | void showError(); 14 | 15 | void showProgress(boolean show); 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/ui/forum/category/CategoryPresenter.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.ui.forum.category; 2 | 3 | import io.reactivex.android.schedulers.AndroidSchedulers; 4 | import io.reactivex.disposables.CompositeDisposable; 5 | import io.reactivex.observers.DisposableSingleObserver; 6 | import io.reactivex.schedulers.Schedulers; 7 | import java.util.List; 8 | 9 | import javax.inject.Inject; 10 | 11 | import ch.redacted.ui.base.BasePresenter; 12 | import ch.redacted.data.DataManager; 13 | import ch.redacted.injection.ConfigPersistent; 14 | 15 | @ConfigPersistent public class CategoryPresenter extends BasePresenter { 16 | 17 | private final DataManager mDataManager; 18 | private CompositeDisposable mSubscription = new CompositeDisposable(); 19 | 20 | @Inject public CategoryPresenter(DataManager dataManager) { 21 | mDataManager = dataManager; 22 | } 23 | 24 | @Override public void attachView(CategoryMvpView mvpView) { 25 | super.attachView(mvpView); 26 | } 27 | 28 | @Override public void detachView() { 29 | super.detachView(); 30 | if (mSubscription != null) mSubscription.dispose(); 31 | } 32 | 33 | public void loadCategories() { 34 | checkViewAttached(); 35 | getMvpView().showProgress(true); 36 | 37 | mSubscription.add(mDataManager.getCategories() 38 | .observeOn(AndroidSchedulers.mainThread()) 39 | .subscribeOn(Schedulers.io()) 40 | .subscribeWith(new DisposableSingleObserver>() { 41 | @Override 42 | public void onSuccess(List items) { 43 | if (items.size() == 0){ 44 | getMvpView().showCategoriesEmpty(); 45 | getMvpView().showProgress(false); 46 | } else { 47 | getMvpView().showCategories(items); 48 | getMvpView().showProgress(false); 49 | } 50 | } 51 | 52 | @Override 53 | public void onError(Throwable error) { 54 | getMvpView().showError(); 55 | error.printStackTrace(); 56 | getMvpView().showProgress(false); 57 | } 58 | })); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/ui/forum/thread/ThreadMvpView.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.ui.forum.thread; 2 | 3 | import ch.redacted.data.model.ForumThread; 4 | import ch.redacted.ui.base.MvpView; 5 | 6 | public interface ThreadMvpView extends MvpView { 7 | 8 | void showSubscribed(boolean subscribed); 9 | 10 | void showPosts(ForumThread threads, boolean scrollToTop); 11 | 12 | void showPostsEmpty(); 13 | 14 | void showError(); 15 | 16 | void showProgress(boolean show); 17 | 18 | void showPostSuccessful(); 19 | 20 | void showPostFailed(); 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/ui/forum/threadList/ThreadListMvpView.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.ui.forum.threadList; 2 | 3 | import ch.redacted.ui.base.MvpView; 4 | import ch.redacted.data.model.ForumView; 5 | 6 | public interface ThreadListMvpView extends MvpView { 7 | 8 | void showThreads(ForumView threads); 9 | 10 | void showThreadsEmpty(); 11 | 12 | void showError(); 13 | 14 | void showProgress(boolean show); 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/ui/forum/threadList/ThreadListPresenter.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.ui.forum.threadList; 2 | 3 | import io.reactivex.android.schedulers.AndroidSchedulers; 4 | import io.reactivex.disposables.CompositeDisposable; 5 | import io.reactivex.observers.DisposableSingleObserver; 6 | import io.reactivex.schedulers.Schedulers; 7 | import javax.inject.Inject; 8 | 9 | import ch.redacted.ui.base.BasePresenter; 10 | import ch.redacted.data.DataManager; 11 | import ch.redacted.data.model.ForumView; 12 | import ch.redacted.injection.ConfigPersistent; 13 | 14 | @ConfigPersistent public class ThreadListPresenter extends BasePresenter { 15 | 16 | private final DataManager mDataManager; 17 | private CompositeDisposable mSubscription = new CompositeDisposable(); 18 | 19 | @Inject public ThreadListPresenter(DataManager dataManager) { 20 | mDataManager = dataManager; 21 | } 22 | 23 | @Override public void attachView(ThreadListMvpView mvpView) { 24 | super.attachView(mvpView); 25 | } 26 | 27 | @Override public void detachView() { 28 | super.detachView(); 29 | if (mSubscription != null) mSubscription.dispose(); 30 | } 31 | 32 | public void loadThreads(int id, int page) { 33 | checkViewAttached(); 34 | getMvpView().showProgress(true); 35 | 36 | mSubscription.add(mDataManager.getThreads(id, page) 37 | .observeOn(AndroidSchedulers.mainThread()) 38 | .subscribeOn(Schedulers.io()) 39 | .subscribeWith(new DisposableSingleObserver() { 40 | @Override 41 | public void onSuccess(ForumView item) { 42 | if (item.response.threads.size() == 0){ 43 | getMvpView().showThreadsEmpty(); 44 | getMvpView().showProgress(false); 45 | } else { 46 | getMvpView().showThreads(item); 47 | getMvpView().showProgress(false); 48 | } 49 | } 50 | 51 | @Override 52 | public void onError(Throwable error) { 53 | getMvpView().showError(); 54 | getMvpView().showProgress(false); 55 | } 56 | })); 57 | } 58 | } 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/ui/inbox/InboxMvpView.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.ui.inbox; 2 | 3 | import java.util.List; 4 | 5 | import ch.redacted.data.model.Conversations; 6 | import ch.redacted.ui.base.MvpView; 7 | 8 | public interface InboxMvpView extends MvpView { 9 | 10 | void showInbox(List messages); 11 | 12 | void showInboxEmpty(); 13 | 14 | void showLoadingProgress(boolean show); 15 | 16 | void showError(String message); 17 | 18 | void showSnackbar(String message); 19 | } -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/ui/inbox/conversation/ConversationMvpView.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.ui.inbox.conversation; 2 | 3 | import java.util.List; 4 | 5 | import ch.redacted.data.model.Conversation; 6 | import ch.redacted.ui.base.MvpView; 7 | 8 | public interface ConversationMvpView extends MvpView { 9 | 10 | void showMessages(List messages); 11 | 12 | void showMessagesEmpty(); 13 | 14 | void showLoadingProgress(boolean show); 15 | 16 | void showError(String message); 17 | 18 | void showSnackbar(String message); 19 | 20 | void setConversationInfo(int convId, String subject, String user); 21 | 22 | void showSuccess(); 23 | } -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/ui/login/LoginMvpView.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.ui.login; 2 | 3 | import ch.redacted.ui.base.MvpView; 4 | 5 | public interface LoginMvpView extends MvpView { 6 | 7 | void showLoginSuccess(); 8 | 9 | void showCookieExpired(); 10 | 11 | void onCookieFound(); 12 | 13 | void showLoadingProgress(boolean show); 14 | 15 | void showError(String message); 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/ui/profile/ProfileMvpView.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.ui.profile; 2 | 3 | import java.util.Date; 4 | import java.util.List; 5 | 6 | import ch.redacted.data.model.Profile; 7 | import ch.redacted.data.model.RanksCommunity; 8 | import ch.redacted.data.model.Recents; 9 | import ch.redacted.ui.base.MvpView; 10 | 11 | public interface ProfileMvpView extends MvpView { 12 | 13 | //these fields cannot be hidden by paranoia 14 | void showUsername(String username); 15 | void showAvatar(String avatarUrl); 16 | void showUserClass(String userClass); 17 | void showJoinedDate(Date date); 18 | void showUserDescription(String description); 19 | void showUserDescriptionEmpty(); 20 | 21 | void showProfileIsLoggedInUser(boolean isUser); 22 | 23 | void showLastSeen(Date lastSeen); 24 | void showLastSeenParanoid(); 25 | 26 | void showRatio(double ratio, double requiredRatio); 27 | void showRatioParanoid(); 28 | 29 | void showDownloaded(int downloadPercentile); 30 | void showDownloadedParanoid(); 31 | 32 | void showUploaded(int uploadedPercentile); 33 | void showUploadedParanoid(); 34 | 35 | void showNumUploads(int numUploadedPercentile); 36 | void showNumUploadsParanoid(); 37 | 38 | void showRequestsFilled(int requestsPercentile); 39 | void showRequestsParanoid(); 40 | 41 | void showBountySpent(int spentPercentile); 42 | void showBountySpentParanoid(); 43 | 44 | void showNumForumPosts(int postsPercentile); 45 | void showNumForumPostsParanoid(); 46 | 47 | void showArtistsAdded(int artistsAddedPercentile); 48 | void showArtistsAddedParanoid(); 49 | 50 | void showOverallRank(int overallPercentile); 51 | void showOverallRankParanoid(); 52 | 53 | void showInvitedCount(); 54 | void showInvitedCountParanoid(); 55 | 56 | void showRecentUploads(List uploads); 57 | void showRecentUploadsEmpty(); //Paranoid 58 | 59 | void showRecentSnatches(List snatches); 60 | void showRecentSnatchesEmpty(); //Paranoid 61 | 62 | void showLoadingProgress(boolean show); 63 | 64 | void showError(String message); 65 | 66 | void showDefaultAvatar(); 67 | 68 | void showSnackbar(String message); 69 | } -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/ui/release/ReleaseMvpView.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.ui.release; 2 | 3 | import java.io.File; 4 | import java.util.List; 5 | 6 | import ch.redacted.data.model.TorrentComments; 7 | import ch.redacted.data.model.TorrentGroup; 8 | import ch.redacted.ui.base.MvpView; 9 | 10 | public interface ReleaseMvpView extends MvpView { 11 | 12 | void showRelease(TorrentGroup torrentGroup); 13 | 14 | void showLoadingProgress(boolean show); 15 | 16 | void showError(String message); 17 | 18 | void showBookmarked(boolean b); 19 | 20 | void showDownloadComplete(File file); 21 | 22 | void showSendToServerComplete(); 23 | 24 | void showTorrents(Object torrent); 25 | 26 | void showMessage(String message); 27 | 28 | } -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/ui/reply/ReplyMvpView.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.ui.reply; 2 | 3 | import ch.redacted.ui.base.MvpView; 4 | 5 | public interface ReplyMvpView extends MvpView { 6 | 7 | void showSuccess(); 8 | 9 | void showFailure(); 10 | } -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/ui/reply/ReplyPresenter.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.ui.reply; 2 | 3 | import ch.redacted.data.DataManager; 4 | import ch.redacted.data.model.Conversation; 5 | import ch.redacted.injection.ConfigPersistent; 6 | import ch.redacted.ui.base.BasePresenter; 7 | import io.reactivex.SingleObserver; 8 | import io.reactivex.android.schedulers.AndroidSchedulers; 9 | import io.reactivex.disposables.CompositeDisposable; 10 | import io.reactivex.disposables.Disposable; 11 | import io.reactivex.observers.DisposableSingleObserver; 12 | import io.reactivex.schedulers.Schedulers; 13 | import javax.inject.Inject; 14 | import retrofit2.HttpException; 15 | 16 | @ConfigPersistent 17 | public class ReplyPresenter extends BasePresenter { 18 | 19 | private final DataManager mDataManager; 20 | private CompositeDisposable mSubscription = new CompositeDisposable(); 21 | 22 | @Inject 23 | public ReplyPresenter(DataManager dataManager) { 24 | mDataManager = dataManager; 25 | } 26 | 27 | @Override 28 | public void attachView(ReplyMvpView mvpView) { 29 | super.attachView(mvpView); 30 | } 31 | 32 | @Override 33 | public void detachView() { 34 | super.detachView(); 35 | if (mSubscription != null) mSubscription.dispose(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/ui/request/RequestMvpView.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.ui.request; 2 | 3 | import ch.redacted.data.model.Request; 4 | import ch.redacted.ui.base.MvpView; 5 | 6 | public interface RequestMvpView extends MvpView { 7 | 8 | void showRequest(Request request); 9 | 10 | void showLoadingProgress(boolean show); 11 | 12 | void showError(String message); 13 | 14 | void showBookmarked(boolean b); 15 | } -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/ui/request/RequestPresenter.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.ui.request; 2 | 3 | import io.reactivex.android.schedulers.AndroidSchedulers; 4 | import io.reactivex.disposables.CompositeDisposable; 5 | import io.reactivex.observers.DisposableSingleObserver; 6 | import io.reactivex.schedulers.Schedulers; 7 | import javax.inject.Inject; 8 | import ch.redacted.data.DataManager; 9 | import ch.redacted.data.model.Request; 10 | import ch.redacted.injection.ConfigPersistent; 11 | import ch.redacted.ui.base.BasePresenter; 12 | 13 | @ConfigPersistent 14 | public class RequestPresenter extends BasePresenter { 15 | 16 | private final DataManager mDataManager; 17 | private CompositeDisposable mSubscription = new CompositeDisposable(); 18 | 19 | @Inject 20 | public RequestPresenter(DataManager dataManager) { 21 | mDataManager = dataManager; 22 | } 23 | 24 | @Override 25 | public void attachView(RequestMvpView mvpView) { 26 | super.attachView(mvpView); 27 | } 28 | 29 | @Override 30 | public void detachView() { 31 | super.detachView(); 32 | if (mSubscription != null) mSubscription.dispose(); 33 | } 34 | 35 | public void loadRequest(int id) { 36 | checkViewAttached(); 37 | getMvpView().showLoadingProgress(true); 38 | 39 | mSubscription.add(mDataManager.getRequest(id) 40 | .observeOn(AndroidSchedulers.mainThread()) 41 | .subscribeOn(Schedulers.io()) 42 | .subscribeWith(new DisposableSingleObserver() { 43 | @Override 44 | public void onSuccess(Request request) { 45 | getMvpView().showRequest(request); 46 | getMvpView().showLoadingProgress(false); 47 | } 48 | 49 | @Override 50 | public void onError(Throwable error) { 51 | getMvpView().showError(error.getMessage()); 52 | getMvpView().showLoadingProgress(false); 53 | } 54 | })); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/ui/search/artist/ArtistSearchMvpView.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.ui.search.artist; 2 | 3 | import ch.redacted.data.model.Artist; 4 | import ch.redacted.ui.base.MvpView; 5 | 6 | public interface ArtistSearchMvpView extends MvpView { 7 | 8 | void showResults(Artist.Response artist); 9 | 10 | void showResultsEmpty(); 11 | 12 | void showError(); 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/ui/search/artist/ArtistSearchPresenter.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.ui.search.artist; 2 | 3 | import io.reactivex.android.schedulers.AndroidSchedulers; 4 | import io.reactivex.disposables.CompositeDisposable; 5 | import io.reactivex.observers.DisposableSingleObserver; 6 | import io.reactivex.schedulers.Schedulers; 7 | import javax.inject.Inject; 8 | 9 | import ch.redacted.data.DataManager; 10 | import ch.redacted.data.model.Artist; 11 | import ch.redacted.injection.ConfigPersistent; 12 | import ch.redacted.ui.base.BasePresenter; 13 | 14 | @ConfigPersistent public class ArtistSearchPresenter extends BasePresenter { 15 | 16 | private final DataManager mDataManager; 17 | private CompositeDisposable mSubscription = new CompositeDisposable(); 18 | 19 | @Inject public ArtistSearchPresenter(DataManager dataManager) { 20 | mDataManager = dataManager; 21 | } 22 | 23 | @Override public void attachView(ArtistSearchMvpView mvpView) { 24 | super.attachView(mvpView); 25 | } 26 | 27 | @Override public void detachView() { 28 | super.detachView(); 29 | if (mSubscription != null) mSubscription.dispose(); 30 | } 31 | 32 | public void loadArtists(String searchTerm) { 33 | checkViewAttached(); 34 | if (searchTerm.isEmpty() || searchTerm.equals("") || searchTerm.equals(null)){ 35 | getMvpView().showError(); 36 | } 37 | 38 | mSubscription.add(mDataManager.artistsSearch(searchTerm) 39 | .observeOn(AndroidSchedulers.mainThread()) 40 | .subscribeOn(Schedulers.io()) 41 | .subscribeWith(new DisposableSingleObserver() { 42 | @Override 43 | public void onSuccess(Artist artist) { 44 | if (artist.response == null){ 45 | getMvpView().showResultsEmpty(); 46 | } else { 47 | getMvpView().showResults(artist.response); 48 | } 49 | } 50 | 51 | @Override 52 | public void onError(Throwable error) { 53 | getMvpView().showResultsEmpty(); 54 | } 55 | })); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/ui/search/collage/CollageSearchMvpView.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.ui.search.collage; 2 | 3 | import java.util.List; 4 | 5 | import ch.redacted.data.model.CollageSearch; 6 | import ch.redacted.ui.base.MvpView; 7 | 8 | public interface CollageSearchMvpView extends MvpView { 9 | 10 | void showResults(List results); 11 | 12 | void showResultsEmpty(); 13 | 14 | void showError(); 15 | 16 | void showProgress(boolean show); 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/ui/search/request/RequestSearchMvpView.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.ui.search.request; 2 | 3 | import java.util.List; 4 | 5 | import ch.redacted.data.model.RequestSearch; 6 | import ch.redacted.ui.base.MvpView; 7 | 8 | public interface RequestSearchMvpView extends MvpView { 9 | 10 | void showResults(List results); 11 | 12 | void showResultsEmpty(); 13 | 14 | void showError(); 15 | 16 | void showProgress(boolean show); 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/ui/search/request/RequestSearchPresenter.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.ui.search.request; 2 | 3 | import io.reactivex.android.schedulers.AndroidSchedulers; 4 | import io.reactivex.disposables.CompositeDisposable; 5 | import io.reactivex.observers.DisposableSingleObserver; 6 | import io.reactivex.schedulers.Schedulers; 7 | import javax.inject.Inject; 8 | 9 | import ch.redacted.data.DataManager; 10 | import ch.redacted.data.model.RequestSearch; 11 | import ch.redacted.injection.ConfigPersistent; 12 | import ch.redacted.ui.base.BasePresenter; 13 | 14 | @ConfigPersistent public class RequestSearchPresenter extends BasePresenter { 15 | 16 | private final DataManager mDataManager; 17 | private CompositeDisposable mSubscription = new CompositeDisposable(); 18 | 19 | @Inject public RequestSearchPresenter(DataManager dataManager) { 20 | mDataManager = dataManager; 21 | } 22 | 23 | @Override public void attachView(RequestSearchMvpView mvpView) { 24 | super.attachView(mvpView); 25 | } 26 | 27 | @Override public void detachView() { 28 | super.detachView(); 29 | if (mSubscription != null) mSubscription.dispose(); 30 | } 31 | 32 | public void loadRequests(String searchTerm) { 33 | checkViewAttached(); 34 | getMvpView().showProgress(true); 35 | if (searchTerm.isEmpty() || searchTerm.equals("") || searchTerm.equals(null)){ 36 | getMvpView().showError(); 37 | } 38 | 39 | mSubscription.add(mDataManager.requestSearch(searchTerm) 40 | .observeOn(AndroidSchedulers.mainThread()) 41 | .subscribeOn(Schedulers.io()) 42 | .subscribeWith(new DisposableSingleObserver() { 43 | @Override 44 | public void onSuccess(RequestSearch requests) { 45 | if (requests.response.results.size() == 0){ 46 | getMvpView().showResultsEmpty(); 47 | getMvpView().showProgress(false); 48 | } else { 49 | getMvpView().showResults(requests.response.results); 50 | getMvpView().showProgress(false); 51 | } 52 | } 53 | 54 | @Override 55 | public void onError(Throwable error) { 56 | getMvpView().showError(); 57 | error.printStackTrace(); 58 | getMvpView().showProgress(false); 59 | } 60 | })); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/ui/search/torrent/TorrentSearchMvpView.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.ui.search.torrent; 2 | 3 | import java.util.List; 4 | 5 | import ch.redacted.data.model.TorrentSearch; 6 | import ch.redacted.ui.base.MvpView; 7 | 8 | public interface TorrentSearchMvpView extends MvpView { 9 | 10 | void showResults(List results); 11 | 12 | void showResultsEmpty(); 13 | 14 | void showError(); 15 | 16 | void showProgress(boolean show); 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/ui/search/torrent/TorrentSearchPresenter.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.ui.search.torrent; 2 | 3 | import io.reactivex.android.schedulers.AndroidSchedulers; 4 | import io.reactivex.disposables.CompositeDisposable; 5 | import io.reactivex.observers.DisposableSingleObserver; 6 | import io.reactivex.schedulers.Schedulers; 7 | import javax.inject.Inject; 8 | 9 | import ch.redacted.data.DataManager; 10 | import ch.redacted.data.model.TorrentSearch; 11 | import ch.redacted.injection.ConfigPersistent; 12 | import ch.redacted.ui.base.BasePresenter; 13 | 14 | @ConfigPersistent public class TorrentSearchPresenter extends BasePresenter { 15 | 16 | private final DataManager mDataManager; 17 | private CompositeDisposable mSubscription = new CompositeDisposable(); 18 | 19 | @Inject public TorrentSearchPresenter(DataManager dataManager) { 20 | mDataManager = dataManager; 21 | } 22 | 23 | @Override public void attachView(TorrentSearchMvpView mvpView) { 24 | super.attachView(mvpView); 25 | } 26 | 27 | @Override public void detachView() { 28 | super.detachView(); 29 | if (mSubscription != null) mSubscription.dispose(); 30 | } 31 | 32 | public void loadTorrents(String searchTerm) { 33 | checkViewAttached(); 34 | getMvpView().showProgress(true); 35 | if (searchTerm.isEmpty() || searchTerm.equals("") || searchTerm.equals(null)){ 36 | getMvpView().showError(); 37 | } 38 | 39 | mSubscription.add(mDataManager.torrentSearch(searchTerm) 40 | .observeOn(AndroidSchedulers.mainThread()) 41 | .subscribeOn(Schedulers.io()) 42 | .subscribeWith(new DisposableSingleObserver() { 43 | @Override 44 | public void onSuccess(TorrentSearch torrents) { 45 | if (torrents.response.results.size() == 0){ 46 | getMvpView().showResultsEmpty(); 47 | getMvpView().showProgress(false); 48 | } else { 49 | getMvpView().showResults(torrents.response.results); 50 | getMvpView().showProgress(false); 51 | } 52 | } 53 | 54 | @Override 55 | public void onError(Throwable error) { 56 | getMvpView().showError(); 57 | error.printStackTrace(); 58 | getMvpView().showProgress(false); 59 | } 60 | })); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/ui/search/user/UserSearchMvpView.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.ui.search.user; 2 | 3 | import java.util.List; 4 | 5 | import ch.redacted.data.model.UserSearch; 6 | import ch.redacted.ui.base.MvpView; 7 | 8 | public interface UserSearchMvpView extends MvpView { 9 | 10 | void showResults(List results); 11 | 12 | void showResultsEmpty(); 13 | 14 | void showError(); 15 | 16 | void showProgress(boolean show); 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/ui/search/user/UserSearchPresenter.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.ui.search.user; 2 | 3 | import io.reactivex.android.schedulers.AndroidSchedulers; 4 | import io.reactivex.disposables.CompositeDisposable; 5 | import io.reactivex.observers.DisposableSingleObserver; 6 | import io.reactivex.schedulers.Schedulers; 7 | import javax.inject.Inject; 8 | 9 | import ch.redacted.data.DataManager; 10 | import ch.redacted.data.model.UserSearch; 11 | import ch.redacted.injection.ConfigPersistent; 12 | import ch.redacted.ui.base.BasePresenter; 13 | 14 | @ConfigPersistent public class UserSearchPresenter extends BasePresenter { 15 | 16 | private final DataManager mDataManager; 17 | private CompositeDisposable mSubscription = new CompositeDisposable(); 18 | 19 | @Inject public UserSearchPresenter(DataManager dataManager) { 20 | mDataManager = dataManager; 21 | } 22 | 23 | @Override public void attachView(UserSearchMvpView mvpView) { 24 | super.attachView(mvpView); 25 | } 26 | 27 | @Override public void detachView() { 28 | super.detachView(); 29 | if (mSubscription != null) mSubscription.dispose(); 30 | } 31 | 32 | public void loadUsers(String searchTerm) { 33 | checkViewAttached(); 34 | getMvpView().showProgress(true); 35 | if (searchTerm.isEmpty() || searchTerm.equals("") || searchTerm.equals(null)){ 36 | getMvpView().showError(); 37 | } 38 | 39 | mSubscription.add(mDataManager.userSearch(searchTerm) 40 | .observeOn(AndroidSchedulers.mainThread()) 41 | .subscribeOn(Schedulers.io()) 42 | .subscribeWith(new DisposableSingleObserver() { 43 | @Override 44 | public void onSuccess(UserSearch users) { 45 | if (users.response.results.size() == 0){ 46 | getMvpView().showResultsEmpty(); 47 | getMvpView().showProgress(false); 48 | } else { 49 | getMvpView().showResults(users.response.results); 50 | getMvpView().showProgress(false); 51 | } 52 | } 53 | 54 | @Override 55 | public void onError(Throwable error) { 56 | getMvpView().showError(); 57 | error.printStackTrace(); 58 | getMvpView().showProgress(false); 59 | } 60 | })); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/ui/settings/SettingsActivity.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.ui.settings; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import ch.redacted.REDApplication; 6 | import ch.redacted.app.R; 7 | import ch.redacted.ui.base.BaseActivity; 8 | import net.rdrei.android.dirchooser.DirectoryChooserActivity; 9 | 10 | /** 11 | * Created by sxo on 27/02/17. 12 | */ 13 | 14 | public class SettingsActivity extends BaseActivity { 15 | @Override 16 | public void onCreate(Bundle savedInstanceState) { 17 | super.onCreate(savedInstanceState); 18 | setContentView(R.layout.activity_settings); 19 | } 20 | 21 | @Override 22 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 23 | super.onActivityResult(requestCode, resultCode, data); 24 | 25 | if (requestCode == 0) { 26 | if (resultCode == DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED) { 27 | REDApplication.get(this).getComponent().preferencesHelper().setDefaultDownloadLocation(data 28 | .getStringExtra(DirectoryChooserActivity.RESULT_SELECTED_DIR)); 29 | } else { 30 | // Nothing selected 31 | } 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/ui/subscriptions/SubscriptionsMvpView.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.ui.subscriptions; 2 | 3 | import java.util.List; 4 | 5 | import ch.redacted.data.model.Subscription; 6 | import ch.redacted.ui.base.MvpView; 7 | 8 | public interface SubscriptionsMvpView extends MvpView { 9 | 10 | void showSubscriptionsEmpty(); 11 | 12 | void showLoadingProgress(boolean show); 13 | 14 | void showError(String message); 15 | 16 | void showSnackbar(String message); 17 | 18 | void showSubscriptions(List threads); 19 | } -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/ui/top10/Top10MvpView.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.ui.top10; 2 | 3 | import java.util.List; 4 | import ch.redacted.data.model.Top10; 5 | import ch.redacted.ui.base.MvpView; 6 | 7 | public interface Top10MvpView extends MvpView { 8 | 9 | void showTop10(List categories); 10 | 11 | void showTop10Empty(); 12 | 13 | void showError(); 14 | 15 | void showProgress(boolean show); 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/ui/top10/Top10Presenter.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.ui.top10; 2 | 3 | import io.reactivex.android.schedulers.AndroidSchedulers; 4 | import io.reactivex.disposables.CompositeDisposable; 5 | import io.reactivex.observers.DisposableSingleObserver; 6 | import io.reactivex.schedulers.Schedulers; 7 | import javax.inject.Inject; 8 | import ch.redacted.data.DataManager; 9 | import ch.redacted.data.model.Top10; 10 | import ch.redacted.injection.ConfigPersistent; 11 | import ch.redacted.ui.base.BasePresenter; 12 | 13 | @ConfigPersistent public class Top10Presenter extends BasePresenter { 14 | 15 | private final DataManager mDataManager; 16 | private CompositeDisposable mSubscription = new CompositeDisposable(); 17 | 18 | @Inject public Top10Presenter(DataManager dataManager) { 19 | mDataManager = dataManager; 20 | } 21 | 22 | @Override public void attachView(Top10MvpView mvpView) { 23 | super.attachView(mvpView); 24 | } 25 | 26 | @Override public void detachView() { 27 | super.detachView(); 28 | if (mSubscription != null) mSubscription.dispose(); 29 | } 30 | 31 | public void loadTopTorrents(String detail) { 32 | checkViewAttached(); 33 | getMvpView().showProgress(true); 34 | 35 | mSubscription.add(mDataManager.getTopTorrents(detail) 36 | .observeOn(AndroidSchedulers.mainThread()) 37 | .subscribeOn(Schedulers.io()) 38 | .subscribeWith(new DisposableSingleObserver() { 39 | @Override public void onSuccess(Top10 items) { 40 | if (items.response == null || items.response.size() == 0) { 41 | getMvpView().showTop10Empty(); 42 | getMvpView().showProgress(false); 43 | } else { 44 | //If you use type=torrents you will always want the first one 45 | getMvpView().showTop10(items.response.get(0).results); 46 | getMvpView().showProgress(false); 47 | } 48 | } 49 | 50 | @Override public void onError(Throwable error) { 51 | getMvpView().showError(); 52 | error.printStackTrace(); 53 | getMvpView().showProgress(false); 54 | } 55 | })); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/util/AndroidComponentUtil.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.util; 2 | 3 | import android.app.ActivityManager; 4 | import android.app.ActivityManager.RunningServiceInfo; 5 | import android.content.ComponentName; 6 | import android.content.Context; 7 | import android.content.pm.PackageManager; 8 | 9 | public final class AndroidComponentUtil { 10 | 11 | public static void toggleComponent(Context context, Class componentClass, boolean enable) { 12 | ComponentName componentName = new ComponentName(context, componentClass); 13 | PackageManager pm = context.getPackageManager(); 14 | pm.setComponentEnabledSetting(componentName, 15 | enable ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED : 16 | PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 17 | PackageManager.DONT_KILL_APP); 18 | } 19 | 20 | public static boolean isServiceRunning(Context context, Class serviceClass) { 21 | ActivityManager manager = 22 | (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); 23 | for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) { 24 | if (serviceClass.getName().equals(service.service.getClassName())) { 25 | return true; 26 | } 27 | } 28 | return false; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/util/Calculator.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.util; 2 | 3 | import java.text.DecimalFormat; 4 | import java.text.NumberFormat; 5 | 6 | import ch.redacted.data.model.Profile; 7 | 8 | /** 9 | * Created by hfatih on 1/6/2017. 10 | */ 11 | 12 | public class Calculator { 13 | 14 | public static String getBuffer(Profile profile) { 15 | //TODO this ratio value should be dynamic 16 | double minRatio = 0.65; 17 | double dl = bytesToGibiBytesDouble(profile.response.stats.downloaded); 18 | double ul = bytesToGibiBytesDouble(profile.response.stats.uploaded); 19 | 20 | double maxDl = ul / minRatio; 21 | double buffer = maxDl - dl; 22 | NumberFormat formatter = new DecimalFormat("#0.00"); 23 | return formatter.format(buffer); 24 | } 25 | 26 | public static String getMaxPossibleBuffer(Profile profile) { 27 | double minRatio = profile.response.stats.requiredRatio; 28 | double dl = bytesToGibiBytesDouble(profile.response.stats.downloaded); 29 | double ul = bytesToGibiBytesDouble(profile.response.stats.uploaded); 30 | 31 | double maxDl = ul / minRatio; 32 | double buffer = maxDl - dl; 33 | NumberFormat formatter = new DecimalFormat("#0.00"); 34 | return formatter.format(buffer); 35 | } 36 | 37 | public static double bytesToGibiBytesDouble(long bytes) { 38 | bytes = bytes / 1073741824; 39 | return bytes; 40 | } 41 | 42 | /** 43 | * Converts a long to a String with a variable number of decimal points 44 | * @param bytes 45 | * @return String 46 | */ 47 | public static String toHumanReadableSize(long bytes, int decimalPoints) { 48 | boolean si = false; 49 | int unit = si ? 1000 : 1024; 50 | if (bytes < unit) 51 | return bytes + " B"; 52 | int exp = (int) (Math.log(bytes) / Math.log(unit)); 53 | String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp - 1) + ""; 54 | return String.format("%." + decimalPoints + "f %sB", bytes / Math.pow(unit, exp), pre); 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/util/Emoji.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.util; 2 | 3 | /** 4 | * Created by sxo on 24/05/17. 5 | */ 6 | 7 | public class Emoji { 8 | 9 | private static final int HAPPY_EMOJI = 0x1F60A; 10 | private static final int TONGUE_OUT_EMOJI = 0x1F61B; 11 | private static final int GRINNING_EMOJI = 0x1F600; 12 | private static final int HEART_EMOJI = 0x2764; 13 | 14 | private static final String HTML_HAPPY = 15 | "\"\""; 16 | private static final String HTML_TOUNGE_OUT = 17 | "\"\""; 18 | private static final String HTML_GRINNING = 19 | "\"\""; 20 | private static final String HTML_HEART = 21 | "\"\""; 22 | 23 | public static String convertEmojis(String body) { 24 | return body.replaceAll(HTML_TOUNGE_OUT, getEmojiByUnicode(TONGUE_OUT_EMOJI)) 25 | .replaceAll(HTML_HAPPY, getEmojiByUnicode(HAPPY_EMOJI)) 26 | .replaceAll(HTML_GRINNING, getEmojiByUnicode(GRINNING_EMOJI)) 27 | .replaceAll(HTML_HEART, getEmojiByUnicode(HEART_EMOJI)); 28 | } 29 | 30 | public static String getEmojiByUnicode(int unicode) { 31 | return new String(Character.toChars(unicode)); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/util/GenericFileProvider.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.util; 2 | 3 | import android.support.v4.content.FileProvider; 4 | 5 | /** 6 | * Created by stu on 30/08/17. 7 | */ 8 | 9 | public class GenericFileProvider extends FileProvider { 10 | 11 | } -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/util/GlideConfiguration.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.util; 2 | 3 | import android.content.Context; 4 | 5 | import com.bumptech.glide.Glide; 6 | import com.bumptech.glide.GlideBuilder; 7 | import com.bumptech.glide.load.DecodeFormat; 8 | import com.bumptech.glide.module.GlideModule; 9 | 10 | /** 11 | * Created by hfatih on 1/20/2017. 12 | */ 13 | 14 | public class GlideConfiguration implements GlideModule { 15 | @Override 16 | public void applyOptions(Context context, GlideBuilder builder) { 17 | // Apply options to the builder here. 18 | builder.setDecodeFormat(DecodeFormat.PREFER_ARGB_8888); 19 | } 20 | @Override 21 | public void registerComponents(Context context, Glide glide) { 22 | // register ModelLoaders here. 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/util/ImageHelper.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.util; 2 | 3 | import android.support.v4.widget.SwipeRefreshLayout; 4 | import android.widget.ImageView; 5 | 6 | import java.lang.reflect.Field; 7 | 8 | import ch.redacted.app.R; 9 | 10 | /** 11 | * Created by sxo on 26/05/17. 12 | */ 13 | 14 | public class ImageHelper { 15 | 16 | public static String replaceImageLinks(String body) { 17 | //should remove from class= to end of onclick 18 | //this is a gross hack that needs to happen because the site is swapping these values because img is some site scrubbed image url 19 | String temp = body.replaceAll("src=\".*?\"", ""); 20 | temp = temp.replaceAll("onclick=\".*?\"", ""); 21 | temp = temp.replaceAll("class=\".*?\"", ""); 22 | 23 | return temp.replace("alt=\"", "src=\""); 24 | } 25 | 26 | public static ImageView getRippy(SwipeRefreshLayout swipeRefreshContainer) { 27 | ImageView img = null; 28 | Field f; 29 | try { 30 | f = swipeRefreshContainer.getClass().getDeclaredField("mCircleView"); 31 | f.setAccessible(true); 32 | img = (ImageView)f.get(swipeRefreshContainer); 33 | img.setImageResource(R.drawable.ic_rippy); 34 | } catch (IllegalAccessException e) { 35 | e.printStackTrace(); 36 | } catch (NoSuchFieldException e) { 37 | e.printStackTrace(); 38 | } 39 | return img; 40 | } 41 | 42 | public static String getFirstImageLink(String body) { 43 | try { 44 | return body.substring(body.indexOf("alt=") + 5, body.indexOf("src=") - 2); 45 | } catch (IndexOutOfBoundsException e) { 46 | return ""; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/util/NetworkUtil.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.util; 2 | 3 | import android.content.Context; 4 | import android.net.ConnectivityManager; 5 | import android.net.NetworkInfo; 6 | import retrofit2.HttpException; 7 | 8 | public class NetworkUtil { 9 | 10 | /** 11 | * Returns true if the Throwable is an instance of RetrofitError with an 12 | * http status code equals to the given one. 13 | */ 14 | public static boolean isHttpStatusCode(Throwable throwable, int statusCode) { 15 | return throwable instanceof HttpException 16 | && ((HttpException) throwable).code() == statusCode; 17 | } 18 | 19 | public static boolean isNetworkConnected(Context context) { 20 | ConnectivityManager cm = 21 | (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); 22 | NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); 23 | return activeNetwork != null && activeNetwork.isConnectedOrConnecting(); 24 | } 25 | 26 | } -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/util/ReleaseTypes.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.util; 2 | 3 | /** 4 | * Created by sxo on 19/01/17. 5 | */ 6 | 7 | public class ReleaseTypes { 8 | 9 | public static String getReleaseType(int releaseId) { 10 | 11 | switch (releaseId) { 12 | case 1: 13 | return "Album"; 14 | case 3: 15 | return "Soundtrack"; 16 | case 5: 17 | return "EP"; 18 | case 6: 19 | return "Remixed By"; 20 | case 7: 21 | return "Compilation"; 22 | case 9: 23 | return "Single"; 24 | case 11: 25 | return "Live Album"; 26 | case 13: 27 | return "Remix"; 28 | case 14: 29 | return "Bootleg"; 30 | case 15: 31 | return "Interview"; 32 | case 16: 33 | return "Mixtape"; 34 | case 17: 35 | return "Demo"; 36 | case 18: 37 | return "Concert Recording"; 38 | case 19: 39 | return "DJ Mix"; 40 | default: 41 | return "Unknown Release Type"; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/util/RxEventBus.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.util; 2 | 3 | import io.reactivex.Observable; 4 | import io.reactivex.functions.Function; 5 | import io.reactivex.functions.Predicate; 6 | import io.reactivex.subjects.PublishSubject; 7 | import javax.inject.Inject; 8 | import javax.inject.Singleton; 9 | 10 | /** 11 | * A simple event bus built with RxJava 12 | */ 13 | @Singleton 14 | public class RxEventBus { 15 | 16 | private final PublishSubject mBusSubject; 17 | 18 | @Inject 19 | public RxEventBus() { 20 | mBusSubject = PublishSubject.create(); 21 | } 22 | 23 | /** 24 | * Posts an object (usually an Event) to the bus 25 | */ 26 | public void post(Object event) { 27 | mBusSubject.onNext(event); 28 | } 29 | 30 | /** 31 | * Observable that will emmit everything posted to the event bus. 32 | */ 33 | public Observable observable() { 34 | return mBusSubject; 35 | } 36 | 37 | /** 38 | * Observable that only emits events of a specific class. 39 | * Use this if you only want to subscribe to one type of events. 40 | */ 41 | public Observable filteredObservable(final Class eventClass) { 42 | 43 | return mBusSubject.filter(new Predicate() { 44 | @Override 45 | public boolean test(Object event) throws Exception { 46 | return eventClass.isInstance(event); 47 | } 48 | }).map(new Function() { 49 | @SuppressWarnings("unchecked") 50 | @Override public T apply(Object event) throws Exception { 51 | return (T) event; 52 | } 53 | }); 54 | } 55 | } -------------------------------------------------------------------------------- /app/src/main/java/ch/redacted/util/Tags.java: -------------------------------------------------------------------------------- 1 | package ch.redacted.util; 2 | 3 | import java.util.Collections; 4 | import java.util.List; 5 | 6 | import ch.redacted.data.model.Artist; 7 | 8 | /** 9 | * Created by sxo on 19/01/17. 10 | */ 11 | 12 | public class Tags { 13 | public static String PrettyTags(int numTags, List input){ 14 | String tags = ""; 15 | for (int i = 0; i < numTags; i++) { 16 | if (input.size() > i){ 17 | tags = tags.concat(input.get(i) + ", "); 18 | } 19 | } 20 | //remove trailing comma 21 | tags = tags.substring(0, tags.length() - 2); 22 | return tags; 23 | } 24 | 25 | public static String PrettyTags(int numTags, String[] input){ 26 | String tags = ""; 27 | for (int i = 0; i < numTags; i++) { 28 | if (input.length > i){ 29 | tags = tags.concat(input[i] + ", "); 30 | } 31 | } 32 | //remove trailing comma 33 | tags = tags.substring(0, tags.length() - 2); 34 | return tags; 35 | } 36 | 37 | public static String PrettyArtistTags(int numTags, List input) { 38 | String tags = ""; 39 | 40 | Collections.sort(input); 41 | 42 | for (int i = 0; i < numTags; i++) { 43 | if (input.size() > i){ 44 | tags = tags.concat(input.get(i).name + ", "); 45 | } 46 | } 47 | //remove trailing comma 48 | tags = tags.substring(0, tags.length() - 2); 49 | return tags; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/res/anim/common_fade_in.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/anim/common_fade_out.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/anim/rotate.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/color/blue_link_text.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/drawer_shadow.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stuxo/REDAndroid/2df211a1872709808e4023448e1611b56eff10b2/app/src/main/res/drawable-hdpi/drawer_shadow.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stuxo/REDAndroid/2df211a1872709808e4023448e1611b56eff10b2/app/src/main/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_locked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stuxo/REDAndroid/2df211a1872709808e4023448e1611b56eff10b2/app/src/main/res/drawable-hdpi/ic_locked.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/no_artwork.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stuxo/REDAndroid/2df211a1872709808e4023448e1611b56eff10b2/app/src/main/res/drawable-hdpi/no_artwork.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/drawer_shadow.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stuxo/REDAndroid/2df211a1872709808e4023448e1611b56eff10b2/app/src/main/res/drawable-mdpi/drawer_shadow.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stuxo/REDAndroid/2df211a1872709808e4023448e1611b56eff10b2/app/src/main/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_locked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stuxo/REDAndroid/2df211a1872709808e4023448e1611b56eff10b2/app/src/main/res/drawable-mdpi/ic_locked.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/no_artwork.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stuxo/REDAndroid/2df211a1872709808e4023448e1611b56eff10b2/app/src/main/res/drawable-mdpi/no_artwork.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/drawer_shadow.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stuxo/REDAndroid/2df211a1872709808e4023448e1611b56eff10b2/app/src/main/res/drawable-xhdpi/drawer_shadow.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stuxo/REDAndroid/2df211a1872709808e4023448e1611b56eff10b2/app/src/main/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_locked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stuxo/REDAndroid/2df211a1872709808e4023448e1611b56eff10b2/app/src/main/res/drawable-xhdpi/ic_locked.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/no_artwork.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stuxo/REDAndroid/2df211a1872709808e4023448e1611b56eff10b2/app/src/main/res/drawable-xhdpi/no_artwork.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/drawer_shadow.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stuxo/REDAndroid/2df211a1872709808e4023448e1611b56eff10b2/app/src/main/res/drawable-xxhdpi/drawer_shadow.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stuxo/REDAndroid/2df211a1872709808e4023448e1611b56eff10b2/app/src/main/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_locked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stuxo/REDAndroid/2df211a1872709808e4023448e1611b56eff10b2/app/src/main/res/drawable-xxhdpi/ic_locked.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/no_artwork.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stuxo/REDAndroid/2df211a1872709808e4023448e1611b56eff10b2/app/src/main/res/drawable-xxhdpi/no_artwork.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/circle.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 9 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/default_avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stuxo/REDAndroid/2df211a1872709808e4023448e1611b56eff10b2/app/src/main/res/drawable/default_avatar.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_add_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_announcement_48px.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_archive_black_24px.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_arrow_downward_48px.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_arrow_upward_48px.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_artists_48px.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_barcode_48px.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_bookmark_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_bookmark_border_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_chevron_left_black_24px.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_chevron_right_black_24px.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_clear_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_content_copy_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_create_black_24px.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_delete_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_drafts_black_24px.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_expand_less_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_expand_more_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_face_black_24px.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 16 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_favorite_48px.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_file_download_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_file_download_black_24px.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_file_upload_black_24px.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 10 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_first_page_black_24px.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_forum_48px.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_forward_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_inbox_48dp.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_insert_chart_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_insert_chart_black_24px.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_last_page_black_24px.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_lock_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_mail_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_message_24px.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_not_interested_48px.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_notifications_active_48px.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_notifications_disabled_48px.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_notify_crash_reports.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stuxo/REDAndroid/2df211a1872709808e4023448e1611b56eff10b2/app/src/main/res/drawable/ic_notify_crash_reports.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_profile_48px.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_redeem_48px.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_refresh_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_replay_48px.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_reply_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_report_48px.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_requests_48px.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_search_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_send_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_star_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_stars_48px.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_top_10_48px.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_torrents_48px.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_unarchive_black_24px.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_users_48px.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_visibility_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_visibility_off_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_warning_48px.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/no_avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stuxo/REDAndroid/2df211a1872709808e4023448e1611b56eff10b2/app/src/main/res/drawable/no_avatar.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/poll_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/pthlogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stuxo/REDAndroid/2df211a1872709808e4023448e1611b56eff10b2/app/src/main/res/drawable/pthlogo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/search_border_line.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 12 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/teal_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stuxo/REDAndroid/2df211a1872709808e4023448e1611b56eff10b2/app/src/main/res/drawable/teal_background.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/whatandroid_logo_beta.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stuxo/REDAndroid/2df211a1872709808e4023448e1611b56eff10b2/app/src/main/res/drawable/whatandroid_logo_beta.png -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_artist_search.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 11 | 12 | 17 | 18 | 21 | 22 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_collage.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | 13 | 23 | 24 | 28 | 29 | 30 | 31 | 32 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_collage_search.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 10 | 11 | 16 | 17 | 20 | 21 | 28 | 29 | 33 | 34 | 39 | 40 | 41 | 42 | 43 | 44 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 11 | 12 | 16 | 17 | 21 | 22 | 29 | 30 | 31 | 32 | 39 | 40 | 41 | 42 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_user_search.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | 13 | 18 | 19 | 21 | 22 | 29 | 30 | 35 | 36 | 41 | 42 | 43 | 44 | 45 | 46 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /app/src/main/res/layout/artist_search_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 24 | 25 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/layout/collage_search_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 23 | 24 | 34 | -------------------------------------------------------------------------------- /app/src/main/res/layout/description_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 11 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/layout/forum_navigation.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 21 | 22 | 29 | 30 |