├── .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 customBanners = null; 35 | @JsonProperty("category_links") 36 | public List categoryLinks = null; 37 | @JsonProperty("categories") 38 | public List categories = null; 39 | @JsonIgnore 40 | private Map additionalProperties = new HashMap(); 41 | public final static Creator CREATOR = new Creator() { 42 | 43 | 44 | @SuppressWarnings({ 45 | "unchecked" 46 | }) 47 | public ApplicationIndexResult createFromParcel(Parcel in) { 48 | ApplicationIndexResult instance = new ApplicationIndexResult(); 49 | instance.collections = new ArrayList<>(); 50 | instance.applications = new ArrayList<>(); 51 | instance.customBanners = new ArrayList<>(); 52 | instance.categoryLinks = new ArrayList<>(); 53 | instance.categories = new ArrayList<>(); 54 | in.readList(instance.collections, (io.rebble.store.api.model.Collection.class.getClassLoader())); 55 | in.readList(instance.applications, (Application.class.getClassLoader())); 56 | in.readList(instance.customBanners, (Object.class.getClassLoader())); 57 | in.readList(instance.categoryLinks, (io.rebble.store.api.model.CategoryLink.class.getClassLoader())); 58 | in.readList(instance.categories, (Category.class.getClassLoader())); 59 | instance.additionalProperties = ((Map ) in.readValue((Map.class.getClassLoader()))); 60 | return instance; 61 | } 62 | 63 | public ApplicationIndexResult[] newArray(int size) { 64 | return (new ApplicationIndexResult[size]); 65 | } 66 | 67 | } 68 | ; 69 | 70 | @JsonAnyGetter 71 | public Map getAdditionalProperties() { 72 | return this.additionalProperties; 73 | } 74 | 75 | @JsonAnySetter 76 | public void setAdditionalProperty(String name, Object value) { 77 | this.additionalProperties.put(name, value); 78 | } 79 | 80 | public void writeToParcel(Parcel dest, int flags) { 81 | dest.writeList(collections); 82 | dest.writeList(applications); 83 | dest.writeList(customBanners); 84 | dest.writeList(categoryLinks); 85 | dest.writeList(categories); 86 | dest.writeValue(additionalProperties); 87 | } 88 | 89 | public int describeContents() { 90 | return 0; 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /app/src/main/java/io/rebble/store/api/model/Category.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 | "name", 23 | "collections", 24 | "custom_banners", 25 | "featured_applications", 26 | "top_recent_applications", 27 | "top_hearted_applications", 28 | "category_links" 29 | }) 30 | public class Category implements Parcelable 31 | { 32 | 33 | @JsonProperty("id") 34 | public String id; 35 | @JsonProperty("href") 36 | public String href; 37 | @JsonProperty("name") 38 | public String name; 39 | @JsonProperty("collections") 40 | public List collections = null; 41 | @JsonProperty("custom_banners") 42 | public List customBanners = null; 43 | @JsonProperty("featured_applications") 44 | public List featuredApplications = null; 45 | @JsonProperty("top_recent_applications") 46 | public List topRecentApplications = null; 47 | @JsonProperty("top_hearted_applications") 48 | public List topHeartedApplications = null; 49 | @JsonProperty("category_links") 50 | public List categoryLinks = null; 51 | @JsonIgnore 52 | private Map additionalProperties = new HashMap(); 53 | public final static Creator CREATOR = new Creator() { 54 | 55 | 56 | @SuppressWarnings({ 57 | "unchecked" 58 | }) 59 | public Category createFromParcel(Parcel in) { 60 | Category instance = new Category(); 61 | instance.id = ((String) in.readValue((String.class.getClassLoader()))); 62 | instance.href = ((String) in.readValue((String.class.getClassLoader()))); 63 | instance.name = ((String) in.readValue((String.class.getClassLoader()))); 64 | instance.collections = new ArrayList<>(); 65 | instance.customBanners = new ArrayList<>(); 66 | instance.featuredApplications = new ArrayList<>(); 67 | instance.topRecentApplications = new ArrayList<>(); 68 | instance.topHeartedApplications = new ArrayList<>(); 69 | instance.categoryLinks = new ArrayList<>(); 70 | in.readList(instance.collections, (String.class.getClassLoader())); 71 | in.readList(instance.customBanners, (Object.class.getClassLoader())); 72 | in.readList(instance.featuredApplications, (String.class.getClassLoader())); 73 | in.readList(instance.topRecentApplications, (String.class.getClassLoader())); 74 | in.readList(instance.topHeartedApplications, (String.class.getClassLoader())); 75 | in.readList(instance.categoryLinks, (String.class.getClassLoader())); 76 | instance.additionalProperties = ((Map ) in.readValue((Map.class.getClassLoader()))); 77 | return instance; 78 | } 79 | 80 | public Category[] newArray(int size) { 81 | return (new Category[size]); 82 | } 83 | 84 | } 85 | ; 86 | 87 | @JsonAnyGetter 88 | public Map getAdditionalProperties() { 89 | return this.additionalProperties; 90 | } 91 | 92 | @JsonAnySetter 93 | public void setAdditionalProperty(String name, Object value) { 94 | this.additionalProperties.put(name, value); 95 | } 96 | 97 | public void writeToParcel(Parcel dest, int flags) { 98 | dest.writeValue(id); 99 | dest.writeValue(href); 100 | dest.writeValue(name); 101 | dest.writeList(collections); 102 | dest.writeList(customBanners); 103 | dest.writeList(featuredApplications); 104 | dest.writeList(topRecentApplications); 105 | dest.writeList(topHeartedApplications); 106 | dest.writeList(categoryLinks); 107 | dest.writeValue(additionalProperties); 108 | } 109 | 110 | public int describeContents() { 111 | return 0; 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /app/src/main/java/io/rebble/store/api/model/CategoryLink.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 | "href", 20 | "name", 21 | "icon_url", 22 | "color", 23 | "apps_count" 24 | }) 25 | public class CategoryLink implements Parcelable 26 | { 27 | 28 | @JsonProperty("id") 29 | public String id; 30 | @JsonProperty("href") 31 | public String href; 32 | @JsonProperty("name") 33 | public String name; 34 | @JsonProperty("icon_url") 35 | public String iconUrl; 36 | @JsonProperty("color") 37 | public String color; 38 | @JsonProperty("apps_count") 39 | public Integer appsCount; 40 | @JsonIgnore 41 | private Map additionalProperties = new HashMap(); 42 | public final static Creator CREATOR = new Creator() { 43 | 44 | 45 | @SuppressWarnings({ 46 | "unchecked" 47 | }) 48 | public CategoryLink createFromParcel(Parcel in) { 49 | CategoryLink instance = new CategoryLink(); 50 | instance.id = ((String) in.readValue((String.class.getClassLoader()))); 51 | instance.href = ((String) in.readValue((String.class.getClassLoader()))); 52 | instance.name = ((String) in.readValue((String.class.getClassLoader()))); 53 | instance.iconUrl = ((String) in.readValue((String.class.getClassLoader()))); 54 | instance.color = ((String) in.readValue((String.class.getClassLoader()))); 55 | instance.appsCount = ((Integer) in.readValue((Integer.class.getClassLoader()))); 56 | instance.additionalProperties = ((Map ) in.readValue((Map.class.getClassLoader()))); 57 | return instance; 58 | } 59 | 60 | public CategoryLink[] newArray(int size) { 61 | return (new CategoryLink[size]); 62 | } 63 | 64 | } 65 | ; 66 | 67 | @JsonAnyGetter 68 | public Map getAdditionalProperties() { 69 | return this.additionalProperties; 70 | } 71 | 72 | @JsonAnySetter 73 | public void setAdditionalProperty(String name, Object value) { 74 | this.additionalProperties.put(name, value); 75 | } 76 | 77 | public void writeToParcel(Parcel dest, int flags) { 78 | dest.writeValue(id); 79 | dest.writeValue(href); 80 | dest.writeValue(name); 81 | dest.writeValue(iconUrl); 82 | dest.writeValue(color); 83 | dest.writeValue(appsCount); 84 | dest.writeValue(additionalProperties); 85 | } 86 | 87 | public int describeContents() { 88 | return 0; 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /app/src/main/java/io/rebble/store/api/model/Collection.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 | "name", 23 | "featured", 24 | "applications" 25 | }) 26 | public class Collection implements Parcelable 27 | { 28 | 29 | @JsonProperty("id") 30 | public String id; 31 | @JsonProperty("href") 32 | public String href; 33 | @JsonProperty("name") 34 | public String name; 35 | @JsonProperty("featured") 36 | public Boolean featured; 37 | @JsonProperty("applications") 38 | public List applications = null; 39 | @JsonIgnore 40 | private Map additionalProperties = new HashMap(); 41 | public final static Creator CREATOR = new Creator() { 42 | 43 | 44 | @SuppressWarnings({ 45 | "unchecked" 46 | }) 47 | public Collection createFromParcel(Parcel in) { 48 | Collection instance = new Collection(); 49 | instance.id = ((String) in.readValue((String.class.getClassLoader()))); 50 | instance.href = ((String) in.readValue((String.class.getClassLoader()))); 51 | instance.name = ((String) in.readValue((String.class.getClassLoader()))); 52 | instance.featured = ((Boolean) in.readValue((Boolean.class.getClassLoader()))); 53 | instance.applications = new ArrayList<>(); 54 | in.readList(instance.applications, (String.class.getClassLoader())); 55 | instance.additionalProperties = ((Map ) in.readValue((Map.class.getClassLoader()))); 56 | return instance; 57 | } 58 | 59 | public Collection[] newArray(int size) { 60 | return (new Collection[size]); 61 | } 62 | 63 | } 64 | ; 65 | 66 | @JsonAnyGetter 67 | public Map getAdditionalProperties() { 68 | return this.additionalProperties; 69 | } 70 | 71 | @JsonAnySetter 72 | public void setAdditionalProperty(String name, Object value) { 73 | this.additionalProperties.put(name, value); 74 | } 75 | 76 | public void writeToParcel(Parcel dest, int flags) { 77 | dest.writeValue(id); 78 | dest.writeValue(href); 79 | dest.writeValue(name); 80 | dest.writeValue(featured); 81 | dest.writeList(applications); 82 | dest.writeValue(additionalProperties); 83 | } 84 | 85 | public int describeContents() { 86 | return 0; 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /app/src/main/java/io/rebble/store/api/model/Compatibility.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 | "platform", 19 | "jsv", 20 | "hardware" 21 | }) 22 | public class Compatibility implements Parcelable 23 | { 24 | 25 | @JsonProperty("platform") 26 | public Boolean platform; 27 | @JsonProperty("jsv") 28 | public Boolean jsv; 29 | @JsonProperty("hardware") 30 | public Boolean hardware; 31 | @JsonIgnore 32 | private Map additionalProperties = new HashMap(); 33 | public final static Creator CREATOR = new Creator() { 34 | 35 | 36 | @SuppressWarnings({ 37 | "unchecked" 38 | }) 39 | public Compatibility createFromParcel(Parcel in) { 40 | Compatibility instance = new Compatibility(); 41 | instance.platform = ((Boolean) in.readValue((Boolean.class.getClassLoader()))); 42 | instance.jsv = ((Boolean) in.readValue((Boolean.class.getClassLoader()))); 43 | instance.hardware = ((Boolean) in.readValue((Boolean.class.getClassLoader()))); 44 | instance.additionalProperties = ((Map ) in.readValue((Map.class.getClassLoader()))); 45 | return instance; 46 | } 47 | 48 | public Compatibility[] newArray(int size) { 49 | return (new Compatibility[size]); 50 | } 51 | 52 | } 53 | ; 54 | 55 | @JsonAnyGetter 56 | public Map getAdditionalProperties() { 57 | return this.additionalProperties; 58 | } 59 | 60 | @JsonAnySetter 61 | public void setAdditionalProperty(String name, Object value) { 62 | this.additionalProperties.put(name, value); 63 | } 64 | 65 | public void writeToParcel(Parcel dest, int flags) { 66 | dest.writeValue(platform); 67 | dest.writeValue(jsv); 68 | dest.writeValue(hardware); 69 | dest.writeValue(additionalProperties); 70 | } 71 | 72 | public int describeContents() { 73 | return 0; 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /app/src/main/java/io/rebble/store/api/model/IosCompanion.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 IosCompanion 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 IosCompanion createFromParcel(Parcel in) { 43 | IosCompanion instance = new IosCompanion(); 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 IosCompanion[] newArray(int size) { 53 | return (new IosCompanion[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/Links.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 | "add", 19 | "remove", 20 | "remove_heart", 21 | "add_heart", 22 | "add_flag", 23 | "remove_flag", 24 | "share" 25 | }) 26 | public class Links implements Parcelable 27 | { 28 | 29 | @JsonProperty("add") 30 | public String add; 31 | @JsonProperty("remove") 32 | public String remove; 33 | @JsonProperty("remove_heart") 34 | public String removeHeart; 35 | @JsonProperty("add_heart") 36 | public String addHeart; 37 | @JsonProperty("add_flag") 38 | public String addFlag; 39 | @JsonProperty("remove_flag") 40 | public String removeFlag; 41 | @JsonProperty("share") 42 | public String share; 43 | @JsonIgnore 44 | private Map additionalProperties = new HashMap(); 45 | public final static Creator CREATOR = new Creator() { 46 | 47 | 48 | @SuppressWarnings({ 49 | "unchecked" 50 | }) 51 | public Links createFromParcel(Parcel in) { 52 | Links instance = new Links(); 53 | instance.add = ((String) in.readValue((String.class.getClassLoader()))); 54 | instance.remove = ((String) in.readValue((String.class.getClassLoader()))); 55 | instance.removeHeart = ((String) in.readValue((String.class.getClassLoader()))); 56 | instance.addHeart = ((String) in.readValue((String.class.getClassLoader()))); 57 | instance.addFlag = ((String) in.readValue((String.class.getClassLoader()))); 58 | instance.removeFlag = ((String) in.readValue((String.class.getClassLoader()))); 59 | instance.share = ((String) in.readValue((String.class.getClassLoader()))); 60 | instance.additionalProperties = ((Map ) in.readValue((Map.class.getClassLoader()))); 61 | return instance; 62 | } 63 | 64 | public Links[] newArray(int size) { 65 | return (new Links[size]); 66 | } 67 | 68 | } 69 | ; 70 | 71 | @JsonAnyGetter 72 | public Map getAdditionalProperties() { 73 | return this.additionalProperties; 74 | } 75 | 76 | @JsonAnySetter 77 | public void setAdditionalProperty(String name, Object value) { 78 | this.additionalProperties.put(name, value); 79 | } 80 | 81 | public void writeToParcel(Parcel dest, int flags) { 82 | dest.writeValue(add); 83 | dest.writeValue(remove); 84 | dest.writeValue(removeHeart); 85 | dest.writeValue(addHeart); 86 | dest.writeValue(addFlag); 87 | dest.writeValue(removeFlag); 88 | dest.writeValue(share); 89 | dest.writeValue(additionalProperties); 90 | } 91 | 92 | public int describeContents() { 93 | return 0; 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /app/src/main/java/io/rebble/store/command/ICommand.java: -------------------------------------------------------------------------------- 1 | package io.rebble.store.command; 2 | 3 | /** 4 | * Created by zhangqichuan on 21/12/16. 5 | */ 6 | 7 | public interface ICommand { 8 | void execute(); 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/io/rebble/store/command/LaunchWatchFaceApplicationDetailsActivityCommand.java: -------------------------------------------------------------------------------- 1 | package io.rebble.store.command; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.os.Build; 7 | import android.support.v4.app.ActivityCompat; 8 | import android.support.v4.app.ActivityOptionsCompat; 9 | import android.support.v4.util.Pair; 10 | import android.view.View; 11 | 12 | import io.rebble.store.R; 13 | import io.rebble.store.activity.WatchFaceApplicationDetailsActivity; 14 | import io.rebble.store.viewmodel.WatchFaceApplicationViewModel; 15 | 16 | /** 17 | * Created by zhangqichuan on 21/12/16. 18 | */ 19 | 20 | public class LaunchWatchFaceApplicationDetailsActivityCommand implements ICommand { 21 | private final Context mContext; 22 | private final WatchFaceApplicationViewModel mModel; 23 | private View mView; 24 | 25 | public LaunchWatchFaceApplicationDetailsActivityCommand(Context context, WatchFaceApplicationViewModel model) { 26 | this.mContext = context; 27 | this.mModel = model; 28 | } 29 | 30 | public LaunchWatchFaceApplicationDetailsActivityCommand(View view, WatchFaceApplicationViewModel mModel) { 31 | this.mContext = view.getContext(); 32 | this.mModel = mModel; 33 | this.mView = view; 34 | } 35 | 36 | public void setView(View view) { 37 | this.mView = view; 38 | } 39 | 40 | @Override 41 | public void execute() { 42 | Intent intent = new Intent(mContext, WatchFaceApplicationDetailsActivity.class); 43 | intent.putExtra(WatchFaceApplicationDetailsActivity.EXTRA_WATCHFACE_APP_DETAILS, mModel.getDataModel()); 44 | if (mContext instanceof Activity && mView != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 45 | ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation((Activity) mContext, 46 | new Pair(mView.findViewById(R.id.img), 47 | mContext.getString(R.string.transition_name_image))); 48 | ActivityCompat.startActivity(mContext, intent, options.toBundle()); 49 | } else { 50 | mContext.startActivity(intent); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/src/main/java/io/rebble/store/fragment/WatchFaceApplicationListFragment.java: -------------------------------------------------------------------------------- 1 | package io.rebble.store.fragment; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v4.app.Fragment; 6 | import android.support.v7.widget.LinearLayoutManager; 7 | import android.support.v7.widget.RecyclerView; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.widget.ProgressBar; 12 | import android.widget.Toast; 13 | 14 | import java.util.ArrayList; 15 | import java.util.HashMap; 16 | import java.util.List; 17 | import java.util.Map; 18 | 19 | import io.rebble.store.R; 20 | import io.rebble.store.adapter.SectionAdapter; 21 | import io.rebble.store.api.Api; 22 | import io.rebble.store.api.model.Application; 23 | import io.rebble.store.api.model.ApplicationIndexResult; 24 | import io.rebble.store.api.model.Collection; 25 | import io.rebble.store.viewmodel.section.ApplicationListSectionViewModel; 26 | import io.rebble.store.viewmodel.section.CarouselSectionViewModel; 27 | import io.rebble.store.viewmodel.section.BaseSectionViewModel; 28 | import io.rebble.store.viewmodel.section.WatchFaceListSectionViewModel; 29 | import rx.Subscriber; 30 | 31 | /** 32 | * Created by zhangqichuan on 15/12/16. 33 | */ 34 | 35 | public class WatchFaceApplicationListFragment extends Fragment { 36 | 37 | private static String EXTRA_TYPE = "LOAD_DATA_TYPE"; 38 | public static int TYPE_WATCHFACES = 1; 39 | public static int TYPE_APPS = 2; 40 | 41 | private RecyclerView mRecyclerView; 42 | private ProgressBar mProgressBar; 43 | private Api mApi = new Api(); 44 | 45 | public static WatchFaceApplicationListFragment create(int type) { 46 | WatchFaceApplicationListFragment watchFaceListFragment = new WatchFaceApplicationListFragment(); 47 | Bundle bundle = new Bundle(); 48 | bundle.putInt(EXTRA_TYPE, type); 49 | watchFaceListFragment.setArguments(bundle); 50 | return watchFaceListFragment; 51 | } 52 | 53 | @Nullable 54 | @Override 55 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, 56 | @Nullable Bundle savedInstanceState) { 57 | 58 | View view = inflater.inflate(R.layout.fragment_watchface_app_list, container, false); 59 | mRecyclerView = (RecyclerView) view.findViewById(R.id.recyclerView); 60 | mProgressBar = (ProgressBar) view.findViewById(R.id.progressBar); 61 | RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getContext(), 62 | LinearLayoutManager.VERTICAL, false); 63 | mRecyclerView.setLayoutManager(layoutManager); 64 | return view; 65 | } 66 | 67 | @Override 68 | public void onCreate(@Nullable Bundle savedInstanceState) { 69 | super.onCreate(savedInstanceState); 70 | loadDataFromServer(); 71 | } 72 | 73 | private void loadDataFromServer() { 74 | final boolean isWatchFaceType = getArguments().getInt(EXTRA_TYPE) == TYPE_WATCHFACES; 75 | Subscriber subscriber = new Subscriber() { 76 | @Override 77 | public void onCompleted() { 78 | mProgressBar.setVisibility(View.INVISIBLE); 79 | } 80 | 81 | @Override 82 | public void onError(Throwable throwable) { 83 | String cause = throwable.getLocalizedMessage(); 84 | Toast.makeText(getActivity(), cause, Toast.LENGTH_SHORT).show(); 85 | } 86 | 87 | @Override 88 | public void onNext(ApplicationIndexResult applicationIndexResult) { 89 | List applications = applicationIndexResult.applications; 90 | Map applicationCache = createApplicationCache(applications); 91 | List collections = applicationIndexResult.collections; 92 | 93 | List sectionViewModels = new ArrayList<>(); 94 | 95 | //Banner, use the first collection for now 96 | Collection bannerCollection = collections.get(0); 97 | CarouselSectionViewModel carouselSectionViewModel = 98 | new CarouselSectionViewModel("", 99 | getApplicationListFromCollection(bannerCollection, applicationCache)); 100 | 101 | sectionViewModels.add(carouselSectionViewModel); 102 | 103 | for (int i = 0; i < collections.size(); i++) { 104 | Collection collection = collections.get(i); 105 | List featuredApplications 106 | = getApplicationListFromCollection(collection, applicationCache); 107 | if (isWatchFaceType) { 108 | sectionViewModels.add(new WatchFaceListSectionViewModel( 109 | (collection.name).toUpperCase(), 110 | featuredApplications)); 111 | } else { 112 | sectionViewModels.add(new ApplicationListSectionViewModel( 113 | (collection.name).toUpperCase(), 114 | featuredApplications)); 115 | } 116 | 117 | } 118 | mRecyclerView.setAdapter(new SectionAdapter(sectionViewModels)); 119 | } 120 | 121 | }; 122 | if (isWatchFaceType) { 123 | mApi.getWatchfaceIndex(subscriber); 124 | } else { 125 | mApi.getApplicationIndex(subscriber); 126 | } 127 | } 128 | 129 | private List getApplicationListFromCollection(Collection collection, 130 | Map applicationCache){ 131 | List featuredApplicationIds = collection.applications; 132 | List applications = new ArrayList<>(); 133 | 134 | for (int j = 0; j < featuredApplicationIds.size(); j++) { 135 | Application application = 136 | applicationCache.get(featuredApplicationIds.get(j)); 137 | if (application != null) { 138 | applications.add(application); 139 | } 140 | } 141 | return applications; 142 | } 143 | 144 | private Map createApplicationCache(List applications) { 145 | Map map = new HashMap<>(); 146 | for (int i = 0; i < applications.size(); i++) { 147 | Application application = applications.get(i); 148 | map.put(application.id, application); 149 | } 150 | return map; 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /app/src/main/java/io/rebble/store/util/BindingAdapterUtil.java: -------------------------------------------------------------------------------- 1 | package io.rebble.store.util; 2 | 3 | import android.databinding.BindingAdapter; 4 | import android.view.View; 5 | import android.view.ViewGroup; 6 | import android.widget.ImageView; 7 | 8 | import com.bumptech.glide.DrawableTypeRequest; 9 | import com.bumptech.glide.Glide; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | 14 | import io.rebble.store.adapter.SliderViewPagerAdapter; 15 | import io.rebble.store.view.WatchFaceApplicationSliderView; 16 | import io.rebble.store.viewmodel.SliderItemViewModel; 17 | 18 | /** 19 | * Created by zhangqichuan on 15/12/16. 20 | */ 21 | 22 | public class BindingAdapterUtil { 23 | @BindingAdapter({"bind:imageUrl"}) 24 | public static void loadImage(ImageView view, String url) { 25 | DrawableTypeRequest request = Glide.with(view.getContext()).load(url); 26 | if (url.endsWith(".gif")) { 27 | request.asGif().into(view); 28 | } else { 29 | request.into(view); 30 | } 31 | } 32 | 33 | @BindingAdapter("android:layout_width") 34 | public static void setLayoutWidth(View view, float width) { 35 | ViewGroup.LayoutParams layoutParams = view.getLayoutParams(); 36 | layoutParams.width = (int) width; 37 | view.setLayoutParams(layoutParams); 38 | } 39 | 40 | @BindingAdapter("android:layout_height") 41 | public static void setLayoutHeight(View view, float height) { 42 | ViewGroup.LayoutParams layoutParams = view.getLayoutParams(); 43 | layoutParams.height = (int) height; 44 | view.setLayoutParams(layoutParams); 45 | } 46 | 47 | @BindingAdapter("bind:imageUrls") 48 | public static void setImageUrls(WatchFaceApplicationSliderView watchFaceApplicationSliderView, 49 | List imageUrls) { 50 | if (imageUrls == null) { 51 | return; 52 | } 53 | List viewModels = new ArrayList<>(); 54 | for (int i = 0; i < imageUrls.size(); i++) { 55 | viewModels.add(new SliderItemViewModel(imageUrls.get(i))); 56 | } 57 | SliderViewPagerAdapter adapter = new SliderViewPagerAdapter(viewModels); 58 | watchFaceApplicationSliderView.setViewPagerAdapter(adapter); 59 | } 60 | 61 | @BindingAdapter("bind:coverImageUrl") 62 | public static void setCoverImageUrl(WatchFaceApplicationSliderView watchFaceApplicationSliderView, 63 | String coverImageUrl) { 64 | watchFaceApplicationSliderView.setCoverImageUrl(coverImageUrl); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /app/src/main/java/io/rebble/store/util/NetworkUtil.java: -------------------------------------------------------------------------------- 1 | package io.rebble.store.util; 2 | 3 | import android.content.Context; 4 | import android.net.ConnectivityManager; 5 | import android.net.NetworkInfo; 6 | 7 | import io.rebble.store.StoreApplication; 8 | 9 | /** 10 | * Created by zhangqichuan on 2/1/17. 11 | */ 12 | 13 | public class NetworkUtil { 14 | public static boolean hasNetwork() { 15 | StoreApplication storeApplication = StoreApplication.getApplication(); 16 | if (storeApplication != null) { 17 | ConnectivityManager cm = (ConnectivityManager) storeApplication 18 | .getSystemService(Context.CONNECTIVITY_SERVICE); 19 | NetworkInfo networkInfo = cm.getActiveNetworkInfo(); 20 | return networkInfo != null && networkInfo.isConnected(); 21 | } 22 | return false; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/io/rebble/store/view/WatchFaceApplicationSliderView.java: -------------------------------------------------------------------------------- 1 | package io.rebble.store.view; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.os.Build; 6 | import android.support.v4.view.PagerAdapter; 7 | import android.support.v4.view.ViewPager; 8 | import android.transition.Transition; 9 | import android.util.AttributeSet; 10 | import android.view.LayoutInflater; 11 | import android.view.View; 12 | import android.widget.ImageView; 13 | import android.widget.RelativeLayout; 14 | 15 | import com.synnapps.carouselview.PageIndicator; 16 | 17 | import io.rebble.store.R; 18 | import io.rebble.store.util.BindingAdapterUtil; 19 | 20 | /** 21 | * Created by zhangqichuan on 20/12/16. 22 | */ 23 | 24 | public class WatchFaceApplicationSliderView extends RelativeLayout { 25 | 26 | private ViewPager mViewPager; 27 | private ImageView mCoverImage; 28 | private PageIndicator mPageIndicator; 29 | 30 | public WatchFaceApplicationSliderView(Context context) { 31 | super(context); 32 | setupView(); 33 | } 34 | 35 | public WatchFaceApplicationSliderView(Context context, AttributeSet attrs) { 36 | super(context, attrs); 37 | setupView(); 38 | } 39 | 40 | public WatchFaceApplicationSliderView(Context context, AttributeSet attrs, int defStyleAttr) { 41 | super(context, attrs, defStyleAttr); 42 | setupView(); 43 | } 44 | 45 | private void setupView() { 46 | LayoutInflater.from(getContext()).inflate(R.layout.view_watchface_app_slider, this); 47 | this.mViewPager = (ViewPager) findViewById(R.id.viewpager); 48 | this.mCoverImage = (ImageView) findViewById(R.id.img_cover); 49 | this.mPageIndicator = (PageIndicator) findViewById(R.id.indicator); 50 | if (getContext() instanceof Activity) { 51 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 52 | 53 | mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { 54 | @Override 55 | public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 56 | 57 | } 58 | 59 | @Override 60 | public void onPageSelected(int position) { 61 | 62 | } 63 | 64 | @Override 65 | public void onPageScrollStateChanged(int state) { 66 | if (state != ViewPager.SCROLL_STATE_IDLE) { 67 | mCoverImage.setVisibility(View.INVISIBLE); 68 | } else { 69 | mCoverImage.setVisibility(View.VISIBLE); 70 | } 71 | } 72 | }); 73 | 74 | ((Activity) getContext()).getWindow().getSharedElementEnterTransition() 75 | .addListener(new Transition.TransitionListener() { 76 | @Override 77 | public void onTransitionStart(Transition transition) { 78 | mViewPager.post(new Runnable() { 79 | @Override 80 | public void run() { 81 | mViewPager.setVisibility(View.INVISIBLE); 82 | mCoverImage.setVisibility(View.VISIBLE); 83 | } 84 | }); 85 | } 86 | 87 | @Override 88 | public void onTransitionEnd(Transition transition) { 89 | mViewPager.post(new Runnable() { 90 | @Override 91 | public void run() { 92 | mViewPager.setVisibility(View.VISIBLE); 93 | mCoverImage.setVisibility(View.INVISIBLE); 94 | } 95 | }); 96 | } 97 | 98 | @Override 99 | public void onTransitionCancel(Transition transition) { 100 | 101 | } 102 | 103 | @Override 104 | public void onTransitionPause(Transition transition) { 105 | 106 | } 107 | 108 | @Override 109 | public void onTransitionResume(Transition transition) { 110 | 111 | } 112 | }); 113 | } 114 | } 115 | } 116 | 117 | public void setViewPagerAdapter(PagerAdapter pagerAdapter) { 118 | mViewPager.setAdapter(pagerAdapter); 119 | mPageIndicator.setViewPager(mViewPager); 120 | } 121 | 122 | public void setCoverImageUrl(String url) { 123 | BindingAdapterUtil.loadImage(mCoverImage, url); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /app/src/main/java/io/rebble/store/viewmodel/CarouselItemViewModel.java: -------------------------------------------------------------------------------- 1 | package io.rebble.store.viewmodel; 2 | 3 | /** 4 | * Created by zhangqichuan on 17/12/16. 5 | */ 6 | 7 | public class CarouselItemViewModel { 8 | 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/io/rebble/store/viewmodel/MainActivityViewModel.java: -------------------------------------------------------------------------------- 1 | package io.rebble.store.viewmodel; 2 | 3 | import io.rebble.store.BuildConfig; 4 | 5 | /** 6 | * Created by zhangqichuan on 4/1/17. 7 | */ 8 | 9 | public class MainActivityViewModel { 10 | 11 | public String getVersionName() { 12 | return BuildConfig.VERSION_NAME; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/io/rebble/store/viewmodel/SliderItemViewModel.java: -------------------------------------------------------------------------------- 1 | package io.rebble.store.viewmodel; 2 | 3 | /** 4 | * Created by zhangqichuan on 20/12/16. 5 | */ 6 | 7 | public class SliderItemViewModel { 8 | private final String imageUrl; 9 | 10 | public SliderItemViewModel(String imageUrl) { 11 | this.imageUrl = imageUrl; 12 | } 13 | 14 | 15 | public String getImageUrl() { 16 | return imageUrl; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/io/rebble/store/viewmodel/WatchFaceApplicationDetailsViewModel.java: -------------------------------------------------------------------------------- 1 | package io.rebble.store.viewmodel; 2 | 3 | import java.util.List; 4 | 5 | import io.rebble.store.api.model.Application; 6 | 7 | /** 8 | * Created by zhangqichuan on 20/12/16. 9 | */ 10 | 11 | public class WatchFaceApplicationDetailsViewModel { 12 | private final Application application; 13 | 14 | public WatchFaceApplicationDetailsViewModel(Application application) { 15 | this.application = application; 16 | } 17 | 18 | public boolean isBackdropExpanded() { 19 | return application.bannerImage != null; 20 | } 21 | 22 | public String getBackdropImageUrl() { 23 | return application.bannerImage; 24 | } 25 | 26 | public String getTitle() { 27 | return application.title.toUpperCase(); 28 | } 29 | 30 | public String getAuthor() { 31 | return application.author; 32 | } 33 | 34 | public List getScreenshotImageUrls() { 35 | return application.screenshotImages; 36 | } 37 | 38 | public String getFirstScreenShotImageUrl() { 39 | return application.screenshotImages.get(0); 40 | } 41 | 42 | public String getDescription() { 43 | return application.description; 44 | } 45 | 46 | public String getCategory() { 47 | return application.categoryName; 48 | } 49 | 50 | public String getUpdated() { 51 | return application.publishedDate; 52 | } 53 | 54 | public String getVersion() { 55 | return application.version; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /app/src/main/java/io/rebble/store/viewmodel/WatchFaceApplicationViewModel.java: -------------------------------------------------------------------------------- 1 | package io.rebble.store.viewmodel; 2 | 3 | import io.rebble.store.api.model.Application; 4 | 5 | /** 6 | * Created by zhangqichuan on 15/12/16. 7 | */ 8 | 9 | public class WatchFaceApplicationViewModel { 10 | 11 | private final Application application; 12 | 13 | public WatchFaceApplicationViewModel(Application application) { 14 | this.application = application; 15 | } 16 | 17 | public String getImageUrl() { 18 | return application.screenshotImages.get(0); 19 | } 20 | 21 | public String getBackdropImageUrl() { 22 | return application.bannerImage; 23 | } 24 | 25 | public String getName() { 26 | return application.title; 27 | } 28 | 29 | public String getLikes() { 30 | return String.valueOf(application.hearts); 31 | } 32 | 33 | public Application getDataModel() { 34 | return application; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/java/io/rebble/store/viewmodel/section/ApplicationListSectionViewModel.java: -------------------------------------------------------------------------------- 1 | package io.rebble.store.viewmodel.section; 2 | 3 | import java.util.List; 4 | 5 | import io.rebble.store.api.model.Application; 6 | 7 | /** 8 | * Created by zhangqichuan on 15/12/16. 9 | */ 10 | 11 | public class ApplicationListSectionViewModel extends BaseSectionViewModel { 12 | 13 | public ApplicationListSectionViewModel(String name, List list) { 14 | super(name, list); 15 | } 16 | 17 | @Override 18 | public int getType() { 19 | return BaseSectionViewModel.TYPE_APPS; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/io/rebble/store/viewmodel/section/BaseSectionViewModel.java: -------------------------------------------------------------------------------- 1 | package io.rebble.store.viewmodel.section; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import io.rebble.store.api.model.Application; 7 | import io.rebble.store.viewmodel.WatchFaceApplicationViewModel; 8 | 9 | /** 10 | * Created by zhangqichuan on 15/12/16. 11 | */ 12 | 13 | public abstract class BaseSectionViewModel { 14 | public static int TYPE_APPS = 1; 15 | public static int TYPE_WATCHFACES = 2; 16 | public static int TYPE_CAROUSEL = 3; 17 | 18 | private List viewModelList; 19 | private String name; 20 | 21 | public BaseSectionViewModel(String name, 22 | List list) { 23 | viewModelList = new ArrayList<>(); 24 | for (Application application : list) { 25 | viewModelList.add(new WatchFaceApplicationViewModel(application)); 26 | } 27 | this.name = name; 28 | } 29 | 30 | public List getViewModelList() { 31 | return viewModelList; 32 | } 33 | 34 | public String getName() { 35 | return name; 36 | } 37 | 38 | public abstract int getType(); 39 | } 40 | -------------------------------------------------------------------------------- /app/src/main/java/io/rebble/store/viewmodel/section/CarouselSectionViewModel.java: -------------------------------------------------------------------------------- 1 | package io.rebble.store.viewmodel.section; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import io.rebble.store.api.model.Application; 7 | 8 | /** 9 | * Created by zhangqichuan on 17/12/16. 10 | */ 11 | 12 | public class CarouselSectionViewModel extends BaseSectionViewModel { 13 | 14 | 15 | public CarouselSectionViewModel(String name, List list) { 16 | super(name, list); 17 | } 18 | 19 | @Override 20 | public int getType() { 21 | return BaseSectionViewModel.TYPE_CAROUSEL; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/io/rebble/store/viewmodel/section/WatchFaceListSectionViewModel.java: -------------------------------------------------------------------------------- 1 | package io.rebble.store.viewmodel.section; 2 | 3 | import java.util.List; 4 | 5 | import io.rebble.store.api.model.Application; 6 | 7 | /** 8 | * Created by zhangqichuan on 15/12/16. 9 | */ 10 | 11 | public class WatchFaceListSectionViewModel extends BaseSectionViewModel { 12 | 13 | 14 | public WatchFaceListSectionViewModel(String name, List list) { 15 | super(name, list); 16 | } 17 | 18 | @Override 19 | public int getType() { 20 | return BaseSectionViewModel.TYPE_WATCHFACES; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/res/anim/fade_in.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/anim/fade_out.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_heart.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_rebble.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pebble-dev/android-store-app/17f6a44788c274cda36a7544b711068fe7057255/app/src/main/res/drawable/ic_rebble.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/screen_splash.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/slider_background_time.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pebble-dev/android-store-app/17f6a44788c274cda36a7544b711068fe7057255/app/src/main/res/drawable/slider_background_time.png -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 15 | 16 | 21 | 22 | 28 | 29 | 30 | 31 | 38 | 39 | 40 | 41 | 46 | 47 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_splash.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_watchface_app_details.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 11 | 12 | 13 | 17 | 18 | 22 | 23 | 33 | 34 | 42 | 43 | 49 | 50 | 51 | 52 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_watchface_app_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 10 | 11 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_app.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 11 | 12 | 13 | 18 | 19 | 23 | 24 | 29 | 30 | 42 | 43 | 50 | 51 | 56 | 57 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_slider.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 10 | 11 | 12 | 16 | 17 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_watchface.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 11 | 12 | 13 | 18 | 19 | 23 | 24 | 30 | 31 | 38 | 39 | 43 | 44 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_watchface_app_details.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 11 | 12 | 13 | 17 | 18 | 26 | 27 | 35 | 36 | 44 | 45 |