├── .gitignore
├── LICENSE
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── io
│ │ └── rebble
│ │ └── store
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── ic_launcher-web.png
│ ├── java
│ │ └── io
│ │ │ └── rebble
│ │ │ └── store
│ │ │ ├── StoreApplication.java
│ │ │ ├── activity
│ │ │ ├── MainActivity.java
│ │ │ ├── SplashActivity.java
│ │ │ └── WatchFaceApplicationDetailsActivity.java
│ │ │ ├── adapter
│ │ │ ├── ApplicationListAdapter.java
│ │ │ ├── DataBindingBaseAdapter.java
│ │ │ ├── SectionAdapter.java
│ │ │ ├── SliderViewPagerAdapter.java
│ │ │ └── WatchFaceListAdapter.java
│ │ │ ├── api
│ │ │ ├── Api.java
│ │ │ ├── ApiService.java
│ │ │ ├── CacheInterceptor.java
│ │ │ ├── OfflineCacheInterceptor.java
│ │ │ └── model
│ │ │ │ ├── AndroidCompanion.java
│ │ │ │ ├── Application.java
│ │ │ │ ├── ApplicationIndexResult.java
│ │ │ │ ├── Category.java
│ │ │ │ ├── CategoryLink.java
│ │ │ │ ├── Collection.java
│ │ │ │ ├── Compatibility.java
│ │ │ │ ├── IosCompanion.java
│ │ │ │ └── Links.java
│ │ │ ├── command
│ │ │ ├── ICommand.java
│ │ │ └── LaunchWatchFaceApplicationDetailsActivityCommand.java
│ │ │ ├── fragment
│ │ │ └── WatchFaceApplicationListFragment.java
│ │ │ ├── util
│ │ │ ├── BindingAdapterUtil.java
│ │ │ └── NetworkUtil.java
│ │ │ ├── view
│ │ │ └── WatchFaceApplicationSliderView.java
│ │ │ └── viewmodel
│ │ │ ├── CarouselItemViewModel.java
│ │ │ ├── MainActivityViewModel.java
│ │ │ ├── SliderItemViewModel.java
│ │ │ ├── WatchFaceApplicationDetailsViewModel.java
│ │ │ ├── WatchFaceApplicationViewModel.java
│ │ │ └── section
│ │ │ ├── ApplicationListSectionViewModel.java
│ │ │ ├── BaseSectionViewModel.java
│ │ │ ├── CarouselSectionViewModel.java
│ │ │ └── WatchFaceListSectionViewModel.java
│ └── res
│ │ ├── anim
│ │ ├── fade_in.xml
│ │ └── fade_out.xml
│ │ ├── drawable
│ │ ├── ic_heart.xml
│ │ ├── ic_rebble.png
│ │ ├── screen_splash.xml
│ │ └── slider_background_time.png
│ │ ├── layout
│ │ ├── activity_main.xml
│ │ ├── activity_splash.xml
│ │ ├── activity_watchface_app_details.xml
│ │ ├── fragment_watchface_app_list.xml
│ │ ├── item_app.xml
│ │ ├── item_slider.xml
│ │ ├── item_watchface.xml
│ │ ├── layout_watchface_app_details.xml
│ │ ├── layout_watchface_app_text_info.xml
│ │ ├── nav.xml
│ │ ├── nav_header.xml
│ │ ├── section_carousel.xml
│ │ ├── section_watchface_app_list.xml
│ │ └── view_watchface_app_slider.xml
│ │ ├── menu
│ │ └── nav_items.xml
│ │ ├── mipmap-hdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-mdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxxhdpi
│ │ └── ic_launcher.png
│ │ ├── values-v21
│ │ └── styles.xml
│ │ ├── values-w820dp
│ │ └── dimens.xml
│ │ └── values
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── io
│ └── rebble
│ └── store
│ └── ExampleUnitTest.java
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── release.jks
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/*
5 | .DS_Store
6 | /build
7 | /app/fabric.properties
8 | /captures
9 | .externalNativeBuild
10 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # android-store-app
2 | The android client app to access pebble apps from panic store
3 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | maven { url 'https://maven.fabric.io/public' }
4 | }
5 |
6 | dependencies {
7 | classpath 'io.fabric.tools:gradle:1.+'
8 | }
9 | }
10 | apply plugin: 'com.android.application'
11 | apply plugin: 'io.fabric'
12 |
13 | repositories {
14 | maven { url 'https://maven.fabric.io/public' }
15 | }
16 |
17 |
18 | android {
19 | compileSdkVersion 25
20 | buildToolsVersion "25.0.2"
21 | defaultConfig {
22 | applicationId "io.rebble.store"
23 | minSdkVersion 16
24 | targetSdkVersion 25
25 | versionCode 3
26 | versionName "1.1.1"
27 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
28 | }
29 | dataBinding {
30 | enabled = true
31 | }
32 | signingConfigs {
33 | release {
34 | storeFile file("../release.jks")
35 | storePassword "pebble"
36 | keyAlias "release"
37 | keyPassword "pebble"
38 | }
39 | }
40 | buildTypes {
41 | release {
42 | minifyEnabled false
43 | signingConfig signingConfigs.release
44 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
45 | }
46 | }
47 | packagingOptions {
48 | exclude 'META-INF/DEPENDENCIES'
49 | exclude 'META-INF/NOTICE'
50 | exclude 'META-INF/LICENSE'
51 | exclude 'META-INF/LICENSE.txt'
52 | exclude 'META-INF/NOTICE.txt'
53 | }
54 | }
55 |
56 | final SUPPORT_LIB_VERSION = '25.1.0'
57 | final JACKSON_VERSION = '2.8.5'
58 | final RETROFIT_VERSION = '2.1.0'
59 |
60 | dependencies {
61 | compile fileTree(dir: 'libs', include: ['*.jar'])
62 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
63 | exclude group: 'com.android.support', module: 'support-annotations'
64 | })
65 | testCompile 'junit:junit:4.12'
66 |
67 | compile "com.android.support:appcompat-v7:${SUPPORT_LIB_VERSION}"
68 | compile "com.android.support:design:${SUPPORT_LIB_VERSION}"
69 | compile "com.fasterxml.jackson.core:jackson-core:${JACKSON_VERSION}"
70 | compile "com.fasterxml.jackson.core:jackson-annotations:${JACKSON_VERSION}"
71 | compile "com.fasterxml.jackson.core:jackson-databind:${JACKSON_VERSION}"
72 | compile "com.squareup.retrofit2:converter-jackson:${RETROFIT_VERSION}"
73 | compile "com.squareup.retrofit2:retrofit:${RETROFIT_VERSION}"
74 | compile "com.squareup.retrofit2:adapter-rxjava:${RETROFIT_VERSION}"
75 | compile 'io.reactivex:rxandroid:1.2.1'
76 | compile 'io.reactivex:rxjava:1.2.4'
77 | compile 'com.github.bumptech.glide:glide:3.7.0'
78 | compile 'com.lapism:searchview:4.0'
79 | compile 'com.synnapps:carouselview:0.0.10'
80 | compile 'com.android.support.constraint:constraint-layout:1.0.0-beta4'
81 | compile('com.crashlytics.sdk.android:crashlytics:2.6.5@aar') {
82 | transitive = true;
83 | }
84 | compile('com.crashlytics.sdk.android:answers:1.3.10@aar') {
85 | transitive = true;
86 | }
87 | }
--------------------------------------------------------------------------------
/app/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 /Users/zhangqichuan/dev/android-sdk-macosx/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 |
19 | #Glide
20 | -keep public class * implements com.bumptech.glide.module.GlideModule
21 | -keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
22 | **[] $VALUES;
23 | public *;
24 | }
25 | -keepresourcexmlelements manifest/application/meta-data@value=GlideModule
26 |
27 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/io/rebble/store/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package io.rebble.store;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("io.rebble.store", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
15 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pebble-dev/android-store-app/17f6a44788c274cda36a7544b711068fe7057255/app/src/main/ic_launcher-web.png
--------------------------------------------------------------------------------
/app/src/main/java/io/rebble/store/StoreApplication.java:
--------------------------------------------------------------------------------
1 | package io.rebble.store;
2 |
3 | import android.app.Application;
4 |
5 | /**
6 | * Created by zhangqichuan on 2/1/17.
7 | */
8 |
9 | public class StoreApplication extends Application {
10 |
11 | private static StoreApplication sInstance;
12 |
13 | public static StoreApplication getApplication() {
14 | return sInstance;
15 | }
16 |
17 | @Override
18 | public void onCreate() {
19 | super.onCreate();
20 | sInstance = this;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/app/src/main/java/io/rebble/store/activity/MainActivity.java:
--------------------------------------------------------------------------------
1 | package io.rebble.store.activity;
2 |
3 | import android.databinding.DataBindingUtil;
4 | import android.databinding.ViewDataBinding;
5 | import android.support.design.widget.NavigationView;
6 | import android.support.design.widget.TabLayout;
7 | import android.support.v4.app.Fragment;
8 | import android.support.v4.app.FragmentManager;
9 | import android.support.v4.app.FragmentPagerAdapter;
10 | import android.support.v4.view.GravityCompat;
11 | import android.support.v4.view.ViewPager;
12 | import android.support.v4.widget.DrawerLayout;
13 | import android.support.v7.app.ActionBarDrawerToggle;
14 | import android.support.v7.app.AppCompatActivity;
15 | import android.os.Bundle;
16 | import android.support.v7.widget.Toolbar;
17 | import android.view.LayoutInflater;
18 | import android.view.View;
19 |
20 | import com.lapism.searchview.SearchView;
21 |
22 | import java.util.ArrayList;
23 | import java.util.List;
24 |
25 | import io.rebble.store.BR;
26 | import io.rebble.store.R;
27 | import io.rebble.store.fragment.WatchFaceApplicationListFragment;
28 | import io.rebble.store.viewmodel.MainActivityViewModel;
29 |
30 | /**
31 | * Created by zhangqichuan on 15/12/16.
32 | */
33 |
34 | public class MainActivity extends AppCompatActivity {
35 |
36 | private Toolbar mToolbar;
37 | private TabLayout mTabLayout;
38 | private ViewPager mViewPager;
39 | private DrawerLayout mDrawerLayout;
40 | private SearchView mSearchView;
41 | private NavigationView mNavigationView;
42 |
43 | private ActionBarDrawerToggle mActionBarDrawerToggle;
44 |
45 | @Override
46 | protected void onCreate(Bundle savedInstanceState) {
47 | super.onCreate(savedInstanceState);
48 | setContentView(R.layout.activity_main);
49 |
50 | mDrawerLayout = (DrawerLayout) findViewById(R.id.drawerLayout);
51 | mToolbar = (Toolbar) findViewById(R.id.toolbar);
52 | mTabLayout = (TabLayout) findViewById(R.id.tabs);
53 | mViewPager = (ViewPager) findViewById(R.id.viewpager);
54 | mSearchView = (SearchView) findViewById(R.id.searchView);
55 | mNavigationView = (NavigationView) findViewById(R.id.nav_view);
56 |
57 | mToolbar.setTitle("");
58 | setSupportActionBar(mToolbar);
59 | setupViewpager(mViewPager);
60 | mTabLayout.setupWithViewPager(mViewPager);
61 | setupDrawer(mDrawerLayout, mToolbar, mSearchView);
62 | setupSearchView(mSearchView, mDrawerLayout);
63 | setupNavigationView(mNavigationView);
64 | }
65 |
66 | private void setupDrawer(DrawerLayout drawerLayout, Toolbar toolbar, final SearchView searchView) {
67 | mActionBarDrawerToggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.open, R.string.close) {
68 | @Override
69 | public void onDrawerOpened(View drawerView) {
70 | super.onDrawerOpened(drawerView);
71 | if (searchView != null && searchView.isSearchOpen()) {
72 | searchView.close(true);
73 | }
74 | }
75 | };
76 | mActionBarDrawerToggle.setDrawerIndicatorEnabled(false);
77 | drawerLayout.addDrawerListener(mActionBarDrawerToggle);
78 | mActionBarDrawerToggle.syncState();
79 | }
80 |
81 | private void setupViewpager(ViewPager viewPager) {
82 | ViewPagerAdapter viewPagerAdapter = new ViewPagerAdapter(getSupportFragmentManager());
83 | viewPagerAdapter.addFragment(WatchFaceApplicationListFragment.create(WatchFaceApplicationListFragment.TYPE_WATCHFACES), getString(R.string.watchfaces));
84 | viewPagerAdapter.addFragment(WatchFaceApplicationListFragment.create(WatchFaceApplicationListFragment.TYPE_APPS), getString(R.string.apps));
85 | viewPager.setAdapter(viewPagerAdapter);
86 | }
87 |
88 | private void setupSearchView(SearchView searchView, final DrawerLayout drawerLayout) {
89 | searchView.setOnMenuClickListener(new SearchView.OnMenuClickListener() {
90 | @Override
91 | public void onMenuClick() {
92 | drawerLayout.openDrawer(GravityCompat.START); // finish();
93 | }
94 | });
95 | }
96 |
97 | private void setupNavigationView(NavigationView navigationView) {
98 | ViewDataBinding dataBinding = DataBindingUtil.inflate(LayoutInflater.from(this),
99 | R.layout.nav_header, navigationView, false);
100 | dataBinding.setVariable(BR.main_activity_model, new MainActivityViewModel());
101 | dataBinding.executePendingBindings();
102 | navigationView.addHeaderView(dataBinding.getRoot());
103 | }
104 |
105 | @Override
106 | public void onBackPressed() {
107 | if (mDrawerLayout.isDrawerOpen(GravityCompat.START)) {
108 | mDrawerLayout.closeDrawer(GravityCompat.START);
109 | } else {
110 | finish();
111 | }
112 | }
113 |
114 | private static class ViewPagerAdapter extends FragmentPagerAdapter {
115 | private final List mFragmentList = new ArrayList<>();
116 | private final List mFragmentTitleList = new ArrayList<>();
117 |
118 | public ViewPagerAdapter(FragmentManager manager) {
119 | super(manager);
120 | }
121 |
122 | @Override
123 | public Fragment getItem(int position) {
124 | return mFragmentList.get(position);
125 | }
126 |
127 | @Override
128 | public int getCount() {
129 | return mFragmentList.size();
130 | }
131 |
132 | public void addFragment(Fragment fragment, String title) {
133 | mFragmentList.add(fragment);
134 | mFragmentTitleList.add(title);
135 | }
136 |
137 | @Override
138 | public CharSequence getPageTitle(int position) {
139 | return mFragmentTitleList.get(position);
140 | }
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/app/src/main/java/io/rebble/store/activity/SplashActivity.java:
--------------------------------------------------------------------------------
1 | package io.rebble.store.activity;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.support.annotation.Nullable;
6 | import android.support.v7.app.AppCompatActivity;
7 |
8 | import com.crashlytics.android.Crashlytics;
9 | import io.fabric.sdk.android.Fabric;
10 | import io.rebble.store.R;
11 |
12 | /**
13 | * Created by zhangqichuan on 15/12/16.
14 | */
15 |
16 | public class SplashActivity extends AppCompatActivity {
17 | @Override
18 | protected void onCreate(@Nullable Bundle savedInstanceState) {
19 | super.onCreate(savedInstanceState);
20 | Fabric.with(this, new Crashlytics());
21 | setContentView(R.layout.activity_splash);
22 |
23 | //TODO initialization tasks
24 | startActivity(new Intent(this, MainActivity.class));
25 | overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
26 |
27 | finish();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/app/src/main/java/io/rebble/store/activity/WatchFaceApplicationDetailsActivity.java:
--------------------------------------------------------------------------------
1 | package io.rebble.store.activity;
2 |
3 | import android.databinding.DataBindingUtil;
4 | import android.databinding.ViewDataBinding;
5 | import android.os.Bundle;
6 | import android.support.annotation.Nullable;
7 | import android.support.v7.app.AppCompatActivity;
8 | import android.support.v7.widget.Toolbar;
9 | import android.view.MenuItem;
10 |
11 | import io.rebble.store.BR;
12 | import io.rebble.store.R;
13 | import io.rebble.store.api.model.Application;
14 | import io.rebble.store.viewmodel.WatchFaceApplicationDetailsViewModel;
15 |
16 | /**
17 | * Created by zhangqichuan on 20/12/16.
18 | */
19 |
20 | public class WatchFaceApplicationDetailsActivity extends AppCompatActivity {
21 |
22 | private Toolbar mToolbar;
23 |
24 | public final static String EXTRA_WATCHFACE_APP_DETAILS = "EXTRA_WATCHFACE_APP_DETAILS";
25 | @Override
26 | protected void onCreate(@Nullable Bundle savedInstanceState) {
27 | super.onCreate(savedInstanceState);
28 | ViewDataBinding viewDataBinding = DataBindingUtil
29 | .setContentView(this, R.layout.activity_watchface_app_details);
30 | mToolbar = (Toolbar) findViewById(R.id.toolbar);
31 | setSupportActionBar(mToolbar);
32 | getSupportActionBar().setDisplayHomeAsUpEnabled(true);
33 |
34 | if (getIntent() != null && getIntent().hasExtra(EXTRA_WATCHFACE_APP_DETAILS)) {
35 | Application application = getIntent().getParcelableExtra(EXTRA_WATCHFACE_APP_DETAILS);
36 | viewDataBinding.setVariable(BR.app, new WatchFaceApplicationDetailsViewModel((application)));
37 | }
38 | }
39 |
40 | @Override
41 | public boolean onOptionsItemSelected(MenuItem item) {
42 | switch (item.getItemId()) {
43 | // Respond to the action bar's Up/Home button
44 | case android.R.id.home:
45 | onBackPressed();
46 | return true;
47 | }
48 | return super.onOptionsItemSelected(item);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/app/src/main/java/io/rebble/store/adapter/ApplicationListAdapter.java:
--------------------------------------------------------------------------------
1 | package io.rebble.store.adapter;
2 |
3 | import android.view.View;
4 |
5 | import java.util.List;
6 |
7 | import io.rebble.store.BR;
8 | import io.rebble.store.R;
9 | import io.rebble.store.command.LaunchWatchFaceApplicationDetailsActivityCommand;
10 | import io.rebble.store.viewmodel.WatchFaceApplicationViewModel;
11 |
12 | /**
13 | * Created by zhangqichuan on 19/12/16.
14 | */
15 |
16 | public class ApplicationListAdapter extends DataBindingBaseAdapter {
17 | public ApplicationListAdapter(List mList) {
18 | super(mList);
19 | }
20 |
21 | @Override
22 | protected int getLayoutResId() {
23 | return R.layout.item_app;
24 | }
25 |
26 | @Override
27 | protected int getBRResId() {
28 | return BR.app;
29 | }
30 |
31 | @Override
32 | protected void onItemClicked(View view, WatchFaceApplicationViewModel item, int position) {
33 | LaunchWatchFaceApplicationDetailsActivityCommand command
34 | = new LaunchWatchFaceApplicationDetailsActivityCommand(view, item);
35 | command.execute();
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/app/src/main/java/io/rebble/store/adapter/DataBindingBaseAdapter.java:
--------------------------------------------------------------------------------
1 | package io.rebble.store.adapter;
2 |
3 | import android.databinding.DataBindingUtil;
4 | import android.databinding.ViewDataBinding;
5 | import android.support.v7.widget.RecyclerView;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 |
10 | import java.util.List;
11 |
12 | /**
13 | * Created by zhangqichuan on 15/12/16.
14 | */
15 |
16 | public abstract class DataBindingBaseAdapter extends
17 | RecyclerView.Adapter {
18 |
19 | private List mList;
20 |
21 | public DataBindingBaseAdapter(List mList) {
22 | this.mList = mList;
23 | }
24 |
25 | @Override
26 | public DataBindingBaseAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
27 | ViewDataBinding viewDataBinding =
28 | DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()),
29 | getLayoutResId(), parent, false);
30 | return new DataBindingBaseAdapter.ViewHolder(viewDataBinding);
31 | }
32 |
33 | @Override
34 | public void onBindViewHolder(DataBindingBaseAdapter.ViewHolder holder, final int position) {
35 | ViewDataBinding viewDataBinding = holder.getViewDataBinding();
36 | final T item = mList.get(position);
37 | viewDataBinding.setVariable(getBRResId(), item);
38 | viewDataBinding.executePendingBindings();
39 | viewDataBinding.getRoot().setOnClickListener(new View.OnClickListener() {
40 | @Override
41 | public void onClick(View view) {
42 | onItemClicked(view, item, position);
43 | }
44 | });
45 | }
46 |
47 | @Override
48 | public int getItemCount() {
49 | if (mList == null) return 0;
50 | return mList.size();
51 | }
52 |
53 | protected abstract int getLayoutResId();
54 |
55 | protected abstract int getBRResId();
56 |
57 | protected abstract void onItemClicked(View view, T item, int position);
58 |
59 | public static class ViewHolder extends RecyclerView.ViewHolder {
60 |
61 | private ViewDataBinding mViewDataBinding;
62 |
63 | public ViewHolder(ViewDataBinding viewDataBinding) {
64 | super(viewDataBinding.getRoot());
65 | mViewDataBinding = viewDataBinding;
66 | }
67 |
68 | public ViewDataBinding getViewDataBinding() {
69 | return mViewDataBinding;
70 | }
71 |
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/app/src/main/java/io/rebble/store/adapter/SectionAdapter.java:
--------------------------------------------------------------------------------
1 | package io.rebble.store.adapter;
2 |
3 | import android.support.v7.widget.LinearLayoutManager;
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.synnapps.carouselview.CarouselView;
12 | import com.synnapps.carouselview.ImageListener;
13 |
14 | import java.util.List;
15 |
16 | import io.rebble.store.R;
17 | import io.rebble.store.command.LaunchWatchFaceApplicationDetailsActivityCommand;
18 | import io.rebble.store.util.BindingAdapterUtil;
19 | import io.rebble.store.viewmodel.WatchFaceApplicationViewModel;
20 | import io.rebble.store.viewmodel.section.ApplicationListSectionViewModel;
21 | import io.rebble.store.viewmodel.section.CarouselSectionViewModel;
22 | import io.rebble.store.viewmodel.section.BaseSectionViewModel;
23 | import io.rebble.store.viewmodel.section.WatchFaceListSectionViewModel;
24 |
25 | /**
26 | * Created by zhangqichuan on 15/12/16.
27 | */
28 |
29 | public class SectionAdapter extends RecyclerView.Adapter {
30 |
31 | private List mSectionList;
32 |
33 | public SectionAdapter(List mSectionList) {
34 | this.mSectionList = mSectionList;
35 | }
36 |
37 | @Override
38 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
39 | if (viewType == BaseSectionViewModel.TYPE_WATCHFACES ||
40 | viewType == BaseSectionViewModel.TYPE_APPS) {
41 | View view = LayoutInflater.from(parent.getContext())
42 | .inflate(R.layout.section_watchface_app_list, parent, false);
43 | return new ListSectionViewHolder(view);
44 | } else if (viewType == BaseSectionViewModel.TYPE_CAROUSEL) {
45 | View view = LayoutInflater.from(parent.getContext())
46 | .inflate(R.layout.section_carousel, parent, false);
47 | return new CarouselSectionViewHolder(view);
48 | }
49 | return null;
50 | }
51 |
52 | @Override
53 | public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
54 | BaseSectionViewModel model = mSectionList.get(position);
55 | int viewType = getItemViewType(position);
56 | if (viewType == BaseSectionViewModel.TYPE_WATCHFACES) {
57 | WatchFaceListSectionViewModel viewModel = (WatchFaceListSectionViewModel) model;
58 | ListSectionViewHolder viewHolder = (ListSectionViewHolder) holder;
59 | RecyclerView.LayoutManager layoutManager = new
60 | LinearLayoutManager(viewHolder.nameTextView.getContext(),
61 | LinearLayoutManager.HORIZONTAL, false);
62 | viewHolder.recyclerView.setLayoutManager(layoutManager);
63 | viewHolder.nameTextView.setText(viewModel.getName());
64 | viewHolder.recyclerView.setAdapter(new WatchFaceListAdapter(viewModel.getViewModelList()));
65 | } else if (viewType == BaseSectionViewModel.TYPE_APPS) {
66 | ApplicationListSectionViewModel viewModel = (ApplicationListSectionViewModel) model;
67 | ListSectionViewHolder viewHolder = (ListSectionViewHolder) holder;
68 | RecyclerView.LayoutManager layoutManager = new
69 | LinearLayoutManager(viewHolder.nameTextView.getContext(),
70 | LinearLayoutManager.HORIZONTAL, false);
71 | viewHolder.recyclerView.setLayoutManager(layoutManager);
72 | viewHolder.nameTextView.setText(viewModel.getName());
73 | viewHolder.recyclerView.setAdapter(new ApplicationListAdapter(viewModel.getViewModelList()));
74 | } else if (viewType == BaseSectionViewModel.TYPE_CAROUSEL) {
75 | CarouselSectionViewModel viewModel = (CarouselSectionViewModel) model;
76 | CarouselSectionViewHolder viewHolder = (CarouselSectionViewHolder) holder;
77 | final List apps = viewModel.getViewModelList();
78 | viewHolder.carouselView.setPageCount(apps.size());
79 | viewHolder.carouselView.setImageListener(new ImageListener() {
80 | @Override
81 | public void setImageForPosition(final int position, ImageView imageView) {
82 | imageView.setOnClickListener(new View.OnClickListener() {
83 | @Override
84 | public void onClick(View view) {
85 | new LaunchWatchFaceApplicationDetailsActivityCommand(
86 | view.getContext(), apps.get(position)).execute();
87 | }
88 | });
89 | BindingAdapterUtil.loadImage(imageView, apps.get(position).getBackdropImageUrl());
90 | }
91 | });
92 | }
93 | }
94 |
95 | @Override
96 | public int getItemCount() {
97 | return mSectionList.size();
98 | }
99 |
100 |
101 | private static class ListSectionViewHolder extends RecyclerView.ViewHolder {
102 |
103 | public TextView nameTextView;
104 | public RecyclerView recyclerView;
105 |
106 | public ListSectionViewHolder(View itemView) {
107 | super(itemView);
108 | nameTextView = (TextView) itemView.findViewById(R.id.text_name);
109 | recyclerView = (RecyclerView) itemView.findViewById(R.id.recyclerView);
110 | recyclerView.setNestedScrollingEnabled(false);
111 | }
112 | }
113 |
114 | private static class CarouselSectionViewHolder extends RecyclerView.ViewHolder {
115 | public CarouselView carouselView;
116 |
117 | public CarouselSectionViewHolder(View itemView) {
118 | super(itemView);
119 | carouselView = (CarouselView) itemView.findViewById(R.id.carouselView);
120 | }
121 | }
122 |
123 | @Override
124 | public int getItemViewType(int position) {
125 | BaseSectionViewModel viewModel = mSectionList.get(position);
126 | return viewModel.getType();
127 | }
128 |
129 | }
130 |
--------------------------------------------------------------------------------
/app/src/main/java/io/rebble/store/adapter/SliderViewPagerAdapter.java:
--------------------------------------------------------------------------------
1 | package io.rebble.store.adapter;
2 |
3 | import android.databinding.DataBindingUtil;
4 | import android.databinding.ViewDataBinding;
5 | import android.os.Build;
6 | import android.support.v4.view.PagerAdapter;
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 |
11 | import java.util.List;
12 |
13 | import io.rebble.store.BR;
14 | import io.rebble.store.R;
15 | import io.rebble.store.viewmodel.SliderItemViewModel;
16 |
17 | /**
18 | * Created by zhangqichuan on 20/12/16.
19 | */
20 |
21 | public class SliderViewPagerAdapter extends PagerAdapter {
22 |
23 | private List items;
24 |
25 | public SliderViewPagerAdapter(List items) {
26 | this.items = items;
27 | }
28 |
29 | @Override
30 | public Object instantiateItem(ViewGroup container, int position) {
31 | ViewDataBinding viewDataBinding =
32 | DataBindingUtil.inflate(LayoutInflater.from(container.getContext()),
33 | R.layout.item_slider, container, false);
34 | viewDataBinding.setVariable(BR.item, items.get(position));
35 | View view = viewDataBinding.getRoot();
36 | container.addView(view);
37 | return view;
38 | }
39 |
40 | @Override
41 | public void destroyItem(ViewGroup container, int position, Object object) {
42 | container.removeView((View) object);
43 | }
44 |
45 | @Override
46 | public int getCount() {
47 | return items.size();
48 | }
49 |
50 | @Override
51 | public boolean isViewFromObject(View view, Object object) {
52 | return view == object;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/app/src/main/java/io/rebble/store/adapter/WatchFaceListAdapter.java:
--------------------------------------------------------------------------------
1 | package io.rebble.store.adapter;
2 |
3 | import android.view.View;
4 |
5 | import java.util.List;
6 |
7 | import io.rebble.store.BR;
8 | import io.rebble.store.R;
9 | import io.rebble.store.command.LaunchWatchFaceApplicationDetailsActivityCommand;
10 | import io.rebble.store.viewmodel.WatchFaceApplicationViewModel;
11 |
12 | /**
13 | * Created by zhangqichuan on 15/12/16.
14 | */
15 |
16 | public class WatchFaceListAdapter extends DataBindingBaseAdapter {
17 | public WatchFaceListAdapter(List mList) {
18 | super(mList);
19 | }
20 |
21 | @Override
22 | protected int getLayoutResId() {
23 | return R.layout.item_watchface;
24 | }
25 |
26 | @Override
27 | protected int getBRResId() {
28 | return BR.watchface;
29 | }
30 |
31 | @Override
32 | protected void onItemClicked(View view, WatchFaceApplicationViewModel item, int position) {
33 | LaunchWatchFaceApplicationDetailsActivityCommand command
34 | = new LaunchWatchFaceApplicationDetailsActivityCommand(view, item);
35 | command.execute();
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/java/io/rebble/store/api/Api.java:
--------------------------------------------------------------------------------
1 | package io.rebble.store.api;
2 |
3 | import android.util.Log;
4 |
5 | import java.io.File;
6 |
7 | import io.rebble.store.StoreApplication;
8 | import io.rebble.store.api.model.ApplicationIndexResult;
9 | import okhttp3.Cache;
10 | import okhttp3.OkHttpClient;
11 | import retrofit2.Retrofit;
12 | import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
13 | import retrofit2.converter.jackson.JacksonConverterFactory;
14 | import rx.Subscriber;
15 | import rx.android.schedulers.AndroidSchedulers;
16 | import rx.schedulers.Schedulers;
17 |
18 | /**
19 | * Created by zhangqichuan on 19/12/16.
20 | */
21 |
22 | public class Api {
23 |
24 | private final ApiService mApiService;
25 |
26 | public Api() {
27 | Retrofit retrofit = new Retrofit.Builder()
28 | .baseUrl("https://dev-portal.getpebble.com/api/")
29 | .client(provideOkHttpClient())
30 | .addConverterFactory(JacksonConverterFactory.create())
31 | .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
32 | .build();
33 | mApiService = retrofit.create(ApiService.class);
34 | }
35 |
36 | public void getApplicationIndex(Subscriber subscriber) {
37 | mApiService.getApplicationIndex()
38 | .subscribeOn(Schedulers.io())
39 | .unsubscribeOn(Schedulers.io())
40 | .observeOn(AndroidSchedulers.mainThread())
41 | .subscribe(subscriber);
42 | }
43 |
44 | public void getWatchfaceIndex(Subscriber subscriber) {
45 | mApiService.getWatchfaceIndex()
46 | .subscribeOn(Schedulers.io())
47 | .unsubscribeOn(Schedulers.io())
48 | .observeOn(AndroidSchedulers.mainThread())
49 | .subscribe(subscriber);
50 | }
51 |
52 | private OkHttpClient provideOkHttpClient ()
53 | {
54 | return new OkHttpClient.Builder()
55 | .addInterceptor( new OfflineCacheInterceptor() )
56 | .addNetworkInterceptor( new CacheInterceptor() )
57 | .cache( provideCache() )
58 | .build();
59 | }
60 |
61 | private Cache provideCache() {
62 | Cache cache = null;
63 | try {
64 | cache = new Cache(new File(StoreApplication.getApplication()
65 | .getCacheDir(), "http-cache"),
66 | 10 * 1024 * 1024); // 10 MB
67 | } catch (Exception e) {
68 | Log.e("Rebble", "Could not create Cache!");
69 | }
70 | return cache;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/app/src/main/java/io/rebble/store/api/ApiService.java:
--------------------------------------------------------------------------------
1 | package io.rebble.store.api;
2 |
3 | import io.rebble.store.api.model.ApplicationIndexResult;
4 | import retrofit2.http.GET;
5 | import rx.Observable;
6 |
7 | /**
8 | * Created by zhangqichuan on 19/12/16.
9 | */
10 |
11 | public interface ApiService {
12 | @GET("categories/index")
13 | Observable getApplicationIndex();
14 |
15 |
16 | @GET("categories/faces")
17 | Observable getWatchfaceIndex();
18 | }
19 |
--------------------------------------------------------------------------------
/app/src/main/java/io/rebble/store/api/CacheInterceptor.java:
--------------------------------------------------------------------------------
1 | package io.rebble.store.api;
2 |
3 | import java.io.IOException;
4 | import java.util.concurrent.TimeUnit;
5 |
6 | import okhttp3.CacheControl;
7 | import okhttp3.Interceptor;
8 | import okhttp3.Response;
9 |
10 | /**
11 | * Created by zhangqichuan on 2/1/17.
12 | */
13 |
14 | public class CacheInterceptor implements Interceptor {
15 | @Override
16 | public Response intercept(Chain chain) throws IOException {
17 | Response response = chain.proceed( chain.request() );
18 |
19 | // re-write response header to force use of cache
20 | CacheControl cacheControl = new CacheControl.Builder()
21 | .maxAge( 2, TimeUnit.MINUTES )
22 | .build();
23 |
24 | return response.newBuilder()
25 | .header( "Cache-Control", cacheControl.toString() )
26 | .build();
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/app/src/main/java/io/rebble/store/api/OfflineCacheInterceptor.java:
--------------------------------------------------------------------------------
1 | package io.rebble.store.api;
2 |
3 | import java.io.IOException;
4 | import java.util.concurrent.TimeUnit;
5 |
6 | import io.rebble.store.util.NetworkUtil;
7 | import okhttp3.CacheControl;
8 | import okhttp3.Interceptor;
9 | import okhttp3.Request;
10 | import okhttp3.Response;
11 |
12 | /**
13 | * Created by zhangqichuan on 2/1/17.
14 | */
15 |
16 | public class OfflineCacheInterceptor implements Interceptor {
17 | @Override
18 | public Response intercept(Chain chain) throws IOException {
19 | Request request = chain.request();
20 |
21 | if (!NetworkUtil.hasNetwork()) {
22 | CacheControl cacheControl = new CacheControl.Builder()
23 | .maxStale(7, TimeUnit.DAYS)
24 | .build();
25 |
26 | request = request.newBuilder()
27 | .cacheControl(cacheControl)
28 | .build();
29 | }
30 |
31 | return chain.proceed(request);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/app/src/main/java/io/rebble/store/api/model/AndroidCompanion.java:
--------------------------------------------------------------------------------
1 |
2 | package io.rebble.store.api.model;
3 |
4 | import java.util.HashMap;
5 | import java.util.Map;
6 | import android.os.Parcel;
7 | import android.os.Parcelable;
8 | import android.os.Parcelable.Creator;
9 | import com.fasterxml.jackson.annotation.JsonAnyGetter;
10 | import com.fasterxml.jackson.annotation.JsonAnySetter;
11 | import com.fasterxml.jackson.annotation.JsonIgnore;
12 | import com.fasterxml.jackson.annotation.JsonInclude;
13 | import com.fasterxml.jackson.annotation.JsonProperty;
14 | import com.fasterxml.jackson.annotation.JsonPropertyOrder;
15 |
16 | @JsonInclude(JsonInclude.Include.NON_NULL)
17 | @JsonPropertyOrder({
18 | "id",
19 | "name",
20 | "icon",
21 | "url"
22 | })
23 | public class AndroidCompanion implements Parcelable
24 | {
25 |
26 | @JsonProperty("id")
27 | public String id;
28 | @JsonProperty("name")
29 | public String name;
30 | @JsonProperty("icon")
31 | public String icon;
32 | @JsonProperty("url")
33 | public String url;
34 | @JsonIgnore
35 | private Map additionalProperties = new HashMap();
36 | public final static Creator CREATOR = new Creator() {
37 |
38 |
39 | @SuppressWarnings({
40 | "unchecked"
41 | })
42 | public AndroidCompanion createFromParcel(Parcel in) {
43 | AndroidCompanion instance = new AndroidCompanion();
44 | instance.id = ((String) in.readValue((String.class.getClassLoader())));
45 | instance.name = ((String) in.readValue((String.class.getClassLoader())));
46 | instance.icon = ((String) in.readValue((String.class.getClassLoader())));
47 | instance.url = ((String) in.readValue((String.class.getClassLoader())));
48 | instance.additionalProperties = ((Map ) in.readValue((Map.class.getClassLoader())));
49 | return instance;
50 | }
51 |
52 | public AndroidCompanion[] newArray(int size) {
53 | return (new AndroidCompanion[size]);
54 | }
55 |
56 | }
57 | ;
58 |
59 | @JsonAnyGetter
60 | public Map getAdditionalProperties() {
61 | return this.additionalProperties;
62 | }
63 |
64 | @JsonAnySetter
65 | public void setAdditionalProperty(String name, Object value) {
66 | this.additionalProperties.put(name, value);
67 | }
68 |
69 | public void writeToParcel(Parcel dest, int flags) {
70 | dest.writeValue(id);
71 | dest.writeValue(name);
72 | dest.writeValue(icon);
73 | dest.writeValue(url);
74 | dest.writeValue(additionalProperties);
75 | }
76 |
77 | public int describeContents() {
78 | return 0;
79 | }
80 |
81 | }
82 |
--------------------------------------------------------------------------------
/app/src/main/java/io/rebble/store/api/model/Application.java:
--------------------------------------------------------------------------------
1 |
2 | package io.rebble.store.api.model;
3 |
4 | import java.util.ArrayList;
5 | import java.util.HashMap;
6 | import java.util.List;
7 | import java.util.Map;
8 | import android.os.Parcel;
9 | import android.os.Parcelable;
10 | import android.os.Parcelable.Creator;
11 | import com.fasterxml.jackson.annotation.JsonAnyGetter;
12 | import com.fasterxml.jackson.annotation.JsonAnySetter;
13 | import com.fasterxml.jackson.annotation.JsonIgnore;
14 | import com.fasterxml.jackson.annotation.JsonInclude;
15 | import com.fasterxml.jackson.annotation.JsonProperty;
16 | import com.fasterxml.jackson.annotation.JsonPropertyOrder;
17 |
18 | @JsonInclude(JsonInclude.Include.NON_NULL)
19 | @JsonPropertyOrder({
20 | "id",
21 | "href",
22 | "title",
23 | "description",
24 | "type",
25 | "author",
26 | "source",
27 | "website",
28 | "banner_image",
29 | "screenshot_images",
30 | "header_images",
31 | "list_image",
32 | "rating",
33 | "hearts",
34 | "icon_image",
35 | "pbw_file",
36 | "uuid",
37 | "published_date",
38 | "version",
39 | "release_id",
40 | "links",
41 | "category_name",
42 | "category_color",
43 | "developer_id",
44 | "compatibility",
45 | "ios_companion",
46 | "android_companion"
47 | })
48 | public class Application implements Parcelable
49 | {
50 |
51 | @JsonProperty("id")
52 | public String id;
53 | @JsonProperty("href")
54 | public String href;
55 | @JsonProperty("title")
56 | public String title;
57 | @JsonProperty("description")
58 | public String description;
59 | @JsonProperty("type")
60 | public String type;
61 | @JsonProperty("author")
62 | public String author;
63 | @JsonProperty("source")
64 | public String source;
65 | @JsonProperty("website")
66 | public String website;
67 | @JsonProperty("banner_image")
68 | public String bannerImage;
69 | @JsonProperty("screenshot_images")
70 | public List screenshotImages = null;
71 | @JsonProperty("header_images")
72 | public List headerImages = null;
73 | @JsonProperty("list_image")
74 | public String listImage;
75 | @JsonProperty("rating")
76 | public Integer rating;
77 | @JsonProperty("hearts")
78 | public Integer hearts;
79 | @JsonProperty("icon_image")
80 | public String iconImage;
81 | @JsonProperty("pbw_file")
82 | public String pbwFile;
83 | @JsonProperty("uuid")
84 | public String uuid;
85 | @JsonProperty("published_date")
86 | public String publishedDate;
87 | @JsonProperty("version")
88 | public String version;
89 | @JsonProperty("release_id")
90 | public String releaseId;
91 | @JsonProperty("links")
92 | public Links links;
93 | @JsonProperty("category_name")
94 | public String categoryName;
95 | @JsonProperty("category_color")
96 | public String categoryColor;
97 | @JsonProperty("developer_id")
98 | public String developerId;
99 | @JsonProperty("compatibility")
100 | public Compatibility compatibility;
101 | @JsonProperty("ios_companion")
102 | public IosCompanion iosCompanion;
103 | @JsonProperty("android_companion")
104 | public AndroidCompanion androidCompanion;
105 | @JsonIgnore
106 | private Map additionalProperties = new HashMap();
107 | public final static Creator CREATOR = new Creator() {
108 |
109 |
110 | @SuppressWarnings({
111 | "unchecked"
112 | })
113 | public Application createFromParcel(Parcel in) {
114 | Application instance = new Application();
115 | instance.id = ((String) in.readValue((String.class.getClassLoader())));
116 | instance.href = ((String) in.readValue((String.class.getClassLoader())));
117 | instance.title = ((String) in.readValue((String.class.getClassLoader())));
118 | instance.description = ((String) in.readValue((String.class.getClassLoader())));
119 | instance.type = ((String) in.readValue((String.class.getClassLoader())));
120 | instance.author = ((String) in.readValue((String.class.getClassLoader())));
121 | instance.source = ((String) in.readValue((String.class.getClassLoader())));
122 | instance.website = ((String) in.readValue((String.class.getClassLoader())));
123 | instance.bannerImage = ((String) in.readValue((String.class.getClassLoader())));
124 | instance.screenshotImages = new ArrayList<>();
125 | in.readList(instance.screenshotImages, (String.class.getClassLoader()));
126 | instance.headerImages = new ArrayList<>();
127 | in.readList(instance.headerImages, (String.class.getClassLoader()));
128 | instance.listImage = ((String) in.readValue((String.class.getClassLoader())));
129 | instance.rating = ((Integer) in.readValue((Integer.class.getClassLoader())));
130 | instance.hearts = ((Integer) in.readValue((Integer.class.getClassLoader())));
131 | instance.iconImage = ((String) in.readValue((String.class.getClassLoader())));
132 | instance.pbwFile = ((String) in.readValue((String.class.getClassLoader())));
133 | instance.uuid = ((String) in.readValue((String.class.getClassLoader())));
134 | instance.publishedDate = ((String) in.readValue((String.class.getClassLoader())));
135 | instance.version = ((String) in.readValue((String.class.getClassLoader())));
136 | instance.releaseId = ((String) in.readValue((String.class.getClassLoader())));
137 | instance.links = ((Links) in.readValue((Links.class.getClassLoader())));
138 | instance.categoryName = ((String) in.readValue((String.class.getClassLoader())));
139 | instance.categoryColor = ((String) in.readValue((String.class.getClassLoader())));
140 | instance.developerId = ((String) in.readValue((String.class.getClassLoader())));
141 | instance.compatibility = ((Compatibility) in.readValue((Compatibility.class.getClassLoader())));
142 | instance.iosCompanion = ((IosCompanion) in.readValue((IosCompanion.class.getClassLoader())));
143 | instance.androidCompanion = ((AndroidCompanion) in.readValue((AndroidCompanion.class.getClassLoader())));
144 | instance.additionalProperties = ((Map ) in.readValue((Map.class.getClassLoader())));
145 | return instance;
146 | }
147 |
148 | public Application[] newArray(int size) {
149 | return (new Application[size]);
150 | }
151 |
152 | }
153 | ;
154 |
155 | @JsonAnyGetter
156 | public Map getAdditionalProperties() {
157 | return this.additionalProperties;
158 | }
159 |
160 | @JsonAnySetter
161 | public void setAdditionalProperty(String name, Object value) {
162 | this.additionalProperties.put(name, value);
163 | }
164 |
165 | public void writeToParcel(Parcel dest, int flags) {
166 | dest.writeValue(id);
167 | dest.writeValue(href);
168 | dest.writeValue(title);
169 | dest.writeValue(description);
170 | dest.writeValue(type);
171 | dest.writeValue(author);
172 | dest.writeValue(source);
173 | dest.writeValue(website);
174 | dest.writeValue(bannerImage);
175 | dest.writeList(screenshotImages);
176 | dest.writeList(headerImages);
177 | dest.writeValue(listImage);
178 | dest.writeValue(rating);
179 | dest.writeValue(hearts);
180 | dest.writeValue(iconImage);
181 | dest.writeValue(pbwFile);
182 | dest.writeValue(uuid);
183 | dest.writeValue(publishedDate);
184 | dest.writeValue(version);
185 | dest.writeValue(releaseId);
186 | dest.writeValue(links);
187 | dest.writeValue(categoryName);
188 | dest.writeValue(categoryColor);
189 | dest.writeValue(developerId);
190 | dest.writeValue(compatibility);
191 | dest.writeValue(iosCompanion);
192 | dest.writeValue(androidCompanion);
193 | dest.writeValue(additionalProperties);
194 | }
195 |
196 | public int describeContents() {
197 | return 0;
198 | }
199 |
200 | }
201 |
--------------------------------------------------------------------------------
/app/src/main/java/io/rebble/store/api/model/ApplicationIndexResult.java:
--------------------------------------------------------------------------------
1 |
2 | package io.rebble.store.api.model;
3 |
4 | import java.util.ArrayList;
5 | import java.util.HashMap;
6 | import java.util.List;
7 | import java.util.Map;
8 | import android.os.Parcel;
9 | import android.os.Parcelable;
10 | import android.os.Parcelable.Creator;
11 | import com.fasterxml.jackson.annotation.JsonAnyGetter;
12 | import com.fasterxml.jackson.annotation.JsonAnySetter;
13 | import com.fasterxml.jackson.annotation.JsonIgnore;
14 | import com.fasterxml.jackson.annotation.JsonInclude;
15 | import com.fasterxml.jackson.annotation.JsonProperty;
16 | import com.fasterxml.jackson.annotation.JsonPropertyOrder;
17 |
18 | @JsonInclude(JsonInclude.Include.NON_NULL)
19 | @JsonPropertyOrder({
20 | "collections",
21 | "applications",
22 | "custom_banners",
23 | "category_links",
24 | "categories"
25 | })
26 | public class ApplicationIndexResult implements Parcelable
27 | {
28 |
29 | @JsonProperty("collections")
30 | public List collections = null;
31 | @JsonProperty("applications")
32 | public List applications = null;
33 | @JsonProperty("custom_banners")
34 | public List