├── .gitignore
├── .travis.yml
├── LICENSE.md
├── Monkey-1.0.0.apk
├── README.md
├── app
├── .gitignore
├── build.gradle
├── google-services.json
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── yeungeek
│ │ └── monkeyandroid
│ │ └── ApplicationTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── assets
│ │ ├── langs.json
│ │ └── markdown_css_themes
│ │ │ ├── alt.css
│ │ │ ├── classic.css
│ │ │ ├── github.css
│ │ │ └── paperwhite.css
│ ├── java
│ │ └── com
│ │ │ └── yeungeek
│ │ │ └── monkeyandroid
│ │ │ ├── MonkeyApplication.java
│ │ │ ├── data
│ │ │ ├── DataManager.java
│ │ │ ├── local
│ │ │ │ ├── DatabaseHelper.java
│ │ │ │ ├── Db.java
│ │ │ │ ├── DbOpenHelper.java
│ │ │ │ ├── LanguageHelper.java
│ │ │ │ └── PreferencesHelper.java
│ │ │ ├── meta
│ │ │ │ └── LibRxJava.java
│ │ │ ├── model
│ │ │ │ ├── AccessTokenResp.java
│ │ │ │ ├── Language.java
│ │ │ │ ├── Pair.java
│ │ │ │ ├── Repo.java
│ │ │ │ ├── RepoContent.java
│ │ │ │ ├── User.java
│ │ │ │ ├── WrapList.java
│ │ │ │ └── WrapUser.java
│ │ │ └── remote
│ │ │ │ ├── GithubApi.java
│ │ │ │ ├── SimpleApi.java
│ │ │ │ ├── TokenInterceptor.java
│ │ │ │ ├── UnauthorisedInterceptor.java
│ │ │ │ └── retrofit2
│ │ │ │ └── StringConverterFactory.java
│ │ │ ├── injection
│ │ │ ├── ActivityContext.java
│ │ │ ├── ApplicationContext.java
│ │ │ ├── PerActivity.java
│ │ │ ├── component
│ │ │ │ ├── ActivityComponent.java
│ │ │ │ ├── ApplicationComponent.java
│ │ │ │ └── ReposComponent.java
│ │ │ └── module
│ │ │ │ ├── ActivityModule.java
│ │ │ │ └── ApplicationModule.java
│ │ │ ├── rxbus
│ │ │ ├── RxBus.java
│ │ │ └── event
│ │ │ │ ├── BusEvent.java
│ │ │ │ └── SignInEvent.java
│ │ │ ├── ui
│ │ │ ├── AboutActivity.java
│ │ │ ├── LauncherActivity.java
│ │ │ ├── base
│ │ │ │ ├── adapter
│ │ │ │ │ ├── EndlessRecyclerOnScrollListener.java
│ │ │ │ │ ├── ExStaggeredGridLayoutManager.java
│ │ │ │ │ ├── HeaderAndFooterRecyclerViewAdapter.java
│ │ │ │ │ ├── HeaderSpanSizeLookup.java
│ │ │ │ │ ├── LoadingFooter.java
│ │ │ │ │ ├── OnListLoadNextPageListener.java
│ │ │ │ │ ├── RecyclerViewStateUtils.java
│ │ │ │ │ └── RecyclerViewUtils.java
│ │ │ │ ├── presenter
│ │ │ │ │ └── MvpLceRxPresenter.java
│ │ │ │ └── view
│ │ │ │ │ ├── BaseActivity.java
│ │ │ │ │ ├── BaseFragment.java
│ │ │ │ │ ├── BaseLceActivity.java
│ │ │ │ │ ├── BaseLceFragment.java
│ │ │ │ │ ├── BasePageFragment.java
│ │ │ │ │ └── BaseToolbarFragment.java
│ │ │ ├── detail
│ │ │ │ ├── DetailActivity.java
│ │ │ │ ├── FollowUserFragment.java
│ │ │ │ ├── FollowUserMvpView.java
│ │ │ │ ├── FollowUserPresenter.java
│ │ │ │ ├── RepoDetailFragment.java
│ │ │ │ ├── RepoDetailMvpView.java
│ │ │ │ ├── RepoDetailPresenter.java
│ │ │ │ ├── UserDetailFragment.java
│ │ │ │ ├── UserDetailMvpView.java
│ │ │ │ └── UserDetailPresenter.java
│ │ │ ├── main
│ │ │ │ ├── MainActivity.java
│ │ │ │ ├── MainMvpView.java
│ │ │ │ └── MainPresenter.java
│ │ │ ├── repos
│ │ │ │ ├── HotRepoFragment.java
│ │ │ │ ├── RepoAdapter.java
│ │ │ │ ├── RepoListFragment.java
│ │ │ │ ├── RepoMvpView.java
│ │ │ │ └── RepoPresenter.java
│ │ │ ├── signin
│ │ │ │ └── SignInDialogFragment.java
│ │ │ ├── trending
│ │ │ │ ├── TrendingFragment.java
│ │ │ │ ├── TrendingListFragment.java
│ │ │ │ ├── TrendingMvpView.java
│ │ │ │ └── TrendingPresenter.java
│ │ │ └── users
│ │ │ │ ├── FamousUserFragment.java
│ │ │ │ ├── UserAdapter.java
│ │ │ │ ├── UserListFragment.java
│ │ │ │ ├── UserMvpView.java
│ │ │ │ └── UserPresenter.java
│ │ │ ├── util
│ │ │ ├── AppCst.java
│ │ │ ├── EncodingUtil.java
│ │ │ ├── HttpStatus.java
│ │ │ └── ImageSize.java
│ │ │ └── views
│ │ │ └── widget
│ │ │ ├── ScrollAwareFABBehavior.java
│ │ │ ├── ScrollOffBottomBehavior.java
│ │ │ └── TriangleLabelView.java
│ └── res
│ │ ├── drawable-xhdpi
│ │ ├── ic_about.png
│ │ ├── ic_arrow_back.png
│ │ ├── ic_arrow_drop.png
│ │ ├── ic_arrow_upward.png
│ │ ├── ic_avatar.png
│ │ ├── ic_favorite.png
│ │ ├── ic_favorite_border.png
│ │ ├── ic_menu.png
│ │ ├── ic_more_vert.png
│ │ ├── ic_person.png
│ │ ├── ic_person_add.png
│ │ ├── ic_repo.png
│ │ ├── ic_retry.png
│ │ ├── ic_trending.png
│ │ └── ic_users.png
│ │ ├── layout
│ │ ├── activity_about.xml
│ │ ├── activity_detail.xml
│ │ ├── activity_main.xml
│ │ ├── activity_repos.xml
│ │ ├── fragment_hot_repos.xml
│ │ ├── fragment_pull_refresh_list.xml
│ │ ├── fragment_repo_detail.xml
│ │ ├── fragment_user_detail.xml
│ │ ├── item_repo.xml
│ │ ├── item_user.xml
│ │ ├── layout_appbar.xml
│ │ ├── layout_common_list_footer.xml
│ │ ├── layout_common_list_footer_end.xml
│ │ ├── layout_common_list_footer_loading.xml
│ │ ├── layout_common_list_footer_network_error.xml
│ │ ├── layout_drawer_header.xml
│ │ ├── layout_spinner_item_actionbar.xml
│ │ ├── layout_spinner_item_dropdown.xml
│ │ ├── layout_trending_repos.xml
│ │ ├── view_error.xml
│ │ └── view_loading.xml
│ │ ├── menu
│ │ ├── menu_drawer.xml
│ │ └── menu_main.xml
│ │ ├── mipmap-hdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_cloud_off.png
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxxhdpi
│ │ └── ic_launcher.png
│ │ ├── values-v21
│ │ └── styles.xml
│ │ ├── values-w820dp
│ │ └── dimens.xml
│ │ └── values
│ │ ├── attrs.xml
│ │ ├── attrs_triangleLabelview.xml
│ │ ├── colors.xml
│ │ ├── colors_material.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── yeungeek
│ └── monkeyandroid
│ ├── DataManagerTest.java
│ ├── EncodingUtilTest.java
│ ├── PreferencesHelperTest.java
│ └── util
│ └── DefaultConfig.java
├── build.gradle
├── buildsystem
├── artifacts.gradle
├── dependencies.gradle
├── jacoco.gradle
├── maven-push-java-lib.gradle
└── maven-push.gradle
├── config
├── keystore
│ ├── debug.keystore
│ └── release.keystore
└── quality
│ ├── checkstyle
│ └── checkstyle-config.xml
│ ├── findbugs
│ └── android-exclude-filter.xml
│ ├── pmd
│ └── pmd-ruleset.xml
│ └── quality.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── images
├── fir.png
├── monkey.gif
├── preview1.png
├── preview2.png
└── preview3.png
├── mvp
├── .gitignore
├── README.md
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── yeungeek
│ │ │ └── mvp
│ │ │ ├── MvpActivity.java
│ │ │ ├── MvpFragment.java
│ │ │ ├── common
│ │ │ ├── Defaults.java
│ │ │ ├── MvpBasePresenter.java
│ │ │ ├── MvpNullObjectBasePresenter.java
│ │ │ ├── MvpPresenter.java
│ │ │ ├── MvpView.java
│ │ │ ├── NoOp.java
│ │ │ └── lce
│ │ │ │ └── MvpLceView.java
│ │ │ └── core
│ │ │ ├── delegate
│ │ │ ├── ActivityMvpDelegate.java
│ │ │ ├── ActivityMvpDelegateCallback.java
│ │ │ ├── ActivityMvpDelegateImpl.java
│ │ │ ├── ActivityMvpNonConfigurationInstances.java
│ │ │ ├── BaseMvpDelegateCallback.java
│ │ │ ├── FragmentMvpDelegate.java
│ │ │ ├── FragmentMvpDelegateImpl.java
│ │ │ └── MvpInternalDelegate.java
│ │ │ └── lce
│ │ │ ├── LceAnimator.java
│ │ │ ├── MvpLceActivity.java
│ │ │ └── MvpLceFragment.java
│ └── res
│ │ └── values
│ │ ├── ids.xml
│ │ └── strings.xml
│ └── test
│ └── java
│ └── com
│ └── yeungeek
│ └── mvp
│ └── ExampleUnitTest.java
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | ## Directory-based project format:
3 | .idea/
4 | .gradle/
5 |
6 | ### Android ###
7 | # Built application files
8 | *.apk
9 | *.ap_
10 | local.properties
11 | .DS_Store
12 | build
13 | /captures
14 | *.txt
15 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | branches:
2 | only:
3 | - master
4 |
5 | env:
6 | matrix:
7 | - ANDROID_TARGET=android-23 ANDROID_ABI=armeabi-v7a
8 |
9 | language: android
10 | sudo: false
11 |
12 | android:
13 | components:
14 | - platform-tools
15 | - tools
16 | - android-23
17 | - build-tools-23.0.2
18 | - extra-android-m2repository
19 | - extra-android-support
20 | - sys-img-armeabi-v7a-android-23
21 |
22 | before_script:
23 | - echo no | android create avd --force -n test -t $ANDROID_TARGET --abi $ANDROID_ABI
24 | - emulator -avd test -no-skin -no-audio -no-window &
25 | - android-wait-for-emulator
26 | - adb shell input keyevent 82 &
27 |
28 | before_install:
29 | - chmod +x gradlew
30 |
31 | after_success:
32 | - ./gradlew testInternalDebugUnitTestCoverage coveralls
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 yeungeek
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 |
--------------------------------------------------------------------------------
/Monkey-1.0.0.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeungeek/monkey-android/f1bc5132b7571766b26d1b07645ffe9f0de5ab81/Monkey-1.0.0.apk
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Monkey for GitHub, Android Version
2 | A GitHub third party client, show the rank of users and repositories,trending.
3 | Base on Material Design,use MVP pattern
4 | iOS version:[Monkey](https://github.com/coderyi/Monkey)
5 |
6 | [](http://android-arsenal.com/details/3/3717)
7 |
8 | ## Status
9 | [](https://travis-ci.org/yeungeek/monkey-android)
10 | [](https://coveralls.io/github/yeungeek/monkey-android?branch=master)
11 |
12 | ## Download
13 | [](https://play.google.com/store/apps/details?id=com.yeungeek.monkeyandroid)
14 |
15 | fir.im: http://fir.im/monkeyandroid
16 |
17 | 
18 |
19 | ## API
20 | GitHub interface: https://developer.github.com/v3/
21 |
22 | ## Function
23 | - [x] sign in
24 | - [x] user list
25 | - [x] repo list
26 | - [x] trending(daily,weekly,monthly)
27 | - [x] user detail
28 | - [x] repo detail
29 | - [x] follow user
30 | - [x] star repo
31 |
32 | ## TO DO
33 | - [ ] search
34 | - [ ] open url(scheme)
35 | - [ ] showcases
36 |
37 | ## App Preview
38 | 
39 |
40 | 
41 | 
42 | 
43 |
44 | ## Open source projects
45 | * [RxJava](https://github.com/ReactiveX/RxJava/)
46 | * [RxAndroid](https://github.com/ReactiveX/RxAndroid/)
47 | * [retrofit](https://github.com/square/retrofit/)
48 | * [OkHttp](https://github.com/square/okhttp)
49 | * [Dagger2](https://github.com/google/dagger/)
50 | * [glide](https://github.com/bumptech/glide/)
51 | * [ButterKnife](https://github.com/JakeWharton/butterknife/)
52 | * [Stetho](https://github.com/facebook/stetho)
53 | * [Sqlbrite](https://github.com/square/sqlbrite)
54 | * [Timber](https://github.com/JakeWharton/timber/)
55 | * [android-Ultra-Pull-To-Refresh](https://github.com/liaohuqiu/android-Ultra-Pull-To-Refresh)
56 | * [PreLollipopTransition](https://github.com/takahirom/PreLollipopTransition)
57 |
58 | ## References
59 | * [ribot-app-android](https://github.com/ribot/ribot-app-android)
60 | * [Monkey](https://github.com/coderyi/Monkey)
61 | * [GithubTrends](https://github.com/laowch/GithubTrends)
62 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/google-services.json:
--------------------------------------------------------------------------------
1 | {
2 | "project_info": {
3 | "project_number": "423857193954",
4 | "firebase_url": "https://monkey-android-7aa77.firebaseio.com",
5 | "project_id": "monkey-android-7aa77",
6 | "storage_bucket": "monkey-android-7aa77.appspot.com"
7 | },
8 | "client": [
9 | {
10 | "client_info": {
11 | "mobilesdk_app_id": "1:423857193954:android:540ddf433cc50b06",
12 | "android_client_info": {
13 | "package_name": "com.yeungeek.monkeyandroid"
14 | }
15 | },
16 | "oauth_client": [
17 | {
18 | "client_id": "423857193954-99shkcq9omsambusgjo3den5pqsqtihb.apps.googleusercontent.com",
19 | "client_type": 3
20 | }
21 | ],
22 | "api_key": [
23 | {
24 | "current_key": "AIzaSyDuo6NGWj9m6C8Hx5Fd7qFc-puIiZBABoE"
25 | }
26 | ],
27 | "services": {
28 | "analytics_service": {
29 | "status": 1
30 | },
31 | "appinvite_service": {
32 | "status": 1,
33 | "other_platform_oauth_client": []
34 | },
35 | "ads_service": {
36 | "status": 2
37 | }
38 | }
39 | }
40 | ],
41 | "configuration_version": "1"
42 | }
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/yeungeek/monkeyandroid/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
23 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
36 |
37 |
39 |
40 |
42 |
43 |
44 |
48 |
49 |
50 |
53 |
54 |
57 |
58 |
61 |
62 |
65 |
66 |
67 |
70 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/app/src/main/assets/markdown_css_themes/alt.css:
--------------------------------------------------------------------------------
1 | body {
2 | line-height: 1.4em;
3 | color: black;
4 | padding: 1em;
5 | margin: auto;
6 | max-width: 42em;
7 | }
8 |
9 | li {
10 | color: black;
11 | }
12 |
13 | h1,h2,h3,h4,h5,h6 {
14 | border: 0 none !important;
15 | }
16 |
17 | h1 {
18 | margin-top: 0.5em;
19 | margin-bottom: 0.5em;
20 | border-bottom: 2px solid #000080 !important;
21 | }
22 |
23 | h2 {
24 | margin-top: 1em;
25 | margin-bottom: 0.5em;
26 | border-bottom: 2px solid #000080 !important;
27 | }
28 |
29 | pre {
30 | background-color: #f8f8f8;
31 | border: 1px solid #2f6fab;
32 | border-radius: 3px;
33 | overflow: auto;
34 | padding: 5px;
35 | }
36 |
37 | pre code {
38 | background-color: inherit;
39 | border: none;
40 | padding: 0;
41 | }
42 |
43 | code {
44 | background-color: #ffffe0;
45 | border: 1px solid orange;
46 | border-radius: 3px;
47 | padding: 0 0.2em;
48 | }
49 |
50 | a {
51 | text-decoration: underline;
52 | }
53 |
54 | ul,ol {
55 | padding-left: 30px;
56 | }
57 |
58 | li {
59 | margin: 0.2em 0 0 0em;
60 | padding: 0px;
61 | }
62 |
63 | em {
64 | color: #b05000;
65 | }
66 |
67 | table.text th,table.text td {
68 | vertical-align: top;
69 | border-top: 1px solid #ccc;
70 | padding: 5px;
71 | }
--------------------------------------------------------------------------------
/app/src/main/assets/markdown_css_themes/classic.css:
--------------------------------------------------------------------------------
1 | @charset "utf-8";
2 |
3 | /**
4 | * markdown.css
5 | *
6 | * This program is free software: you can redistribute it and/or modify it under
7 | * the terms of the GNU Lesser General Public License as published by the Free
8 | * Software Foundation, either version 3 of the License, or (at your option) any
9 | * later version.
10 | *
11 | * This program is distributed in the hope that it will be useful, but WITHOUT
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
14 | * details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with this program. If not, see http://gnu.org/licenses/lgpl.txt.
18 | *
19 | * @project Weblog and Open Source Projects of Florian Wolters
20 | * @version GIT: $Id$
21 | * @package xhtml-css
22 | * @author Florian Wolters
23 | * @copyright 2012 Florian Wolters
24 | * @cssdoc version 1.0-pre
25 | * @license http://gnu.org/licenses/lgpl.txt GNU Lesser General Public License
26 | * @link http://github.com/FlorianWolters/jekyll-bootstrap-theme
27 | * @media all
28 | * @valid true
29 | */
30 |
31 | body {
32 | font-family: Helvetica, Arial, Freesans, clean, sans-serif;
33 | padding:1em;
34 | margin:auto;
35 | max-width:42em;
36 | background:#fefefe;
37 | }
38 |
39 | h1, h2, h3, h4, h5, h6 {
40 | font-weight: bold;
41 | }
42 |
43 | h1 {
44 | color: #000000;
45 | font-size: 28px;
46 | }
47 |
48 | h2 {
49 | border-bottom: 1px solid #CCCCCC;
50 | color: #000000;
51 | font-size: 24px;
52 | }
53 |
54 | h3 {
55 | font-size: 18px;
56 | }
57 |
58 | h4 {
59 | font-size: 16px;
60 | }
61 |
62 | h5 {
63 | font-size: 14px;
64 | }
65 |
66 | h6 {
67 | color: #777777;
68 | background-color: inherit;
69 | font-size: 14px;
70 | }
71 |
72 | hr {
73 | height: 0.2em;
74 | border: 0;
75 | color: #CCCCCC;
76 | background-color: #CCCCCC;
77 | }
78 |
79 | p, blockquote, ul, ol, dl, li, table, pre {
80 | margin: 15px 0;
81 | }
82 |
83 | code, pre {
84 | border-radius: 3px;
85 | background-color: #F8F8F8;
86 | color: inherit;
87 | }
88 |
89 | code {
90 | border: 1px solid #EAEAEA;
91 | margin: 0 2px;
92 | padding: 0 5px;
93 | }
94 |
95 | pre {
96 | border: 1px solid #CCCCCC;
97 | line-height: 1.25em;
98 | overflow: auto;
99 | padding: 6px 10px;
100 | }
101 |
102 | pre > code {
103 | border: 0;
104 | margin: 0;
105 | padding: 0;
106 | }
107 |
108 | a, a:visited {
109 | color: #4183C4;
110 | background-color: inherit;
111 | text-decoration: none;
112 | }
113 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/MonkeyApplication.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid;
2 |
3 | import android.app.Application;
4 | import android.content.Context;
5 |
6 | import com.facebook.stetho.Stetho;
7 | import com.tencent.bugly.Bugly;
8 | import com.tencent.bugly.beta.Beta;
9 | import com.yeungeek.monkeyandroid.injection.component.ApplicationComponent;
10 | import com.yeungeek.monkeyandroid.injection.component.DaggerApplicationComponent;
11 | import com.yeungeek.monkeyandroid.injection.module.ApplicationModule;
12 |
13 | import timber.log.Timber;
14 |
15 | /**
16 | * Created by yeungeek on 2016/1/8.
17 | */
18 | public class MonkeyApplication extends Application {
19 | @Override
20 | public void onCreate() {
21 | super.onCreate();
22 |
23 | if (BuildConfig.DEBUG) {
24 | Timber.plant(new Timber.DebugTree());
25 | }
26 |
27 | initComponent();
28 | initStetho();
29 | initUpgrade();
30 | }
31 |
32 | private void initComponent() {
33 | if (BuildConfig.DEBUG) {
34 | Timber.d("dagger inject");
35 | }
36 | mApplicationComponent = DaggerApplicationComponent.builder()
37 | .applicationModule(new ApplicationModule(this))
38 | .build();
39 | mApplicationComponent.inject(this);
40 | }
41 |
42 | private void initStetho() {
43 | Stetho.initializeWithDefaults(this);
44 | }
45 |
46 | private void initUpgrade() {
47 | Beta.autoInit = false;
48 | Beta.autoCheckUpgrade = true;
49 | Beta.upgradeCheckPeriod = 60 * 1000;
50 |
51 | Bugly.init(this, BuildConfig.BUGLY_APPID, false);
52 | }
53 |
54 | public static MonkeyApplication get(final Context context) {
55 | return (MonkeyApplication) context.getApplicationContext();
56 | }
57 |
58 | public ApplicationComponent getComponent() {
59 | return mApplicationComponent;
60 | }
61 |
62 | ApplicationComponent mApplicationComponent;
63 | }
64 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/data/local/DatabaseHelper.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.data.local;
2 |
3 | import android.content.ContentValues;
4 | import android.database.Cursor;
5 |
6 | import com.squareup.sqlbrite.BriteDatabase;
7 | import com.squareup.sqlbrite.SqlBrite;
8 | import com.yeungeek.monkeyandroid.data.model.Repo;
9 |
10 | import java.util.List;
11 |
12 | import javax.inject.Inject;
13 | import javax.inject.Singleton;
14 |
15 | import rx.Observable;
16 | import rx.Subscriber;
17 |
18 | /**
19 | * Created by yeungeek on 2016/1/18.
20 | */
21 | @Singleton
22 | public class DatabaseHelper {
23 | private final BriteDatabase mDb;
24 |
25 | @Inject
26 | public DatabaseHelper(DbOpenHelper dbOpenHelper) {
27 | mDb = SqlBrite.create().wrapDatabaseHelper(dbOpenHelper);
28 | }
29 |
30 | public BriteDatabase getBriteDb() {
31 | return mDb;
32 | }
33 |
34 | /**
35 | * Repo
36 | */
37 | public Observable> addRepos(final List repos) {
38 | return Observable.create(new Observable.OnSubscribe>() {
39 | @Override
40 | public void call(Subscriber super List> subscriber) {
41 | BriteDatabase.Transaction transaction = mDb.newTransaction();
42 | try {
43 | //clear
44 | mDb.delete(Db.RepoTable.TABLE_NAME,null);
45 |
46 | for (Repo repo : repos) {
47 | ContentValues contentValues = Db.RepoTable.toContentValues(repo);
48 | mDb.insert(Db.RepoTable.TABLE_NAME, contentValues);
49 | }
50 |
51 | transaction.markSuccessful();
52 | // subscriber.onCompleted();
53 | subscriber.onNext(repos);
54 | subscriber.onCompleted();
55 | } finally {
56 | transaction.end();
57 | }
58 | }
59 | });
60 | }
61 |
62 | /**
63 | * Remove all the data from all the tables in the database.
64 | */
65 | public Observable clearTables() {
66 | return Observable.create(new Observable.OnSubscribe() {
67 | @Override
68 | public void call(Subscriber super Void> subscriber) {
69 | BriteDatabase.Transaction transaction = mDb.newTransaction();
70 | try {
71 | Cursor cursor = mDb.query("SELECT name FROM sqlite_master WHERE type='table'");
72 | while (cursor.moveToNext()) {
73 | mDb.delete(cursor.getString(cursor.getColumnIndex("name")), null);
74 | }
75 |
76 | cursor.close();
77 | transaction.markSuccessful();
78 | subscriber.onCompleted();
79 | } finally {
80 | transaction.end();
81 | }
82 | }
83 | });
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/data/local/Db.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.data.local;
2 |
3 | import android.content.ContentValues;
4 | import android.database.Cursor;
5 |
6 | import com.yeungeek.monkeyandroid.data.model.Repo;
7 |
8 | /**
9 | * Created by yeungeek on 2016/1/18.
10 | */
11 | public class Db {
12 | public Db() {
13 | }
14 |
15 | private static class BaseTable {
16 | public static final String COLUMN_INDEX = "_index";
17 | }
18 |
19 | public static final class RepoTable extends BaseTable {
20 | public static final String TABLE_NAME = "repo";
21 |
22 | public static final String COLUMN_ID = "_id";
23 | public static final String COLUMN_NAME = "_name";
24 | public static final String COLUMN_DESC = "_desc";
25 | public static final String COLUMN_OWERID = "_owerId";
26 |
27 | public static final String CREATE =
28 | "CREATE TABLE " + TABLE_NAME + " ("
29 | + COLUMN_INDEX + " INTEGER PRIMARY KEY AUTOINCREMENT,"
30 | + COLUMN_ID + " INTEGER NOT NULL,"
31 | + COLUMN_NAME + " TEXT,"
32 | + COLUMN_DESC + " TEXT,"
33 | + COLUMN_OWERID + " INTEGER"
34 | + " );";
35 |
36 | public static ContentValues toContentValues(Repo repo) {
37 | ContentValues values = new ContentValues();
38 | values.put(COLUMN_ID, repo.getId());
39 | values.put(COLUMN_NAME, repo.getName());
40 | values.put(COLUMN_DESC, repo.getDescription());
41 | return values;
42 | }
43 |
44 | public static Repo parseCursor(Cursor cursor) {
45 | Repo repo = new Repo();
46 | repo.setId(cursor.getInt(cursor.getColumnIndexOrThrow(COLUMN_ID)));
47 | repo.setName(cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_NAME)));
48 | repo.setDescription(cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_DESC)));
49 | return repo;
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/data/local/DbOpenHelper.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.data.local;
2 |
3 | import android.content.Context;
4 | import android.database.sqlite.SQLiteDatabase;
5 | import android.database.sqlite.SQLiteOpenHelper;
6 |
7 | import com.yeungeek.monkeyandroid.injection.ApplicationContext;
8 |
9 | import javax.inject.Inject;
10 |
11 | /**
12 | * Created by yeungeek on 2016/1/18.
13 | */
14 | public class DbOpenHelper extends SQLiteOpenHelper {
15 | public static final String DATABASE_NAME = "monkey_app.db";
16 | public static final int DATABASE_VERSION = 1;
17 |
18 | @Inject
19 | public DbOpenHelper(@ApplicationContext Context context) {
20 | super(context, DATABASE_NAME, null, DATABASE_VERSION);
21 | }
22 |
23 | @Override
24 | public void onCreate(SQLiteDatabase db) {
25 | db.beginTransaction();
26 | try {
27 | db.execSQL(Db.RepoTable.CREATE);
28 | db.setTransactionSuccessful();
29 | } finally {
30 | db.endTransaction();
31 | }
32 | }
33 |
34 | @Override
35 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
36 |
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/data/local/LanguageHelper.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.data.local;
2 |
3 | import android.content.Context;
4 |
5 | import com.google.gson.Gson;
6 | import com.yeungeek.monkeyandroid.data.model.Language;
7 | import com.yeungeek.monkeyandroid.injection.ApplicationContext;
8 |
9 | import java.io.BufferedReader;
10 | import java.io.InputStream;
11 | import java.io.InputStreamReader;
12 | import java.util.ArrayList;
13 | import java.util.HashMap;
14 | import java.util.List;
15 |
16 | import javax.inject.Inject;
17 | import javax.inject.Singleton;
18 |
19 | /**
20 | * Created by yeungeek on 2016/3/30.
21 | */
22 | @Singleton
23 | public class LanguageHelper {
24 | private HashMap languageMap = new HashMap<>();
25 | private List selectedLanguages = new ArrayList<>();
26 | private Language[] allLanguages;
27 | private Context mContext;
28 | private Gson mGson;
29 |
30 | @Inject
31 | public LanguageHelper(@ApplicationContext Context context, Gson gson) {
32 | mContext = context;
33 | mGson = gson;
34 | selectedLanguages.addAll(getDefaultLanguage());
35 | }
36 |
37 | public Language getAllLanguage() {
38 | return getLanguageByName("All Language");
39 | }
40 |
41 | public List getLanguage() {
42 | return selectedLanguages;
43 | }
44 |
45 | private List getDefaultLanguage() {
46 | String[] defaultLanguagesName = new String[]{"Java", "JavaScript", "Go", "CSS", "Objective-C", "Python", "Swift", "HTML"};
47 |
48 | List defaultLanguages = new ArrayList<>();
49 | for (String langNAme : defaultLanguagesName) {
50 | defaultLanguages.add(getLanguageByName(langNAme));
51 | }
52 | return defaultLanguages;
53 | }
54 |
55 | public Language getLanguageByName(String languageName) {
56 | if (languageMap.size() == 0) {
57 |
58 | for (Language language : getAllLanguages()) {
59 | languageMap.put(language.name, language);
60 | }
61 | }
62 |
63 | return languageMap.get(languageName);
64 | }
65 |
66 | public Language[] getAllLanguages() {
67 | if (allLanguages != null) {
68 | return allLanguages;
69 | }
70 |
71 | try {
72 | StringBuilder buf = new StringBuilder();
73 |
74 | InputStream inputStream = mContext.getAssets().open("langs.json");
75 | BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
76 | String str;
77 | while ((str = in.readLine()) != null) {
78 | buf.append(str);
79 | }
80 | in.close();
81 |
82 | allLanguages = mGson.fromJson(buf.toString(), Language[].class);
83 | } catch (Exception e) {
84 | }
85 | return allLanguages;
86 | }
87 |
88 | }
89 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/data/local/PreferencesHelper.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.data.local;
2 |
3 | import android.content.Context;
4 | import android.content.SharedPreferences;
5 | import android.support.annotation.Nullable;
6 |
7 | import com.yeungeek.monkeyandroid.injection.ApplicationContext;
8 |
9 | import javax.inject.Inject;
10 | import javax.inject.Singleton;
11 |
12 | /**
13 | * Created by yeungeek on 2016/3/13.
14 | */
15 | @Singleton
16 | public class PreferencesHelper {
17 | public static final String PREF_FILE_NAME = "monkey_app_pref_file";
18 |
19 | private static final String PREF_KEY_ACCESS_TOKEN = "PREF_KEY_ACCESS_TOKEN";
20 | private static final String PREF_KEY_USER_LOGIN = "PREF_KEY_USER_LOGIN";
21 | private static final String PREF_KEY_USER_EMAIL = "PREF_KEY_USER_EMAIL";
22 | private static final String PREF_KEY_USER_AVATAR = "PREF_KEY_USER_AVATAR";
23 |
24 | private final SharedPreferences mPref;
25 |
26 | @Inject
27 | public PreferencesHelper(@ApplicationContext Context context) {
28 | mPref = context.getSharedPreferences(PREF_FILE_NAME, Context.MODE_PRIVATE);
29 | }
30 |
31 | public void putAccessToken(String accessToken) {
32 | mPref.edit().putString(PREF_KEY_ACCESS_TOKEN, accessToken).apply();
33 | }
34 |
35 | public void putUserLogin(String login) {
36 | mPref.edit().putString(PREF_KEY_USER_LOGIN, login).apply();
37 | }
38 |
39 | public void putUserEmail(String email) {
40 | mPref.edit().putString(PREF_KEY_USER_EMAIL, email).apply();
41 | }
42 |
43 | public void putUserAvatar(String avatar) {
44 | mPref.edit().putString(PREF_KEY_USER_AVATAR, avatar).apply();
45 | }
46 |
47 | @Nullable
48 | public String getAccessToken() {
49 | return mPref.getString(PREF_KEY_ACCESS_TOKEN, null);
50 | }
51 |
52 | @Nullable
53 | public String getUserLogin() {
54 | return mPref.getString(PREF_KEY_USER_LOGIN, null);
55 | }
56 |
57 | @Nullable
58 | public String getUserEmail() {
59 | return mPref.getString(PREF_KEY_USER_EMAIL, null);
60 | }
61 |
62 | @Nullable
63 | public String getUserAvatar() {
64 | return mPref.getString(PREF_KEY_USER_AVATAR, null);
65 | }
66 |
67 | public void clear() {
68 | mPref.edit().clear().apply();
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/data/meta/LibRxJava.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.data.meta;
2 |
3 | import com.snilius.aboutit.L;
4 | import com.snilius.aboutit.LibSkeleton;
5 |
6 | /**
7 | * Created by yeungeek on 2016/4/11.
8 | */
9 | public class LibRxJava extends LibSkeleton {
10 | public LibRxJava() {
11 | super("RxJava", "ReactiveX", L.AP2, "https://github.com/ReactiveX/RxJava");
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/data/model/AccessTokenResp.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.data.model;
2 |
3 | import com.google.gson.annotations.SerializedName;
4 |
5 | /**
6 | * Created by yeungeek on 2016/3/13.
7 | * Accept: application/json
8 | * {"access_token":"e72e16c7e42f292c6912e7710c838347ae178b4a", "scope":"repo,gist", "token_type":"bearer"}
9 | */
10 | public class AccessTokenResp {
11 | @SerializedName(value = "access_token")
12 | private String accessToken;
13 | private String scope;
14 | @SerializedName(value = "token_type")
15 | private String tokenType;
16 |
17 | public String getAccessToken() {
18 | return accessToken;
19 | }
20 |
21 | public AccessTokenResp setAccessToken(String accessToken) {
22 | this.accessToken = accessToken;
23 | return this;
24 | }
25 |
26 | public String getScope() {
27 | return scope;
28 | }
29 |
30 | public AccessTokenResp setScope(String scope) {
31 | this.scope = scope;
32 | return this;
33 | }
34 |
35 | public String getTokenType() {
36 | return tokenType;
37 | }
38 |
39 | public AccessTokenResp setTokenType(String tokenType) {
40 | this.tokenType = tokenType;
41 | return this;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/data/model/Language.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.data.model;
2 |
3 | import com.google.gson.annotations.SerializedName;
4 |
5 | import java.io.Serializable;
6 |
7 |
8 | public class Language implements Serializable {
9 | public String name;
10 | public String path;
11 | @SerializedName("short_name")
12 | private String shortName;
13 |
14 | public String getShortName() {
15 | return shortName == null ? name : shortName;
16 | }
17 |
18 | public Language() {
19 | }
20 |
21 | public Language(String name, String path) {
22 | this.name = name;
23 | this.path = path;
24 | }
25 |
26 | @Override
27 | public boolean equals(Object o) {
28 | if (o instanceof Language) {
29 | return name.equals(((Language) o).name);
30 | }
31 | return false;
32 | }
33 |
34 | @Override
35 | public int hashCode() {
36 | return name.hashCode();
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/data/model/Pair.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.data.model;
2 |
3 | import java.io.Serializable;
4 |
5 | /**
6 | * Created by yeungeek on 2016/4/19.
7 | */
8 | public class Pair implements Serializable{
9 | public final F first;
10 | public final S second;
11 |
12 | /**
13 | * Constructor for a Pair.
14 | *
15 | * @param first the first object in the Pair
16 | * @param second the second object in the pair
17 | */
18 | public Pair(F first, S second) {
19 | this.first = first;
20 | this.second = second;
21 | }
22 |
23 | /**
24 | * Checks the two objects for equality by delegating to their respective
25 | * {@link Object#equals(Object)} methods.
26 | *
27 | * @param o the {@link Pair} to which this one is to be checked for equality
28 | * @return true if the underlying objects of the Pair are both considered
29 | * equal
30 | */
31 | @Override
32 | public boolean equals(Object o) {
33 | if (!(o instanceof Pair)) {
34 | return false;
35 | }
36 | Pair, ?> p = (Pair, ?>) o;
37 | return objectsEqual(p.first, first) && objectsEqual(p.second, second);
38 | }
39 |
40 | private static boolean objectsEqual(Object a, Object b) {
41 | return a == b || (a != null && a.equals(b));
42 | }
43 |
44 | /**
45 | * Compute a hash code using the hash codes of the underlying objects
46 | *
47 | * @return a hashcode of the Pair
48 | */
49 | @Override
50 | public int hashCode() {
51 | return (first == null ? 0 : first.hashCode()) ^ (second == null ? 0 : second.hashCode());
52 | }
53 |
54 | /**
55 | * Convenience method for creating an appropriately typed pair.
56 | *
57 | * @param a the first object in the Pair
58 | * @param b the second object in the pair
59 | * @return a Pair that is templatized with the types of a and b
60 | */
61 | public static Pair create(A a, B b) {
62 | return new Pair (a, b);
63 | }
64 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/data/model/RepoContent.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.data.model;
2 |
3 | import java.io.Serializable;
4 |
5 | /**
6 | * Created by yeungeek on 2016/4/13.
7 | */
8 | public class RepoContent implements Serializable{
9 | private String name;
10 | private String path;
11 | private String sha;
12 | private int size;
13 | private String url;
14 | private String html_url;
15 | private String git_url;
16 | private String file;
17 | private String content;
18 | private String encoding;
19 | //links
20 |
21 | public String getName() {
22 | return name;
23 | }
24 |
25 | public RepoContent setName(String name) {
26 | this.name = name;
27 | return this;
28 | }
29 |
30 | public String getPath() {
31 | return path;
32 | }
33 |
34 | public RepoContent setPath(String path) {
35 | this.path = path;
36 | return this;
37 | }
38 |
39 | public String getSha() {
40 | return sha;
41 | }
42 |
43 | public RepoContent setSha(String sha) {
44 | this.sha = sha;
45 | return this;
46 | }
47 |
48 | public int getSize() {
49 | return size;
50 | }
51 |
52 | public RepoContent setSize(int size) {
53 | this.size = size;
54 | return this;
55 | }
56 |
57 | public String getUrl() {
58 | return url;
59 | }
60 |
61 | public RepoContent setUrl(String url) {
62 | this.url = url;
63 | return this;
64 | }
65 |
66 | public String getHtml_url() {
67 | return html_url;
68 | }
69 |
70 | public RepoContent setHtml_url(String html_url) {
71 | this.html_url = html_url;
72 | return this;
73 | }
74 |
75 | public String getGit_url() {
76 | return git_url;
77 | }
78 |
79 | public RepoContent setGit_url(String git_url) {
80 | this.git_url = git_url;
81 | return this;
82 | }
83 |
84 | public String getFile() {
85 | return file;
86 | }
87 |
88 | public RepoContent setFile(String file) {
89 | this.file = file;
90 | return this;
91 | }
92 |
93 | public String getContent() {
94 | return content;
95 | }
96 |
97 | public RepoContent setContent(String content) {
98 | this.content = content;
99 | return this;
100 | }
101 |
102 | public String getEncoding() {
103 | return encoding;
104 | }
105 |
106 | public RepoContent setEncoding(String encoding) {
107 | this.encoding = encoding;
108 | return this;
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/data/model/WrapList.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.data.model;
2 |
3 | import java.util.List;
4 |
5 | /**
6 | * Created by yeungeek on 2016/4/3.
7 | */
8 | public class WrapList {
9 | private List items;
10 | private int total_count;
11 | private boolean incomplete_results;
12 |
13 | public List getItems() {
14 | return items;
15 | }
16 |
17 | public WrapList setItems(List items) {
18 | this.items = items;
19 | return this;
20 | }
21 |
22 | public int getTotal_count() {
23 | return total_count;
24 | }
25 |
26 | public WrapList setTotal_count(int total_count) {
27 | this.total_count = total_count;
28 | return this;
29 | }
30 |
31 | public boolean isIncomplete_results() {
32 | return incomplete_results;
33 | }
34 |
35 | public WrapList setIncomplete_results(boolean incomplete_results) {
36 | this.incomplete_results = incomplete_results;
37 | return this;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/data/model/WrapUser.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.data.model;
2 |
3 | /**
4 | * Created by yeungeek on 2016/4/18.
5 | */
6 | public class WrapUser extends User {
7 | //check if is followed
8 | private boolean isFollowed;
9 |
10 | public boolean isFollowed() {
11 | return isFollowed;
12 | }
13 |
14 | public WrapUser setFollowed(boolean followed) {
15 | isFollowed = followed;
16 | return this;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/data/remote/SimpleApi.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.data.remote;
2 |
3 | import retrofit2.http.Body;
4 | import retrofit2.http.Header;
5 | import retrofit2.http.Headers;
6 | import retrofit2.http.POST;
7 | import rx.Observable;
8 |
9 | /**
10 | * Created by yeungeek on 2016/4/14.
11 | */
12 | public interface SimpleApi {
13 | @Headers({
14 | "Content-Type: text/plain"
15 | })
16 | @POST("markdown/raw")
17 | Observable markdown(@Body String readme);
18 | }
19 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/data/remote/TokenInterceptor.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.data.remote;
2 |
3 | import android.content.Context;
4 | import android.text.TextUtils;
5 |
6 | import com.yeungeek.monkeyandroid.MonkeyApplication;
7 | import com.yeungeek.monkeyandroid.data.local.PreferencesHelper;
8 |
9 | import java.io.IOException;
10 |
11 | import javax.inject.Inject;
12 |
13 | import okhttp3.Interceptor;
14 | import okhttp3.Request;
15 | import okhttp3.Response;
16 |
17 | /**
18 | * Created by yeungeek on 2016/4/19.
19 | */
20 | public class TokenInterceptor implements Interceptor {
21 | @Inject
22 | PreferencesHelper preferencesHelper;
23 |
24 | public TokenInterceptor(Context context) {
25 | MonkeyApplication.get(context).getComponent().inject(this);
26 | }
27 |
28 | @Override
29 | public Response intercept(Chain chain) throws IOException {
30 | Request original = chain.request();
31 | Request.Builder requestBuilder = original.newBuilder()
32 | .method(original.method(), original.body());
33 | if (null != preferencesHelper && !TextUtils.isEmpty(preferencesHelper.getAccessToken())) {
34 | requestBuilder.header(GithubApi.AUTH_HEADER, GithubApi.AUTH_TOKEN + preferencesHelper.getAccessToken());
35 | }
36 |
37 | Request request = requestBuilder.build();
38 | return chain.proceed(request);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/data/remote/UnauthorisedInterceptor.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.data.remote;
2 |
3 | import android.content.Context;
4 |
5 | import com.yeungeek.monkeyandroid.MonkeyApplication;
6 | import com.yeungeek.monkeyandroid.rxbus.RxBus;
7 | import com.yeungeek.monkeyandroid.rxbus.event.BusEvent;
8 | import com.yeungeek.monkeyandroid.util.HttpStatus;
9 |
10 | import java.io.IOException;
11 |
12 | import javax.inject.Inject;
13 |
14 | import okhttp3.Interceptor;
15 | import okhttp3.Response;
16 | import timber.log.Timber;
17 |
18 | /**
19 | * Created by yeungeek on 2016/4/8.
20 | */
21 | public class UnauthorisedInterceptor implements Interceptor {
22 | @Inject
23 | RxBus rxBus;
24 |
25 | public UnauthorisedInterceptor(Context context) {
26 | MonkeyApplication.get(context).getComponent().inject(this);
27 | }
28 |
29 | @Override
30 | public Response intercept(Chain chain) throws IOException {
31 | Response response = chain.proceed(chain.request());
32 | if (response.code() == HttpStatus.HTTP_UNAUTHORIZED) {
33 | Timber.e("### unauthorized");
34 | rxBus.send(new BusEvent.AuthenticationError());
35 | }
36 | return response;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/data/remote/retrofit2/StringConverterFactory.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.data.remote.retrofit2;
2 |
3 | import java.io.IOException;
4 | import java.lang.annotation.Annotation;
5 | import java.lang.reflect.Type;
6 |
7 | import okhttp3.MediaType;
8 | import okhttp3.RequestBody;
9 | import okhttp3.ResponseBody;
10 | import retrofit2.Converter;
11 | import retrofit2.Retrofit;
12 |
13 | /**
14 | * Created by yeungeek on 2016/4/14.
15 | */
16 | public class StringConverterFactory extends Converter.Factory {
17 | @Override
18 | public Converter, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
19 | return new Converter() {
20 | @Override
21 | public RequestBody convert(String value) throws IOException {
22 | return RequestBody.create(MediaType.parse("text/plain"), value);
23 | }
24 | };
25 | }
26 |
27 | @Override
28 | public Converter responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
29 | return new Converter() {
30 | @Override
31 | public String convert(ResponseBody value) throws IOException {
32 | return value.string();
33 | }
34 | };
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/injection/ActivityContext.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.injection;
2 |
3 | import java.lang.annotation.Retention;
4 | import java.lang.annotation.RetentionPolicy;
5 |
6 | import javax.inject.Qualifier;
7 |
8 | /**
9 | * Created by yeungeek on 2016/1/14.
10 | */
11 | @Qualifier
12 | @Retention(RetentionPolicy.RUNTIME)
13 | public @interface ActivityContext {
14 | }
15 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/injection/ApplicationContext.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.injection;
2 |
3 | import java.lang.annotation.Retention;
4 | import java.lang.annotation.RetentionPolicy;
5 |
6 | import javax.inject.Qualifier;
7 |
8 | /**
9 | * Created by yeungeek on 2016/1/14.
10 | */
11 | @Qualifier
12 | @Retention(RetentionPolicy.RUNTIME)
13 | public @interface ApplicationContext {
14 | }
15 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/injection/PerActivity.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.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 DataManager to be memorised in the
11 | * correct component.
12 | */
13 |
14 | @Scope
15 | @Retention(RetentionPolicy.RUNTIME)
16 | public @interface PerActivity {
17 | }
18 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/injection/component/ActivityComponent.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.injection.component;
2 |
3 | import com.yeungeek.monkeyandroid.injection.PerActivity;
4 | import com.yeungeek.monkeyandroid.injection.module.ActivityModule;
5 | import com.yeungeek.monkeyandroid.ui.AboutActivity;
6 | import com.yeungeek.monkeyandroid.ui.base.view.BaseToolbarFragment;
7 | import com.yeungeek.monkeyandroid.ui.detail.FollowUserFragment;
8 | import com.yeungeek.monkeyandroid.ui.detail.RepoDetailFragment;
9 | import com.yeungeek.monkeyandroid.ui.detail.UserDetailFragment;
10 | import com.yeungeek.monkeyandroid.ui.main.MainActivity;
11 | import com.yeungeek.monkeyandroid.ui.repos.RepoListFragment;
12 | import com.yeungeek.monkeyandroid.ui.signin.SignInDialogFragment;
13 | import com.yeungeek.monkeyandroid.ui.trending.TrendingListFragment;
14 | import com.yeungeek.monkeyandroid.ui.users.UserListFragment;
15 |
16 | import dagger.Component;
17 |
18 | /**
19 | * Created by yeungeek on 2016/1/17.
20 | */
21 | @PerActivity
22 | @Component(dependencies = ApplicationComponent.class, modules = ActivityModule.class)
23 | public interface ActivityComponent {
24 |
25 | void inject(MainActivity mainActivity);
26 |
27 | void inject(AboutActivity aboutActivity);
28 |
29 | void inject(SignInDialogFragment signInDialogFragment);
30 |
31 | void inject(BaseToolbarFragment baseToolbarFragment);
32 |
33 | void inject(RepoListFragment repoListFragment);
34 |
35 | void inject(FollowUserFragment followUserFragment);
36 |
37 | void inject(RepoDetailFragment repoDetailFragment);
38 |
39 | void inject(UserDetailFragment userDetailFragment);
40 |
41 | void inject(UserListFragment userListFragment);
42 |
43 | void inject(TrendingListFragment trendingListFragment);
44 | }
45 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/injection/component/ApplicationComponent.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.injection.component;
2 |
3 | import android.app.Application;
4 | import android.content.Context;
5 |
6 | import com.google.gson.Gson;
7 | import com.yeungeek.monkeyandroid.MonkeyApplication;
8 | import com.yeungeek.monkeyandroid.data.DataManager;
9 | import com.yeungeek.monkeyandroid.data.local.DatabaseHelper;
10 | import com.yeungeek.monkeyandroid.data.local.PreferencesHelper;
11 | import com.yeungeek.monkeyandroid.data.remote.GithubApi;
12 | import com.yeungeek.monkeyandroid.data.remote.SimpleApi;
13 | import com.yeungeek.monkeyandroid.data.remote.TokenInterceptor;
14 | import com.yeungeek.monkeyandroid.data.remote.UnauthorisedInterceptor;
15 | import com.yeungeek.monkeyandroid.injection.ApplicationContext;
16 | import com.yeungeek.monkeyandroid.injection.module.ApplicationModule;
17 | import com.yeungeek.monkeyandroid.rxbus.RxBus;
18 |
19 | import javax.inject.Singleton;
20 |
21 | import dagger.Component;
22 |
23 | @Singleton
24 | @Component(modules = ApplicationModule.class)
25 | public interface ApplicationComponent {
26 |
27 | void inject(MonkeyApplication monkeyApplication);
28 | void inject(UnauthorisedInterceptor unauthorisedInterceptor);
29 | void inject(TokenInterceptor tokenInterceptor);
30 |
31 | //Exposed to sub-graphs.
32 | @ApplicationContext
33 | Context context();
34 |
35 | Application application();
36 |
37 | GithubApi githubApi();
38 | SimpleApi simpleApi();
39 |
40 | DatabaseHelper databaseHelper();
41 |
42 | PreferencesHelper preferencesHelper();
43 |
44 | DataManager dataManager();
45 |
46 | RxBus rxBus();
47 |
48 | Gson gson();
49 | }
50 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/injection/component/ReposComponent.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.injection.component;
2 |
3 | import com.yeungeek.monkeyandroid.ui.base.view.BaseToolbarFragment;
4 |
5 | /**
6 | * Created by yeungeek on 2016/1/18.
7 | */
8 | public interface ReposComponent {
9 | void inject(BaseToolbarFragment baseToolbarFragment);
10 | }
11 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/injection/module/ActivityModule.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.injection.module;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 |
6 | import com.yeungeek.monkeyandroid.injection.ActivityContext;
7 |
8 | import dagger.Module;
9 | import dagger.Provides;
10 |
11 | /**
12 | * Created by yeungeek on 2016/1/17.
13 | */
14 | @Module
15 | public class ActivityModule {
16 | private Activity mActivity;
17 |
18 | public ActivityModule(final Activity activity) {
19 | this.mActivity = activity;
20 | }
21 |
22 | /**
23 | * Expose the activity to dependents in the graph.
24 | */
25 | @Provides
26 | Activity provideActivity() {
27 | return mActivity;
28 | }
29 |
30 | @Provides
31 | @ActivityContext
32 | Context providesContext(){
33 | return mActivity;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/injection/module/ApplicationModule.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.injection.module;
2 |
3 | import android.app.Application;
4 | import android.content.Context;
5 |
6 | import com.facebook.stetho.okhttp3.StethoInterceptor;
7 | import com.google.gson.Gson;
8 | import com.yeungeek.monkeyandroid.BuildConfig;
9 | import com.yeungeek.monkeyandroid.data.remote.GithubApi;
10 | import com.yeungeek.monkeyandroid.data.remote.SimpleApi;
11 | import com.yeungeek.monkeyandroid.data.remote.TokenInterceptor;
12 | import com.yeungeek.monkeyandroid.data.remote.UnauthorisedInterceptor;
13 | import com.yeungeek.monkeyandroid.data.remote.retrofit2.StringConverterFactory;
14 | import com.yeungeek.monkeyandroid.injection.ApplicationContext;
15 | import com.yeungeek.monkeyandroid.rxbus.RxBus;
16 |
17 | import javax.inject.Singleton;
18 |
19 | import dagger.Module;
20 | import dagger.Provides;
21 | import okhttp3.OkHttpClient;
22 | import okhttp3.logging.HttpLoggingInterceptor;
23 | import retrofit2.Retrofit;
24 | import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
25 | import retrofit2.converter.gson.GsonConverterFactory;
26 |
27 | /**
28 | * Created by yeungeek on 2016/1/14.
29 | */
30 | @Module
31 | public class ApplicationModule {
32 | protected final Application mApplication;
33 |
34 | public ApplicationModule(final Application application) {
35 | this.mApplication = application;
36 | }
37 |
38 | @Provides
39 | Application provideApplication() {
40 | return mApplication;
41 | }
42 |
43 | @Provides
44 | @ApplicationContext
45 | Context provideContext() {
46 | return mApplication;
47 | }
48 |
49 | @Provides
50 | @Singleton
51 | GithubApi provideGithubApi(Retrofit retrofit) {
52 | return retrofit.create(GithubApi.class);
53 | }
54 |
55 | @Provides
56 | @Singleton
57 | SimpleApi provideSimpleApi(OkHttpClient okHttpClient) {
58 | Retrofit retrofit = new Retrofit.Builder()
59 | .baseUrl(GithubApi.ENDPOINT)
60 | .client(okHttpClient)
61 | .addConverterFactory(new StringConverterFactory())
62 | .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
63 | .build();
64 |
65 | return retrofit.create(SimpleApi.class);
66 | }
67 |
68 | @Provides
69 | @Singleton
70 | OkHttpClient provideOkHttpClient() {
71 | final OkHttpClient.Builder builder = new OkHttpClient.Builder();
72 | HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
73 | logging.setLevel(BuildConfig.DEBUG ? HttpLoggingInterceptor.Level.BODY : HttpLoggingInterceptor.Level.NONE);
74 |
75 | //@see https://github.com/square/okhttp/blob/master/okhttp-logging-interceptor
76 | final OkHttpClient okHttpClient = builder.addInterceptor(logging)
77 | .addInterceptor(new UnauthorisedInterceptor(mApplication))
78 | .addInterceptor(new TokenInterceptor(mApplication))
79 | .addNetworkInterceptor(new StethoInterceptor())
80 | .build();
81 | return okHttpClient;
82 | }
83 |
84 | @Provides
85 | @Singleton
86 | Retrofit provideRetrofit(OkHttpClient okHttpClient) {
87 | Retrofit retrofit = new Retrofit.Builder()
88 | .baseUrl(GithubApi.ENDPOINT)
89 | .client(okHttpClient)
90 | .addConverterFactory(GsonConverterFactory.create())
91 | .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
92 | .build();
93 | return retrofit;
94 | }
95 |
96 | @Provides
97 | @Singleton
98 | RxBus provideRxBus() {
99 | return new RxBus();
100 | }
101 |
102 | @Provides
103 | @Singleton
104 | Gson provideGson() {
105 | return new Gson();
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/rxbus/RxBus.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.rxbus;
2 |
3 | import rx.Observable;
4 | import rx.subjects.PublishSubject;
5 | import rx.subjects.SerializedSubject;
6 | import rx.subjects.Subject;
7 |
8 | /**
9 | * Created by yeungeek on 2016/3/11.
10 | *
11 | * @see https://gist.github.com/benjchristensen/04eef9ca0851f3a5d7bf
12 | */
13 | public class RxBus {
14 | private final Subject bus = new SerializedSubject<>(PublishSubject.create());
15 |
16 | public void send(final Object o){
17 | bus.onNext(o);
18 | }
19 |
20 | public Observable toObservable(){
21 | return bus;
22 | }
23 |
24 | public boolean hasObservers(){
25 | return bus.hasObservers();
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/rxbus/event/BusEvent.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.rxbus.event;
2 |
3 | /**
4 | * Created by yeungeek on 2016/3/13.
5 | */
6 | public class BusEvent {
7 | public static class SignedOut{}
8 | public static class AuthenticationError {}
9 | }
10 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/rxbus/event/SignInEvent.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.rxbus.event;
2 |
3 | import android.net.Uri;
4 |
5 | /**
6 | * Created by yeungeek on 2016/3/12.
7 | */
8 | public class SignInEvent {
9 | private Uri uri;
10 | public SignInEvent(final Uri uri){
11 | this.uri = uri;
12 | }
13 |
14 | public Uri getUri() {
15 | return uri;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/ui/LauncherActivity.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.ui;
2 |
3 | import com.viksaa.sssplash.lib.activity.AwesomeSplash;
4 | import com.viksaa.sssplash.lib.model.ConfigSplash;
5 | import com.yeungeek.monkeyandroid.R;
6 | import com.yeungeek.monkeyandroid.ui.main.MainActivity;
7 | import com.yeungeek.monkeyandroid.util.AppCst;
8 |
9 | /**
10 | * Created by yeungeek on 2016/3/16.
11 | */
12 | public class LauncherActivity extends AwesomeSplash {
13 |
14 | @Override
15 | public void initSplash(ConfigSplash configSplash) {
16 | //Title
17 | configSplash.setTitleSplash(getString(R.string.title_app));
18 | configSplash.setBackgroundColor(R.color.colorPrimary);
19 | configSplash.setTitleTextSize(30f);
20 |
21 | //path
22 | configSplash.setPathSplash(AppCst.GITHUB); //set path String
23 | configSplash.setOriginalHeight(512); //in relation to your svg (path) resource
24 | configSplash.setOriginalWidth(512); //in relation to your svg (path) resource
25 | configSplash.setAnimPathStrokeDrawingDuration(2000);
26 | configSplash.setPathSplashStrokeSize(3); //I advise value be <5
27 | configSplash.setPathSplashStrokeColor(R.color.colorAccent); //any color you want form colors.xml
28 | configSplash.setAnimPathFillingDuration(2500);
29 | configSplash.setPathSplashFillColor(R.color.blue_200); //path object filling color
30 | }
31 |
32 | @Override
33 | public void animationsFinished() {
34 | startActivity(MainActivity.getStartIntent(this));
35 | finish();
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/ui/base/adapter/ExStaggeredGridLayoutManager.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.ui.base.adapter;
2 |
3 | import android.support.v7.widget.GridLayoutManager;
4 | import android.support.v7.widget.RecyclerView;
5 | import android.support.v7.widget.StaggeredGridLayoutManager;
6 | import android.view.View;
7 |
8 | /**
9 | * Created by cundong on 2015/10/9.
10 | *
11 | * 拓展的StaggeredGridLayoutManager,tks @Jack Tony
12 | */
13 | public class ExStaggeredGridLayoutManager extends StaggeredGridLayoutManager {
14 |
15 | private final String TAG = getClass().getSimpleName();
16 |
17 | GridLayoutManager.SpanSizeLookup mSpanSizeLookup;
18 |
19 | public ExStaggeredGridLayoutManager(int spanCount, int orientation) {
20 | super(spanCount, orientation);
21 | }
22 |
23 | /**
24 | * Returns the current used by the GridLayoutManager.
25 | *
26 | * @return The current used by the GridLayoutManager.
27 | */
28 | public GridLayoutManager.SpanSizeLookup getSpanSizeLookup() {
29 | return mSpanSizeLookup;
30 | }
31 |
32 | /**
33 | * 设置某个位置的item的跨列程度,这里和GridLayoutManager有点不一样,
34 | * 如果你设置某个位置的item的span>1了,那么这个item会占据所有列
35 | *
36 | * @param spanSizeLookup instance to be used to query number of spans
37 | * occupied by each item
38 | */
39 | public void setSpanSizeLookup(GridLayoutManager.SpanSizeLookup spanSizeLookup) {
40 | mSpanSizeLookup = spanSizeLookup;
41 | }
42 |
43 | @Override
44 | public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) {
45 | //Log.d(TAG, "item count = " + getItemCount());
46 | for (int i = 0; i < getItemCount(); i++) {
47 |
48 | if (mSpanSizeLookup.getSpanSize(i) > 1) {
49 | //Log.d(TAG, "lookup > 1 = " + i);
50 | try {
51 | //fix 动态添加时报IndexOutOfBoundsException
52 | View view = recycler.getViewForPosition(i);
53 | if (view != null) {
54 | /**
55 | *占用所有的列
56 | * @see https://plus.google.com/+EtienneLawlor/posts/c5T7fu9ujqi
57 | */
58 | StaggeredGridLayoutManager.LayoutParams lp = (StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams();
59 | lp.setFullSpan(true);
60 | }
61 | // recycler.recycleView(view);
62 | } catch (Exception e) {
63 | e.printStackTrace();
64 | }
65 | }
66 | }
67 | super.onMeasure(recycler, state, widthSpec, heightSpec);
68 | }
69 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/ui/base/adapter/HeaderSpanSizeLookup.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.ui.base.adapter;
2 |
3 | import android.support.v7.widget.GridLayoutManager;
4 |
5 | /**
6 | * Created by cundong on 2015/10/23.
7 | *
8 | * RecyclerView为GridLayoutManager时,设置了HeaderView,就会用到这个SpanSizeLookup
9 | */
10 | public class HeaderSpanSizeLookup extends GridLayoutManager.SpanSizeLookup {
11 |
12 | private HeaderAndFooterRecyclerViewAdapter adapter;
13 | private int mSpanSize = 1;
14 |
15 | public HeaderSpanSizeLookup(HeaderAndFooterRecyclerViewAdapter adapter, int spanSize) {
16 | this.adapter = adapter;
17 | this.mSpanSize = spanSize;
18 | }
19 |
20 | @Override
21 | public int getSpanSize(int position) {
22 | boolean isHeaderOrFooter = adapter.isHeader(position) || adapter.isFooter(position);
23 | return isHeaderOrFooter ? mSpanSize : 1;
24 | }
25 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/ui/base/adapter/OnListLoadNextPageListener.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.ui.base.adapter;
2 |
3 | import android.view.View;
4 |
5 | /**
6 | * Created by cundong on 2015/10/9.
7 | * RecyclerView/ListView/GridView 滑动加载下一页时的回调接口
8 | */
9 | public interface OnListLoadNextPageListener {
10 |
11 | /**
12 | * 开始加载下一页
13 | *
14 | * @param view 当前RecyclerView/ListView/GridView
15 | */
16 | public void onLoadNextPage(View view);
17 | }
18 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/ui/base/presenter/MvpLceRxPresenter.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.ui.base.presenter;
2 |
3 | import com.fernandocejas.frodo.annotation.RxLogSubscriber;
4 | import com.yeungeek.mvp.common.MvpBasePresenter;
5 | import com.yeungeek.mvp.common.MvpPresenter;
6 | import com.yeungeek.mvp.common.lce.MvpLceView;
7 |
8 | import rx.Observable;
9 | import rx.Subscriber;
10 | import rx.android.schedulers.AndroidSchedulers;
11 | import rx.schedulers.Schedulers;
12 |
13 | /**
14 | * A presenter for RxJava, that assumes that only one Observable is subscribed by this presenter.
15 | * The idea is, that you make your (chain of) Observable and pass it to {@link
16 | * #subscribe(Observable, boolean)}. The presenter internally subscribes himself as Subscriber to
17 | * the
18 | * observable
19 | * (which executes the observable).
20 | *
21 | * @author Hannes Dorfmann
22 | * @since 1.0.0
23 | */
24 | public abstract class MvpLceRxPresenter, M>
25 | extends MvpBasePresenter implements MvpPresenter {
26 |
27 | protected Subscriber subscriber;
28 |
29 | /**
30 | * Unsubscribes the subscriber and set it to null
31 | */
32 | protected void unsubscribe() {
33 | if (null != subscriber && !subscriber.isUnsubscribed()) {
34 | subscriber.unsubscribe();
35 | }
36 |
37 | subscriber = null;
38 | }
39 |
40 | /**
41 | * Subscribes the presenter himself as subscriber on the observable
42 | *
43 | * @param observable The observable to subscribe
44 | * @param pullToRefresh Pull to refresh?
45 | */
46 | public void subscribe(final Observable observable, final boolean pullToRefresh) {
47 | if (isViewAttached()) {
48 | getView().showLoading(pullToRefresh);
49 | }
50 |
51 | unsubscribe();
52 |
53 | subscriber = new RxSubscriber(pullToRefresh);
54 |
55 | observable.subscribeOn(Schedulers.io())
56 | .observeOn(AndroidSchedulers.mainThread())
57 | .subscribe(subscriber);
58 | }
59 |
60 | @RxLogSubscriber
61 | private class RxSubscriber extends Subscriber {
62 | final private boolean ptr;
63 |
64 | public RxSubscriber(final boolean pullToRefresh) {
65 | this.ptr = pullToRefresh;
66 | }
67 |
68 | @Override
69 | public void onCompleted() {
70 | MvpLceRxPresenter.this.onCompleted();
71 | }
72 |
73 | @Override
74 | public void onError(Throwable e) {
75 | MvpLceRxPresenter.this.onError(e, ptr);
76 | }
77 |
78 | @Override
79 | public void onNext(M m) {
80 | MvpLceRxPresenter.this.onNext(m);
81 | }
82 | }
83 |
84 | protected void onCompleted() {
85 | if (isViewAttached()) {
86 | getView().showContent();
87 | }
88 | unsubscribe();
89 | }
90 |
91 | protected void onError(Throwable e, boolean pullToRefresh) {
92 | if (isViewAttached()) {
93 | getView().showError(e, pullToRefresh);
94 | }
95 | unsubscribe();
96 | }
97 |
98 | protected void onNext(M data) {
99 | if (isViewAttached()) {
100 | getView().setData(data);
101 | }
102 | }
103 |
104 | @Override
105 | public void detachView(boolean retainInstance) {
106 | super.detachView(retainInstance);
107 | if (!retainInstance) {
108 | unsubscribe();
109 | }
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/ui/base/view/BaseActivity.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.ui.base.view;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.view.View;
7 |
8 | import com.yeungeek.monkeyandroid.MonkeyApplication;
9 | import com.yeungeek.monkeyandroid.injection.component.ActivityComponent;
10 | import com.yeungeek.monkeyandroid.injection.component.ApplicationComponent;
11 | import com.yeungeek.monkeyandroid.injection.component.DaggerActivityComponent;
12 | import com.yeungeek.monkeyandroid.injection.module.ActivityModule;
13 |
14 | import butterknife.ButterKnife;
15 |
16 | /**
17 | * Created by yeungeek on 2016/1/8.
18 | */
19 | public abstract class BaseActivity extends AppCompatActivity implements View.OnClickListener{
20 | @Override
21 | protected void onCreate(@Nullable Bundle savedInstanceState) {
22 | injectDependencies();
23 | super.onCreate(savedInstanceState);
24 | }
25 |
26 | @Override
27 | public void onContentChanged() {
28 | super.onContentChanged();
29 | ButterKnife.bind(this);
30 | }
31 |
32 | protected void injectDependencies() {
33 |
34 | }
35 |
36 | public ActivityComponent activityComponent() {
37 | if (null == mActivityComponent) {
38 | mActivityComponent = DaggerActivityComponent.builder()
39 | .activityModule(getActivityModule())
40 | .applicationComponent(getApplicationComponent())
41 | .build();
42 | }
43 | return mActivityComponent;
44 | }
45 |
46 | protected ApplicationComponent getApplicationComponent() {
47 | return MonkeyApplication.get(this).getComponent();
48 | }
49 |
50 | protected ActivityModule getActivityModule() {
51 | return new ActivityModule(this);
52 | }
53 |
54 | private ActivityComponent mActivityComponent;
55 |
56 | @Override
57 | public void onClick(View v) {
58 |
59 | }
60 |
61 | @Override
62 | protected void onDestroy() {
63 | super.onDestroy();
64 | ButterKnife.unbind(this);
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/ui/base/view/BaseFragment.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.ui.base.view;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.LayoutRes;
5 | import android.support.annotation.Nullable;
6 | import android.support.v4.app.Fragment;
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 |
11 | import butterknife.ButterKnife;
12 |
13 | /**
14 | * Created by yeungeek on 2016/1/10.
15 | */
16 | public abstract class BaseFragment extends Fragment {
17 | @Override
18 | public void onCreate(@Nullable Bundle savedInstanceState) {
19 | super.onCreate(savedInstanceState);
20 | init();
21 | }
22 |
23 | @Nullable
24 | @Override
25 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
26 | return inflater.inflate(getLayoutRes(), container, false);
27 | }
28 |
29 | @Override
30 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
31 | injectDependencies();
32 | super.onViewCreated(view, savedInstanceState);
33 | ButterKnife.bind(this, view);
34 | initViews();
35 | }
36 |
37 | @Override
38 | public void onDestroyView() {
39 | super.onDestroyView();
40 | ButterKnife.unbind(this);
41 | }
42 |
43 | @LayoutRes
44 | protected abstract int getLayoutRes();
45 |
46 | /**
47 | * Inject the dependencies
48 | */
49 | protected void injectDependencies() {
50 |
51 | }
52 |
53 | protected void init() {
54 | }
55 |
56 | protected void initViews() {
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/ui/base/view/BaseLceActivity.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.ui.base.view;
2 |
3 | import android.os.Bundle;
4 | import android.view.View;
5 |
6 | import com.yeungeek.monkeyandroid.MonkeyApplication;
7 | import com.yeungeek.monkeyandroid.injection.component.ActivityComponent;
8 | import com.yeungeek.monkeyandroid.injection.component.ApplicationComponent;
9 | import com.yeungeek.monkeyandroid.injection.component.DaggerActivityComponent;
10 | import com.yeungeek.monkeyandroid.injection.module.ActivityModule;
11 | import com.yeungeek.mvp.common.MvpPresenter;
12 | import com.yeungeek.mvp.common.lce.MvpLceView;
13 | import com.yeungeek.mvp.core.lce.MvpLceActivity;
14 |
15 | import butterknife.ButterKnife;
16 |
17 | /**
18 | * Created by yeungeek on 2016/1/10.
19 | */
20 | public abstract class BaseLceActivity, P extends MvpPresenter>
21 | extends MvpLceActivity implements View.OnClickListener{
22 | @Override
23 | public void onCreate(Bundle savedInstanceState) {
24 | injectDependencies();
25 | super.onCreate(savedInstanceState);
26 | }
27 |
28 | @Override
29 | public void onContentChanged() {
30 | super.onContentChanged();
31 | ButterKnife.bind(this);
32 | }
33 |
34 | @Override
35 | protected void onDestroy() {
36 | super.onDestroy();
37 | ButterKnife.unbind(this);
38 | }
39 |
40 | @Override
41 | public void onClick(View v) {
42 |
43 | }
44 |
45 | /**
46 | * mvp
47 | */
48 | @Override
49 | protected String getErrorMessage(Throwable e, boolean pullToRefresh) {
50 | return null;
51 | }
52 |
53 | @Override
54 | public void loadData(boolean pullToRefresh) {
55 |
56 | }
57 |
58 | protected void injectDependencies() {
59 |
60 | }
61 |
62 | public ActivityComponent activityComponent() {
63 | if (null == mActivityComponent) {
64 | mActivityComponent = DaggerActivityComponent.builder()
65 | .activityModule(getActivityModule())
66 | .applicationComponent(getApplicationComponent())
67 | .build();
68 | }
69 | return mActivityComponent;
70 | }
71 |
72 | protected ApplicationComponent getApplicationComponent() {
73 | return MonkeyApplication.get(this).getComponent();
74 | }
75 |
76 | protected ActivityModule getActivityModule() {
77 | return new ActivityModule(this);
78 | }
79 |
80 | private ActivityComponent mActivityComponent;
81 | }
82 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/ui/base/view/BaseLceFragment.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.ui.base.view;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.LayoutRes;
5 | import android.support.annotation.Nullable;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 |
10 | import com.yeungeek.mvp.common.MvpPresenter;
11 | import com.yeungeek.mvp.common.lce.MvpLceView;
12 | import com.yeungeek.mvp.core.lce.MvpLceFragment;
13 |
14 | import butterknife.ButterKnife;
15 |
16 | /**
17 | * Created by yeungeek on 2016/1/10.
18 | */
19 | public abstract class BaseLceFragment, P extends MvpPresenter>
20 | extends MvpLceFragment {
21 | @Override
22 | public void onCreate(Bundle savedInstanceState) {
23 | super.onCreate(savedInstanceState);
24 | init();
25 | }
26 |
27 | @Nullable
28 | @Override
29 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
30 | return inflater.inflate(getLayoutRes(), container, false);
31 | }
32 |
33 | @Override
34 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
35 | injectDependencies();
36 | super.onViewCreated(view, savedInstanceState);
37 | ButterKnife.bind(this, view);
38 | initViews();
39 | }
40 |
41 | @Override
42 | public void onDestroyView() {
43 | super.onDestroyView();
44 | ButterKnife.unbind(this);
45 | }
46 |
47 | @LayoutRes
48 | protected abstract int getLayoutRes();
49 |
50 | /**
51 | * Inject the dependencies
52 | */
53 | protected void injectDependencies() {
54 |
55 | }
56 |
57 | protected void init() {
58 | }
59 | protected void initViews(){}
60 | }
61 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/ui/base/view/BaseToolbarFragment.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.ui.base.view;
2 |
3 | import android.support.design.widget.AppBarLayout;
4 | import android.support.design.widget.FloatingActionButton;
5 | import android.support.design.widget.TabLayout;
6 | import android.support.v4.view.ViewPager;
7 | import android.support.v7.app.ActionBar;
8 | import android.support.v7.app.AppCompatActivity;
9 | import android.support.v7.widget.Toolbar;
10 |
11 | import com.yeungeek.monkeyandroid.R;
12 | import com.yeungeek.monkeyandroid.data.DataManager;
13 |
14 | import javax.inject.Inject;
15 |
16 | import butterknife.Bind;
17 | import timber.log.Timber;
18 |
19 | /**
20 | * Created by yeungeek on 2016/3/29.
21 | */
22 | public abstract class BaseToolbarFragment extends BaseFragment {
23 | @Bind(R.id.toolbar)
24 | Toolbar toolbar;
25 | @Bind(R.id.tabs)
26 | TabLayout tabLayout;
27 | @Bind(R.id.pager)
28 | ViewPager viewPager;
29 | @Bind(R.id.fab)
30 | FloatingActionButton floatingActionButton;
31 | @Bind(R.id.app_bar)
32 | AppBarLayout appbar;
33 |
34 | @Inject
35 | protected DataManager dataManager;
36 | protected ViewPager.OnPageChangeListener onPageChangeListener;
37 | protected int mCurrentPosition = 0;
38 | private ActionBar actionBar;
39 |
40 | protected int appbarOffset;
41 |
42 | @Override
43 | protected int getLayoutRes() {
44 | return R.layout.layout_appbar;
45 | }
46 |
47 | @Override
48 | protected void initViews() {
49 | super.initViews();
50 |
51 | if (null != toolbar) {
52 | ((AppCompatActivity) getActivity()).setSupportActionBar(toolbar);
53 | actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar();
54 | if (null != actionBar) {
55 | actionBar.setDisplayHomeAsUpEnabled(true);
56 | actionBar.setHomeAsUpIndicator(R.drawable.ic_menu);
57 | initToolbar();
58 | }
59 | }
60 |
61 | getViewPager().addOnPageChangeListener(onPageChangeListener = new ViewPager.OnPageChangeListener() {
62 | @Override
63 | public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
64 |
65 | }
66 |
67 | @Override
68 | public void onPageSelected(int position) {
69 | Timber.d("### onItemSelected onPageSelected position: %d", position);
70 | mCurrentPosition = position;
71 | }
72 |
73 | @Override
74 | public void onPageScrollStateChanged(int state) {
75 |
76 | }
77 | });
78 |
79 | appbar.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
80 | @Override
81 | public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
82 | Timber.d("### onOffsetChanged verticalOffset:%s,", verticalOffset);
83 | appbarOffset = verticalOffset;
84 | }
85 | });
86 | }
87 |
88 | @Override
89 | protected void injectDependencies() {
90 | super.injectDependencies();
91 | if (getActivity() instanceof BaseLceActivity) {
92 | ((BaseLceActivity) getActivity()).activityComponent().inject(this);
93 | }
94 | }
95 |
96 | protected abstract void initToolbar();
97 |
98 | public ActionBar getActionBar() {
99 | return actionBar;
100 | }
101 |
102 | public Toolbar getToolbar() {
103 | return toolbar;
104 | }
105 |
106 | public TabLayout getTabLayout() {
107 | return tabLayout;
108 | }
109 |
110 | public ViewPager getViewPager() {
111 | return viewPager;
112 | }
113 |
114 | public FloatingActionButton getFloatingActionButton() {
115 | return floatingActionButton;
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/ui/detail/DetailActivity.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.ui.detail;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.support.annotation.Nullable;
7 | import android.support.v4.app.FragmentManager;
8 | import android.support.v4.app.FragmentTransaction;
9 | import android.view.MenuItem;
10 |
11 | import com.yeungeek.monkeyandroid.R;
12 | import com.yeungeek.monkeyandroid.data.model.Repo;
13 | import com.yeungeek.monkeyandroid.data.model.User;
14 | import com.yeungeek.monkeyandroid.ui.base.view.BaseActivity;
15 |
16 | import java.io.Serializable;
17 |
18 | /**
19 | * Created by yeungeek on 2016/4/10.
20 | */
21 | public class DetailActivity extends BaseActivity {
22 | private static final String EXTRA_DETAIL = "EXTRA_DETAIL";
23 |
24 | private Serializable serializable;
25 |
26 | public static Intent getStartIntent(Context context, Serializable serializable) {
27 | Intent intent = new Intent(context, DetailActivity.class);
28 | intent.putExtra(EXTRA_DETAIL, serializable);
29 | return intent;
30 | }
31 |
32 | @Override
33 | protected void onCreate(@Nullable Bundle savedInstanceState) {
34 | super.onCreate(savedInstanceState);
35 | setContentView(R.layout.activity_detail);
36 |
37 | serializable = getIntent().getSerializableExtra(EXTRA_DETAIL);
38 | initViews();
39 | }
40 |
41 | @Override
42 | public boolean onOptionsItemSelected(MenuItem item) {
43 | int id = item.getItemId();
44 | switch (id) {
45 | case android.R.id.home:
46 | finish();
47 | return true;
48 | }
49 | return super.onOptionsItemSelected(item);
50 | }
51 |
52 | private void initViews() {
53 | FragmentManager fm = getSupportFragmentManager();
54 | FragmentTransaction transaction = fm.beginTransaction();
55 |
56 | if (null != serializable) {
57 | if (serializable instanceof Repo) {
58 | transaction.replace(R.id.id_detail, RepoDetailFragment.newInstance(this, (Repo) serializable));
59 | } else if (serializable instanceof User) {
60 | transaction.replace(R.id.id_detail, UserDetailFragment.newInstance(this, (User) serializable));
61 | }
62 | }
63 |
64 | transaction.commit();
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/ui/detail/FollowUserFragment.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.ui.detail;
2 |
3 | import android.content.Context;
4 | import android.os.Bundle;
5 | import android.support.annotation.Nullable;
6 | import android.support.v4.app.Fragment;
7 | import android.support.v7.widget.LinearLayoutManager;
8 |
9 | import com.yeungeek.monkeyandroid.data.model.Pair;
10 | import com.yeungeek.monkeyandroid.data.model.User;
11 | import com.yeungeek.monkeyandroid.data.model.WrapUser;
12 | import com.yeungeek.monkeyandroid.ui.base.adapter.HeaderAndFooterRecyclerViewAdapter;
13 | import com.yeungeek.monkeyandroid.ui.base.view.BaseActivity;
14 | import com.yeungeek.monkeyandroid.ui.base.view.BaseLceActivity;
15 | import com.yeungeek.monkeyandroid.ui.base.view.BasePageFragment;
16 | import com.yeungeek.monkeyandroid.ui.users.UserAdapter;
17 | import com.yeungeek.monkeyandroid.util.AppCst;
18 |
19 | import java.util.List;
20 |
21 | import javax.inject.Inject;
22 |
23 | /**
24 | * Created by yeungeek on 2016/4/18.
25 | */
26 | public class FollowUserFragment extends BasePageFragment, FollowUserMvpView, FollowUserPresenter> implements FollowUserMvpView {
27 | @Inject
28 | FollowUserPresenter followUserPresenter;
29 |
30 | private Pair pair;
31 |
32 | private UserAdapter adapter;
33 | private HeaderAndFooterRecyclerViewAdapter mHeaderAdapter;
34 |
35 | public static Fragment newInstance(Context context, final Pair pair) {
36 | Bundle bundle = new Bundle();
37 | bundle.putSerializable(AppCst.EXTRA_USER_TYPE, pair);
38 | return Fragment.instantiate(context, FollowUserFragment.class.getName(), bundle);
39 | }
40 |
41 | @Override
42 | public FollowUserPresenter createPresenter() {
43 | return followUserPresenter;
44 | }
45 |
46 | @Override
47 | public void onCreate(@Nullable Bundle savedInstanceState) {
48 | super.onCreate(savedInstanceState);
49 | pair = (Pair) getArguments().getSerializable(AppCst.EXTRA_USER_TYPE);
50 | }
51 |
52 | @Override
53 | protected void initAdapter() {
54 | adapter = new UserAdapter(getActivity());
55 | mHeaderAdapter = new HeaderAndFooterRecyclerViewAdapter(adapter);
56 | recyclerView.setAdapter(mHeaderAdapter);
57 | recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
58 | }
59 |
60 | @Override
61 | protected String getErrorMessage(Throwable e, boolean pullToRefresh) {
62 | return e.getMessage();
63 | }
64 |
65 | @Override
66 | public void setData(List data) {
67 | switch (pair.first) {
68 | case AppCst.TITLE_FOLLOWERS:
69 | mCount = pair.second.getFollowers();
70 | break;
71 | case AppCst.TITLE_FOLLOWING:
72 | mCount = pair.second.getFollowing();
73 | break;
74 | }
75 |
76 | if (!mLoadMore) {
77 | adapter.addTopAll(data);
78 | mCurrentSize = data.size();
79 | } else {
80 | adapter.addAll(data);
81 | mCurrentSize += data.size();
82 | }
83 |
84 | checkViewState();
85 | }
86 |
87 | @Override
88 | public void loadData(boolean pullToRefresh) {
89 | getPresenter().getUsers(pair.first, pair.second.getLogin(), mPage, pullToRefresh);
90 | }
91 |
92 | @Override
93 | protected void injectDependencies() {
94 | super.injectDependencies();
95 | if (getActivity() instanceof BaseActivity) {
96 | ((BaseActivity) getActivity()).activityComponent().inject(this);
97 | }
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/ui/detail/FollowUserMvpView.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.ui.detail;
2 |
3 | import com.yeungeek.monkeyandroid.data.model.User;
4 | import com.yeungeek.mvp.common.lce.MvpLceView;
5 |
6 | import java.util.List;
7 |
8 | /**
9 | * Created by yeungeek on 2016/4/18.
10 | */
11 | public interface FollowUserMvpView extends MvpLceView> {
12 | }
13 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/ui/detail/FollowUserPresenter.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.ui.detail;
2 |
3 | import com.yeungeek.monkeyandroid.data.DataManager;
4 | import com.yeungeek.monkeyandroid.data.model.User;
5 | import com.yeungeek.monkeyandroid.ui.base.presenter.MvpLceRxPresenter;
6 | import com.yeungeek.monkeyandroid.util.AppCst;
7 | import com.yeungeek.mvp.common.MvpPresenter;
8 |
9 | import java.util.List;
10 |
11 | import javax.inject.Inject;
12 |
13 | import rx.Observable;
14 |
15 | /**
16 | * Created by yeungeek on 2016/4/18.
17 | */
18 | public class FollowUserPresenter extends MvpLceRxPresenter> implements MvpPresenter {
19 | private final DataManager dataManager;
20 |
21 | @Inject
22 | public FollowUserPresenter(final DataManager dataManager) {
23 | this.dataManager = dataManager;
24 | }
25 |
26 | public void getUsers(final String type, final String username, final int page, final boolean pullToRefresh) {
27 | Observable> users = null;
28 | switch (type) {
29 | case AppCst.TITLE_FOLLOWING:
30 | users = dataManager.getFollowing(username, page);
31 | break;
32 | case AppCst.TITLE_FOLLOWERS:
33 | users = dataManager.getFollowers(username, page);
34 | break;
35 | }
36 |
37 | if (null == users) {
38 | return;
39 | }
40 | subscribe(users, pullToRefresh);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/ui/detail/RepoDetailMvpView.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.ui.detail;
2 |
3 | import com.yeungeek.mvp.common.lce.MvpLceView;
4 |
5 | /**
6 | * Created by yeungeek on 2016/4/13.
7 | */
8 | public interface RepoDetailMvpView extends MvpLceView {
9 | void starStatus(boolean isStaring);
10 | void notLogined();
11 | }
12 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/ui/detail/UserDetailMvpView.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.ui.detail;
2 |
3 | import com.yeungeek.monkeyandroid.data.model.WrapUser;
4 | import com.yeungeek.mvp.common.lce.MvpLceView;
5 |
6 | /**
7 | * Created by yeungeek on 2016/4/13.
8 | */
9 | public interface UserDetailMvpView extends MvpLceView {
10 | void followStatus(boolean isFollowing);
11 | void notLogined();
12 | }
13 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/ui/detail/UserDetailPresenter.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.ui.detail;
2 |
3 | import android.text.TextUtils;
4 |
5 | import com.fernandocejas.frodo.annotation.RxLogSubscriber;
6 | import com.yeungeek.monkeyandroid.data.DataManager;
7 | import com.yeungeek.monkeyandroid.data.model.WrapUser;
8 | import com.yeungeek.monkeyandroid.ui.base.presenter.MvpLceRxPresenter;
9 | import com.yeungeek.monkeyandroid.util.HttpStatus;
10 | import com.yeungeek.mvp.common.MvpPresenter;
11 |
12 | import javax.inject.Inject;
13 |
14 | import retrofit2.Response;
15 | import rx.Subscriber;
16 | import rx.android.schedulers.AndroidSchedulers;
17 | import rx.schedulers.Schedulers;
18 |
19 | /**
20 | * Created by yeungeek on 2016/4/18.
21 | */
22 | public class UserDetailPresenter extends MvpLceRxPresenter implements MvpPresenter {
23 | private final DataManager dataManager;
24 |
25 | private FollowSubscriber mFollow;
26 |
27 | @Inject
28 | public UserDetailPresenter(final DataManager dataManager) {
29 | this.dataManager = dataManager;
30 | }
31 |
32 | public void getSingleUser(final String login, final boolean pullToRefresh) {
33 | subscribe(dataManager.getSingleUser(login), pullToRefresh);
34 | }
35 |
36 | public void followUser(final String login) {
37 | mFollow = new FollowSubscriber(true);
38 | dataManager.followUser(login)
39 | .subscribeOn(Schedulers.io())
40 | .observeOn(AndroidSchedulers.mainThread())
41 | .subscribe(mFollow);
42 | }
43 |
44 | public void unfollowUser(final String login) {
45 | mFollow = new FollowSubscriber(false);
46 | dataManager.unfollowUser(login)
47 | .subscribeOn(Schedulers.io())
48 | .observeOn(AndroidSchedulers.mainThread())
49 | .subscribe(mFollow);
50 | }
51 |
52 | @Override
53 | protected void unsubscribe() {
54 | super.unsubscribe();
55 | if (null != mFollow && mFollow.isUnsubscribed()) {
56 | mFollow.unsubscribe();
57 | }
58 |
59 | mFollow = null;
60 | }
61 |
62 | public boolean checkLogin() {
63 | if(TextUtils.isEmpty(dataManager.getPreferencesHelper().getAccessToken())){
64 | // dataManager.getRxBus().send(new BusEvent.AuthenticationError());
65 | getView().notLogined();
66 | return false;
67 | }
68 |
69 | return true;
70 | }
71 |
72 | @RxLogSubscriber
73 | private class FollowSubscriber extends Subscriber> {
74 | private boolean isFollow;
75 |
76 | public FollowSubscriber(final boolean isFollow) {
77 | this.isFollow = isFollow;
78 | }
79 |
80 | @Override
81 | public void onCompleted() {
82 | if (isViewAttached()) {
83 | getView().showContent();
84 | }
85 | unsubscribe();
86 | }
87 |
88 | @Override
89 | public void onError(Throwable e) {
90 | if (isViewAttached()) {
91 | getView().showError(e, true);
92 | }
93 | unsubscribe();
94 | }
95 |
96 | @Override
97 | public void onNext(Response response) {
98 | if (null != response && response.code() == HttpStatus.HTTP_NO_CONTENT) {
99 | if (isFollow) {
100 | getView().followStatus(true);
101 | } else {
102 | getView().followStatus(false);
103 | }
104 | } else {
105 | if (isFollow) {
106 | getView().followStatus(false);
107 | } else {
108 | getView().followStatus(true);
109 | }
110 | }
111 | }
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/ui/main/MainMvpView.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.ui.main;
2 |
3 | import com.yeungeek.monkeyandroid.data.model.User;
4 | import com.yeungeek.mvp.common.lce.MvpLceView;
5 |
6 | /**
7 | * Created by yeungeek on 2016/3/13.
8 | */
9 | public interface MainMvpView extends MvpLceView {
10 | void unauthorized();
11 | }
12 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/ui/main/MainPresenter.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.ui.main;
2 |
3 | import com.yeungeek.monkeyandroid.data.DataManager;
4 | import com.yeungeek.monkeyandroid.data.model.User;
5 | import com.yeungeek.monkeyandroid.rxbus.event.BusEvent;
6 | import com.yeungeek.monkeyandroid.rxbus.event.SignInEvent;
7 | import com.yeungeek.monkeyandroid.ui.base.presenter.MvpLceRxPresenter;
8 | import com.yeungeek.mvp.common.MvpPresenter;
9 |
10 | import javax.inject.Inject;
11 |
12 | import rx.android.schedulers.AndroidSchedulers;
13 | import rx.functions.Action1;
14 | import rx.schedulers.Schedulers;
15 | import rx.subscriptions.CompositeSubscription;
16 | import timber.log.Timber;
17 |
18 | /**
19 | * Created by yeungeek on 2016/3/12.
20 | */
21 | public class MainPresenter extends MvpLceRxPresenter implements MvpPresenter {
22 | private final DataManager dataManager;
23 | private CompositeSubscription mSubscriptions;
24 |
25 | @Inject
26 | public MainPresenter(final DataManager dataManager) {
27 | this.dataManager = dataManager;
28 | }
29 |
30 | @Override
31 | public void attachView(MainMvpView view) {
32 | super.attachView(view);
33 | mSubscriptions = new CompositeSubscription();
34 | mSubscriptions.add(dataManager.getRxBus().toObservable()
35 | .subscribeOn(Schedulers.io())
36 | .observeOn(AndroidSchedulers.mainThread())
37 | .subscribe(new Action1() {
38 | @Override
39 | public void call(Object o) {
40 | if (o instanceof SignInEvent) {
41 | SignInEvent event = (SignInEvent) o;
42 | if (null != event.getUri().getQueryParameter("code")) {
43 | String code = event.getUri().getQueryParameter("code");
44 | Timber.d("### receive event code: %s", code);
45 | getAccessToken(code);
46 | }
47 | } else if (o instanceof BusEvent.AuthenticationError) {
48 | dataManager.clearWebCache();
49 | getView().unauthorized();
50 | }
51 | }
52 | }));
53 | }
54 |
55 | @Override
56 | public void detachView(boolean retainInstance) {
57 | super.detachView(retainInstance);
58 | mSubscriptions.unsubscribe();
59 | }
60 |
61 | public void getAccessToken(String code) {
62 | subscribe(dataManager.getAccessToken(code), false);
63 | }
64 |
65 | public void checkUserStatus() {
66 | User user = null;
67 | if (null != dataManager.getPreferencesHelper().getAccessToken()) {
68 | //if token is exist, user is exist
69 | user = new User();
70 | user.setLogin(dataManager.getPreferencesHelper().getUserLogin());
71 | user.setEmail(dataManager.getPreferencesHelper().getUserEmail());
72 | user.setAvatar_url(dataManager.getPreferencesHelper().getUserAvatar());
73 | }
74 |
75 | getView().setData(user);
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/ui/repos/HotRepoFragment.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.ui.repos;
2 |
3 | import android.support.v4.app.Fragment;
4 | import android.support.v4.app.FragmentManager;
5 | import android.support.v4.app.FragmentPagerAdapter;
6 | import android.view.View;
7 |
8 | import com.yeungeek.monkeyandroid.R;
9 | import com.yeungeek.monkeyandroid.data.model.Language;
10 | import com.yeungeek.monkeyandroid.ui.base.view.BasePageFragment;
11 | import com.yeungeek.monkeyandroid.ui.base.view.BaseToolbarFragment;
12 |
13 | import java.util.ArrayList;
14 | import java.util.List;
15 |
16 | /**
17 | * Created by yeungeek on 2016/3/29.
18 | */
19 | public class HotRepoFragment extends BaseToolbarFragment {
20 | private LanguagesPagerAdapter mPagerAdapter;
21 |
22 | @Override
23 | protected void initToolbar() {
24 | getActionBar().setTitle(R.string.menu_title_repo);
25 | }
26 |
27 | @Override
28 | protected void initViews() {
29 | super.initViews();
30 |
31 | mPagerAdapter = new LanguagesPagerAdapter(getChildFragmentManager());
32 | getViewPager().setAdapter(mPagerAdapter);
33 | getTabLayout().setupWithViewPager(getViewPager());
34 |
35 | getFloatingActionButton().setOnClickListener(new View.OnClickListener() {
36 | @Override
37 | public void onClick(View v) {
38 | Fragment fragment = getChildFragmentManager().findFragmentByTag(mPagerAdapter.getFragmentTag(R.id.pager, mCurrentPosition));
39 | if (null != fragment && fragment instanceof BasePageFragment) {
40 | ((BasePageFragment) fragment).scrollToTop();
41 | }
42 | }
43 | });
44 | }
45 |
46 | public class LanguagesPagerAdapter extends FragmentPagerAdapter {
47 | List languagesArray = new ArrayList<>();
48 |
49 | public LanguagesPagerAdapter(FragmentManager fm) {
50 | super(fm);
51 | languagesArray.addAll(dataManager.getLanguageHelper().getLanguage());
52 | }
53 |
54 | @Override
55 | public Fragment getItem(int position) {
56 | return RepoListFragment.newInstance(getContext(), languagesArray.get(position));
57 | }
58 |
59 | @Override
60 | public int getCount() {
61 | return languagesArray.size();
62 | }
63 |
64 | @Override
65 | public CharSequence getPageTitle(int position) {
66 | return languagesArray.get(position).name;
67 | }
68 |
69 | public String getFragmentTag(int viewPagerId, int fragmentPosition) {
70 | return "android:switcher:" + viewPagerId + ":" + fragmentPosition;
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/ui/repos/RepoListFragment.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.ui.repos;
2 |
3 | import android.content.Context;
4 | import android.os.Bundle;
5 | import android.support.annotation.Nullable;
6 | import android.support.v4.app.Fragment;
7 | import android.support.v7.widget.LinearLayoutManager;
8 |
9 | import com.yeungeek.monkeyandroid.R;
10 | import com.yeungeek.monkeyandroid.data.model.Language;
11 | import com.yeungeek.monkeyandroid.data.model.Repo;
12 | import com.yeungeek.monkeyandroid.data.model.WrapList;
13 | import com.yeungeek.monkeyandroid.ui.base.adapter.HeaderAndFooterRecyclerViewAdapter;
14 | import com.yeungeek.monkeyandroid.ui.base.view.BaseLceActivity;
15 | import com.yeungeek.monkeyandroid.ui.base.view.BasePageFragment;
16 | import com.yeungeek.monkeyandroid.util.AppCst;
17 |
18 | import javax.inject.Inject;
19 |
20 | /**
21 | * Created by yeungeek on 2016/3/30.
22 | */
23 | public class RepoListFragment extends BasePageFragment, RepoMvpView, RepoPresenter> implements RepoMvpView {
24 | @Inject
25 | RepoPresenter repoPresenter;
26 |
27 | Language language;
28 | private RepoAdapter adapter;
29 | private HeaderAndFooterRecyclerViewAdapter mHeaderAdapter;
30 |
31 | public static Fragment newInstance(Context context, Language language) {
32 | Bundle bundle = new Bundle();
33 | bundle.putSerializable(AppCst.EXTRA_LANGUAGE, language);
34 | return Fragment.instantiate(context, RepoListFragment.class.getName(), bundle);
35 | }
36 |
37 | @Override
38 | public RepoPresenter createPresenter() {
39 | return repoPresenter;
40 | }
41 |
42 | @Override
43 | public void onCreate(@Nullable Bundle savedInstanceState) {
44 | super.onCreate(savedInstanceState);
45 | language = (Language) getArguments().getSerializable(AppCst.EXTRA_LANGUAGE);
46 | }
47 |
48 | @Override
49 | protected void initAdapter() {
50 | adapter = new RepoAdapter(getActivity(), language);
51 |
52 | mHeaderAdapter = new HeaderAndFooterRecyclerViewAdapter(adapter);
53 | recyclerView.setAdapter(mHeaderAdapter);
54 | recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
55 | }
56 |
57 | @Override
58 | protected String getErrorMessage(Throwable e, boolean pullToRefresh) {
59 | return getString(R.string.error_repositories) + "\n" + e.getMessage();
60 | }
61 |
62 | @Override
63 | public void setData(WrapList data) {
64 | mCount = data.getTotal_count();
65 | if (!mLoadMore) {
66 | adapter.addTopAll(data.getItems());
67 | mCurrentSize = data.getItems().size();
68 | } else {
69 | adapter.addAll(data.getItems());
70 | mCurrentSize += data.getItems().size();
71 | }
72 |
73 | checkViewState();
74 | }
75 |
76 | @Override
77 | public void loadData(boolean pullToRefresh) {
78 | getPresenter().listRepos(AppCst.LANGUAGE_PREFIX + language.path, mPage, pullToRefresh);
79 | }
80 |
81 | @Override
82 | protected void injectDependencies() {
83 | super.injectDependencies();
84 | if (getActivity() instanceof BaseLceActivity) {
85 | ((BaseLceActivity) getActivity()).activityComponent().inject(this);
86 | }
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/ui/repos/RepoMvpView.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.ui.repos;
2 |
3 | import com.yeungeek.monkeyandroid.data.model.Repo;
4 | import com.yeungeek.monkeyandroid.data.model.WrapList;
5 | import com.yeungeek.mvp.common.lce.MvpLceView;
6 |
7 | import java.util.List;
8 |
9 | /**
10 | * Created by yeungeek on 2016/3/31.
11 | */
12 | public interface RepoMvpView extends MvpLceView> {
13 | }
14 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/ui/repos/RepoPresenter.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.ui.repos;
2 |
3 | import com.yeungeek.monkeyandroid.data.DataManager;
4 | import com.yeungeek.monkeyandroid.data.model.Repo;
5 | import com.yeungeek.monkeyandroid.data.model.WrapList;
6 | import com.yeungeek.monkeyandroid.ui.base.presenter.MvpLceRxPresenter;
7 | import com.yeungeek.mvp.common.MvpPresenter;
8 |
9 | import javax.inject.Inject;
10 |
11 | import timber.log.Timber;
12 |
13 | /**
14 | * Created by yeungeek on 2016/3/31.
15 | */
16 | public class RepoPresenter extends MvpLceRxPresenter> implements MvpPresenter {
17 | private final DataManager dataManager;
18 |
19 | @Inject
20 | public RepoPresenter(final DataManager dataManager) {
21 | this.dataManager = dataManager;
22 | }
23 |
24 | public void listRepos(final String query, final int page, final boolean pullToRefresh) {
25 | Timber.d("### get list repos query:%s, page: %d", query, page);
26 | subscribe(dataManager.getRepos(query, page), pullToRefresh);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/ui/signin/SignInDialogFragment.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.ui.signin;
2 |
3 | import android.app.AlertDialog;
4 | import android.app.Dialog;
5 | import android.graphics.Bitmap;
6 | import android.graphics.Rect;
7 | import android.net.Uri;
8 | import android.os.Bundle;
9 | import android.support.annotation.NonNull;
10 | import android.support.v4.app.DialogFragment;
11 | import android.view.View;
12 | import android.webkit.WebView;
13 | import android.webkit.WebViewClient;
14 |
15 | import com.yeungeek.monkeyandroid.rxbus.RxBus;
16 | import com.yeungeek.monkeyandroid.rxbus.event.SignInEvent;
17 | import com.yeungeek.monkeyandroid.ui.base.view.BaseLceActivity;
18 |
19 | import javax.inject.Inject;
20 |
21 | import timber.log.Timber;
22 |
23 |
24 | public class SignInDialogFragment extends DialogFragment {
25 | private String url;
26 | private final static String EXTRA_URL = "extra_url";
27 |
28 | @Inject
29 | RxBus rxBus;
30 |
31 | public static SignInDialogFragment newInstance(final String url) {
32 | SignInDialogFragment fragment = new SignInDialogFragment();
33 | Bundle bundle = new Bundle();
34 | bundle.putString(EXTRA_URL, url);
35 | fragment.setArguments(bundle);
36 | return fragment;
37 | }
38 |
39 | @Override
40 | public void onCreate(Bundle savedInstanceState) {
41 | super.onCreate(savedInstanceState);
42 | ((BaseLceActivity) getActivity()).activityComponent().inject(this);
43 | url = getArguments().getString(EXTRA_URL);
44 | }
45 |
46 | @NonNull
47 | @Override
48 | public Dialog onCreateDialog(Bundle savedInstanceState) {
49 | AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
50 | final WebView webView = new WebView(this.getActivity()) {
51 | boolean layoutChangedOnce = false;
52 | @Override
53 | protected void onLayout(boolean changed, int l, int t, int r, int b) {
54 | if (!layoutChangedOnce) {
55 | super.onLayout(changed, l, t, r, b);
56 | layoutChangedOnce = true;
57 | }
58 | }
59 |
60 | @Override
61 | protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
62 | super.onFocusChanged(true, direction, previouslyFocusedRect);
63 | }
64 |
65 | @Override
66 | public boolean onCheckIsTextEditor() {
67 | return true;
68 | }
69 | };
70 |
71 | webView.loadUrl(url);
72 | webView.setFocusable(true);
73 | webView.setFocusableInTouchMode(true);
74 | webView.requestFocus(View.FOCUS_DOWN);
75 | webView.setWebViewClient(new WebViewClient() {
76 | @Override
77 | public void onPageStarted(WebView view, String url, Bitmap favicon) {
78 | super.onPageStarted(view, url, favicon);
79 | }
80 |
81 | @Override
82 | public void onPageFinished(WebView view, String url) {
83 | super.onPageFinished(view, url);
84 | }
85 |
86 | @Override
87 | public boolean shouldOverrideUrlLoading(WebView view, String url) {
88 | Uri uri = Uri.parse(url);
89 | if (uri.getScheme().equals("http")) {
90 | Timber.d("### get url %s",url);
91 | if(null != rxBus && rxBus.hasObservers()){
92 | rxBus.send(new SignInEvent(uri));
93 | }
94 |
95 | SignInDialogFragment.this.dismiss();
96 | return true;
97 | }
98 | return super.shouldOverrideUrlLoading(view, url);
99 | }
100 | });
101 |
102 | webView.requestFocus(View.FOCUS_DOWN);
103 | builder.setView(webView);
104 | return builder.create();
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/ui/trending/TrendingMvpView.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.ui.trending;
2 |
3 | import com.yeungeek.monkeyandroid.data.model.Repo;
4 | import com.yeungeek.mvp.common.lce.MvpLceView;
5 |
6 | import java.util.List;
7 |
8 | /**
9 | * Created by yeungeek on 2016/3/31.
10 | */
11 | public interface TrendingMvpView extends MvpLceView> {
12 | }
13 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/ui/trending/TrendingPresenter.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.ui.trending;
2 |
3 | import com.yeungeek.monkeyandroid.data.DataManager;
4 | import com.yeungeek.monkeyandroid.data.model.Repo;
5 | import com.yeungeek.monkeyandroid.ui.base.presenter.MvpLceRxPresenter;
6 | import com.yeungeek.mvp.common.MvpPresenter;
7 |
8 | import java.util.List;
9 |
10 | import javax.inject.Inject;
11 |
12 | import timber.log.Timber;
13 |
14 | /**
15 | * Created by yeungeek on 2016/3/31.
16 | */
17 | public class TrendingPresenter extends MvpLceRxPresenter> implements MvpPresenter {
18 | private final DataManager dataManager;
19 |
20 | @Inject
21 | public TrendingPresenter(final DataManager dataManager) {
22 | this.dataManager = dataManager;
23 | }
24 |
25 | public void listTrending(final String language, final String since, final boolean pullToRefresh) {
26 | Timber.d("### get list repos language:%s, since: %s", language, since);
27 | subscribe(dataManager.getTrending(language, since), pullToRefresh);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/ui/users/FamousUserFragment.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.ui.users;
2 |
3 | import android.support.v4.app.Fragment;
4 | import android.support.v4.app.FragmentManager;
5 | import android.support.v4.app.FragmentPagerAdapter;
6 | import android.view.View;
7 |
8 | import com.yeungeek.monkeyandroid.R;
9 | import com.yeungeek.monkeyandroid.data.model.Language;
10 | import com.yeungeek.monkeyandroid.ui.base.view.BasePageFragment;
11 | import com.yeungeek.monkeyandroid.ui.base.view.BaseToolbarFragment;
12 | import com.yeungeek.monkeyandroid.util.AppCst;
13 |
14 | import java.util.ArrayList;
15 | import java.util.List;
16 |
17 | /**
18 | * Created by yeungeek on 2016/4/8.
19 | */
20 | public class FamousUserFragment extends BaseToolbarFragment {
21 | private LanguagesPagerAdapter mPagerAdapter;
22 |
23 | @Override
24 | protected void initToolbar() {
25 | getActionBar().setTitle(R.string.menu_title_user);
26 | }
27 |
28 | @Override
29 | protected void initViews() {
30 | super.initViews();
31 |
32 | mPagerAdapter = new LanguagesPagerAdapter(getChildFragmentManager());
33 | getViewPager().setAdapter(mPagerAdapter);
34 | getTabLayout().setupWithViewPager(getViewPager());
35 |
36 | getFloatingActionButton().setOnClickListener(new View.OnClickListener() {
37 | @Override
38 | public void onClick(View v) {
39 | Fragment fragment = getChildFragmentManager().findFragmentByTag(mPagerAdapter.getFragmentTag(R.id.pager, mCurrentPosition));
40 | if (null != fragment && fragment instanceof BasePageFragment) {
41 | ((BasePageFragment) fragment).scrollToTop();
42 | }
43 | }
44 | });
45 | }
46 |
47 | public class LanguagesPagerAdapter extends FragmentPagerAdapter {
48 | List languagesArray = new ArrayList<>();
49 |
50 | public LanguagesPagerAdapter(FragmentManager fm) {
51 | super(fm);
52 | languagesArray.addAll(dataManager.getLanguageHelper().getLanguage());
53 | Language language = new Language(AppCst.USER_CHINA_ALL, AppCst.USER_LOCATION_CHINA);
54 | languagesArray.add(0, language);
55 | }
56 |
57 | @Override
58 | public Fragment getItem(int position) {
59 | return UserListFragment.newInstance(getContext(), languagesArray.get(position));
60 | }
61 |
62 | @Override
63 | public int getCount() {
64 | return languagesArray.size();
65 | }
66 |
67 | @Override
68 | public CharSequence getPageTitle(int position) {
69 | return languagesArray.get(position).name;
70 | }
71 |
72 | public String getFragmentTag(int viewPagerId, int fragmentPosition) {
73 | return "android:switcher:" + viewPagerId + ":" + fragmentPosition;
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/ui/users/UserAdapter.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.ui.users;
2 |
3 | import android.content.Context;
4 | import android.support.v7.widget.RecyclerView;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.widget.ImageView;
9 | import android.widget.TextView;
10 |
11 | import com.bumptech.glide.Glide;
12 | import com.yeungeek.monkeyandroid.R;
13 | import com.yeungeek.monkeyandroid.data.model.User;
14 | import com.yeungeek.monkeyandroid.ui.detail.DetailActivity;
15 |
16 | import java.util.ArrayList;
17 | import java.util.List;
18 |
19 | import butterknife.Bind;
20 | import butterknife.ButterKnife;
21 | import butterknife.OnClick;
22 |
23 | /**
24 | * Created by yeungeek on 2016/4/8.
25 | */
26 | public class UserAdapter extends RecyclerView.Adapter {
27 | private Context mContext;
28 | private List users = new ArrayList<>();
29 | private OnItemClickListener mOnItemClickListener;
30 |
31 | public UserAdapter(final Context context) {
32 | this.mContext = context;
33 | }
34 |
35 | @Override
36 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
37 | View view = LayoutInflater.from(mContext).inflate(R.layout.item_user, parent, false);
38 | UserViewHolder viewHolder = new UserViewHolder(view);
39 | if (null != mOnItemClickListener) {
40 | viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
41 | @Override
42 | public void onClick(View v) {
43 | mOnItemClickListener.onItemClick(v);
44 | }
45 | });
46 | }
47 | return viewHolder;
48 | }
49 |
50 | @Override
51 | public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
52 | final User user = users.get(position);
53 | UserViewHolder viewHolder = (UserViewHolder) holder;
54 | viewHolder.user = user;
55 |
56 | viewHolder.login.setText(user.getLogin());
57 | Glide.with(mContext).load(user.getAvatarUrl()).into(viewHolder.userAvatar);
58 | }
59 |
60 | @Override
61 | public int getItemCount() {
62 | return users.size();
63 | }
64 |
65 | public void addAll(final List list) {
66 | users.addAll(list);
67 | }
68 |
69 | public void addTopAll(final List list) {
70 | users.clear();
71 | users.addAll(list);
72 | notifyDataSetChanged();
73 | }
74 |
75 | public class UserViewHolder extends RecyclerView.ViewHolder {
76 | User user;
77 |
78 | @Bind(R.id.id_user_login)
79 | TextView login;
80 | @Bind(R.id.id_user_avatar)
81 | ImageView userAvatar;
82 |
83 | // @OnClick(R.id.id_user_card)
84 | // public void onItemClick() {
85 | // mContext.startActivity(DetailActivity.getStartIntent(mContext, user));
86 | // }
87 |
88 | public UserViewHolder(View itemView) {
89 | super(itemView);
90 | ButterKnife.bind(this, itemView);
91 | }
92 | }
93 |
94 | public User getUser(int position) {
95 | return users.get(position);
96 | }
97 |
98 | public UserAdapter setOnItemClickListener(OnItemClickListener onItemClickListener) {
99 | this.mOnItemClickListener = onItemClickListener;
100 | return this;
101 | }
102 |
103 | public static interface OnItemClickListener {
104 | void onItemClick(View view);
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/ui/users/UserMvpView.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.ui.users;
2 |
3 | import com.yeungeek.monkeyandroid.data.model.User;
4 | import com.yeungeek.monkeyandroid.data.model.WrapList;
5 | import com.yeungeek.mvp.common.lce.MvpLceView;
6 |
7 | /**
8 | * Created by yeungeek on 2016/4/8.
9 | */
10 | public interface UserMvpView extends MvpLceView> {
11 | }
12 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/ui/users/UserPresenter.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.ui.users;
2 |
3 | import com.yeungeek.monkeyandroid.data.DataManager;
4 | import com.yeungeek.monkeyandroid.data.model.User;
5 | import com.yeungeek.monkeyandroid.data.model.WrapList;
6 | import com.yeungeek.monkeyandroid.ui.base.presenter.MvpLceRxPresenter;
7 | import com.yeungeek.mvp.common.MvpPresenter;
8 |
9 | import javax.inject.Inject;
10 |
11 | import timber.log.Timber;
12 |
13 | /**
14 | * Created by yeungeek on 2016/4/8.
15 | */
16 | public class UserPresenter extends MvpLceRxPresenter> implements MvpPresenter {
17 | private final DataManager dataManager;
18 |
19 | @Inject
20 | public UserPresenter(final DataManager dataManager) {
21 | this.dataManager = dataManager;
22 | }
23 |
24 | public void listUsers(final String query, final int page, final boolean pullToRefresh) {
25 | Timber.d("### get list users query:%s, page: %d", query, page);
26 | subscribe(dataManager.getUsers(query, page), pullToRefresh);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/util/EncodingUtil.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.util;
2 |
3 | import android.util.Base64;
4 |
5 | /**
6 | * Created by yeungeek on 2016/4/13.
7 | */
8 | public class EncodingUtil {
9 | public static final byte[] fromBase64(String content) {
10 | return Base64.decode(content, Base64.DEFAULT);
11 | }
12 |
13 | public static final String toBase64(final byte[] content) {
14 | return Base64.encodeToString(content, Base64.DEFAULT);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/util/HttpStatus.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.util;
2 |
3 | /**
4 | * Created by yeungeek on 2016/4/8.
5 | */
6 | public interface HttpStatus {
7 | int HTTP_SWITCHING_PROTOCOLS = 101;
8 | int HTTP_OK = 200;
9 | int HTTP_NO_CONTENT = 204;
10 | int HTTP_UNAUTHORIZED = 401;
11 | int HTTP_NOT_FOUND = 404;
12 | int HTTP_INTERNAL_SERVER_ERROR = 500;
13 | int HTTP_NOT_IMPLEMENTED = 501;
14 | }
15 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/util/ImageSize.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.util;
2 |
3 | /**
4 | * Created by yeungeek on 2016/4/3.
5 | */
6 | public interface ImageSize {
7 | String AVATAR_120 = "&s=120";
8 | }
9 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/views/widget/ScrollAwareFABBehavior.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.views.widget;
2 |
3 | import android.content.Context;
4 | import android.support.design.widget.CoordinatorLayout;
5 | import android.support.design.widget.FloatingActionButton;
6 | import android.support.v4.view.ViewCompat;
7 | import android.util.AttributeSet;
8 | import android.view.View;
9 |
10 | /**
11 | * Created by yeungeek on 2016/4/15.
12 | *
13 | * @see 'https://github.com/ianhanniballake/cheesesquare/blob/92bcf7c8b57459051424cd512a032c12d24a41b3/app/src/main/java/com/support/android/designlibdemo/ScrollAwareFABBehavior.java'
14 | */
15 | public class ScrollAwareFABBehavior extends FloatingActionButton.Behavior {
16 | public ScrollAwareFABBehavior(Context context, AttributeSet attrs) {
17 | super();
18 | }
19 |
20 | @Override
21 | public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, FloatingActionButton child, View directTargetChild, View target, int nestedScrollAxes) {
22 | return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL ||
23 | super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target,
24 | nestedScrollAxes);
25 | }
26 |
27 | @Override
28 | public void onNestedScroll(CoordinatorLayout coordinatorLayout, FloatingActionButton child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
29 | if (dyConsumed > 0 && child.getVisibility() == View.VISIBLE) {
30 | child.hide();
31 | } else if (dyConsumed < 0 && child.getVisibility() != View.VISIBLE) {
32 | child.show();
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yeungeek/monkeyandroid/views/widget/ScrollOffBottomBehavior.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.views.widget;
2 |
3 | import android.animation.ObjectAnimator;
4 | import android.content.Context;
5 | import android.support.design.widget.CoordinatorLayout;
6 | import android.support.design.widget.FloatingActionButton;
7 | import android.support.v4.view.ViewCompat;
8 | import android.util.AttributeSet;
9 | import android.view.View;
10 |
11 | /**
12 | * Created by yeungeek on 2016/4/15.
13 | */
14 | public class ScrollOffBottomBehavior extends FloatingActionButton.Behavior {
15 | private int mViewHeight;
16 | private ObjectAnimator mAnimator;
17 |
18 | public ScrollOffBottomBehavior(Context context, AttributeSet attrs) {
19 | super();
20 | }
21 |
22 | @Override
23 | public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, FloatingActionButton child, View directTargetChild, View target, int nestedScrollAxes) {
24 | return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL ||
25 | super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target,
26 | nestedScrollAxes);
27 | }
28 |
29 | @Override
30 | public void onNestedScroll(CoordinatorLayout coordinatorLayout, FloatingActionButton child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
31 | if (dyConsumed > 0 && child.getVisibility() == View.VISIBLE) {
32 | child.show();
33 | } else if (dyConsumed < 0 && child.getVisibility() != View.VISIBLE) {
34 | child.hide();
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_about.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeungeek/monkey-android/f1bc5132b7571766b26d1b07645ffe9f0de5ab81/app/src/main/res/drawable-xhdpi/ic_about.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_arrow_back.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeungeek/monkey-android/f1bc5132b7571766b26d1b07645ffe9f0de5ab81/app/src/main/res/drawable-xhdpi/ic_arrow_back.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_arrow_drop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeungeek/monkey-android/f1bc5132b7571766b26d1b07645ffe9f0de5ab81/app/src/main/res/drawable-xhdpi/ic_arrow_drop.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_arrow_upward.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeungeek/monkey-android/f1bc5132b7571766b26d1b07645ffe9f0de5ab81/app/src/main/res/drawable-xhdpi/ic_arrow_upward.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_avatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeungeek/monkey-android/f1bc5132b7571766b26d1b07645ffe9f0de5ab81/app/src/main/res/drawable-xhdpi/ic_avatar.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_favorite.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeungeek/monkey-android/f1bc5132b7571766b26d1b07645ffe9f0de5ab81/app/src/main/res/drawable-xhdpi/ic_favorite.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_favorite_border.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeungeek/monkey-android/f1bc5132b7571766b26d1b07645ffe9f0de5ab81/app/src/main/res/drawable-xhdpi/ic_favorite_border.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_menu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeungeek/monkey-android/f1bc5132b7571766b26d1b07645ffe9f0de5ab81/app/src/main/res/drawable-xhdpi/ic_menu.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_more_vert.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeungeek/monkey-android/f1bc5132b7571766b26d1b07645ffe9f0de5ab81/app/src/main/res/drawable-xhdpi/ic_more_vert.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_person.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeungeek/monkey-android/f1bc5132b7571766b26d1b07645ffe9f0de5ab81/app/src/main/res/drawable-xhdpi/ic_person.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_person_add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeungeek/monkey-android/f1bc5132b7571766b26d1b07645ffe9f0de5ab81/app/src/main/res/drawable-xhdpi/ic_person_add.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_repo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeungeek/monkey-android/f1bc5132b7571766b26d1b07645ffe9f0de5ab81/app/src/main/res/drawable-xhdpi/ic_repo.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_retry.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeungeek/monkey-android/f1bc5132b7571766b26d1b07645ffe9f0de5ab81/app/src/main/res/drawable-xhdpi/ic_retry.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_trending.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeungeek/monkey-android/f1bc5132b7571766b26d1b07645ffe9f0de5ab81/app/src/main/res/drawable-xhdpi/ic_trending.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_users.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeungeek/monkey-android/f1bc5132b7571766b26d1b07645ffe9f0de5ab81/app/src/main/res/drawable-xhdpi/ic_users.png
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_about.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
23 |
24 |
31 |
32 |
39 |
40 |
41 |
42 |
43 |
47 |
48 |
53 |
54 |
55 |
62 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_detail.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
11 |
12 |
16 |
17 |
18 |
19 |
20 |
21 |
25 |
26 |
27 |
34 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_repos.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
15 |
16 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_hot_repos.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_pull_refresh_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
14 |
15 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_repo.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
16 |
17 |
24 |
25 |
31 |
32 |
37 |
38 |
44 |
45 |
51 |
52 |
53 |
68 |
69 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_user.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
17 |
18 |
24 |
25 |
33 |
34 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_appbar.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
22 |
23 |
29 |
30 |
31 |
32 |
37 |
38 |
45 |
46 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_common_list_footer.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
14 |
15 |
20 |
21 |
26 |
27 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_common_list_footer_end.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_common_list_footer_loading.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
14 |
15 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_common_list_footer_network_error.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_drawer_header.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
14 |
15 |
21 |
22 |
28 |
29 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_spinner_item_actionbar.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_spinner_item_dropdown.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_trending_repos.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/view_error.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/view_loading.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_drawer.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
12 |
16 |
17 |
18 | -
21 |
22 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
5 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeungeek/monkey-android/f1bc5132b7571766b26d1b07645ffe9f0de5ab81/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_cloud_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeungeek/monkey-android/f1bc5132b7571766b26d1b07645ffe9f0de5ab81/app/src/main/res/mipmap-xhdpi/ic_cloud_off.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeungeek/monkey-android/f1bc5132b7571766b26d1b07645ffe9f0de5ab81/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeungeek/monkey-android/f1bc5132b7571766b26d1b07645ffe9f0de5ab81/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeungeek/monkey-android/f1bc5132b7571766b26d1b07645ffe9f0de5ab81/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/values-v21/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
16 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/app/src/main/res/values/attrs_triangleLabelview.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FF3F51B5
4 | #FF303F9F
5 | #FFFF4081
6 |
7 |
8 | #FF000000
9 | #FF27D34D
10 | #FF2A91BD
11 | #FFFF9D2F
12 | #FFFF432F
13 | #FFFFFFFF
14 | #FFC0C0C0
15 |
16 |
17 | @color/black
18 | @color/blue_300
19 |
20 | #8A000000
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 | 16dp
6 |
7 |
8 | 18sp
9 | 16sp
10 | 14sp
11 | 12sp
12 | 9sp
13 |
14 |
15 | 40dp
16 | 24dp
17 | 14dp
18 | 10dp
19 | 4dp
20 |
21 |
22 | 72dp
23 | 60dp
24 | 40dp
25 | 32dp
26 | 20dp
27 |
28 |
29 | 20dp
30 | 16dp
31 | 15dp
32 | 10dp
33 | 8dp
34 | 4dp
35 | 2dp
36 |
37 |
38 | 128dp
39 | 64dp
40 | 48dp
41 | 30dp
42 | 15dp
43 | 10dp
44 | 8dp
45 | 4dp
46 | 2dp
47 |
48 | 168dp
49 |
50 |
51 | 230dp
52 | 64dp
53 | 48dp
54 |
55 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Monkey
3 | Monkey For Android
4 |
5 |
6 | Network error
7 | Error while loading repositories
8 | Error while loading users
9 | Please login!
10 |
11 |
12 | win
13 |
14 | Click to reload
15 | Already ended
16 | Loading...
17 |
18 | username
19 | email
20 | Home
21 | Famous user
22 | Hot repo
23 | Today
24 | This Week
25 | This Month
26 |
27 | star: %1$d
28 | fork: %1$d
29 |
30 | Following(%1$d)
31 | Followers(%1$d)
32 |
33 | Enter
34 | Settings
35 |
36 |
37 |
38 |
39 | @string/title_user
40 | @string/title_repo
41 | Trending
42 | About
43 |
44 | Monkey android is a GitHub third party client, show the rank of users and repositories,trending. Base on Material Design,use MVP pattern
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
15 |
16 |
17 |
18 |
19 |
20 |
26 |
27 |
31 |
32 |
37 |
38 |
39 |
43 |
44 |
48 |
49 |
53 |
54 |
58 |
59 |
63 |
64 |
68 |
69 |
72 |
73 |
76 |
77 |
--------------------------------------------------------------------------------
/app/src/test/java/com/yeungeek/monkeyandroid/DataManagerTest.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid;
2 |
3 | import com.yeungeek.monkeyandroid.data.DataManager;
4 | import com.yeungeek.monkeyandroid.data.local.DatabaseHelper;
5 | import com.yeungeek.monkeyandroid.data.local.LanguageHelper;
6 | import com.yeungeek.monkeyandroid.data.local.PreferencesHelper;
7 | import com.yeungeek.monkeyandroid.data.remote.GithubApi;
8 | import com.yeungeek.monkeyandroid.data.remote.SimpleApi;
9 | import com.yeungeek.monkeyandroid.rxbus.RxBus;
10 |
11 | import org.junit.Before;
12 | import org.junit.Test;
13 | import org.junit.runner.RunWith;
14 | import org.mockito.Mock;
15 | import org.mockito.Mockito;
16 | import org.mockito.runners.MockitoJUnitRunner;
17 |
18 | import rx.Observable;
19 |
20 | /**
21 | * Created by yeungeek on 2016/4/27.
22 | */
23 | @RunWith(MockitoJUnitRunner.class)
24 | public class DataManagerTest {
25 | @Mock
26 | GithubApi mGithubApi;
27 | @Mock
28 | SimpleApi mSimpleApi;
29 | @Mock
30 | RxBus mRxBus;
31 | @Mock
32 | PreferencesHelper mPreferencesHelper;
33 | @Mock
34 | DatabaseHelper mDatabaseHelper;
35 | @Mock
36 | LanguageHelper mLanguageHelper;
37 |
38 | DataManager mDataManager;
39 | MonkeyApplication mApplication;
40 |
41 | @Before
42 | public void setUp() {
43 | mApplication = Mockito.mock(MonkeyApplication.class);
44 | mDataManager = new DataManager(mApplication, mGithubApi, mSimpleApi, mRxBus, mPreferencesHelper, mDatabaseHelper, mLanguageHelper);
45 | }
46 |
47 | @Test
48 | public void clearTables() {
49 | Mockito.doReturn(Observable.empty())
50 | .when(mDatabaseHelper)
51 | .clearTables();
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/app/src/test/java/com/yeungeek/monkeyandroid/EncodingUtilTest.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid;
2 |
3 | import com.yeungeek.monkeyandroid.util.EncodingUtil;
4 |
5 | import org.junit.Assert;
6 | import org.junit.Test;
7 |
8 | /**
9 | * Created by yeungeek on 2016/4/24.
10 | */
11 | public class EncodingUtilTest {
12 | @Test
13 | public void testFromBase64() throws Exception {
14 | String str = "YW5kcm9pZA==";
15 | Assert.assertEquals(null, EncodingUtil.fromBase64(str));
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/app/src/test/java/com/yeungeek/monkeyandroid/PreferencesHelperTest.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid;
2 |
3 | import com.yeungeek.monkeyandroid.data.local.PreferencesHelper;
4 | import com.yeungeek.monkeyandroid.util.DefaultConfig;
5 |
6 | import org.junit.Assert;
7 | import org.junit.Before;
8 | import org.junit.Test;
9 | import org.junit.runner.RunWith;
10 | import org.robolectric.RobolectricGradleTestRunner;
11 | import org.robolectric.RuntimeEnvironment;
12 | import org.robolectric.annotation.Config;
13 |
14 | /**
15 | * Created by yeungeek on 2016/4/25.
16 | */
17 |
18 | @RunWith(RobolectricGradleTestRunner.class)
19 | @Config(constants = BuildConfig.class, sdk = DefaultConfig.EMULATE_SDK)
20 | public class PreferencesHelperTest {
21 | private PreferencesHelper mPreferencesHelper =
22 | new PreferencesHelper(RuntimeEnvironment.application);
23 |
24 | @Before
25 | public void setUp() {
26 | mPreferencesHelper.clear();
27 | }
28 |
29 | @Test
30 | public void testPutGetAccessToken() {
31 | String token = "token";
32 | mPreferencesHelper.putAccessToken(token);
33 | Assert.assertEquals(token, mPreferencesHelper.getAccessToken());
34 |
35 |
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/app/src/test/java/com/yeungeek/monkeyandroid/util/DefaultConfig.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.monkeyandroid.util;
2 |
3 | /**
4 | * Created by yeungeek on 2016/4/25.
5 | */
6 | public class DefaultConfig {
7 | //The api level that Roboelectric will use to run the unit tests
8 | public static final int EMULATE_SDK = 21;
9 | }
10 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | apply from: 'buildsystem/dependencies.gradle'
3 |
4 | buildscript {
5 | repositories {
6 | jcenter()
7 | maven {
8 | url 'https://maven.google.com/'
9 | name 'Google'
10 | }
11 | }
12 | dependencies {
13 | classpath 'com.android.tools.build:gradle:2.2.2'
14 | classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
15 |
16 | // NOTE: Do not place your application dependencies here; they belong
17 | // in the individual module build.gradle files
18 | classpath "com.fernandocejas.frodo:frodo-plugin:0.8.2"
19 | classpath "net.rdrei.android.buildtimetracker:gradle-plugin:0.5.+"
20 | classpath 'com.tencent.bugly:symtabfileuploader:1.3.9'
21 | classpath 'org.kt3k.gradle.plugin:coveralls-gradle-plugin:2.6.3'
22 | //play
23 | classpath 'com.google.gms:google-services:3.0.0'
24 | }
25 | }
26 |
27 | task clean(type: Delete) {
28 | delete rootProject.buildDir
29 | }
30 |
31 | task wrapper(type: Wrapper) {
32 | description 'Creates the gradle wrapper.'
33 | gradleVersion '2.10'
34 | }
--------------------------------------------------------------------------------
/buildsystem/artifacts.gradle:
--------------------------------------------------------------------------------
1 | // applicationName property to gradle.properties
2 | android.applicationVariants.all { variant ->
3 | def appName
4 | if (project.hasProperty("applicationName")) {
5 | appName = applicationName
6 | } else {
7 | appName = project.name
8 | }
9 |
10 | variant.outputs.each { output ->
11 | def newApkName
12 | if (output.zipAlign) {
13 | newApkName = "${appName}-${output.baseName}-${variant.versionName}.apk"
14 | } else {
15 | newApkName = "${appName}-${output.baseName}-${variant.versionName}-unaligned.apk"
16 | }
17 | output.outputFile = new File(output.outputFile.parent, newApkName)
18 | }
19 | }
--------------------------------------------------------------------------------
/buildsystem/jacoco.gradle:
--------------------------------------------------------------------------------
1 | //https://blog.gouline.net/code-coverage-on-android-with-jacoco-92ec90c9355e#.v34ksl11k
2 | //https://github.com/bumptech/glide
3 | //https://github.com/kt3k/coveralls-gradle-plugin
4 | apply plugin: 'jacoco'
5 |
6 | jacoco {
7 | toolVersion = "0.7.5.201505241946"
8 | }
9 |
10 | project.afterEvaluate {
11 | // Grab all build types and product flavors
12 | def buildTypes = android.buildTypes.collect { type -> type.name }
13 | def productFlavors = android.productFlavors.collect { flavor -> flavor.name }
14 |
15 | // When no product flavors defined, use empty
16 | if (!productFlavors) productFlavors.add('')
17 |
18 | productFlavors.each { productFlavorName ->
19 | buildTypes.each { buildTypeName ->
20 | def sourceName, sourcePath
21 | if (!productFlavorName) {
22 | sourceName = sourcePath = "${buildTypeName}"
23 | } else {
24 | sourceName = "${productFlavorName}${buildTypeName.capitalize()}"
25 | sourcePath = "${productFlavorName}/${buildTypeName}"
26 | }
27 | def testTaskName = "test${sourceName.capitalize()}UnitTest"
28 |
29 | // Create coverage task of form 'testFlavorTypeCoverage' depending on 'testFlavorTypeUnitTest'
30 | task "${testTaskName}Coverage"(type: JacocoReport, dependsOn: "$testTaskName") {
31 | group = "Reporting"
32 | description = "Generate Jacoco coverage reports on the ${sourceName.capitalize()} build."
33 |
34 | classDirectories = fileTree(
35 | dir: "${project.buildDir}/intermediates/classes/${sourcePath}",
36 | excludes: ['**/R.class',
37 | '**/R$*.class',
38 | '**/*$ViewInjector*.*',
39 | '**/*$ViewBinder*.*',
40 | '**/BuildConfig.*',
41 | '**/Manifest*.*']
42 | )
43 |
44 | def coverageSourceDirs = [
45 | "src/main/java",
46 | "src/$productFlavorName/java",
47 | "src/$buildTypeName/java"
48 | ]
49 | additionalSourceDirs = files(coverageSourceDirs)
50 | sourceDirectories = files(coverageSourceDirs)
51 | executionData = files("${project.buildDir}/jacoco/${testTaskName}.exec")
52 |
53 | reports {
54 | xml.enabled = true
55 | html.enabled = true
56 | }
57 | }
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/buildsystem/maven-push-java-lib.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Chris Banes
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | apply plugin: 'maven'
18 | apply plugin: 'signing'
19 |
20 | def isReleaseBuild() {
21 | return VERSION_NAME.contains("SNAPSHOT") == false
22 | }
23 |
24 | def getReleaseRepositoryUrl() {
25 | return hasProperty('RELEASE_REPOSITORY_URL') ? RELEASE_REPOSITORY_URL :
26 | "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
27 | }
28 |
29 | def getSnapshotRepositoryUrl() {
30 | return hasProperty('SNAPSHOT_REPOSITORY_URL') ? SNAPSHOT_REPOSITORY_URL :
31 | "https://oss.sonatype.org/content/repositories/snapshots/"
32 | }
33 |
34 | def getRepositoryUsername() {
35 | return hasProperty('NEXUS_USERNAME') ? NEXUS_USERNAME : ""
36 | }
37 |
38 | def getRepositoryPassword() {
39 | return hasProperty('NEXUS_PASSWORD') ? NEXUS_PASSWORD : ""
40 | }
41 |
42 | afterEvaluate { project ->
43 | uploadArchives {
44 | repositories {
45 | mavenDeployer {
46 | beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
47 |
48 | pom.groupId = GROUP
49 | pom.artifactId = POM_ARTIFACT_ID
50 | pom.version = VERSION_NAME
51 |
52 | repository(url: getReleaseRepositoryUrl()) {
53 | authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
54 | }
55 | snapshotRepository(url: getSnapshotRepositoryUrl()) {
56 | authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
57 | }
58 |
59 | pom.project {
60 | name POM_NAME
61 | packaging POM_PACKAGING
62 | description POM_DESCRIPTION
63 | url POM_URL
64 |
65 | scm {
66 | url POM_SCM_URL
67 | connection POM_SCM_CONNECTION
68 | developerConnection POM_SCM_DEV_CONNECTION
69 | }
70 |
71 | licenses {
72 | license {
73 | name POM_LICENCE_NAME
74 | url POM_LICENCE_URL
75 | distribution POM_LICENCE_DIST
76 | }
77 | }
78 |
79 | developers {
80 | developer {
81 | id POM_DEVELOPER_ID
82 | name POM_DEVELOPER_NAME
83 | }
84 | }
85 | }
86 |
87 |
88 | // Resolve dependencies to other modules
89 | pom.whenConfigured { pom ->
90 | pom.dependencies.findAll { dep -> dep.groupId == rootProject.name }.collect { dep ->
91 | dep.groupId = pom.groupId = project.GROUP
92 | dep.version = pom.version = project.VERSION_NAME
93 | }
94 | }
95 | }
96 | }
97 | }
98 |
99 | signing {
100 | required { isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") }
101 | sign configurations.archives
102 | }
103 |
104 | /*
105 | task javadocJar(type: Jar) {
106 | classifier = 'javadoc'
107 | from javadoc
108 |
109 | if (JavaVersion.current().isJava8Compatible()) {
110 | allprojects {
111 | tasks.withType(Javadoc) {
112 | options.addStringOption('Xdoclint:none', '-quiet')
113 | }
114 | }
115 | }
116 |
117 | }
118 |
119 | task sourceJar (type : Jar) {
120 | classifier = 'sources'
121 | from sourceSets.main.allSource
122 | }
123 |
124 | artifacts {
125 | archives javadocJar
126 | archives sourceJar
127 | }
128 |
129 | */
130 |
131 | }
--------------------------------------------------------------------------------
/config/keystore/debug.keystore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeungeek/monkey-android/f1bc5132b7571766b26d1b07645ffe9f0de5ab81/config/keystore/debug.keystore
--------------------------------------------------------------------------------
/config/keystore/release.keystore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeungeek/monkey-android/f1bc5132b7571766b26d1b07645ffe9f0de5ab81/config/keystore/release.keystore
--------------------------------------------------------------------------------
/config/quality/findbugs/android-exclude-filter.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/config/quality/pmd/pmd-ruleset.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 | Custom ruleset for ribot Android application
8 |
9 | .*/R.java
10 | .*/gen/.*
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/config/quality/quality.gradle:
--------------------------------------------------------------------------------
1 | /**
2 | * Set up Checkstyle, Findbugs and PMD to perform extensive code analysis.
3 | *
4 | * Gradle tasks added:
5 | * - checkstyle
6 | * - findbugs
7 | * - pmd
8 | *
9 | * The three tasks above are added as dependencies of the check task so running check will
10 | * run all of them.
11 | *
12 | * @see https://github.com/checkstyle/checkstyle
13 | */
14 |
15 | apply plugin: 'checkstyle'
16 | apply plugin: 'findbugs'
17 | apply plugin: 'pmd'
18 |
19 | dependencies {
20 | checkstyle 'com.puppycrawl.tools:checkstyle:6.15'
21 | }
22 |
23 | def qualityConfigDir = "$project.rootDir/config/quality";
24 | def reportsDir = "$project.buildDir/reports"
25 |
26 | check.dependsOn 'checkstyle', 'findbugs'//, 'pmd'
27 |
28 | task checkstyle(type: Checkstyle, group: 'Verification', description: 'Runs code style checks') {
29 | configFile file("$qualityConfigDir/checkstyle/checkstyle-config.xml")
30 | source 'src'
31 | include '**/*.java'
32 |
33 | reports {
34 | xml.enabled = true
35 | xml {
36 | destination "$reportsDir/checkstyle/checkstyle.xml"
37 | }
38 | }
39 |
40 | classpath = files( )
41 | }
42 |
43 | task findbugs(type: FindBugs,
44 | group: 'Verification',
45 | description: 'Inspect java bytecode for bugs',
46 | dependsOn: ['compileInternalDebugSources','compileInternalReleaseSources']) {
47 |
48 | ignoreFailures = false
49 | effort = "max"
50 | reportLevel = "high"
51 | excludeFilter = new File("$qualityConfigDir/findbugs/android-exclude-filter.xml")
52 | classes = files("$project.rootDir/app/build/intermediates/classes")
53 |
54 | source 'src'
55 | include '**/*.java'
56 | exclude '**/gen/**'
57 |
58 | reports {
59 | xml.enabled = true
60 | html.enabled = false
61 | xml {
62 | destination "$reportsDir/findbugs/findbugs.xml"
63 | }
64 | html {
65 | destination "$reportsDir/findbugs/findbugs.html"
66 | }
67 | }
68 |
69 | classpath = files()
70 | }
71 |
72 |
73 | task pmd(type: Pmd, group: 'Verification', description: 'Inspect sourcecode for bugs') {
74 | ruleSetFiles = files("$qualityConfigDir/pmd/pmd-ruleset.xml")
75 | ignoreFailures = false
76 | ruleSets = []
77 |
78 | source 'src'
79 | include '**/*.java'
80 | exclude '**/gen/**'
81 |
82 | reports {
83 | xml.enabled = true
84 | html.enabled = true
85 | xml {
86 | destination "$reportsDir/pmd/pmd.xml"
87 | }
88 | html {
89 | destination "$reportsDir/pmd/pmd.html"
90 | }
91 | }
92 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
19 |
20 | #http://tools.android.com/tech-docs/new-build-system/gradle-experimental
21 | android.useDeprecatedNdk=true
22 |
23 | VERSION_NAME=1.0
24 | VERSION_CODE=1
25 | GROUP=com.yeungeek.monkeyandroid
26 | applicationName= Monkey
27 |
28 | POM_DESCRIPTION=Monkey for Android
29 | POM_URL=https://github.com/yeungeek/monkey-android
30 | POM_SCM_URL=https://github.com/yeungeek/monkey-android
31 | POM_SCM_CONNECTION=scm:git@github.com:yeungeek/monkey-android.git
32 | POM_SCM_DEV_CONNECTION=scm:git@github.com:yeungeek/monkey-android.git
33 | POM_LICENCE_NAME=The Apache Software License, Version 2.0
34 | POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt
35 | POM_LICENCE_DIST=repo
36 | POM_DEVELOPER_ID=yeungeek
37 | POM_DEVELOPER_NAME=yeungeek
38 |
39 | # bugly
40 | BUGLY_APPID=900018605
41 | BUGLY_APPKEY=pxz0zlygwYavlJ4y
42 |
43 | # ads
44 | BANNER_AD_UNIT_ID_DEBUG=ca-app-pub-4106776683609657/2279239023
45 | BANNER_AD_UNIT_ID_RELEASE=ca-app-pub-4106776683609657/9302978224
46 |
47 | ###############################################################################
48 | # App variables.
49 | ###############################################################################
50 | monkeyAppKeystoreDebugLocation = ../config/keystore/debug.keystore
51 | monkeyAppDebugKeyAlias = androiddebugkey
52 | monkeyAppDebugStorePassword = android
53 | monkeyAppDebugKeyPassword = android
54 |
55 | # The location of the keystore, alias and passwords used when creating a release build. The values
56 | # below are just defaults, these will need to be set to your own values. Make sure you generate a
57 | # new keystore and place it under the keystore folder or point this to the location of your release
58 | # keystore.
59 | monkeyAppKeystoreReleaseLocation = ../config/keystore/release.keystore
60 | monkeyAppReleaseKeyAlias = android
61 | monkeyAppReleaseStorePassword = android
62 | monkeyAppReleaseKeyPassword = android
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeungeek/monkey-android/f1bc5132b7571766b26d1b07645ffe9f0de5ab81/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Sep 28 10:17:05 CST 2016
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/images/fir.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeungeek/monkey-android/f1bc5132b7571766b26d1b07645ffe9f0de5ab81/images/fir.png
--------------------------------------------------------------------------------
/images/monkey.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeungeek/monkey-android/f1bc5132b7571766b26d1b07645ffe9f0de5ab81/images/monkey.gif
--------------------------------------------------------------------------------
/images/preview1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeungeek/monkey-android/f1bc5132b7571766b26d1b07645ffe9f0de5ab81/images/preview1.png
--------------------------------------------------------------------------------
/images/preview2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeungeek/monkey-android/f1bc5132b7571766b26d1b07645ffe9f0de5ab81/images/preview2.png
--------------------------------------------------------------------------------
/images/preview3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeungeek/monkey-android/f1bc5132b7571766b26d1b07645ffe9f0de5ab81/images/preview3.png
--------------------------------------------------------------------------------
/mvp/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/mvp/README.md:
--------------------------------------------------------------------------------
1 | ## MVP based architecture
2 | github: https://github.com/sockeqwe/mosby
--------------------------------------------------------------------------------
/mvp/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion rootProject.ext.compileSdkVersion
5 | buildToolsVersion rootProject.ext.buildToolsVersion
6 |
7 | defaultConfig {
8 | minSdkVersion rootProject.ext.minSdk
9 | targetSdkVersion rootProject.ext.targetSdk
10 | versionCode 1
11 | versionName "1.0"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | }
20 |
21 | dependencies {
22 | compile fileTree(dir: 'libs', include: ['*.jar'])
23 | compile supportDependencies.appcompat
24 |
25 | // Test
26 | testCompile domainTestDependencies.junit
27 | }
28 |
--------------------------------------------------------------------------------
/mvp/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in E:\dev\Android\sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/mvp/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/mvp/src/main/java/com/yeungeek/mvp/common/Defaults.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.mvp.common;
2 |
3 | import java.util.HashMap;
4 | import java.util.Map;
5 |
6 | import static java.util.Collections.unmodifiableMap;
7 |
8 |
9 | final class Defaults {
10 | private static final Map, Object> DEFAULTS =
11 | unmodifiableMap(new HashMap, Object>() {
12 | {
13 | put(Boolean.TYPE, false);
14 | put(Byte.TYPE, (byte) 0);
15 | put(Character.TYPE, '\000');
16 | put(Double.TYPE, 0.0d);
17 | put(Float.TYPE, 0.0f);
18 | put(Integer.TYPE, 0);
19 | put(Long.TYPE, 0L);
20 | put(Short.TYPE, (short) 0);
21 | }
22 | });
23 |
24 | private Defaults() {
25 | // no instances
26 | }
27 |
28 | @SuppressWarnings("unchecked")
29 | public static T defaultValue(Class type) {
30 | return (T) DEFAULTS.get(type);
31 | }
32 | }
--------------------------------------------------------------------------------
/mvp/src/main/java/com/yeungeek/mvp/common/MvpBasePresenter.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.mvp.common;
2 |
3 | import android.support.annotation.Nullable;
4 |
5 | import java.lang.ref.WeakReference;
6 |
7 | /**
8 | * A base implementation of a {@link MvpPresenter} that uses a WeakReference for referring
9 | * to the attached view.
10 | */
11 | public class MvpBasePresenter implements MvpPresenter {
12 |
13 | private WeakReference viewRef;
14 |
15 | @Override
16 | public void attachView(V view) {
17 | viewRef = new WeakReference(view);
18 | }
19 |
20 | @Override
21 | public void detachView(boolean retainInstance) {
22 | if (null != viewRef) {
23 | viewRef.clear();
24 | viewRef = null;
25 | }
26 | }
27 |
28 | @Nullable
29 | public V getView() {
30 | return null == viewRef ? null : viewRef.get();
31 | }
32 |
33 | public boolean isViewAttached() {
34 | return viewRef != null && viewRef.get() != null;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/mvp/src/main/java/com/yeungeek/mvp/common/MvpNullObjectBasePresenter.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.mvp.common;
2 |
3 | import java.lang.reflect.ParameterizedType;
4 | import java.lang.reflect.Type;
5 |
6 | /**
7 | * A {@link MvpPresenter} implmenetation that implements the null
8 | * object pattern for the attached mvp view. So whenever the view gets detached from this
9 | * presenter by calling{@link #detachView(boolean)}, a new "null object" view gets dynamically
10 | * instantiated by using reflections and set as the current
11 | * view (instead of null). The new "null object" view simply does nothing. This avoids null pointer
12 | * exceptions and checks like {@code if (getView() != null)}
13 | */
14 | public class MvpNullObjectBasePresenter implements MvpPresenter {
15 | private V view;
16 |
17 | @Override
18 | public void attachView(V view) {
19 | this.view = view;
20 | }
21 |
22 | @Override
23 | public void detachView(boolean retainInstance) {
24 | if (null != view) {
25 | Type[] types =
26 | ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments();
27 |
28 | final Class viewClass = (Class) types[0];
29 | view = NoOp.of(viewClass);
30 | }
31 | }
32 |
33 | public V getView() {
34 | if (null == view) {
35 | throw new NullPointerException("MvpView reference is null. Have you called attachView()?");
36 | }
37 | return view;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/mvp/src/main/java/com/yeungeek/mvp/common/MvpPresenter.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.mvp.common;
2 |
3 | /**
4 | * Created by yeungeek on 2015/12/24.
5 | */
6 | public interface MvpPresenter {
7 |
8 | void attachView(V view);
9 |
10 | void detachView(boolean retainInstance);
11 | }
12 |
--------------------------------------------------------------------------------
/mvp/src/main/java/com/yeungeek/mvp/common/MvpView.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.mvp.common;
2 |
3 | /**
4 | * Created by yeungeek on 2016/1/8.
5 | */
6 | public interface MvpView {
7 | }
8 |
--------------------------------------------------------------------------------
/mvp/src/main/java/com/yeungeek/mvp/common/NoOp.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.mvp.common;
2 |
3 | import java.lang.reflect.InvocationHandler;
4 | import java.lang.reflect.Method;
5 | import java.lang.reflect.Proxy;
6 |
7 | /**
8 | * Created by yeungeek on 2015/12/24.
9 | */
10 | public final class NoOp {
11 | private NoOp() {
12 |
13 | }
14 |
15 | private static final InvocationHandler DEFAULT_VALUE = new DefaultValueInvocationHandler();
16 |
17 | public static T of(Class interfaceClass) {
18 | return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class[]{interfaceClass}, DEFAULT_VALUE);
19 | }
20 |
21 | private static class DefaultValueInvocationHandler implements InvocationHandler {
22 | @Override
23 | public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
24 | return Defaults.defaultValue(method.getReturnType());
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/mvp/src/main/java/com/yeungeek/mvp/common/lce/MvpLceView.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.mvp.common.lce;
2 |
3 |
4 | import com.yeungeek.mvp.common.MvpView;
5 |
6 | /**
7 | * A {@link MvpView} that assumes that there are 3 display operation:
8 | *
9 | * {@link #showLoading(boolean)}: Display a loading animation while loading data in background
10 | * by
11 | * invoking the corresponding presenter method
12 | *
13 | * {@link #showError(Throwable, boolean)}: Display a error view (a TextView) on the screen if
14 | * an error has occurred while loading data. You can distinguish between a pull-to-refresh error by
15 | * checking the boolean parameter and display the error message in another, more suitable way like
16 | * a
17 | * Toast
18 | *
19 | * {@link #showContent()}: After the content has been loaded the presenter calls {@link
20 | * #setData(Object)} to fill the view with data. Afterwards, the presenter calls {@link
21 | * #showContent()} to display the data
22 | *
23 | */
24 | public interface MvpLceView extends MvpView {
25 |
26 | /**
27 | * Display a loading view while loading data in background.
28 | * The loading view must have the id = R.id.loadingView
29 | *
30 | * @param pullToRefresh true, if pull-to-refresh has been invoked loading.
31 | */
32 | void showLoading(boolean pullToRefresh);
33 |
34 | void showContent();
35 |
36 | void showError(Throwable e, boolean pullToRefresh);
37 |
38 | void setData(V data);
39 |
40 | /**
41 | * Load the data. Typically invokes the presenter method to load the desired data.
42 | *
43 | * Should not be called from presenter to prevent infinity loops. The method is declared
44 | * in
45 | * the views interface to add support for view state easily.
46 | *
47 | *
48 | * @param pullToRefresh true, if triggered by a pull to refresh. Otherwise false.
49 | */
50 | void loadData(boolean pullToRefresh);
51 | }
52 |
--------------------------------------------------------------------------------
/mvp/src/main/java/com/yeungeek/mvp/core/delegate/ActivityMvpDelegate.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.mvp.core.delegate;
2 |
3 | import android.app.Activity;
4 | import android.os.Bundle;
5 | import android.support.v4.app.FragmentActivity;
6 |
7 | import com.yeungeek.mvp.common.MvpPresenter;
8 | import com.yeungeek.mvp.common.MvpView;
9 |
10 | /**
11 | * A delegate for Activities to attach them to mosbies mvp.
12 | *
13 | *
14 | * The following methods must be invoked from the corresponding Activities lifecycle methods:
15 | *
16 | * {@link #onCreate(Bundle)}
17 | * {@link #onDestroy()}
18 | * {@link #onPause()}
19 | * {@link #onResume()}
20 | * {@link #onStart()}
21 | * {@link #onStop()}
22 | * {@link #onRestart()}
23 | * {@link #onContentChanged()}
24 | * {@link #onSaveInstanceState(Bundle)}
25 | * {@link #onPostCreate(Bundle)}
26 | *
27 | *
28 | *
29 | *
30 | * @param The type of {@link MvpView}
31 | * @param The type of {@link MvpPresenter}
32 | * @author Hannes Dorfmann
33 | * @since 1.1.0
34 | */
35 | public interface ActivityMvpDelegate> {
36 |
37 | /**
38 | * This method must be called from {@link Activity#onCreate(Bundle)}.
39 | * This method internally creates the presenter and attaches the view to it.
40 | */
41 | void onCreate(Bundle bundle);
42 |
43 | /**
44 | * This method must be called from {@link Activity#onDestroy()}}.
45 | * This method internally detaches the view from presenter
46 | */
47 | void onDestroy();
48 |
49 | /**
50 | * This method must be called from {@link Activity#onPause()}
51 | */
52 | void onPause();
53 |
54 | /**
55 | * This method must be called from {@link Activity#onResume()}
56 | */
57 | void onResume();
58 |
59 | /**
60 | * This method must be called from {@link Activity#onStart()}
61 | */
62 | void onStart();
63 |
64 | /**
65 | * This method must be called from {@link Activity#onStop()}
66 | */
67 | void onStop();
68 |
69 | /**
70 | * This method must be called from {@link Activity#onRestart()}
71 | */
72 | void onRestart();
73 |
74 | /**
75 | * This method must be called from {@link Activity#onContentChanged()}
76 | */
77 | void onContentChanged();
78 |
79 | /**
80 | * This method must be called from {@link Activity#onSaveInstanceState(Bundle)}
81 | */
82 | void onSaveInstanceState(Bundle outState);
83 |
84 | /**
85 | * This method must be called from {@link Activity#onPostCreate(Bundle)}
86 | */
87 | void onPostCreate(Bundle savedInstanceState);
88 |
89 | /**
90 | * This method must be called from {@link FragmentActivity#onRetainCustomNonConfigurationInstance()}
91 | *
92 | * @return Don't forget to return the value returned by this delegate method
93 | */
94 | Object onRetainCustomNonConfigurationInstance();
95 |
96 | /**
97 | * @return the value returned from {@link ActivityMvpDelegateCallback#onRetainNonMosbyCustomNonConfigurationInstance()}
98 | */
99 | Object getNonMosbyLastCustomNonConfigurationInstance();
100 | }
101 |
--------------------------------------------------------------------------------
/mvp/src/main/java/com/yeungeek/mvp/core/delegate/ActivityMvpDelegateCallback.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.mvp.core.delegate;
2 |
3 | import android.support.v4.app.FragmentActivity;
4 |
5 | import com.yeungeek.mvp.common.MvpPresenter;
6 | import com.yeungeek.mvp.common.MvpView;
7 |
8 | /**
9 | * The MvpDelegate callback that will be called from {@link
10 | * ActivityMvpDelegate}. This interface must be implemented by all
11 | * Activities that you want to support mosby's mvp.
12 | *
13 | * @author Hannes Dorfmann
14 | * @see BaseMvpDelegateCallback
15 | * @since 2.0.0
16 | */
17 | public interface ActivityMvpDelegateCallback>
18 | extends BaseMvpDelegateCallback {
19 |
20 | /**
21 | * Return any Object holding the desired state to propagate to the next activity instance. Please
22 | * note that mosby internals like the presenter are already saved internally and you don't have
23 | * to take them into account. You can retrieve this value later with {@link
24 | * ActivityMvpDelegate#getNonMosbyLastCustomNonConfigurationInstance()}.
25 | *
26 | *
27 | * This mechanism works pretty the same way as {@link FragmentActivity#onRetainCustomNonConfigurationInstance()}
28 | * and {@link #getNonMosbyLastCustomNonConfigurationInstance()}
29 | *
30 | *
31 | * @return Object holding state.
32 | */
33 | Object onRetainNonMosbyCustomNonConfigurationInstance();
34 |
35 | /**
36 | * @return Return the value previously returned from {@link FragmentActivity#onRetainCustomNonConfigurationInstance()}.
37 | */
38 | Object getLastCustomNonConfigurationInstance();
39 |
40 | /**
41 | * This method should invoke {@link
42 | * ActivityMvpDelegate#getNonMosbyLastCustomNonConfigurationInstance()}.
43 | *
44 | *
45 | * This method is not really a "callback" method (will not invoked from delegate somehow).
46 | * However, it's part of this interface to ensure that no custom implementation will miss this
47 | * method since this method is the counterpart to {@link #onRetainNonMosbyCustomNonConfigurationInstance()}
48 | *
49 | */
50 | Object getNonMosbyLastCustomNonConfigurationInstance();
51 | }
52 |
--------------------------------------------------------------------------------
/mvp/src/main/java/com/yeungeek/mvp/core/delegate/ActivityMvpDelegateImpl.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.mvp.core.delegate;
2 |
3 | import android.os.Bundle;
4 |
5 | import com.yeungeek.mvp.common.MvpPresenter;
6 | import com.yeungeek.mvp.common.MvpView;
7 |
8 | /**
9 | * The concrete implementation of {@link}
10 | */
11 | public class ActivityMvpDelegateImpl>
12 | implements ActivityMvpDelegate {
13 | protected MvpInternalDelegate internalDelegate;
14 | protected ActivityMvpDelegateCallback delegateCallback;
15 |
16 | public ActivityMvpDelegateImpl(ActivityMvpDelegateCallback delegateCallback) {
17 | if (delegateCallback == null) {
18 | throw new NullPointerException("MvpDelegateCallback is null!");
19 | }
20 | this.delegateCallback = delegateCallback;
21 | }
22 |
23 | /**
24 | * Get the internal delegate.
25 | */
26 | protected MvpInternalDelegate getInternalDelegate() {
27 | if (internalDelegate == null) {
28 | internalDelegate = new MvpInternalDelegate<>(delegateCallback);
29 | }
30 |
31 | return internalDelegate;
32 | }
33 |
34 | @Override
35 | public void onCreate(Bundle bundle) {
36 | ActivityMvpNonConfigurationInstances nci =
37 | (ActivityMvpNonConfigurationInstances) delegateCallback.getLastCustomNonConfigurationInstance();
38 |
39 | if (null != nci && null != nci.presenter) {
40 | delegateCallback.setPresenter(nci.presenter);
41 | } else {
42 | getInternalDelegate().createPresenter();
43 | }
44 |
45 | getInternalDelegate().attachView();
46 | }
47 |
48 | @Override
49 | public void onDestroy() {
50 | getInternalDelegate().detachView();
51 | }
52 |
53 | @Override
54 | public void onPause() {
55 |
56 | }
57 |
58 | @Override
59 | public void onResume() {
60 |
61 | }
62 |
63 | @Override
64 | public void onStart() {
65 |
66 | }
67 |
68 | @Override
69 | public void onStop() {
70 |
71 | }
72 |
73 | @Override
74 | public void onRestart() {
75 |
76 | }
77 |
78 | @Override
79 | public void onContentChanged() {
80 |
81 | }
82 |
83 | @Override
84 | public void onSaveInstanceState(Bundle outState) {
85 |
86 | }
87 |
88 | @Override
89 | public void onPostCreate(Bundle savedInstanceState) {
90 |
91 | }
92 |
93 | @Override
94 | public Object onRetainCustomNonConfigurationInstance() {
95 | P presenter = delegateCallback.shouldInstanceBeRetained() ? delegateCallback.getPresenter() : null;
96 | Object nonMosbyConfiguraionInstance =
97 | delegateCallback.onRetainNonMosbyCustomNonConfigurationInstance();
98 |
99 | if (presenter == null && nonMosbyConfiguraionInstance == null) {
100 | return null;
101 | }
102 |
103 | return new ActivityMvpNonConfigurationInstances<>(presenter, nonMosbyConfiguraionInstance);
104 | }
105 |
106 | @Override
107 | public Object getNonMosbyLastCustomNonConfigurationInstance() {
108 | ActivityMvpNonConfigurationInstances last =
109 | (ActivityMvpNonConfigurationInstances) delegateCallback.getLastCustomNonConfigurationInstance();
110 | return last == null ? null : last.nonMosbyCustomConfigurationInstance;
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/mvp/src/main/java/com/yeungeek/mvp/core/delegate/ActivityMvpNonConfigurationInstances.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.mvp.core.delegate;
2 |
3 |
4 | import com.yeungeek.mvp.common.MvpPresenter;
5 | import com.yeungeek.mvp.common.MvpView;
6 |
7 | /**
8 | * This kind of class is used in Activities to save the presenter in retaining activities. It's a
9 | * mosby internal class.
10 | *
11 | * @author Hannes Dorfmann
12 | * @since 2.0.0
13 | */
14 | class ActivityMvpNonConfigurationInstances> {
15 |
16 | /**
17 | * The reference to the presenter
18 | */
19 | P presenter;
20 |
21 | /**
22 | * The reference to the custom non configuration.
23 | */
24 | Object nonMosbyCustomConfigurationInstance;
25 |
26 | /**
27 | * Constructor
28 | *
29 | * @param presenter The retaining presenter
30 | * @param nonMosbyCustomConfigurationInstance the other custom object
31 | */
32 | ActivityMvpNonConfigurationInstances(P presenter, Object nonMosbyCustomConfigurationInstance) {
33 | this.presenter = presenter;
34 | this.nonMosbyCustomConfigurationInstance = nonMosbyCustomConfigurationInstance;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/mvp/src/main/java/com/yeungeek/mvp/core/delegate/BaseMvpDelegateCallback.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.mvp.core.delegate;
2 |
3 | import android.app.Activity;
4 |
5 | import com.yeungeek.mvp.common.MvpPresenter;
6 | import com.yeungeek.mvp.common.MvpView;
7 |
8 | /**
9 | * The MvpDelegate callback that will be called from {@link
10 | * FragmentMvpDelegate} or {@link ViewGroupMvpDelegate}. This interface must be implemented by all
11 | * Fragment or android.view.View that you want to support mosbys mvp. Please note that Activties
12 | * need a special callback {@link ActivityMvpDelegateCallback}
13 | *
14 | * @param The type of {@link MvpView}
15 | * @param The type of {@link MvpPresenter}
16 | */
17 | public interface BaseMvpDelegateCallback> {
18 | P createPresenter();
19 |
20 | P getPresenter();
21 |
22 | void setPresenter(P presenter);
23 |
24 | V getMvpView();
25 |
26 | /**
27 | * Indicate whether the retain instance feature is enabled by this view or not
28 | */
29 | boolean isRetainInstance();
30 |
31 | /**
32 | * Mark this instance as retaining. This means that the feature of a retaining instance is
33 | * enabled.
34 | */
35 | void setRetainInstance(boolean retainingInstance);
36 |
37 | /**
38 | * Indicates whether or not the the view will be retained during next screen orientation change.
39 | * This boolean flag is used for {@link MvpPresenter#detachView(boolean)}
40 | * as parameter. Usually you should take {@link Activity#isChangingConfigurations()} into
41 | * account. The difference between {@link #shouldInstanceBeRetained()} and {@link
42 | * #isRetainInstance()} is that {@link #isRetainInstance()} indicates that retain instance
43 | * feature is enabled or disabled while {@link #shouldInstanceBeRetained()} indicates if the
44 | * view is going to be destroyed permanently and hence should no more be retained (i.e. Activity
45 | * is finishing and not just screen orientation changing)
46 | *
47 | * @return true if the instance should be retained, otherwise false
48 | */
49 | boolean shouldInstanceBeRetained();
50 | }
51 |
--------------------------------------------------------------------------------
/mvp/src/main/java/com/yeungeek/mvp/core/delegate/FragmentMvpDelegateImpl.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.mvp.core.delegate;
2 |
3 | import android.app.Activity;
4 | import android.os.Bundle;
5 | import android.support.annotation.Nullable;
6 | import android.view.View;
7 |
8 | import com.yeungeek.mvp.common.MvpPresenter;
9 | import com.yeungeek.mvp.common.MvpView;
10 |
11 | /**
12 | * The default implementation of {@link FragmentMvpDelegate}
13 | */
14 | public class FragmentMvpDelegateImpl>
15 | implements FragmentMvpDelegate {
16 | protected BaseMvpDelegateCallback delegateCallback;
17 | protected MvpInternalDelegate internalDelegate;
18 |
19 | public FragmentMvpDelegateImpl(final BaseMvpDelegateCallback delegateCallback) {
20 | if (null == delegateCallback) {
21 | throw new NullPointerException("MvpDelegateCallback is null!");
22 | }
23 |
24 | this.delegateCallback = delegateCallback;
25 | }
26 |
27 | protected MvpInternalDelegate getInternalDelegate() {
28 | if (internalDelegate == null) {
29 | internalDelegate = new MvpInternalDelegate<>(delegateCallback);
30 | }
31 | return internalDelegate;
32 | }
33 |
34 | @Override
35 | public void onCreate(Bundle saved) {
36 |
37 | }
38 |
39 | @Override
40 | public void onDestroy() {
41 |
42 | }
43 |
44 | @Override
45 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
46 | getInternalDelegate().createPresenter();
47 | getInternalDelegate().attachView();
48 | }
49 |
50 | @Override
51 | public void onDestroyView() {
52 | getInternalDelegate().detachView();
53 | }
54 |
55 | @Override
56 | public void onPause() {
57 |
58 | }
59 |
60 | @Override
61 | public void onResume() {
62 |
63 | }
64 |
65 | @Override
66 | public void onStart() {
67 |
68 | }
69 |
70 | @Override
71 | public void onStop() {
72 |
73 | }
74 |
75 | @Override
76 | public void onActivityCreated(Bundle savedInstanceState) {
77 |
78 | }
79 |
80 | @Override
81 | public void onAttach(Activity activity) {
82 |
83 | }
84 |
85 | @Override
86 | public void onDetach() {
87 |
88 | }
89 |
90 | @Override
91 | public void onSaveInstanceState(Bundle outState) {
92 |
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/mvp/src/main/java/com/yeungeek/mvp/core/delegate/MvpInternalDelegate.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.mvp.core.delegate;
2 |
3 | import com.yeungeek.mvp.common.MvpPresenter;
4 | import com.yeungeek.mvp.common.MvpView;
5 |
6 | /**
7 | * This is just the internal implementation for the delegate. Don't use it by your own.
8 | */
9 | class MvpInternalDelegate> {
10 | protected BaseMvpDelegateCallback delegateCallback;
11 |
12 | MvpInternalDelegate(BaseMvpDelegateCallback delegateCallback) {
13 | if (delegateCallback == null) {
14 | throw new NullPointerException("MvpDelegateCallback is null!");
15 | }
16 | this.delegateCallback = delegateCallback;
17 | }
18 |
19 | /**
20 | * Called to create the presenter (if no other one already exisits)
21 | */
22 | void createPresenter() {
23 | P presenter = delegateCallback.getPresenter();
24 | if (presenter == null) {
25 | presenter = delegateCallback.createPresenter();
26 | }
27 | if (presenter == null) {
28 | throw new NullPointerException("Presenter is null! Do you return null in createPresenter()?");
29 | }
30 |
31 | delegateCallback.setPresenter(presenter);
32 | }
33 |
34 | /**
35 | * Attaches the view to the presenter
36 | */
37 | void attachView() {
38 | getPresenter().attachView(delegateCallback.getMvpView());
39 | }
40 |
41 | /**
42 | * Called to detach the view from presenter
43 | */
44 | void detachView() {
45 | getPresenter().detachView(delegateCallback.shouldInstanceBeRetained());
46 | }
47 |
48 | private P getPresenter() {
49 | P presenter = delegateCallback.getPresenter();
50 | if (presenter == null) {
51 | throw new NullPointerException("Presenter returned from getPresenter() is null");
52 | }
53 | return presenter;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/mvp/src/main/res/values/ids.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/mvp/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | mvp
3 |
4 |
--------------------------------------------------------------------------------
/mvp/src/test/java/com/yeungeek/mvp/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.yeungeek.mvp;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * To work on unit tests, switch the Test Artifact in the Build Variants view.
9 | */
10 | public class ExampleUnitTest {
11 | @Test
12 | public void addition_isCorrect() throws Exception {
13 | assertEquals(4, 2 + 2);
14 | }
15 | }
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':mvp'
2 |
--------------------------------------------------------------------------------