├── .circleci └── config.yml ├── .github └── workflows │ └── android.yml ├── .gitignore ├── .idea ├── assetWizardSettings.xml ├── codeStyles │ ├── Project.xml │ └── codeStyleConfig.xml ├── copyright │ ├── apache_license.xml │ └── profiles_settings.xml ├── encodings.xml ├── jarRepositories.xml ├── misc.xml ├── modules.xml └── vcs.xml ├── CONTRIBUTING.md ├── LICENSE ├── PRIVACY.md ├── README.md ├── app ├── .gitignore ├── build.gradle ├── google-services.json ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── hossainkhan │ │ └── android │ │ └── demo │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── hossainkhan │ │ │ └── android │ │ │ └── demo │ │ │ ├── base │ │ │ ├── AppConfig.kt │ │ │ └── DemoApplication.kt │ │ │ ├── data │ │ │ ├── AppDataStore.kt │ │ │ ├── FirestoreDateFormatter.kt │ │ │ ├── LayoutDataStore.kt │ │ │ ├── LayoutInformation.kt │ │ │ ├── ResourceInfo.kt │ │ │ └── ResourceResult.kt │ │ │ ├── di │ │ │ ├── ActivityBindingModule.kt │ │ │ ├── ActivityScope.kt │ │ │ ├── ApplicationModule.kt │ │ │ ├── DataStoreModule.kt │ │ │ ├── DemoApplicationComponent.kt │ │ │ ├── LayoutBrowseActivityModule.kt │ │ │ ├── LayoutBrowseSubcomponent.kt │ │ │ ├── ViewModelKey.kt │ │ │ └── ViewModelModule.kt │ │ │ ├── ui │ │ │ ├── browse │ │ │ │ ├── BrowseResult.kt │ │ │ │ ├── LayoutBrowseActivity.kt │ │ │ │ ├── LayoutBrowseAdapter.kt │ │ │ │ └── LayoutBrowseViewModel.kt │ │ │ ├── common │ │ │ │ ├── DataBoundListAdapter.kt │ │ │ │ ├── DataBoundViewHolder.kt │ │ │ │ └── LiveEvent.kt │ │ │ ├── dialog │ │ │ │ └── LayoutInfoDialog.kt │ │ │ ├── functionaldemo │ │ │ │ ├── MovieDetailsPreviewActivity.kt │ │ │ │ ├── MoviePosterAdapter.kt │ │ │ │ ├── PinCodeEntryActivity.kt │ │ │ │ └── TedTalkPlaybackActivity.kt │ │ │ ├── layoutpreview │ │ │ │ ├── LayoutChainStyleActivity.kt │ │ │ │ ├── LayoutDimensionMinMaxActivity.kt │ │ │ │ ├── LayoutGuidelineBarrierActivity.kt │ │ │ │ ├── LayoutGuidelineGroupActivity.kt │ │ │ │ ├── LayoutInfoViewModel.kt │ │ │ │ ├── LayoutPreviewBaseActivity.kt │ │ │ │ └── LayoutVisibilityGoneActivity.kt │ │ │ └── resource │ │ │ │ ├── LearningResourceActivity.kt │ │ │ │ ├── LearningResourceViewModel.kt │ │ │ │ └── ResourceListAdapter.kt │ │ │ └── viewmodel │ │ │ └── ViewModelProviderFactory.kt │ └── res │ │ ├── drawable-xxxhdpi │ │ ├── poster_angry_birds.webp │ │ ├── poster_dragon3.webp │ │ ├── poster_finding_nemo.webp │ │ ├── poster_i1.webp │ │ ├── poster_i2.webp │ │ ├── poster_lego_batman.webp │ │ ├── poster_lego_movie.webp │ │ ├── poster_spider_verse_detail.webp │ │ ├── poster_wreckit_ralph.webp │ │ ├── spider_verse_background.webp │ │ ├── spider_verse_poster.webp │ │ ├── thumb_roger_hanlon.png │ │ └── thumb_ted_talk.webp │ │ ├── drawable │ │ ├── circle.xml │ │ ├── ic_baseline_4k_18dp.xml │ │ ├── ic_book_128dp.xml │ │ ├── ic_circle_overlay.xml │ │ ├── ic_dotted_line_overlay.xml │ │ ├── ic_forward_30_black_42dp.xml │ │ ├── ic_github_logo.xml │ │ ├── ic_grid_overlay.xml │ │ ├── ic_image_black_140dp.xml │ │ ├── ic_info_outline_black_24dp.xml │ │ ├── ic_launcher_background.xml │ │ ├── ic_launcher_foreground.xml │ │ ├── ic_library_books_black_42dp.xml │ │ ├── ic_ondemand_video_black_24dp.xml │ │ ├── ic_outline_backspace_24.xml │ │ ├── ic_outline_check_circle_outline_24.xml │ │ ├── ic_people_black_18dp.xml │ │ ├── ic_pin_entry_preview.xml │ │ ├── ic_pin_filled.xml │ │ ├── ic_pin_outline.xml │ │ ├── ic_play_arrow_black_42dp.xml │ │ ├── ic_play_circle_filled_black_42dp.xml │ │ ├── ic_play_circle_outline_black_24dp.xml │ │ ├── ic_playlist_add_black_24dp.xml │ │ ├── ic_replay_30_black_42dp.xml │ │ ├── ic_skip_next_black_42dp.xml │ │ ├── ic_skip_previous_black_42dp.xml │ │ ├── ic_star_black_18dp.xml │ │ ├── ic_ted_talks_logo.xml │ │ ├── ic_thumb_down_black_24dp.xml │ │ ├── ic_thumb_up_black_24dp.xml │ │ ├── thumb_chain_style.xml │ │ ├── thumb_dimension_min_max.xml │ │ ├── thumb_dimension_percentage.xml │ │ ├── thumb_dimension_ratio.xml │ │ ├── thumb_positioning_bias.xml │ │ ├── thumb_positioning_center.xml │ │ ├── thumb_positioning_circular.xml │ │ ├── thumb_positioning_top_left.xml │ │ ├── thumb_virtual_helper_barrier.xml │ │ ├── thumb_virtual_helper_group.xml │ │ ├── thumb_virtual_helper_guideline.xml │ │ └── thumb_visibility_behaviour.xml │ │ ├── layout │ │ ├── .README.md │ │ ├── activity_learning_resource.xml │ │ ├── activity_main.xml │ │ ├── demo_movie_details.xml │ │ ├── demo_pin_code_entry.xml │ │ ├── demo_ted_talk_playback.xml │ │ ├── dialog_layout_info_sheet.xml │ │ ├── include_layout_chain_style.xml │ │ ├── include_layout_positioning_bias.xml │ │ ├── include_layout_positioning_circle_overlay.xml │ │ ├── list_item_layout_preview.xml │ │ ├── list_item_poster.xml │ │ ├── list_item_resource_tech_talk.xml │ │ ├── preview_chain_style_main.xml │ │ ├── preview_chain_weighted.xml │ │ ├── preview_dimension_min_max.xml │ │ ├── preview_dimension_percent.xml │ │ ├── preview_dimension_ratio.xml │ │ ├── preview_positioning_bias.xml │ │ ├── preview_positioning_centered.xml │ │ ├── preview_positioning_circular.xml │ │ ├── preview_positioning_top_left.xml │ │ ├── preview_virtual_helper_barrier.xml │ │ ├── preview_virtual_helper_group.xml │ │ ├── preview_virtual_helper_guideline.xml │ │ └── preview_visibility_gone.xml │ │ ├── menu │ │ ├── menu_layout_browse.xml │ │ └── menu_layout_positioning.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── values-land │ │ └── dimens.xml │ │ ├── values-sw760dp-land │ │ └── dimens.xml │ │ ├── values-sw760dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── colors_material_design.xml │ │ ├── dimens.xml │ │ ├── ic_launcher_background.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── hossainkhan │ └── android │ └── demo │ ├── data │ ├── LayoutDataStoreTest.kt │ └── ResourceInfoTest.kt │ └── ui │ ├── browse │ ├── LayoutBrowseViewModelTest.kt │ └── TestLifecycleOwner.kt │ └── layoutpreview │ └── LayoutInfoViewModelTest.kt ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── resources ├── documents │ └── ConstraintLayout_Documentation_Snapshot.pdf ├── google-play │ ├── Constraint Layout - Google Play Banner.svg │ ├── ConstraintLayout-banner.png │ ├── ic_launcher-web.png │ └── screenshots │ │ ├── phone-6inch │ │ └── phone_04_ted.png │ │ └── tablet-10inch │ │ ├── tablet_01-2.png │ │ ├── tablet_01.png │ │ ├── tablet_02.png │ │ └── tablet_03.png ├── raw-screenshots │ ├── device-2019-06-01-234353.png │ ├── device-2019-06-01-234602-small.png │ ├── device-2019-06-01-234602.png │ ├── device-2019-06-06-190330.png │ ├── device-2020-07-15-205904.png │ ├── device-2020-07-15-205931.png │ ├── device-2020-07-15-205948.png │ ├── device-2020-07-15-210018.png │ ├── device-2020-07-15-210033.png │ ├── device-2020-07-15-210105.png │ ├── device-2020-07-15-210133.png │ ├── device-2020-07-15-210211.png │ └── device-nexus-9-resources.png └── vector │ ├── README.md │ ├── grid_overlay.svg │ ├── ic_chain_style.svg │ ├── ic_dimension_min_max.svg │ ├── ic_dimension_percentage.svg │ ├── ic_dimension_ratio.svg │ ├── ic_positioning_bias.svg │ ├── ic_positioning_center.svg │ ├── ic_positioning_circular.svg │ ├── ic_positioning_top_left.svg │ ├── ic_virtual_helper_barrier.svg │ ├── ic_virtual_helper_group.svg │ ├── ic_virtual_helper_guideline.svg │ └── ic_visibility_behaviour.svg └── settings.gradle /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | 3 | # https://circleci.com/docs/2.0/language-android/ 4 | orbs: 5 | android: circleci/android@0.2.0 6 | 7 | jobs: 8 | build: 9 | executor: android/android 10 | 11 | steps: 12 | - checkout 13 | - run: 14 | command: ./gradlew build 15 | - run: 16 | name: Run Tests 17 | command: ./gradlew lint test 18 | - store_artifacts: 19 | # Stores mobile apk for local testing 20 | path: app/build/outputs/apk 21 | destination: mobile-apk -------------------------------------------------------------------------------- /.github/workflows/android.yml: -------------------------------------------------------------------------------- 1 | name: Android CI 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v1 12 | - name: set up JDK 1.8 13 | uses: actions/setup-java@v1 14 | with: 15 | java-version: 1.8 16 | - name: Build with Gradle 17 | run: ./gradlew assembleDebug 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the ART/Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | out/ 15 | 16 | # Gradle files 17 | .gradle/ 18 | build/ 19 | 20 | # Local configuration file (sdk path, etc) 21 | local.properties 22 | 23 | # Proguard folder generated by Eclipse 24 | proguard/ 25 | 26 | # Log Files 27 | *.log 28 | 29 | # Android Studio Navigation editor temp files 30 | .navigation/ 31 | 32 | # Android Studio captures folder 33 | captures/ 34 | 35 | # Intellij 36 | *.iml 37 | .idea/workspace.xml 38 | .idea/tasks.xml 39 | .idea/gradle.xml 40 | .idea/dictionaries 41 | .idea/libraries 42 | 43 | # Keystore files 44 | *.jks 45 | 46 | # External native build folder generated in Android Studio 2.2 and later 47 | .externalNativeBuild 48 | 49 | # Google Services (e.g. APIs or Firebase) 50 | google-services.json 51 | 52 | # Freeline 53 | freeline.py 54 | freeline/ 55 | freeline_project_description.json 56 | output.json 57 | build_file_checksums.ser 58 | .DS_Store 59 | -------------------------------------------------------------------------------- /.idea/assetWizardSettings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 51 | 52 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/copyright/apache_license.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Contribution Guideline 2 | ===================== 3 | 4 | You are more than welcome to enhance, fix any demo you see in the app. A good way to start is look into existing [issues](https://github.com/amardeshbd/android-constraint-layout-cheatsheet/issues) and see 5 | if any of them interests you. 6 | 7 | Development Guide 8 | ---------------------- 9 | It is important to keep consistency in the project. Here are some of the key things you need to keep in mind: 10 | 11 | * Follow existing app architecture for previewing demo 12 | * Use `LayoutPreviewBaseActivity` if the demo does not need special user interaction 13 | * or, Create subclass of `LayoutPreviewBaseActivity` with user interaction specific binding. See `LayoutVisibilityGoneActivity` as an example. 14 | * Follow existing resource naming convention. See [README](https://github.com/amardeshbd/android-constraint-layout-cheatsheet/blob/master/app/src/main/res/layout/.README.md) 15 | * Create vector assets and save it to [raw resources](https://github.com/amardeshbd/android-constraint-layout-cheatsheet/tree/master/resources/vector) for later use. See [README](https://github.com/amardeshbd/android-constraint-layout-cheatsheet/blob/master/resources/vector/README.md) for example resource and how to create new resource. 16 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/google-services.json: -------------------------------------------------------------------------------- 1 | { 2 | "project_info": { 3 | "project_number": "98405830882", 4 | "firebase_url": "https://constraintlayout-demo.firebaseio.com", 5 | "project_id": "constraintlayout-demo", 6 | "storage_bucket": "constraintlayout-demo.appspot.com" 7 | }, 8 | "client": [ 9 | { 10 | "client_info": { 11 | "mobilesdk_app_id": "1:98405830882:android:8d24bba2add2a5f0", 12 | "android_client_info": { 13 | "package_name": "com.hossainkhan.android.constraintlayout" 14 | } 15 | }, 16 | "oauth_client": [ 17 | { 18 | "client_id": "98405830882-mm815s1f4l9cpjh59rk02hchs4cp60kg.apps.googleusercontent.com", 19 | "client_type": 3 20 | } 21 | ], 22 | "api_key": [ 23 | { 24 | "current_key": "AIzaSyDdPaT1FWfc8jxPg0uUsxlvq798YYy1FQU" 25 | } 26 | ], 27 | "services": { 28 | "analytics_service": { 29 | "status": 1 30 | }, 31 | "appinvite_service": { 32 | "status": 1, 33 | "other_platform_oauth_client": [] 34 | }, 35 | "ads_service": { 36 | "status": 2 37 | } 38 | } 39 | } 40 | ], 41 | "configuration_version": "1" 42 | } -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/hossainkhan/android/demo/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.hossainkhan.android.demo 2 | 3 | import androidx.test.InstrumentationRegistry 4 | import androidx.test.runner.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getTargetContext() 22 | assertEquals("com.hossainkhan.android.demo", appContext.packageName) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 25 | 28 | 31 | 34 | 37 | 40 | 43 | 46 | 49 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /app/src/main/java/com/hossainkhan/android/demo/base/AppConfig.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Hossain Khan 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.hossainkhan.android.demo.base 18 | 19 | /** 20 | * Application configurations. 21 | */ 22 | object AppConfig { 23 | const val GITHUB_BASE_URL = "https://github.com/amardeshbd/android-constraint-layout-cheatsheet" 24 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hossainkhan/android/demo/base/DemoApplication.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Hossain Khan 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.hossainkhan.android.demo.base 18 | 19 | import android.app.Activity 20 | import android.app.Application 21 | import com.hossainkhan.android.demo.BuildConfig 22 | import com.hossainkhan.android.demo.di.DaggerDemoApplicationComponent 23 | import dagger.android.AndroidInjector 24 | import dagger.android.DispatchingAndroidInjector 25 | import dagger.android.HasActivityInjector 26 | import timber.log.Timber 27 | import javax.inject.Inject 28 | 29 | 30 | class DemoApplication : Application(), HasActivityInjector { 31 | @Inject 32 | lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector 33 | 34 | override fun onCreate() { 35 | super.onCreate() 36 | 37 | // Prepares dagger 38 | DaggerDemoApplicationComponent.builder() 39 | .application(this) 40 | .build() 41 | .inject(this) 42 | 43 | if (BuildConfig.DEBUG) { 44 | Timber.plant(Timber.DebugTree()) 45 | } 46 | } 47 | 48 | override fun activityInjector(): AndroidInjector { 49 | return dispatchingAndroidInjector 50 | } 51 | 52 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hossainkhan/android/demo/data/AppDataStore.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Hossain Khan 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.hossainkhan.android.demo.data 18 | 19 | import android.content.SharedPreferences 20 | import javax.inject.Inject 21 | 22 | /** 23 | * Application wide data storage and preferences backed by [SharedPreferences]. 24 | */ 25 | class AppDataStore @Inject constructor( 26 | private val preferences: SharedPreferences, 27 | val layoutStore: LayoutDataStore) { 28 | 29 | private companion object { 30 | private const val PREF_KEY_IS_FIRST_TIME_USER = "KEY_IS_FIRST_TIME_USER" 31 | } 32 | 33 | fun isFirstTime(): Boolean { 34 | return preferences.getBoolean(PREF_KEY_IS_FIRST_TIME_USER, true) 35 | } 36 | 37 | fun updateFirstTimeUser(isFirstTime: Boolean) { 38 | preferences.edit().putBoolean(PREF_KEY_IS_FIRST_TIME_USER, isFirstTime).apply() 39 | } 40 | 41 | /** 42 | * Checks if layout information should be shown to user, and updates the flag if it should be shown. 43 | * 44 | * @return `true`, if it's first time being checked, else `false` 45 | */ 46 | fun shouldshowLayoutInformation(layoutId: Int): Boolean { 47 | val layoutPreferenceKey = layoutStore.getLayoutUrl(layoutId) 48 | val shouldShow = preferences.getBoolean(layoutPreferenceKey, true) 49 | if (shouldShow) { 50 | preferences.edit().putBoolean(layoutPreferenceKey, false).apply() 51 | } 52 | return shouldShow 53 | } 54 | 55 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hossainkhan/android/demo/data/FirestoreDateFormatter.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Hossain Khan 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.hossainkhan.android.demo.data 18 | 19 | import com.google.firebase.Timestamp 20 | import java.text.SimpleDateFormat 21 | import java.util.Date 22 | import java.util.Locale 23 | 24 | 25 | object FirestoreDateFormatter { 26 | fun date(timestamp: Timestamp): String { 27 | val sfd = SimpleDateFormat("EEEE, MMMM d", Locale.CANADA) 28 | return sfd.format(timestamp.toDate()) 29 | } 30 | 31 | fun date(date: Date): String { 32 | val sfd = SimpleDateFormat("MMMM d, yyyy", Locale.CANADA) 33 | return sfd.format(date) 34 | } 35 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hossainkhan/android/demo/data/LayoutInformation.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Hossain Khan 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.hossainkhan.android.demo.data 18 | 19 | import androidx.annotation.DrawableRes 20 | import androidx.annotation.LayoutRes 21 | 22 | /** 23 | * A simple data class containing layout resource ID and it's respective description. 24 | */ 25 | data class LayoutInformation( 26 | @LayoutRes 27 | val layoutResourceId: Int, 28 | @DrawableRes 29 | val thumbnailResourceId: Int, 30 | val title: CharSequence, 31 | val description: CharSequence 32 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/hossainkhan/android/demo/data/ResourceInfo.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Hossain Khan 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.hossainkhan.android.demo.data 18 | 19 | import android.net.Uri 20 | import com.google.firebase.Timestamp 21 | import java.util.Date 22 | 23 | 24 | /** 25 | * External resource info like Youtube video or technical articles online. 26 | * 27 | * Example: 28 | * - author: Nicolas Roard & John Hoford 29 | * - event: Google I/O'19 30 | * - publish_date: 9 May 2019 31 | * - summary: Learn the capabilities of ConstraintLayout 32 | * - title: What's New in ConstraintLayout 33 | * - type: techtalk 34 | * - url: https://www.youtube.com/watch?v=29gLA90m6Gk 35 | */ 36 | data class ResourceInfo( 37 | var author: String = "", 38 | var summary: String = "", 39 | var title: String = "", 40 | var event: String = "", 41 | var url: String = "", 42 | var publish_date: Timestamp? = null, 43 | /** 44 | * Possible values: 45 | * "techarticle", "techtalk" 46 | */ 47 | var type: String = "techtalk" 48 | ) { 49 | val formattedDate: String 50 | get() { 51 | val date = publish_date?.toDate() ?: Date() 52 | return FirestoreDateFormatter.date(date) 53 | } 54 | 55 | val isYouTubeUrl: Boolean 56 | get() = url.contains("youtube.com/watch?v=", ignoreCase = true) 57 | 58 | /** 59 | * Provides [Uri] for directly invoking youtube app via Android Intent. 60 | * @throws IllegalStateException if the URL is not for youtube. Check [isYouTubeUrl] first. 61 | */ 62 | val youtubeIntentUri: String 63 | get() = if (isYouTubeUrl) ("vnd.youtube:" + url.split("=")[1]) else throw IllegalStateException("Not a YouTube URL.") 64 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hossainkhan/android/demo/data/ResourceResult.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Hossain Khan 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.hossainkhan.android.demo.data 18 | 19 | 20 | /** 21 | * A class to represent external resource request with data or error on fail. 22 | */ 23 | class ResourceResult( 24 | val resources: List = emptyList(), 25 | val error: Exception? = null 26 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/hossainkhan/android/demo/di/ActivityScope.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Hossain Khan 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.hossainkhan.android.demo.di 18 | 19 | import javax.inject.Scope 20 | 21 | @Scope 22 | @Retention(AnnotationRetention.RUNTIME) 23 | annotation class ActivityScope 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/hossainkhan/android/demo/di/ApplicationModule.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Hossain Khan 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.hossainkhan.android.demo.di 18 | 19 | import android.app.Application 20 | import android.content.Context 21 | import dagger.Binds 22 | import dagger.Module 23 | 24 | /** 25 | * This is a Dagger module. We use this to bind our Application class as a Context in 26 | * the [DemoApplicationComponent] By using Dagger Android we do not need to pass 27 | * our Application instance to any module, we simply need to expose our Application as Context. 28 | * One of the advantages of Dagger.Android is that your 29 | * Application & Activities are provided into your graph for you. 30 | * 31 | * @see DemoApplicationComponent 32 | */ 33 | @Module(includes = [ViewModelModule::class]) 34 | abstract class ApplicationModule { 35 | //expose Application as an injectable context 36 | @Binds 37 | internal abstract fun bindContext(application: Application): Context 38 | 39 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hossainkhan/android/demo/di/DataStoreModule.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Hossain Khan 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.hossainkhan.android.demo.di 18 | 19 | import android.content.Context 20 | import android.content.SharedPreferences 21 | import android.content.res.Resources 22 | import com.google.firebase.firestore.FirebaseFirestore 23 | import dagger.Module 24 | import dagger.Provides 25 | 26 | @Module 27 | class DataStoreModule { 28 | @Provides 29 | internal fun provideSharedPreferences(context: Context): SharedPreferences { 30 | return context.getSharedPreferences("app_preferences", Context.MODE_PRIVATE) 31 | } 32 | 33 | @Provides 34 | internal fun provideAndroidResoures(context: Context): Resources { 35 | return context.resources 36 | } 37 | 38 | @Provides 39 | internal fun provideFirestore(context: Context): FirebaseFirestore { 40 | return FirebaseFirestore.getInstance() 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/com/hossainkhan/android/demo/di/DemoApplicationComponent.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Hossain Khan 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.hossainkhan.android.demo.di 18 | 19 | import android.app.Application 20 | import com.hossainkhan.android.demo.base.DemoApplication 21 | import dagger.BindsInstance 22 | import dagger.Component 23 | import javax.inject.Singleton 24 | 25 | @Singleton 26 | @Component(modules = arrayOf( 27 | ApplicationModule::class, 28 | ActivityBindingModule::class, 29 | DataStoreModule::class, 30 | LayoutBrowseActivityModule::class)) 31 | interface DemoApplicationComponent { 32 | fun inject(app: DemoApplication) 33 | 34 | // Gives us syntactic sugar. we can then do DaggerAppComponent.builder().application(this).build().inject(this); 35 | // never having to instantiate any modules or say which module we are passing the application to. 36 | // Application will just be provided into our app graph now. 37 | @Component.Builder 38 | interface Builder { 39 | @BindsInstance 40 | fun application(application: Application): DemoApplicationComponent.Builder 41 | 42 | fun build(): DemoApplicationComponent 43 | } 44 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hossainkhan/android/demo/di/LayoutBrowseActivityModule.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Hossain Khan 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.hossainkhan.android.demo.di 18 | 19 | import android.app.Activity 20 | import com.hossainkhan.android.demo.ui.browse.LayoutBrowseActivity 21 | import dagger.Binds 22 | import dagger.Module 23 | import dagger.android.ActivityKey 24 | import dagger.android.AndroidInjector 25 | import dagger.multibindings.IntoMap 26 | 27 | @Module(subcomponents = [LayoutBrowseSubcomponent::class]) 28 | abstract class LayoutBrowseActivityModule { 29 | 30 | @Binds 31 | @IntoMap 32 | @ActivityKey(LayoutBrowseActivity::class) 33 | abstract fun bindMainActivityInjectorFactory( 34 | builder: LayoutBrowseSubcomponent.Builder): AndroidInjector.Factory 35 | 36 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hossainkhan/android/demo/di/LayoutBrowseSubcomponent.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Hossain Khan 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.hossainkhan.android.demo.di 18 | 19 | import com.hossainkhan.android.demo.ui.browse.LayoutBrowseActivity 20 | import dagger.Subcomponent 21 | import dagger.android.AndroidInjector 22 | 23 | @Subcomponent 24 | interface LayoutBrowseSubcomponent : AndroidInjector { 25 | @Subcomponent.Builder 26 | abstract class Builder : AndroidInjector.Builder() 27 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hossainkhan/android/demo/di/ViewModelKey.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Hossain Khan 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.hossainkhan.android.demo.di 18 | 19 | import androidx.lifecycle.ViewModel 20 | import dagger.MapKey 21 | import kotlin.reflect.KClass 22 | 23 | /** 24 | * See https://dagger.dev/multibindings.html 25 | */ 26 | @MustBeDocumented 27 | @Target( 28 | AnnotationTarget.FUNCTION, 29 | AnnotationTarget.PROPERTY_GETTER, 30 | AnnotationTarget.PROPERTY_SETTER 31 | ) 32 | @Retention(AnnotationRetention.RUNTIME) 33 | @MapKey 34 | annotation class ViewModelKey(val value: KClass) 35 | -------------------------------------------------------------------------------- /app/src/main/java/com/hossainkhan/android/demo/di/ViewModelModule.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Hossain Khan 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.hossainkhan.android.demo.di 18 | 19 | import androidx.lifecycle.ViewModel 20 | import androidx.lifecycle.ViewModelProvider 21 | import com.hossainkhan.android.demo.ui.browse.LayoutBrowseViewModel 22 | import com.hossainkhan.android.demo.ui.layoutpreview.LayoutInfoViewModel 23 | import com.hossainkhan.android.demo.ui.resource.LearningResourceViewModel 24 | import com.hossainkhan.android.demo.viewmodel.ViewModelProviderFactory 25 | import dagger.Binds 26 | import dagger.Module 27 | import dagger.multibindings.IntoMap 28 | 29 | /** 30 | * Uses dagger multi-binding to provide [ViewModel] instances used in the app. 31 | * 32 | * @see Multibindings 33 | */ 34 | @Suppress("unused") 35 | @Module 36 | abstract class ViewModelModule { 37 | @Binds 38 | @IntoMap 39 | @ViewModelKey(LayoutBrowseViewModel::class) 40 | abstract fun bindLayoutBrowserViewModel(viewModel: LayoutBrowseViewModel): ViewModel 41 | 42 | @Binds 43 | @IntoMap 44 | @ViewModelKey(LayoutInfoViewModel::class) 45 | abstract fun bindLayoutInfoViewModel(viewModel: LayoutInfoViewModel): ViewModel 46 | 47 | @Binds 48 | @IntoMap 49 | @ViewModelKey(LearningResourceViewModel::class) 50 | abstract fun bindResourceViewModel(viewModel: LearningResourceViewModel): ViewModel 51 | 52 | @Binds 53 | abstract fun bindViewModelFactory(factory: ViewModelProviderFactory): ViewModelProvider.Factory 54 | } 55 | -------------------------------------------------------------------------------- /app/src/main/java/com/hossainkhan/android/demo/ui/browse/BrowseResult.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Hossain Khan 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.hossainkhan.android.demo.ui.browse 18 | 19 | class BrowseResult( 20 | val clazz: Class? = null, 21 | val layoutResId: Int? = null 22 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/hossainkhan/android/demo/ui/common/DataBoundViewHolder.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Hossain Khan 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.hossainkhan.android.demo.ui.common 18 | 19 | import androidx.databinding.ViewDataBinding 20 | import androidx.recyclerview.widget.RecyclerView 21 | 22 | /** 23 | * A generic ViewHolder that works with a [ViewDataBinding]. 24 | * @param The type of the ViewDataBinding. 25 | */ 26 | class DataBoundViewHolder constructor( 27 | val binding: T 28 | ) : RecyclerView.ViewHolder(binding.root) 29 | -------------------------------------------------------------------------------- /app/src/main/java/com/hossainkhan/android/demo/ui/functionaldemo/MoviePosterAdapter.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Hossain Khan 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.hossainkhan.android.demo.ui.functionaldemo 18 | 19 | import android.view.LayoutInflater 20 | import android.view.ViewGroup 21 | import android.widget.ImageView 22 | import androidx.recyclerview.widget.RecyclerView 23 | import com.hossainkhan.android.demo.R 24 | 25 | /** 26 | * A simple adapter container movie poster images. 27 | */ 28 | class MoviePosterAdapter : RecyclerView.Adapter() { 29 | private val posterImageResourceIds = listOf( 30 | R.drawable.poster_lego_batman, 31 | R.drawable.poster_i2, 32 | R.drawable.poster_angry_birds, 33 | R.drawable.poster_lego_movie, 34 | R.drawable.poster_wreckit_ralph, 35 | R.drawable.poster_dragon3, 36 | R.drawable.poster_i1, 37 | R.drawable.poster_finding_nemo 38 | ) 39 | 40 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PosterViewHolder { 41 | // create a new view 42 | val posterView = LayoutInflater.from(parent.context) 43 | .inflate(R.layout.list_item_poster, parent, false) as ImageView 44 | 45 | return PosterViewHolder(posterView) 46 | } 47 | 48 | override fun getItemCount(): Int { 49 | return posterImageResourceIds.size 50 | } 51 | 52 | override fun onBindViewHolder(holder: PosterViewHolder, position: Int) { 53 | holder.posterView.setImageResource(posterImageResourceIds[position]) 54 | } 55 | 56 | // Provide a reference to the views for each data item 57 | class PosterViewHolder(val posterView: ImageView) : RecyclerView.ViewHolder(posterView) 58 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hossainkhan/android/demo/ui/functionaldemo/PinCodeEntryActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Hossain Khan 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.hossainkhan.android.demo.ui.functionaldemo 18 | 19 | import com.hossainkhan.android.demo.ui.layoutpreview.LayoutPreviewBaseActivity 20 | 21 | class PinCodeEntryActivity : LayoutPreviewBaseActivity() { 22 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hossainkhan/android/demo/ui/functionaldemo/TedTalkPlaybackActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Hossain Khan 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.hossainkhan.android.demo.ui.functionaldemo 18 | 19 | import android.os.Bundle 20 | import android.view.View 21 | import android.widget.ImageButton 22 | import android.widget.Toast 23 | import com.hossainkhan.android.demo.R 24 | import com.hossainkhan.android.demo.ui.layoutpreview.LayoutPreviewBaseActivity 25 | 26 | class TedTalkPlaybackActivity : LayoutPreviewBaseActivity() { 27 | private val generalClickListener = View.OnClickListener { view -> 28 | Toast.makeText(view.context, "You tapped on ${view}", Toast.LENGTH_SHORT).show() 29 | } 30 | 31 | override fun onCreate(savedInstanceState: Bundle?) { 32 | super.onCreate(savedInstanceState) 33 | 34 | // Apply generic toast listener to touchable views so that user gets feedback when they tap it 35 | applyToastListener( 36 | findViewById(R.id.action_prev_track), 37 | findViewById(R.id.action_rewind15), 38 | findViewById(R.id.action_play_pause), 39 | findViewById(R.id.action_forward15), 40 | findViewById(R.id.action_next_track) 41 | ) 42 | } 43 | 44 | private fun applyToastListener(vararg views: View) { 45 | views.forEach { 46 | it.setOnClickListener(generalClickListener) 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hossainkhan/android/demo/ui/layoutpreview/LayoutDimensionMinMaxActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Hossain Khan 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.hossainkhan.android.demo.ui.layoutpreview 18 | 19 | import android.os.Bundle 20 | import android.widget.Button 21 | import android.widget.TextView 22 | import com.hossainkhan.android.demo.R 23 | 24 | /** 25 | * Activity showcasing how virtual guideline group containing multiple views and how it can be changed. 26 | * 27 | * See https://developer.android.com/reference/android/support/constraint/Barrier 28 | */ 29 | class LayoutDimensionMinMaxActivity : LayoutPreviewBaseActivity() { 30 | 31 | override fun onCreate(savedInstanceState: Bundle?) { 32 | super.onCreate(savedInstanceState) 33 | 34 | // Setup additional view that is only available in this screen. 35 | val toggleButton = findViewById