├── .DS_Store
├── .gitattributes
├── .gitignore
├── .idea
├── .gitignore
├── .name
├── compiler.xml
├── jarRepositories.xml
└── misc.xml
├── README.md
├── app
├── .DS_Store
├── .gitignore
├── build.gradle
├── extensions
│ ├── .DS_Store
│ ├── .gitignore
│ ├── build.gradle
│ ├── consumer-rules.pro
│ ├── proguard-rules.pro
│ └── src
│ │ ├── .DS_Store
│ │ ├── androidTest
│ │ └── java
│ │ │ └── com
│ │ │ └── demo
│ │ │ └── extensions
│ │ │ └── ExampleInstrumentedTest.kt
│ │ ├── main
│ │ ├── .DS_Store
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ │ ├── .DS_Store
│ │ │ └── com
│ │ │ ├── .DS_Store
│ │ │ └── demo
│ │ │ ├── .DS_Store
│ │ │ └── extensions
│ │ │ ├── activity
│ │ │ └── ActivityExt.kt
│ │ │ ├── fragment
│ │ │ └── FragmentManagerExt.kt
│ │ │ ├── intent
│ │ │ └── IntentData.kt
│ │ │ ├── snackbar
│ │ │ └── SnackbarExtensions.kt
│ │ │ ├── string
│ │ │ └── StringExt.kt
│ │ │ ├── toast
│ │ │ └── ToastExt.kt
│ │ │ └── view
│ │ │ └── ViewExt.kt
│ │ └── test
│ │ └── java
│ │ └── com
│ │ └── demo
│ │ └── extensions
│ │ └── ExampleUnitTest.kt
├── proguard-rules.pro
└── src
│ ├── .DS_Store
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── demo
│ │ └── code
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── .DS_Store
│ ├── AndroidManifest.xml
│ ├── assets
│ │ └── movie_data.json
│ ├── java
│ │ └── com
│ │ │ └── demo
│ │ │ └── code
│ │ │ ├── .DS_Store
│ │ │ ├── JetPackFeatureSelectionActivity.kt
│ │ │ ├── base
│ │ │ ├── BaseActivity.kt
│ │ │ └── BaseFragment.kt
│ │ │ ├── camerax
│ │ │ ├── activities
│ │ │ │ └── CameraxActivity.kt
│ │ │ └── placeholder
│ │ │ ├── dataStore
│ │ │ ├── activities
│ │ │ │ └── DataStoreActivity.kt
│ │ │ ├── fragments
│ │ │ │ ├── SelectionDataStoreFragment.kt
│ │ │ │ ├── preferenceDataStore
│ │ │ │ │ └── PreferenceDataStoreFragment.kt
│ │ │ │ └── protoDataStore
│ │ │ │ │ └── ProtoDataStoreFragment.kt
│ │ │ └── util
│ │ │ │ └── DataManager.kt
│ │ │ ├── lifecycle
│ │ │ ├── actions
│ │ │ │ └── ExoplayerAction.kt
│ │ │ ├── activities
│ │ │ │ └── ExoplayerActivity.kt
│ │ │ └── util
│ │ │ │ └── ExoplayerActivityObserver.kt
│ │ │ ├── liveData
│ │ │ ├── activity
│ │ │ │ └── LiveDataActivity.kt
│ │ │ ├── mediatorLiveData
│ │ │ │ ├── fragments
│ │ │ │ │ └── MediatorLiveDataFragment.kt
│ │ │ │ └── vm
│ │ │ │ │ └── MediatorLiveDataViewModel.kt
│ │ │ ├── mutableLiveData
│ │ │ │ ├── fragments
│ │ │ │ │ └── MutableLiveDataFragment.kt
│ │ │ │ └── vm
│ │ │ │ │ └── MutableLiveDataViewModel.kt
│ │ │ └── selection
│ │ │ │ ├── fragments
│ │ │ │ └── SelectionLiveDataFragment.kt
│ │ │ │ └── vm
│ │ │ │ └── SelectionLiveDataViewModel.kt
│ │ │ ├── navigation
│ │ │ ├── activities
│ │ │ │ ├── BottomNavigationActivity.kt
│ │ │ │ ├── NavigationDrawerActivity.kt
│ │ │ │ ├── SelectionScreenActivity.kt
│ │ │ │ └── TwoFragmentContainerActivity.kt
│ │ │ └── fragments
│ │ │ │ ├── FragmentA.kt
│ │ │ │ ├── FragmentB.kt
│ │ │ │ ├── FragmentC.kt
│ │ │ │ ├── FragmentD.kt
│ │ │ │ ├── FragmentE.kt
│ │ │ │ └── FragmentF.kt
│ │ │ ├── paging
│ │ │ ├── .DS_Store
│ │ │ ├── Paging3Activity.kt
│ │ │ ├── usingLocalSource
│ │ │ │ ├── Executors.kt
│ │ │ │ ├── Extensions.kt
│ │ │ │ ├── db
│ │ │ │ │ ├── MovieDao.kt
│ │ │ │ │ └── MovieDatabase.kt
│ │ │ │ ├── model
│ │ │ │ │ ├── Movie.kt
│ │ │ │ │ └── MovieData.kt
│ │ │ │ └── ui
│ │ │ │ │ ├── MovieListAdapter.kt
│ │ │ │ │ ├── MovieListViewModel.kt
│ │ │ │ │ └── PagingFromLocalDbActivity.kt
│ │ │ ├── usingRemoteAndLocalSource
│ │ │ │ ├── database
│ │ │ │ │ ├── LocalDatabase.kt
│ │ │ │ │ └── dao
│ │ │ │ │ │ ├── KeysDao.kt
│ │ │ │ │ │ └── PostsDao.kt
│ │ │ │ ├── models
│ │ │ │ │ ├── FeedPost.kt
│ │ │ │ │ ├── PostContainer.kt
│ │ │ │ │ ├── PostsApiResponse.kt
│ │ │ │ │ ├── PostsKeys.kt
│ │ │ │ │ └── PostsListing.kt
│ │ │ │ ├── networking
│ │ │ │ │ ├── ApiClient.kt
│ │ │ │ │ └── RemoteService.kt
│ │ │ │ ├── repositories
│ │ │ │ │ ├── DataMediator.kt
│ │ │ │ │ └── Repository.kt
│ │ │ │ ├── ui
│ │ │ │ │ ├── LocalRemoteApiLoadingAdapter.kt
│ │ │ │ │ ├── LocalRemoteApiViewModel.kt
│ │ │ │ │ ├── PagingFromLocalRemoteApiActivity.kt
│ │ │ │ │ └── RemoteApiAdapter.kt
│ │ │ │ └── utils
│ │ │ │ │ └── DiffUtilCallBack.kt
│ │ │ └── usingRemoteSource
│ │ │ │ ├── database
│ │ │ │ ├── LocalDatabase.kt
│ │ │ │ └── dao
│ │ │ │ │ ├── KeysDao.kt
│ │ │ │ │ └── PostsDao.kt
│ │ │ │ ├── models
│ │ │ │ ├── FeedPost.kt
│ │ │ │ ├── PostContainer.kt
│ │ │ │ ├── PostsApiResponse.kt
│ │ │ │ ├── PostsKeys.kt
│ │ │ │ └── PostsListing.kt
│ │ │ │ ├── networking
│ │ │ │ ├── ApiClient.kt
│ │ │ │ └── RemoteService.kt
│ │ │ │ ├── placeholder
│ │ │ │ ├── repositories
│ │ │ │ ├── DataMediator.kt
│ │ │ │ ├── DataSource.kt
│ │ │ │ └── Repository.kt
│ │ │ │ ├── ui
│ │ │ │ ├── PagingFromRemoteApiActivity.kt
│ │ │ │ ├── RemoteApiAdapter.kt
│ │ │ │ ├── RemoteApiLoadingAdapter.kt
│ │ │ │ └── RemoteApiViewModel.kt
│ │ │ │ └── utils
│ │ │ │ └── DiffUtilCallBack.kt
│ │ │ ├── utils
│ │ │ ├── Constants.kt
│ │ │ └── placeholder.kt
│ │ │ └── workmanager
│ │ │ ├── WorkManagerActivity.kt
│ │ │ ├── chainingworker
│ │ │ ├── ChainingWorkerActivity.kt
│ │ │ └── workers
│ │ │ │ ├── DownloadWorker.kt
│ │ │ │ └── FileClearWorker.kt
│ │ │ ├── exampleone
│ │ │ ├── ImageUtils.kt
│ │ │ ├── WorkManagerExampleOneActivity.kt
│ │ │ └── workers
│ │ │ │ ├── CleanFilesWorker.kt
│ │ │ │ ├── CompressWorker.kt
│ │ │ │ ├── FilterWorker.kt
│ │ │ │ └── UploadWorker.kt
│ │ │ └── simpleworker
│ │ │ ├── SimpleWorkerActivity.kt
│ │ │ └── workers
│ │ │ └── SimpleDownloadWorker.kt
│ └── res
│ │ ├── .DS_Store
│ │ ├── drawable-v24
│ │ ├── ic_camera_black_48dp.xml
│ │ ├── ic_camera_front_black_24dp.xml
│ │ ├── ic_camera_rear_black_48dp.xml
│ │ ├── ic_flash_off_black_48dp.xml
│ │ └── ic_launcher_foreground.xml
│ │ ├── drawable
│ │ ├── ic_comment.xml
│ │ ├── ic_flash_on_black_48dp.xml
│ │ ├── ic_home.xml
│ │ ├── ic_launcher_background.xml
│ │ ├── ic_launcher_foreground.xml
│ │ ├── ic_menu_camera.xml
│ │ ├── ic_menu_gallery.xml
│ │ ├── ic_menu_slideshow.xml
│ │ ├── ic_star.xml
│ │ ├── ic_vertical_align_bottom_white_24px.xml
│ │ ├── ic_vertical_align_top_white_24px.xml
│ │ └── side_nav_bar.xml
│ │ ├── layout
│ │ ├── activity_bottom_navigation.xml
│ │ ├── activity_camera_x.xml
│ │ ├── activity_chain_worker.xml
│ │ ├── activity_data_store.xml
│ │ ├── activity_jetpack_selection.xml
│ │ ├── activity_live_data_layout.xml
│ │ ├── activity_navigation_drawer.xml
│ │ ├── activity_paging.xml
│ │ ├── activity_paging_from_local_db.xml
│ │ ├── activity_paging_from_local_remote_api.xml
│ │ ├── activity_paging_from_remote_api.xml
│ │ ├── activity_player.xml
│ │ ├── activity_selection.xml
│ │ ├── activity_simple_worker.xml
│ │ ├── activity_two_frag_containers.xml
│ │ ├── activity_work_manager.xml
│ │ ├── activity_work_manager_example_one.xml
│ │ ├── adapter_row.xml
│ │ ├── app_bar_main.xml
│ │ ├── content_main.xml
│ │ ├── fragment_layout_a.xml
│ │ ├── fragment_layout_b.xml
│ │ ├── fragment_layout_c.xml
│ │ ├── fragment_layout_d.xml
│ │ ├── fragment_layout_e.xml
│ │ ├── fragment_layout_f.xml
│ │ ├── fragment_preference_data_store.xml
│ │ ├── fragment_proto_data_store.xml
│ │ ├── fragment_selection_data_store.xml
│ │ ├── horizontal_paging_fragment.xml
│ │ ├── item_loading_state.xml
│ │ ├── list_item.xml
│ │ ├── list_item_movie.xml
│ │ ├── mediator_live_data_fragment.xml
│ │ ├── mutable_live_data_fragment.xml
│ │ ├── nav_header_main.xml
│ │ ├── selection_live_data_fragment.xml
│ │ └── selection_paging_fragment.xml
│ │ ├── menu
│ │ ├── activity_main_drawer.xml
│ │ ├── bottom_menu_nav.xml
│ │ ├── main.xml
│ │ └── menu.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
│ │ ├── navigation
│ │ ├── data_store_nav.xml
│ │ ├── live_data_nav.xml
│ │ ├── nav_graph_a.xml
│ │ ├── nav_graph_b.xml
│ │ ├── nav_graph_bottom_navigation.xml
│ │ ├── nav_graph_drawer.xml
│ │ └── paging_nav.xml
│ │ ├── values-night
│ │ └── themes.xml
│ │ └── values
│ │ ├── colors.xml
│ │ ├── colours_material.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ ├── styles.xml
│ │ └── themes.xml
│ └── test
│ └── java
│ └── com
│ └── demo
│ └── code
│ └── ExampleUnitTest.kt
├── build.gradle
├── buildsystem
├── dependencies.gradle
└── version.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── images
├── .DS_Store
├── Logo-new.png
├── alltools.png
├── android-jetpack.png
├── android_jetpack_lifecycle.jpeg
├── assistant.png
├── camerax.png
├── data_source_types.png
├── datastore.jpeg
├── jetpacknavigation.png
├── liveData.jpeg
├── local_remote_paging.png
├── mediator_paging.png
├── mobile_server.png
├── navigationgraph.png
├── page_struct.png
├── paging.png
├── pagingBanner.jpeg
├── paging_elements.png
├── prefdatastore.jpeg
├── proposed_arch.png
├── protodatastore.jpeg
├── recyclerview.jpeg
├── supporting_caching.png
└── types_of_work_manager.png
└── settings.gradle
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/.DS_Store
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.ap_
4 | *.aab
5 |
6 | # Files for the ART/Dalvik VM
7 | *.dex
8 |
9 | # Java class files
10 | *.class
11 |
12 | # Generated files
13 | bin/
14 | gen/
15 | out/
16 | # Uncomment the following line in case you need and you don't have the release build type files in your app
17 | # release/
18 |
19 | # Gradle files
20 | .gradle/
21 | build/
22 |
23 | # Local configuration file (sdk path, etc)
24 | local.properties
25 |
26 | # Proguard folder generated by Eclipse
27 | proguard/
28 |
29 | # Log Files
30 | *.log
31 |
32 | # Android Studio Navigation editor temp files
33 | .navigation/
34 |
35 | # Android Studio captures folder
36 | captures/
37 |
38 | # IntelliJ
39 | *.iml
40 | .idea/workspace.xml
41 | .idea/tasks.xml
42 | .idea/gradle.xml
43 | .idea/assetWizardSettings.xml
44 | .idea/dictionaries
45 | .idea/libraries
46 | # Android Studio 3 in .gitignore file.
47 | .idea/caches
48 | .idea/modules.xml
49 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you
50 | .idea/navEditor.xml
51 |
52 | # Keystore files
53 | # Uncomment the following lines if you do not want to check your keystore files in.
54 | #*.jks
55 | #*.keystore
56 |
57 | # External native build folder generated in Android Studio 2.2 and later
58 | .externalNativeBuild
59 |
60 | # Google Services (e.g. APIs or Firebase)
61 | # google-services.json
62 |
63 | # Freeline
64 | freeline.py
65 | freeline/
66 | freeline_project_description.json
67 |
68 | # fastlane
69 | fastlane/report.xml
70 | fastlane/Preview.html
71 | fastlane/screenshots
72 | fastlane/test_output
73 | fastlane/readme.md
74 |
75 | # Version control
76 | vcs.xml
77 |
78 | # lint
79 | lint/intermediates/
80 | lint/generated/
81 | lint/outputs/
82 | lint/tmp/
83 | # lint/reports/
84 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/.idea/.name:
--------------------------------------------------------------------------------
1 | code
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/jarRepositories.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | | Documentation links of Wiki is present below |
18 | | --- |
19 | | [Navigation](https://github.com/devrath/DroidAndroidJetpack/wiki/Jetpack-Navigation) |
20 | | [Life-cycle aware component](https://github.com/devrath/DroidAndroidJetpack/wiki/Lifecycle-Aware-Components) |
21 | | [Data Store](https://github.com/devrath/DroidAndroidJetpack/wiki/Data-Store) |
22 | | [Live Data](https://github.com/devrath/DroidAndroidJetpack/wiki/Live-Data) |
23 | | [CameraX](https://github.com/devrath/DroidAndroidJetpack/wiki/CameraX) |
24 | | [Work Manager](https://github.com/devrath/DroidAndroidJetpack/wiki/Workmanager) |
25 | | [Paging3](https://github.com/devrath/DroidAndroidJetpack/wiki/Paging-Library) |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/app/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/app/.DS_Store
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/app/extensions/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/app/extensions/.DS_Store
--------------------------------------------------------------------------------
/app/extensions/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/app/extensions/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.library'
3 | id 'kotlin-android'
4 | }
5 |
6 | android {
7 | compileSdkVersion 30
8 | buildToolsVersion "30.0.3"
9 |
10 | defaultConfig {
11 | minSdkVersion 16
12 | targetSdkVersion 30
13 | versionCode 1
14 | versionName "1.0"
15 |
16 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
17 | consumerProguardFiles "consumer-rules.pro"
18 | }
19 |
20 | buildTypes {
21 | release {
22 | minifyEnabled false
23 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
24 | }
25 | }
26 | compileOptions {
27 | sourceCompatibility JavaVersion.VERSION_1_8
28 | targetCompatibility JavaVersion.VERSION_1_8
29 | }
30 | kotlinOptions {
31 | jvmTarget = '1.8'
32 | }
33 | }
34 |
35 | dependencies {
36 |
37 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
38 | implementation 'androidx.core:core-ktx:1.3.2'
39 | implementation 'androidx.appcompat:appcompat:1.2.0'
40 | implementation 'com.google.android.material:material:1.3.0'
41 | testImplementation 'junit:junit:4.+'
42 | androidTestImplementation 'androidx.test.ext:junit:1.1.2'
43 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
44 | }
--------------------------------------------------------------------------------
/app/extensions/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/app/extensions/consumer-rules.pro
--------------------------------------------------------------------------------
/app/extensions/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
--------------------------------------------------------------------------------
/app/extensions/src/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/app/extensions/src/.DS_Store
--------------------------------------------------------------------------------
/app/extensions/src/androidTest/java/com/demo/extensions/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.demo.extensions
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.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.getInstrumentation().targetContext
22 | assertEquals("com.demo.extensions.test", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/app/extensions/src/main/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/app/extensions/src/main/.DS_Store
--------------------------------------------------------------------------------
/app/extensions/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/app/extensions/src/main/java/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/app/extensions/src/main/java/.DS_Store
--------------------------------------------------------------------------------
/app/extensions/src/main/java/com/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/app/extensions/src/main/java/com/.DS_Store
--------------------------------------------------------------------------------
/app/extensions/src/main/java/com/demo/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/app/extensions/src/main/java/com/demo/.DS_Store
--------------------------------------------------------------------------------
/app/extensions/src/main/java/com/demo/extensions/activity/ActivityExt.kt:
--------------------------------------------------------------------------------
1 | package com.demo.extensions.activity
2 |
3 | import android.app.Activity
4 | import android.util.DisplayMetrics
5 |
6 |
7 |
8 |
9 |
10 | fun Activity.isInPortrait(): Boolean {
11 | val displayMetrics = DisplayMetrics()
12 | windowManager.defaultDisplay.getMetrics(displayMetrics)
13 | return displayMetrics.heightPixels > displayMetrics.widthPixels
14 | }
--------------------------------------------------------------------------------
/app/extensions/src/main/java/com/demo/extensions/fragment/FragmentManagerExt.kt:
--------------------------------------------------------------------------------
1 | package com.demo.extensions.fragment
2 |
3 | import androidx.fragment.app.FragmentManager
4 | import androidx.fragment.app.FragmentTransaction
5 |
6 | inline fun FragmentManager.inTransactionCommit(func: FragmentTransaction.() -> Unit) {
7 | val fragmentTransaction = beginTransaction()
8 | fragmentTransaction.func()
9 | fragmentTransaction.commit()
10 | }
11 |
12 | inline fun FragmentManager.inTransactionCommitAllowingStateLoss(func: FragmentTransaction.() -> Unit) {
13 | val fragmentTransaction = beginTransaction()
14 | fragmentTransaction.func()
15 | fragmentTransaction.commitAllowingStateLoss()
16 | }
--------------------------------------------------------------------------------
/app/extensions/src/main/java/com/demo/extensions/snackbar/SnackbarExtensions.kt:
--------------------------------------------------------------------------------
1 | package com.demo.extensions.snackbar
2 |
3 | import android.view.View
4 | import androidx.annotation.StringRes
5 | import androidx.core.content.ContextCompat
6 | import com.google.android.material.snackbar.Snackbar
7 |
8 | inline fun View.snack(@StringRes messageRes: Int, length: Int = Snackbar.LENGTH_LONG, f: Snackbar.() -> Unit) {
9 | snack(resources.getString(messageRes), length, f)
10 | }
11 |
12 | inline fun View.snack(message: String, length: Int = Snackbar.LENGTH_LONG, f: Snackbar.() -> Unit) {
13 | val snack = Snackbar.make(this, message, length)
14 | snack.f()
15 | snack.show()
16 | }
17 |
18 | fun Snackbar.action(@StringRes actionRes: Int, color: Int? = null, listener: (View) -> Unit) {
19 | action(view.resources.getString(actionRes), color, listener)
20 | }
21 |
22 | fun Snackbar.action(action: String, color: Int? = null, listener: (View) -> Unit) {
23 | setAction(action, listener)
24 | color?.let { setActionTextColor(ContextCompat.getColor(context, color)) }
25 | }
--------------------------------------------------------------------------------
/app/extensions/src/main/java/com/demo/extensions/string/StringExt.kt:
--------------------------------------------------------------------------------
1 | package com.demo.extensions.string
2 |
3 | import java.security.MessageDigest
4 |
5 |
6 | fun String.md5() = encrypt(this, "MD5")
7 |
8 | fun String.sha1() = encrypt(this, "SHA-1")
9 |
10 | fun String.isIdcard(): Boolean {
11 | val p18 = "^[1-9]\\d{5}(18|19|([23]\\d))\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]\$".toRegex()
12 | val p15 = "^[1-9]\\d{5}\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{2}[0-9Xx]\$".toRegex()
13 | return matches(p18) || matches(p15)
14 | }
15 |
16 | fun String.isPhone(): Boolean {
17 | val p = "^1([34578])\\d{9}\$".toRegex()
18 | return matches(p)
19 | }
20 |
21 | fun String.isEmail(): Boolean {
22 | val p = "^(\\w)+(\\.\\w+)*@(\\w)+((\\.\\w+)+)\$".toRegex()
23 | return matches(p)
24 | }
25 |
26 | fun String.isNumeric(): Boolean {
27 | val p = "^[0-9]+$".toRegex()
28 | return matches(p)
29 | }
30 |
31 | fun String.equalsIgnoreCase(other: String) = this.toLowerCase().contentEquals(other.toLowerCase())
32 |
33 | private fun encrypt(string: String?, type: String): String {
34 | val bytes = MessageDigest.getInstance(type).digest(string!!.toByteArray())
35 | return bytes2Hex(bytes)
36 | }
37 |
38 | internal fun bytes2Hex(bts: ByteArray): String {
39 | var des = ""
40 | var tmp: String
41 | for (i in bts.indices) {
42 | tmp = Integer.toHexString(bts[i].toInt() and 0xFF)
43 | if (tmp.length == 1) {
44 | des += "0"
45 | }
46 | des += tmp
47 | }
48 | return des
49 | }
50 |
--------------------------------------------------------------------------------
/app/extensions/src/main/java/com/demo/extensions/toast/ToastExt.kt:
--------------------------------------------------------------------------------
1 | package com.demo.extensions.toast
2 |
3 | import android.annotation.SuppressLint
4 | import android.content.Context
5 | import android.widget.Toast
6 |
7 | private var toast: Toast? = null
8 |
9 | @SuppressLint("ShowToast")
10 | fun toast(msg: Any?, isShort: Boolean = true, context : Context) {
11 | msg?.let {
12 | if (toast == null) {
13 | toast = Toast.makeText(context, msg.toString(), Toast.LENGTH_SHORT)
14 | } else {
15 | toast!!.setText(msg.toString())
16 | }
17 | toast!!.duration = if (isShort) Toast.LENGTH_SHORT else Toast.LENGTH_LONG
18 | toast!!.show()
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/app/extensions/src/test/java/com/demo/extensions/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.demo.extensions
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/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
--------------------------------------------------------------------------------
/app/src/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/app/src/.DS_Store
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/demo/code/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.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.getInstrumentation().targetContext
22 | assertEquals("com.demo.code", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/app/src/main/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/app/src/main/.DS_Store
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/app/src/main/java/com/demo/code/.DS_Store
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/JetPackFeatureSelectionActivity.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code
2 |
3 | import android.os.Bundle
4 | import com.demo.code.base.BaseActivity
5 | import com.demo.code.camerax.activities.CameraxActivity
6 | import com.demo.code.dataStore.activities.DataStoreActivity
7 | import com.demo.code.databinding.ActivityJetpackSelectionBinding
8 | import com.demo.code.lifecycle.activities.ExoplayerActivity
9 | import com.demo.code.liveData.activity.LiveDataActivity
10 | import com.demo.code.navigation.activities.SelectionScreenActivity
11 | import com.demo.code.paging.Paging3Activity
12 | import com.demo.code.workmanager.WorkManagerActivity
13 | import com.demo.extensions.intent.openActivity
14 |
15 | class JetPackFeatureSelectionActivity : BaseActivity() {
16 |
17 | private lateinit var binding: ActivityJetpackSelectionBinding
18 |
19 | override fun onCreate(savedInstanceState: Bundle?) {
20 | super.onCreate(savedInstanceState)
21 | binding = ActivityJetpackSelectionBinding.inflate(layoutInflater)
22 | setContentView(binding.root)
23 |
24 | binding.apply {
25 | this.jetpackNavigationId.setOnClickListener {
26 | openActivity(SelectionScreenActivity::class.java)
27 | }
28 | this.jetPackLifeCycleAwareId.setOnClickListener {
29 | openActivity(ExoplayerActivity::class.java)
30 | }
31 | this.jetPackPaging3Id.setOnClickListener{
32 | openActivity(Paging3Activity::class.java)
33 | }
34 | this.jetDataStoreId.setOnClickListener{
35 | openActivity(DataStoreActivity::class.java)
36 | }
37 | this.jetLiveDataId.setOnClickListener{
38 | openActivity(LiveDataActivity::class.java)
39 | }
40 | this.jetPackCameraXId.setOnClickListener{
41 | openActivity(CameraxActivity::class.java)
42 | }
43 | this.workManagerId.setOnClickListener{
44 | openActivity(WorkManagerActivity::class.java)
45 | }
46 | }
47 | }
48 |
49 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/base/BaseActivity.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.base
2 |
3 | import androidx.appcompat.app.AppCompatActivity
4 |
5 | open class BaseActivity : AppCompatActivity() {
6 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/base/BaseFragment.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.base
2 |
3 | import androidx.fragment.app.Fragment
4 |
5 | open class BaseFragment : Fragment() {
6 |
7 |
8 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/camerax/activities/CameraxActivity.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.camerax.activities
2 |
3 | import android.os.Bundle
4 | import com.demo.code.base.BaseActivity
5 | import com.demo.code.databinding.ActivityCameraXBinding
6 |
7 | class CameraxActivity: BaseActivity() {
8 |
9 | private lateinit var binding: ActivityCameraXBinding
10 |
11 |
12 | override fun onCreate(savedInstanceState: Bundle?) {
13 | super.onCreate(savedInstanceState)
14 | binding = ActivityCameraXBinding.inflate(layoutInflater)
15 | setContentView(binding.root)
16 | }
17 |
18 |
19 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/camerax/placeholder:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/app/src/main/java/com/demo/code/camerax/placeholder
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/dataStore/activities/DataStoreActivity.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.dataStore.activities
2 |
3 | import android.os.Bundle
4 | import com.demo.code.base.BaseActivity
5 | import com.demo.code.databinding.ActivityDataStoreBinding
6 |
7 | class DataStoreActivity : BaseActivity() {
8 |
9 | private lateinit var binding: ActivityDataStoreBinding
10 |
11 | override fun onCreate(savedInstanceState: Bundle?) {
12 | super.onCreate(savedInstanceState)
13 | binding = ActivityDataStoreBinding.inflate(layoutInflater)
14 | setContentView(binding.root)
15 | }
16 |
17 |
18 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/dataStore/fragments/SelectionDataStoreFragment.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.dataStore.fragments
2 |
3 | import android.os.Bundle
4 | import androidx.fragment.app.Fragment
5 | import android.view.LayoutInflater
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import androidx.navigation.fragment.findNavController
9 | import com.demo.code.R
10 | import com.demo.code.databinding.ActivityDataStoreBinding
11 | import com.demo.code.databinding.FragmentSelectionDataStoreBinding
12 | import com.demo.code.navigation.activities.NavigationDrawerActivity
13 | import com.demo.code.navigation.activities.TwoFragmentContainerActivity
14 | import com.demo.extensions.intent.openActivity
15 |
16 |
17 | class SelectionDataStoreFragment : Fragment(), View.OnClickListener {
18 |
19 | private var _binding: FragmentSelectionDataStoreBinding? = null
20 | private val binding get() = _binding!!
21 |
22 | override fun onCreateView(
23 | inflater: LayoutInflater, container: ViewGroup?,
24 | savedInstanceState: Bundle?
25 | ): View? {
26 | _binding = FragmentSelectionDataStoreBinding.inflate(inflater, container, false)
27 | return binding.root
28 | }
29 |
30 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
31 | super.onViewCreated(view, savedInstanceState)
32 | setClickListener()
33 | }
34 |
35 | private fun setClickListener() {
36 | binding.preferencesDsId.setOnClickListener(this)
37 | binding.protoDsId.setOnClickListener(this)
38 | }
39 |
40 | override fun onClick(view: View?) {
41 | when(view?.id){
42 | R.id.preferencesDsId -> findNavController().navigate(R.id.preferenceDataStoreFragment)
43 | R.id.protoDsId -> findNavController().navigate(R.id.protoDataStoreFragment)
44 | }
45 | }
46 |
47 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/dataStore/fragments/preferenceDataStore/PreferenceDataStoreFragment.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.dataStore.fragments.preferenceDataStore
2 |
3 | import android.content.Context
4 | import android.os.Bundle
5 | import android.os.UserManager
6 | import androidx.fragment.app.Fragment
7 | import android.view.LayoutInflater
8 | import android.view.View
9 | import android.view.ViewGroup
10 | import androidx.lifecycle.asLiveData
11 | import com.demo.code.R
12 | import com.demo.code.dataStore.util.DataManager
13 | import com.demo.code.databinding.FragmentPreferenceDataStoreBinding
14 | import com.demo.code.databinding.FragmentProtoDataStoreBinding
15 | import kotlinx.coroutines.GlobalScope
16 | import kotlinx.coroutines.launch
17 |
18 | class PreferenceDataStoreFragment : Fragment() {
19 |
20 | private var _binding: FragmentPreferenceDataStoreBinding? = null
21 | private val binding get() = _binding!!
22 |
23 | lateinit var dataManager: DataManager
24 | var name = ""
25 |
26 | override fun onCreateView(
27 | inflater: LayoutInflater, container: ViewGroup?,
28 | savedInstanceState: Bundle?
29 | ): View? {
30 | _binding = FragmentPreferenceDataStoreBinding.inflate(inflater, container, false)
31 | return binding.root
32 | }
33 |
34 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
35 | super.onViewCreated(view, savedInstanceState)
36 | initDataStore()
37 | observeData()
38 | saveData()
39 | }
40 |
41 | private fun observeData() {
42 | // of UserManager class
43 | this.dataManager.dataAsFlow.asLiveData().observe(requireActivity()) {
44 | binding.displayTextId.text = it.toString()
45 | }
46 | }
47 |
48 | private fun saveData() {
49 | binding.apply {
50 | saveDataId.setOnClickListener {
51 | val dataToSave = binding.editTextTextPersonName.text.toString()
52 | GlobalScope.launch { dataManager.storeData(dataToSave) }
53 | }
54 | }
55 | }
56 |
57 | private fun initDataStore() {
58 | // Get reference to our userManager class
59 | dataManager = DataManager(requireContext())
60 | }
61 |
62 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/dataStore/fragments/protoDataStore/ProtoDataStoreFragment.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.dataStore.fragments.protoDataStore
2 |
3 | import android.os.Bundle
4 | import androidx.fragment.app.Fragment
5 | import android.view.LayoutInflater
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import com.demo.code.R
9 | import com.demo.code.databinding.FragmentProtoDataStoreBinding
10 | import com.demo.code.databinding.FragmentSelectionDataStoreBinding
11 |
12 | class ProtoDataStoreFragment : Fragment() {
13 |
14 | private var _binding: FragmentProtoDataStoreBinding? = null
15 | private val binding get() = _binding!!
16 |
17 | override fun onCreateView(
18 | inflater: LayoutInflater, container: ViewGroup?,
19 | savedInstanceState: Bundle?
20 | ): View? {
21 | _binding = FragmentProtoDataStoreBinding.inflate(inflater, container, false)
22 | return binding.root
23 | }
24 |
25 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/dataStore/util/DataManager.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.dataStore.util
2 |
3 | import android.content.Context
4 | import androidx.datastore.core.DataStore
5 | import androidx.datastore.preferences.core.Preferences
6 | import androidx.datastore.preferences.core.edit
7 | import androidx.datastore.preferences.core.stringPreferencesKey
8 | import androidx.datastore.preferences.preferencesDataStore
9 | import kotlinx.coroutines.flow.Flow
10 | import kotlinx.coroutines.flow.map
11 |
12 |
13 | const val DATA_STORE_NAME = "user_prefs"
14 | const val DATA_KEY = "data_key"
15 |
16 | class DataManager(val context: Context) {
17 |
18 | // Create the dataStore and give it a name same as shared preferences
19 | val Context.dataStore: DataStore by preferencesDataStore(name = DATA_STORE_NAME)
20 |
21 | // Create some keys we will use them to store and retrieve the data
22 | companion object {
23 | val DATA_KEY_KEY = stringPreferencesKey(DATA_KEY)
24 | }
25 |
26 | // Store user data
27 | suspend fun storeData(data: String) {
28 | context.dataStore.edit { it[DATA_KEY_KEY] = data }
29 | }
30 |
31 | // Retrieve the data
32 | val dataAsFlow: Flow = context.dataStore.data
33 | .map { preferences -> preferences[DATA_KEY_KEY] ?: "" }
34 |
35 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/lifecycle/actions/ExoplayerAction.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.lifecycle.actions
2 |
3 | import android.net.Uri
4 | import com.google.android.exoplayer2.SimpleExoPlayer
5 |
6 | sealed class ExoplayerAction {
7 | data class BindExoplayer(val simpleExoplayer: SimpleExoPlayer) : ExoplayerAction()
8 | data class ProgressBarVisibility(val isVisible: Boolean) : ExoplayerAction()
9 | }
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/lifecycle/activities/ExoplayerActivity.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.lifecycle.activities
2 |
3 | import android.os.Bundle
4 | import android.view.View
5 | import com.demo.code.base.BaseActivity
6 | import com.demo.code.databinding.ActivityPlayerBinding
7 | import com.demo.code.lifecycle.actions.ExoplayerAction
8 | import com.demo.code.lifecycle.util.ExoplayerActivityObserver
9 | import com.google.android.exoplayer2.Player
10 |
11 |
12 | class ExoplayerActivity : BaseActivity(), Player.EventListener {
13 |
14 | private lateinit var binding: ActivityPlayerBinding
15 |
16 | private lateinit var locationListener: ExoplayerActivityObserver
17 |
18 | override fun onCreate(savedInstanceState: Bundle?) {
19 | super.onCreate(savedInstanceState)
20 | binding = ActivityPlayerBinding.inflate(layoutInflater)
21 | setContentView(binding.root)
22 | initExoplayerListener()
23 | }
24 |
25 | private fun initExoplayerListener() {
26 | locationListener = ExoplayerActivityObserver(lifecycle,this) { it ->
27 | when(it) {
28 | is ExoplayerAction.BindExoplayer -> binding.exoplayerView.player = it.simpleExoplayer
29 | is ExoplayerAction.ProgressBarVisibility -> handleProgressVisibilityOfPlayer(it.isVisible)
30 | }
31 | }
32 | }
33 |
34 | private fun handleProgressVisibilityOfPlayer(visible: Boolean) {
35 | if (visible)
36 | binding.progressBar.visibility = View.VISIBLE
37 | else
38 | binding.progressBar.visibility = View.INVISIBLE
39 | }
40 |
41 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/liveData/activity/LiveDataActivity.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.liveData.activity
2 |
3 | import android.os.Bundle
4 | import com.demo.code.base.BaseActivity
5 | import com.demo.code.databinding.ActivityLiveDataLayoutBinding
6 |
7 | class LiveDataActivity : BaseActivity() {
8 |
9 | private lateinit var binding: ActivityLiveDataLayoutBinding
10 |
11 | override fun onCreate(savedInstanceState: Bundle?) {
12 | super.onCreate(savedInstanceState)
13 | binding = ActivityLiveDataLayoutBinding.inflate(layoutInflater)
14 | setContentView(binding.root)
15 | }
16 |
17 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/liveData/mediatorLiveData/fragments/MediatorLiveDataFragment.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.liveData.mediatorLiveData.fragments
2 |
3 | import androidx.lifecycle.ViewModelProvider
4 | import android.os.Bundle
5 | import androidx.fragment.app.Fragment
6 | import android.view.LayoutInflater
7 | import android.view.View
8 | import android.view.ViewGroup
9 | import com.demo.code.databinding.MediatorLiveDataFragmentBinding
10 | import com.demo.code.liveData.mediatorLiveData.vm.MediatorLiveDataViewModel
11 |
12 | class MediatorLiveDataFragment : Fragment() {
13 |
14 | companion object {
15 | fun newInstance() = MediatorLiveDataFragment()
16 | }
17 |
18 | private var _binding: MediatorLiveDataFragmentBinding? = null
19 | private val binding get() = _binding!!
20 |
21 | private lateinit var viewModel: MediatorLiveDataViewModel
22 |
23 | override fun onCreateView(
24 | inflater: LayoutInflater, container: ViewGroup?,
25 | savedInstanceState: Bundle?
26 | ): View? {
27 | _binding = MediatorLiveDataFragmentBinding.inflate(inflater, container, false)
28 | return binding.root
29 | }
30 |
31 | override fun onActivityCreated(savedInstanceState: Bundle?) {
32 | super.onActivityCreated(savedInstanceState)
33 | viewModel = ViewModelProvider(this).get(MediatorLiveDataViewModel::class.java)
34 | observeLiveData()
35 | setClickListener()
36 | }
37 |
38 | private fun setClickListener() {
39 | binding.serverCounterId.setOnClickListener {
40 | viewModel.fetchDataFromServer()
41 | }
42 | binding.localCounterId.setOnClickListener {
43 | viewModel.fetchDataFromLocalDb()
44 | }
45 | }
46 |
47 | private fun observeLiveData() {
48 | viewModel.observeData().observe(viewLifecycleOwner,{
49 | binding.counterValueId.text = it.toString()
50 | })
51 | }
52 |
53 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/liveData/mediatorLiveData/vm/MediatorLiveDataViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.liveData.mediatorLiveData.vm
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.MediatorLiveData
5 | import androidx.lifecycle.MutableLiveData
6 | import androidx.lifecycle.ViewModel
7 |
8 | class MediatorLiveDataViewModel : ViewModel() {
9 |
10 | private var counter : Int = 0
11 |
12 | private var counterFromServerLiveData : MutableLiveData = MutableLiveData()
13 | private var counterFromLocalDbLiveData : MutableLiveData = MutableLiveData()
14 |
15 | fun observeData(): LiveData {
16 |
17 | val dataSourceLiveData : MediatorLiveData = MediatorLiveData()
18 |
19 | dataSourceLiveData.addSource(counterFromServerLiveData) {
20 | dataSourceLiveData.value = it
21 | }
22 | dataSourceLiveData.addSource(counterFromLocalDbLiveData) {
23 | dataSourceLiveData.value = it
24 | }
25 |
26 | return dataSourceLiveData
27 | }
28 |
29 | fun fetchDataFromServer() {
30 | counterFromServerLiveData.value = counter++
31 | }
32 |
33 | fun fetchDataFromLocalDb() {
34 | counterFromLocalDbLiveData.value = counter++
35 | }
36 |
37 |
38 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/liveData/mutableLiveData/fragments/MutableLiveDataFragment.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.liveData.mutableLiveData.fragments
2 |
3 | import androidx.lifecycle.ViewModelProvider
4 | import android.os.Bundle
5 | import androidx.fragment.app.Fragment
6 | import android.view.LayoutInflater
7 | import android.view.View
8 | import android.view.ViewGroup
9 | import com.demo.code.databinding.MutableLiveDataFragmentBinding
10 | import com.demo.code.liveData.mutableLiveData.vm.MutableLiveDataViewModel
11 |
12 | class MutableLiveDataFragment : Fragment() {
13 |
14 | private var _binding: MutableLiveDataFragmentBinding? = null
15 | private val binding get() = _binding!!
16 |
17 | private lateinit var viewModel: MutableLiveDataViewModel
18 |
19 | override fun onCreateView(
20 | inflater: LayoutInflater, container: ViewGroup?,
21 | savedInstanceState: Bundle?
22 | ): View? {
23 | _binding = MutableLiveDataFragmentBinding.inflate(inflater, container, false)
24 | return binding.root
25 | }
26 |
27 | override fun onActivityCreated(savedInstanceState: Bundle?) {
28 | super.onActivityCreated(savedInstanceState)
29 | viewModel = ViewModelProvider(this).get(MutableLiveDataViewModel::class.java)
30 | observeLiveData()
31 | setClickListener()
32 | }
33 |
34 | private fun setClickListener() {
35 | binding.buttonId.setOnClickListener {
36 | viewModel.fetchDataFromServer()
37 | }
38 | }
39 |
40 | private fun observeLiveData() {
41 | viewModel.dataFromRepository().observe(viewLifecycleOwner,{
42 | binding.counterValueId.text = it.toString()
43 | })
44 | }
45 |
46 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/liveData/mutableLiveData/vm/MutableLiveDataViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.liveData.mutableLiveData.vm
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.MutableLiveData
5 | import androidx.lifecycle.ViewModel
6 |
7 | /**
8 | * Live data is something that can be observed but can't be set
9 | * Mutable live data can be modified
10 | */
11 | class MutableLiveDataViewModel : ViewModel() {
12 |
13 | private var counter : Int = 0
14 |
15 | private var counterLiveData : MutableLiveData = MutableLiveData()
16 |
17 | /**
18 | * Observe the live data from the Activity/Fragment
19 | */
20 | fun dataFromRepository() : LiveData = counterLiveData
21 |
22 | /**
23 | * Simulation: New value obtained from the server
24 | */
25 | fun fetchDataFromServer() {
26 | // Here we are updating the mutable live data
27 | counterLiveData.value = counter++
28 | }
29 |
30 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/liveData/selection/fragments/SelectionLiveDataFragment.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.liveData.selection.fragments
2 |
3 | import androidx.lifecycle.ViewModelProvider
4 | import android.os.Bundle
5 | import androidx.fragment.app.Fragment
6 | import android.view.LayoutInflater
7 | import android.view.View
8 | import android.view.ViewGroup
9 | import androidx.navigation.fragment.findNavController
10 | import com.demo.code.R
11 | import com.demo.code.databinding.FragmentSelectionDataStoreBinding
12 | import com.demo.code.databinding.SelectionLiveDataFragmentBinding
13 | import com.demo.code.liveData.selection.vm.SelectionLiveDataViewModel
14 |
15 | class SelectionLiveDataFragment : Fragment(), View.OnClickListener {
16 |
17 | companion object {
18 | fun newInstance() = SelectionLiveDataFragment()
19 | }
20 |
21 | private var _binding: SelectionLiveDataFragmentBinding? = null
22 | private val binding get() = _binding!!
23 |
24 | private lateinit var viewModel: SelectionLiveDataViewModel
25 |
26 | override fun onCreateView(
27 | inflater: LayoutInflater, container: ViewGroup?,
28 | savedInstanceState: Bundle?
29 | ): View? {
30 | _binding = SelectionLiveDataFragmentBinding.inflate(inflater, container, false)
31 | return binding.root
32 | }
33 |
34 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
35 | super.onViewCreated(view, savedInstanceState)
36 | viewModel = ViewModelProvider(this).get(SelectionLiveDataViewModel::class.java)
37 | setClickListener()
38 | }
39 |
40 | private fun setClickListener() {
41 | binding.mutableLiveDataId.setOnClickListener(this)
42 | binding.mediatorLiveDataId.setOnClickListener(this)
43 | }
44 |
45 | override fun onClick(view: View?) {
46 | when(view?.id){
47 | R.id.mutableLiveDataId -> {
48 | findNavController().navigate(R.id.mutableLiveDataFragment)
49 | }
50 | R.id.mediatorLiveDataId -> {
51 | findNavController().navigate(R.id.mediatorLiveDataFragment)
52 | }
53 | }
54 | }
55 |
56 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/liveData/selection/vm/SelectionLiveDataViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.liveData.selection.vm
2 |
3 | import androidx.lifecycle.ViewModel
4 |
5 | class SelectionLiveDataViewModel : ViewModel() {
6 | // TODO: Implement the ViewModel
7 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/navigation/activities/BottomNavigationActivity.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.navigation.activities
2 |
3 | import android.os.Bundle
4 | import androidx.navigation.fragment.NavHostFragment
5 | import androidx.navigation.ui.NavigationUI
6 | import com.demo.code.R
7 | import com.demo.code.base.BaseActivity
8 | import com.demo.code.databinding.ActivityBottomNavigationBinding
9 |
10 | class BottomNavigationActivity : BaseActivity() {
11 |
12 | private lateinit var binding: ActivityBottomNavigationBinding
13 |
14 | override fun onCreate(savedInstanceState: Bundle?) {
15 | super.onCreate(savedInstanceState)
16 | binding = ActivityBottomNavigationBinding.inflate(layoutInflater)
17 | setContentView(binding.root)
18 | setUpNavigation()
19 | }
20 |
21 | private fun setUpNavigation() {
22 | val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment?
23 | NavigationUI.setupWithNavController(binding.bttmNav, navHostFragment!!.navController)
24 | }
25 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/navigation/activities/SelectionScreenActivity.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.navigation.activities
2 |
3 | import android.os.Bundle
4 | import android.view.View
5 | import com.demo.code.R
6 | import com.demo.code.base.BaseActivity
7 | import com.demo.code.databinding.ActivitySelectionBinding
8 | import com.demo.extensions.intent.openActivity
9 |
10 | class SelectionScreenActivity : BaseActivity() , View.OnClickListener {
11 |
12 | private lateinit var binding: ActivitySelectionBinding
13 |
14 | override fun onCreate(savedInstanceState: Bundle?) {
15 | super.onCreate(savedInstanceState)
16 | binding = ActivitySelectionBinding.inflate(layoutInflater)
17 | setContentView(binding.root)
18 | setClickListener()
19 | }
20 |
21 | private fun setClickListener() {
22 | binding.navDrawerActivity.setOnClickListener(this)
23 | binding.navTwoContainerActivity.setOnClickListener(this)
24 | binding.navBottomNavigationActivity.setOnClickListener(this)
25 | }
26 |
27 | override fun onClick(view: View?) {
28 | when(view?.id){
29 | R.id.navDrawerActivity -> openActivity(NavigationDrawerActivity::class.java)
30 | R.id.navTwoContainerActivity -> openActivity(TwoFragmentContainerActivity::class.java)
31 | R.id.navBottomNavigationActivity -> openActivity(BottomNavigationActivity::class.java)
32 | }
33 | }
34 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/navigation/activities/TwoFragmentContainerActivity.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.navigation.activities
2 |
3 | import android.os.Bundle
4 | import com.demo.code.R
5 | import com.demo.code.base.BaseActivity
6 |
7 | class TwoFragmentContainerActivity : BaseActivity() {
8 | override fun onCreate(savedInstanceState: Bundle?) {
9 | super.onCreate(savedInstanceState)
10 | setContentView(R.layout.activity_two_frag_containers)
11 | }
12 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/navigation/fragments/FragmentA.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.navigation.fragments
2 |
3 | import android.os.Bundle
4 | import androidx.fragment.app.Fragment
5 | import android.view.LayoutInflater
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import androidx.navigation.fragment.findNavController
9 | import com.demo.code.R
10 | import com.demo.code.databinding.FragmentLayoutABinding
11 |
12 | class FragmentA : Fragment() {
13 |
14 | private var _binding: FragmentLayoutABinding? = null
15 | private val binding get() = _binding!!
16 |
17 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
18 | savedInstanceState: Bundle?): View? {
19 | _binding = FragmentLayoutABinding.inflate(inflater, container, false)
20 | return binding.root
21 | }
22 |
23 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
24 | super.onViewCreated(view, savedInstanceState)
25 | binding.apply {
26 | this.FragmentANextId.setOnClickListener{
27 | findNavController().navigate(R.id.fragmentC)
28 | }
29 | this.FragmentABackId.setOnClickListener{
30 | findNavController().popBackStack()
31 | }
32 | }
33 | }
34 |
35 | override fun onDestroyView() {
36 | super.onDestroyView()
37 | _binding = null
38 | }
39 |
40 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/navigation/fragments/FragmentB.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.navigation.fragments
2 |
3 | import android.os.Bundle
4 | import androidx.fragment.app.Fragment
5 | import android.view.LayoutInflater
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import androidx.navigation.fragment.findNavController
9 | import com.demo.code.R
10 | import com.demo.code.databinding.FragmentLayoutBBinding
11 |
12 | class FragmentB : Fragment() {
13 |
14 | private var _binding: FragmentLayoutBBinding? = null
15 | private val binding get() = _binding!!
16 |
17 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
18 | savedInstanceState: Bundle?): View? {
19 | _binding = FragmentLayoutBBinding.inflate(inflater, container, false)
20 | return binding.root
21 | }
22 |
23 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
24 | super.onViewCreated(view, savedInstanceState)
25 | binding.apply {
26 | this.FragmentBNextId.setOnClickListener{
27 | findNavController().navigate(R.id.fragmentD)
28 | }
29 | this.FragmentBBackId.setOnClickListener{
30 | findNavController().popBackStack()
31 | }
32 | }
33 | }
34 |
35 | override fun onDestroyView() {
36 | super.onDestroyView()
37 | _binding = null
38 | }
39 |
40 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/navigation/fragments/FragmentC.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.navigation.fragments
2 |
3 | import android.os.Bundle
4 | import androidx.fragment.app.Fragment
5 | import android.view.LayoutInflater
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import androidx.navigation.fragment.findNavController
9 | import com.demo.code.databinding.FragmentLayoutCBinding
10 | import com.demo.extensions.toast.toast
11 |
12 | class FragmentC : Fragment() {
13 |
14 | private var _binding: FragmentLayoutCBinding? = null
15 | private val binding get() = _binding!!
16 |
17 | override fun onCreateView(
18 | inflater: LayoutInflater, container: ViewGroup?,
19 | savedInstanceState: Bundle?
20 | ): View? {
21 | _binding = FragmentLayoutCBinding.inflate(inflater, container, false)
22 | return binding.root
23 | }
24 |
25 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
26 | super.onViewCreated(view, savedInstanceState)
27 | binding.apply {
28 | this.FragmentCNextId.setOnClickListener{
29 | activity?.let {
30 | toast("Last Fragment",false,it)
31 | }
32 | }
33 | this.FragmentCBackId.setOnClickListener{
34 | findNavController().popBackStack()
35 | }
36 | }
37 | }
38 |
39 | override fun onDestroyView() {
40 | super.onDestroyView()
41 | _binding = null
42 | }
43 |
44 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/navigation/fragments/FragmentD.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.navigation.fragments
2 |
3 | import android.os.Bundle
4 | import androidx.fragment.app.Fragment
5 | import android.view.LayoutInflater
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import androidx.navigation.fragment.findNavController
9 | import com.demo.code.R
10 | import com.demo.code.databinding.FragmentLayoutDBinding
11 |
12 | class FragmentD : Fragment() {
13 |
14 | private var _binding: FragmentLayoutDBinding? = null
15 | private val binding get() = _binding!!
16 |
17 | override fun onCreateView(
18 | inflater: LayoutInflater, container: ViewGroup?,
19 | savedInstanceState: Bundle?
20 | ): View? {
21 | _binding = FragmentLayoutDBinding.inflate(inflater, container, false)
22 | return binding.root
23 | }
24 |
25 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
26 | super.onViewCreated(view, savedInstanceState)
27 | binding.apply {
28 | this.FragmentDNextId.setOnClickListener{
29 | findNavController().navigate(R.id.fragmentE)
30 | }
31 | this.FragmentDBackId.setOnClickListener{
32 | findNavController().popBackStack()
33 | }
34 | }
35 | }
36 |
37 | override fun onDestroyView() {
38 | super.onDestroyView()
39 | _binding = null
40 | }
41 |
42 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/navigation/fragments/FragmentE.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.navigation.fragments
2 |
3 | import android.os.Bundle
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import androidx.fragment.app.Fragment
8 | import androidx.navigation.fragment.findNavController
9 | import com.demo.code.R
10 | import com.demo.code.databinding.FragmentLayoutEBinding
11 |
12 | class FragmentE : Fragment() {
13 |
14 | private var _binding: FragmentLayoutEBinding? = null
15 | private val binding get() = _binding!!
16 |
17 | override fun onCreateView(
18 | inflater: LayoutInflater, container: ViewGroup?,
19 | savedInstanceState: Bundle?
20 | ): View? {
21 | _binding = FragmentLayoutEBinding.inflate(inflater, container, false)
22 | return binding.root
23 | }
24 |
25 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
26 | super.onViewCreated(view, savedInstanceState)
27 | binding.apply {
28 | this.FragmentDNextId.setOnClickListener{
29 | findNavController().navigate(R.id.fragmentF)
30 | }
31 | this.FragmentDBackId.setOnClickListener{
32 | findNavController().popBackStack()
33 | }
34 | }
35 | }
36 |
37 | override fun onDestroyView() {
38 | super.onDestroyView()
39 | _binding = null
40 | }
41 |
42 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/navigation/fragments/FragmentF.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.navigation.fragments
2 |
3 | import android.os.Bundle
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import androidx.fragment.app.Fragment
8 | import androidx.navigation.fragment.findNavController
9 | import com.demo.code.databinding.FragmentLayoutFBinding
10 | import com.demo.extensions.toast.toast
11 |
12 | class FragmentF : Fragment() {
13 |
14 | private var _binding: FragmentLayoutFBinding? = null
15 | private val binding get() = _binding!!
16 |
17 | override fun onCreateView(
18 | inflater: LayoutInflater, container: ViewGroup?,
19 | savedInstanceState: Bundle?
20 | ): View? {
21 | _binding = FragmentLayoutFBinding.inflate(inflater, container, false)
22 | return binding.root
23 | }
24 |
25 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
26 | super.onViewCreated(view, savedInstanceState)
27 | binding.apply {
28 | this.FragmentDNextId.setOnClickListener{
29 | activity?.let {
30 | toast("Last Fragment",false,it)
31 | }
32 | }
33 | this.FragmentDBackId.setOnClickListener{
34 | findNavController().popBackStack()
35 | }
36 | }
37 | }
38 |
39 | override fun onDestroyView() {
40 | super.onDestroyView()
41 | _binding = null
42 | }
43 |
44 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/paging/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/app/src/main/java/com/demo/code/paging/.DS_Store
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/paging/Paging3Activity.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.paging
2 |
3 | import android.os.Bundle
4 | import com.demo.code.base.BaseActivity
5 | import com.demo.code.databinding.ActivityPagingBinding
6 | import com.demo.code.paging.usingLocalSource.ui.PagingFromLocalDbActivity
7 | import com.demo.code.paging.usingRemoteAndLocalSource.ui.PagingFromLocalRemoteApiActivity
8 | import com.demo.code.paging.usingRemoteSource.ui.PagingFromRemoteApiActivity
9 | import com.demo.extensions.intent.openActivity
10 |
11 | class Paging3Activity : BaseActivity() {
12 |
13 | private lateinit var binding: ActivityPagingBinding
14 |
15 | override fun onCreate(savedInstanceState: Bundle?) {
16 | super.onCreate(savedInstanceState)
17 | binding = ActivityPagingBinding.inflate(layoutInflater)
18 | setContentView(binding.root)
19 |
20 | binding.apply {
21 | this.pagingFromLocalDbId.setOnClickListener {
22 | openActivity(PagingFromLocalDbActivity::class.java)
23 | }
24 | this.pagingFromRemoteApiId.setOnClickListener {
25 | openActivity(PagingFromRemoteApiActivity::class.java)
26 | }
27 | this.pagingFromLocalRemoteApiId.setOnClickListener {
28 | openActivity(PagingFromLocalRemoteApiActivity::class.java)
29 | }
30 | }
31 | }
32 |
33 |
34 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/paging/usingLocalSource/Executors.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.paging.usingLocalSource
2 |
3 | import java.util.concurrent.Executors
4 |
5 | private val BG_EXECUTOR = Executors.newSingleThreadExecutor()
6 |
7 | fun bgThread(f : () -> Unit) {
8 | BG_EXECUTOR.execute(f)
9 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/paging/usingLocalSource/Extensions.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.paging.usingLocalSource
2 |
3 | import android.view.LayoutInflater
4 | import android.view.View
5 | import android.view.ViewGroup
6 | import androidx.annotation.LayoutRes
7 |
8 | fun ViewGroup.inflate(@LayoutRes layoutRes: Int, attachToRoot: Boolean = false): View {
9 | return LayoutInflater.from(context).inflate(layoutRes, this, attachToRoot)
10 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/paging/usingLocalSource/db/MovieDao.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.paging.usingLocalSource.db
2 |
3 | import androidx.paging.DataSource
4 | import androidx.room.Dao
5 | import androidx.room.Delete
6 | import androidx.room.Insert
7 | import androidx.room.Query
8 | import com.demo.code.paging.usingLocalSource.model.Movie
9 |
10 | @Dao
11 | interface MovieDao {
12 |
13 | /*
14 | *
15 | *
16 | *
17 | @Query("SELECT * FROM Movie ORDER BY ranking")
18 | fun allMovies(): LiveData>
19 | *
20 | *
21 | --- Instead of Live data we shall replace with a factory that returns the positional data source
22 | *
23 | */
24 | @Query("SELECT * FROM Movie ORDER BY ranking")
25 | fun allMovies(): DataSource.Factory
26 |
27 | @Insert
28 | fun insert(movies: List)
29 |
30 | @Insert
31 | fun insert(movie: Movie)
32 |
33 | @Delete
34 | fun delete(movie: Movie)
35 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/paging/usingLocalSource/db/MovieDatabase.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.paging.usingLocalSource.db
2 |
3 | import android.content.Context
4 | import android.util.Log
5 | import androidx.room.Database
6 | import androidx.room.Room
7 | import androidx.room.RoomDatabase
8 | import androidx.sqlite.db.SupportSQLiteDatabase
9 | import com.demo.code.paging.usingLocalSource.bgThread
10 | import com.demo.code.paging.usingLocalSource.model.Movie
11 | import com.demo.code.paging.usingLocalSource.model.MovieData
12 | import com.google.gson.Gson
13 | import java.io.IOException
14 | import java.nio.charset.StandardCharsets
15 |
16 | @Database(entities = [(Movie::class)], version = 1, exportSchema = false)
17 | abstract class MovieDatabase : RoomDatabase() {
18 | abstract fun movieDao(): MovieDao
19 |
20 | companion object {
21 | private const val TAG = "MovieDatabase"
22 | private var instance: MovieDatabase? = null
23 |
24 | @Synchronized
25 | fun get(context: Context): MovieDatabase {
26 | if (instance == null) {
27 | instance = Room.databaseBuilder(context.applicationContext,
28 | MovieDatabase::class.java, "MovieDatabase")
29 | .addCallback(object : RoomDatabase.Callback() {
30 | override fun onCreate(db: SupportSQLiteDatabase) {
31 | fillInDatabase(context.applicationContext)
32 | }
33 | }).build()
34 | }
35 | return instance!!
36 | }
37 |
38 | private fun fillInDatabase(context: Context) {
39 | bgThread {
40 | val jsonString = readJson(context)
41 |
42 | if (jsonString != null) {
43 | val movieData = Gson().fromJson(jsonString, MovieData::class.java)
44 | get(context).movieDao().insert(movieData.movies)
45 | Log.v(TAG, movieData.toString())
46 | }
47 | }
48 | }
49 |
50 | private fun readJson(context: Context): String? {
51 | var json: String? = null
52 |
53 | try {
54 | val inputStream = context.assets.open("movie_data.json")
55 | val size = inputStream.available()
56 | val buffer = ByteArray(size)
57 | inputStream.read(buffer)
58 | inputStream.close()
59 | json = String(buffer, StandardCharsets.UTF_8)
60 | } catch (e: IOException) {
61 | Log.e(TAG, "Error reading JSON data ::: " + e.message, e)
62 | }
63 |
64 | return json
65 | }
66 | }
67 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/paging/usingLocalSource/model/Movie.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.paging.usingLocalSource.model
2 | import androidx.room.Entity
3 | import androidx.room.PrimaryKey
4 | import com.google.gson.annotations.SerializedName
5 |
6 | @Entity
7 | data class Movie(
8 | @PrimaryKey(autoGenerate = true) val id: Int,
9 | val title: String,
10 | val rating: Double,
11 | @SerializedName("release_date") val releaseDate: String,
12 | val ranking: Int)
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/paging/usingLocalSource/model/MovieData.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.paging.usingLocalSource.model
2 |
3 |
4 | data class MovieData(var movies: List)
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/paging/usingLocalSource/ui/MovieListAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.paging.usingLocalSource.ui
2 |
3 | import android.view.View
4 | import android.view.ViewGroup
5 | import androidx.paging.PagedListAdapter
6 | import androidx.recyclerview.widget.DiffUtil
7 | import androidx.recyclerview.widget.RecyclerView
8 | import com.demo.code.R
9 | import com.demo.code.paging.usingLocalSource.inflate
10 | import kotlinx.android.extensions.LayoutContainer
11 | import com.demo.code.paging.usingLocalSource.model.Movie
12 | import kotlinx.android.synthetic.main.list_item_movie.*
13 |
14 | /**
15 | * @param Movie -> Type of the data per each item row
16 | * @param ViewHolder -> View holder patter to recycle the views
17 | * @param diffCallback -> We pass the diff util callback to the page list adapter so it updates the page list
18 | */
19 | class MovieListAdapter : PagedListAdapter(diffCallback) {
20 |
21 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
22 | MovieViewHolder(parent.inflate(R.layout.list_item_movie))
23 |
24 | override fun onBindViewHolder(holder: MovieViewHolder, position: Int) {
25 | holder.bind(getItem(position))
26 | }
27 |
28 | companion object {
29 |
30 | private val diffCallback = object : DiffUtil.ItemCallback() {
31 | override fun areItemsTheSame(oldItem: Movie, newItem: Movie): Boolean =
32 | oldItem.id == newItem.id
33 | override fun areContentsTheSame(oldItem: Movie, newItem: Movie): Boolean =
34 | oldItem == newItem
35 | }
36 | }
37 |
38 | class MovieViewHolder(override val containerView: View)
39 | : RecyclerView.ViewHolder(containerView), LayoutContainer {
40 |
41 | var movie: Movie? = null
42 |
43 | fun bind(movie: Movie?) {
44 | this.movie = movie
45 | title.text = movie?.title
46 | releaseDate.text = movie?.releaseDate?.substring(0, 4)
47 | rating.text = movie?.rating.toString()
48 | }
49 | }
50 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/paging/usingLocalSource/ui/MovieListViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.paging.usingLocalSource.ui
2 |
3 | import android.app.Application
4 | import androidx.lifecycle.AndroidViewModel
5 | import androidx.paging.LivePagedListBuilder
6 | import androidx.paging.PagedList
7 | import com.demo.code.paging.usingLocalSource.bgThread
8 | import com.demo.code.paging.usingLocalSource.db.MovieDatabase
9 | import com.demo.code.paging.usingLocalSource.model.Movie
10 |
11 | class MovieListViewModel(application: Application) : AndroidViewModel(application) {
12 | private val dao = MovieDatabase.get(application).movieDao()
13 |
14 | val allMovies = LivePagedListBuilder(dao.allMovies(), PagedList.Config.Builder()
15 | .setPageSize(PAGE_SIZE)
16 | .setEnablePlaceholders(ENABLE_PLACEHOLDERS)
17 | .build()).build()
18 |
19 | fun remove(movie: Movie) = bgThread {
20 | dao.delete(movie)
21 | }
22 |
23 | companion object {
24 | private const val PAGE_SIZE = 30
25 | private const val ENABLE_PLACEHOLDERS = true
26 | }
27 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/paging/usingRemoteAndLocalSource/database/LocalDatabase.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.paging.usingRemoteAndLocalSource.database
2 |
3 | import android.content.Context
4 | import androidx.room.Database
5 | import androidx.room.Room
6 | import androidx.room.RoomDatabase
7 | import com.demo.code.paging.usingRemoteSource.database.dao.KeysDao
8 | import com.demo.code.paging.usingRemoteSource.models.PostsKeys
9 | import com.demo.code.paging.usingRemoteSource.models.FeedPost
10 | import com.demo.code.paging.usingRemoteSource.database.dao.PostsDao
11 | import com.demo.code.paging.usingRemoteSource.database.LocalDatabase
12 |
13 | @Database(
14 | entities = [FeedPost::class, PostsKeys::class],
15 | version = 1,
16 | exportSchema = false
17 | )
18 | abstract class LocalDatabase : RoomDatabase() {
19 |
20 | companion object {
21 |
22 | private const val DATABASE_NAME = "paging_demo.db"
23 | private val LOCAL_DATABASE = LocalDatabase::class.java
24 |
25 | fun create(context: Context): LocalDatabase {
26 | val databaseBuilder = Room.databaseBuilder(context, LOCAL_DATABASE, DATABASE_NAME)
27 | return databaseBuilder.build()
28 | }
29 | }
30 |
31 | abstract fun postsDao(): PostsDao
32 | abstract fun keysDao(): KeysDao
33 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/paging/usingRemoteAndLocalSource/database/dao/KeysDao.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.paging.usingRemoteAndLocalSource.database.dao
2 |
3 | import androidx.room.Dao
4 | import androidx.room.Insert
5 | import androidx.room.OnConflictStrategy.REPLACE
6 | import androidx.room.Query
7 | import com.demo.code.paging.usingRemoteSource.models.PostsKeys
8 |
9 | @Dao
10 | interface KeysDao {
11 |
12 | @Insert(onConflict = REPLACE)
13 | suspend fun savePostsKeys(postsKey: PostsKeys)
14 |
15 | @Query("SELECT * FROM postKeys ORDER BY id DESC")
16 | suspend fun getPostsKeys(): List
17 |
18 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/paging/usingRemoteAndLocalSource/database/dao/PostsDao.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.paging.usingRemoteAndLocalSource.database.dao
2 |
3 | import androidx.paging.PagingSource
4 | import androidx.room.Dao
5 | import androidx.room.Insert
6 | import androidx.room.OnConflictStrategy.REPLACE
7 | import androidx.room.Query
8 | import com.demo.code.paging.usingRemoteSource.models.FeedPost
9 |
10 | @Dao
11 | interface PostsDao {
12 |
13 | @Insert(onConflict = REPLACE)
14 | suspend fun savePosts(feedPosts: List)
15 |
16 | @Query("SELECT * FROM feedPosts")
17 | fun getPosts(): PagingSource
18 |
19 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/paging/usingRemoteAndLocalSource/models/FeedPost.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.paging.usingRemoteAndLocalSource.models
2 |
3 | import androidx.room.Entity
4 | import androidx.room.PrimaryKey
5 | import com.google.gson.annotations.SerializedName
6 |
7 | @Entity(tableName = "feedPosts")
8 | data class FeedPost(
9 | @SerializedName("name")
10 | @PrimaryKey
11 | val key: String,
12 | @SerializedName("title")
13 | val title: String,
14 | @SerializedName("score")
15 | val score: Int,
16 | @SerializedName("author")
17 | val author: String,
18 | @SerializedName("num_comments")
19 | val commentCount: Int
20 | )
21 |
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/paging/usingRemoteAndLocalSource/models/PostContainer.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.paging.usingRemoteAndLocalSource.models
2 |
3 | import com.demo.code.paging.usingRemoteSource.models.FeedPost
4 |
5 | class PostContainer(val data: FeedPost)
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/paging/usingRemoteAndLocalSource/models/PostsApiResponse.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.paging.usingRemoteAndLocalSource.models
2 |
3 | import com.demo.code.paging.usingRemoteSource.models.PostsListing
4 |
5 |
6 | class PostsApiResponse(val data: PostsListing)
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/paging/usingRemoteAndLocalSource/models/PostsKeys.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.paging.usingRemoteAndLocalSource.models
2 |
3 | import androidx.room.Entity
4 | import androidx.room.PrimaryKey
5 |
6 | @Entity(tableName = "postKeys")
7 | data class PostsKeys(
8 | @PrimaryKey(autoGenerate = true)
9 | val id: Int,
10 | val after: String?,
11 | val before: String?
12 | )
13 |
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/paging/usingRemoteAndLocalSource/models/PostsListing.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.paging.usingRemoteAndLocalSource.models
2 |
3 | import com.demo.code.paging.usingRemoteSource.models.PostContainer
4 |
5 | class PostsListing(val children: List, val after: String?, val before: String?)
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/paging/usingRemoteAndLocalSource/networking/ApiClient.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.paging.usingRemoteAndLocalSource.networking
2 |
3 | import retrofit2.Retrofit
4 | import retrofit2.converter.gson.GsonConverterFactory
5 |
6 | class ApiClient {
7 |
8 | companion object {
9 |
10 | private const val BASE_URL = "https://www.reddit.com/"
11 | private var retrofit: Retrofit? = null
12 |
13 | fun getClient(): Retrofit {
14 | when (retrofit) {
15 | null -> retrofit = Retrofit.Builder()
16 | .baseUrl(BASE_URL)
17 | .addConverterFactory(GsonConverterFactory.create())
18 | .build()
19 | }
20 | return retrofit as Retrofit
21 | }
22 |
23 | }
24 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/paging/usingRemoteAndLocalSource/networking/RemoteService.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.paging.usingRemoteAndLocalSource.networking
2 |
3 | import com.demo.code.paging.usingRemoteSource.models.PostsApiResponse
4 | import com.demo.code.paging.usingRemoteSource.networking.RemoteService
5 | import retrofit2.Response
6 | import retrofit2.http.GET
7 | import retrofit2.http.Query
8 |
9 | interface RemoteService {
10 |
11 | companion object {
12 | val service = RemoteService::class.java
13 | }
14 |
15 | @GET("/r/aww/hot.json")
16 | suspend fun fetchPosts(
17 | @Query("limit") loadSize: Int = 0,
18 | @Query("after") after: String? = null,
19 | @Query("before") before: String? = null
20 | ): Response
21 |
22 |
23 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/paging/usingRemoteAndLocalSource/repositories/DataMediator.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.paging.usingRemoteAndLocalSource.repositories
2 |
3 | import androidx.paging.*
4 | import androidx.room.withTransaction
5 | import com.demo.code.paging.usingRemoteSource.database.LocalDatabase
6 | import com.demo.code.paging.usingRemoteSource.models.PostsKeys
7 | import com.demo.code.paging.usingRemoteSource.models.FeedPost
8 | import com.demo.code.paging.usingRemoteSource.networking.RemoteService
9 | import retrofit2.HttpException
10 | import java.io.IOException
11 |
12 | @OptIn(ExperimentalPagingApi::class)
13 | class DataMediator(
14 | private val remoteService: RemoteService,
15 | private val LocalDatabase: LocalDatabase
16 | ) : RemoteMediator() {
17 |
18 | override suspend fun load(
19 | loadType: LoadType,
20 | state: PagingState
21 | ): MediatorResult {
22 |
23 | return try {
24 |
25 | val loadKey = when(loadType){
26 | LoadType.REFRESH -> null
27 | LoadType.PREPEND -> return MediatorResult.Success(endOfPaginationReached = true)
28 | LoadType.APPEND ->{
29 | state.lastItemOrNull()
30 | ?: return MediatorResult.Success(endOfPaginationReached = true)
31 | getRedditKeys()
32 | }
33 | }
34 |
35 | val response = remoteService.fetchPosts(
36 | loadSize = state.config.pageSize,
37 | after = loadKey?.after,
38 | before = loadKey?.before
39 | )
40 |
41 | val listing = response.body()?.data
42 |
43 | val feedPosts = listing?.children?.map { it.data }
44 |
45 | if (feedPosts != null) {
46 | LocalDatabase.withTransaction {
47 | LocalDatabase.keysDao()
48 | .savePostsKeys(PostsKeys(0, listing.after, listing.before))
49 | LocalDatabase.postsDao().savePosts(feedPosts)
50 | }
51 |
52 | }
53 | MediatorResult.Success(endOfPaginationReached = listing?.after == null)
54 |
55 | } catch (exception: IOException) {
56 | MediatorResult.Error(exception)
57 | } catch (exception: HttpException) {
58 | MediatorResult.Error(exception)
59 | }
60 |
61 | }
62 |
63 | private suspend fun getRedditKeys(): PostsKeys? {
64 | return LocalDatabase.keysDao().getPostsKeys().firstOrNull()
65 | }
66 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/paging/usingRemoteAndLocalSource/repositories/Repository.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.paging.usingRemoteAndLocalSource.repositories
2 |
3 | import android.content.Context
4 | import androidx.paging.ExperimentalPagingApi
5 | import androidx.paging.Pager
6 | import androidx.paging.PagingConfig
7 | import androidx.paging.PagingData
8 | import com.demo.code.paging.usingRemoteSource.database.LocalDatabase
9 | import com.demo.code.paging.usingRemoteSource.models.FeedPost
10 | import com.demo.code.paging.usingRemoteSource.networking.ApiClient
11 | import com.demo.code.paging.usingRemoteSource.networking.RemoteService
12 | import com.demo.code.paging.usingRemoteSource.repositories.DataMediator
13 | import kotlinx.coroutines.flow.Flow
14 |
15 | class Repository(context: Context) {
16 |
17 | // Remote API reference
18 | private val apiService = ApiClient.getClient().create(RemoteService.service)
19 | // Local database reference
20 | private val localDatabase = LocalDatabase.create(context)
21 |
22 | /**
23 | * @return Flow of Paging data
24 | */
25 | @OptIn(ExperimentalPagingApi::class)
26 | fun fetchPosts(): Flow> {
27 |
28 | return Pager(
29 | PagingConfig(pageSize = 10, enablePlaceholders = false, prefetchDistance = 1),
30 | remoteMediator = DataMediator(apiService, localDatabase),
31 | pagingSourceFactory = { localDatabase.postsDao().getPosts() }
32 | ).flow
33 |
34 | }
35 |
36 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/paging/usingRemoteAndLocalSource/ui/LocalRemoteApiLoadingAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.paging.usingRemoteAndLocalSource.ui
2 |
3 | import android.view.LayoutInflater
4 | import android.view.View
5 | import android.view.ViewGroup
6 | import android.widget.Button
7 | import android.widget.ProgressBar
8 | import android.widget.TextView
9 | import androidx.core.view.isVisible
10 | import androidx.paging.LoadState
11 | import androidx.paging.LoadStateAdapter
12 | import androidx.recyclerview.widget.RecyclerView
13 | import com.demo.code.R
14 | import kotlinx.android.synthetic.main.item_loading_state.view.*
15 |
16 | class LocalRemoteApiLoadingAdapter(private val retry: () -> Unit) :
17 | LoadStateAdapter() {
18 |
19 | override fun onBindViewHolder(holder: LoadingStateViewHolder, loadState: LoadState) {
20 | holder.bindState(loadState)
21 | }
22 |
23 | override fun onCreateViewHolder(
24 | parent: ViewGroup,
25 | loadState: LoadState
26 | ): LoadingStateViewHolder {
27 | val view = LayoutInflater.from(parent.context)
28 | .inflate(R.layout.item_loading_state, parent, false)
29 | return LoadingStateViewHolder(view, retry)
30 | }
31 |
32 |
33 | class LoadingStateViewHolder(itemView: View, retry: () -> Unit) :
34 | RecyclerView.ViewHolder(itemView) {
35 |
36 | private val tvErrorMessage: TextView = itemView.tvErrorMessage
37 | private val progressBar: ProgressBar = itemView.progress_bar
38 | private val btnRetry: Button = itemView.btnRetry
39 |
40 | init {
41 | btnRetry.setOnClickListener {
42 | retry.invoke()
43 | }
44 | }
45 |
46 |
47 | fun bindState(loadState: LoadState) {
48 | if (loadState is LoadState.Error) {
49 | tvErrorMessage.text = loadState.error.localizedMessage
50 | }
51 | progressBar.isVisible = loadState is LoadState.Loading
52 | tvErrorMessage.isVisible = loadState !is LoadState.Loading
53 | btnRetry.isVisible = loadState !is LoadState.Loading
54 | }
55 |
56 | }
57 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/paging/usingRemoteAndLocalSource/ui/LocalRemoteApiViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.paging.usingRemoteAndLocalSource.ui
2 |
3 | import android.app.Application
4 | import androidx.lifecycle.AndroidViewModel
5 | import androidx.lifecycle.viewModelScope
6 | import androidx.paging.PagingData
7 | import androidx.paging.cachedIn
8 | import com.demo.code.paging.usingRemoteSource.models.FeedPost
9 | import com.demo.code.paging.usingRemoteSource.repositories.Repository
10 | import kotlinx.coroutines.flow.Flow
11 |
12 | class LocalRemoteApiViewModel(application: Application) : AndroidViewModel(application) {
13 |
14 | companion object {
15 | val thisClass = LocalRemoteApiViewModel::class.java
16 | }
17 |
18 | private val redditRepo = Repository(application)
19 |
20 | fun fetchPosts(): Flow> {
21 |
22 | return redditRepo.fetchPosts().cachedIn(viewModelScope)
23 |
24 | }
25 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/paging/usingRemoteAndLocalSource/ui/PagingFromLocalRemoteApiActivity.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.paging.usingRemoteAndLocalSource.ui
2 |
3 | import android.os.Bundle
4 | import androidx.lifecycle.ViewModelProvider
5 | import androidx.lifecycle.lifecycleScope
6 | import com.demo.code.R
7 | import com.demo.code.base.BaseActivity
8 | import com.demo.code.databinding.ActivityPagingFromLocalRemoteApiBinding
9 | import kotlinx.coroutines.flow.collectLatest
10 | import kotlinx.coroutines.launch
11 |
12 | class PagingFromLocalRemoteApiActivity : BaseActivity() {
13 |
14 | // Binding: View references
15 | private lateinit var binding: ActivityPagingFromLocalRemoteApiBinding
16 |
17 | // Adapter: List of items
18 | private val adapter = RemoteApiAdapter()
19 |
20 | // viewModel reference
21 | private val localRemoteApiViewModel: LocalRemoteApiViewModel by lazy {
22 | ViewModelProvider(this).get(LocalRemoteApiViewModel.thisClass)
23 | }
24 |
25 | override fun onCreate(savedInstanceState: Bundle?) {
26 | setTheme(R.style.AppTheme)
27 | super.onCreate(savedInstanceState)
28 | binding = ActivityPagingFromLocalRemoteApiBinding.inflate(layoutInflater)
29 | setContentView(binding.root)
30 | setupViews()
31 | fetchPosts()
32 | }
33 |
34 | private fun fetchPosts() {
35 | lifecycleScope.launch {
36 |
37 | localRemoteApiViewModel.fetchPosts().collectLatest { pagingData ->
38 | // We get the new data from the flow - We publish the new data to adapter
39 | adapter.submitData(pagingData)
40 | }
41 | }
42 | }
43 |
44 | private fun setupViews() {
45 | binding.apply {
46 | // Adapter: List of items
47 | rvPosts.adapter = adapter
48 | // Adapters: Header and Footer item
49 | rvPosts.adapter = adapter.withLoadStateHeaderAndFooter(
50 | // Header
51 | header = LocalRemoteApiLoadingAdapter { adapter.retry() },
52 | // Footer
53 | footer = LocalRemoteApiLoadingAdapter { adapter.retry() }
54 | )
55 | }
56 | }
57 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/paging/usingRemoteAndLocalSource/ui/RemoteApiAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.paging.usingRemoteAndLocalSource.ui
2 |
3 | import android.view.LayoutInflater
4 | import android.view.View
5 | import android.view.ViewGroup
6 | import android.widget.TextView
7 | import androidx.paging.PagingDataAdapter
8 | import androidx.recyclerview.widget.RecyclerView
9 | import com.demo.code.R
10 | import com.demo.code.paging.usingRemoteSource.models.FeedPost
11 | import com.demo.code.paging.usingRemoteSource.utils.DiffUtilCallBack
12 | import kotlinx.android.synthetic.main.adapter_row.view.*
13 |
14 | class RemoteApiAdapter :
15 | PagingDataAdapter(DiffUtilCallBack()) {
16 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RedditViewHolder {
17 | val view = LayoutInflater.from(parent.context).inflate(R.layout.adapter_row, parent, false)
18 | return RedditViewHolder(view)
19 | }
20 |
21 | override fun onBindViewHolder(holder: RedditViewHolder, position: Int) {
22 | getItem(position)?.let { holder.bindPost(it) }
23 | }
24 |
25 | class RedditViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
26 | private val titleText: TextView = itemView.title
27 |
28 | fun bindPost(feedPost: FeedPost) {
29 | with(feedPost) {
30 | titleText.text = title
31 | }
32 | }
33 | }
34 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/paging/usingRemoteAndLocalSource/utils/DiffUtilCallBack.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.paging.usingRemoteAndLocalSource.utils
2 |
3 | import androidx.recyclerview.widget.DiffUtil
4 | import com.demo.code.paging.usingRemoteSource.models.FeedPost
5 |
6 | class DiffUtilCallBack : DiffUtil.ItemCallback() {
7 | override fun areItemsTheSame(oldItem: FeedPost, newItem: FeedPost): Boolean {
8 | return oldItem.key == newItem.key
9 | }
10 |
11 | override fun areContentsTheSame(oldItem: FeedPost, newItem: FeedPost): Boolean {
12 | return oldItem.key == newItem.key
13 | && oldItem.score == newItem.score
14 | && oldItem.commentCount == newItem.commentCount
15 | }
16 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/paging/usingRemoteSource/database/LocalDatabase.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.paging.usingRemoteSource.database
2 |
3 | import android.content.Context
4 | import androidx.room.Database
5 | import androidx.room.Room
6 | import androidx.room.RoomDatabase
7 | import com.demo.code.paging.usingRemoteSource.database.dao.KeysDao
8 | import com.demo.code.paging.usingRemoteSource.models.PostsKeys
9 | import com.demo.code.paging.usingRemoteSource.models.FeedPost
10 | import com.demo.code.paging.usingRemoteSource.database.dao.PostsDao
11 |
12 | @Database(
13 | entities = [FeedPost::class, PostsKeys::class],
14 | version = 1,
15 | exportSchema = false
16 | )
17 | abstract class LocalDatabase : RoomDatabase() {
18 |
19 | companion object {
20 |
21 | private const val DATABASE_NAME = "paging_demo.db"
22 | private val LOCAL_DATABASE = LocalDatabase::class.java
23 |
24 | fun create(context: Context): LocalDatabase {
25 | val databaseBuilder = Room.databaseBuilder(context, LOCAL_DATABASE, DATABASE_NAME)
26 | return databaseBuilder.build()
27 | }
28 | }
29 |
30 | abstract fun postsDao(): PostsDao
31 | abstract fun keysDao(): KeysDao
32 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/paging/usingRemoteSource/database/dao/KeysDao.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.paging.usingRemoteSource.database.dao
2 |
3 | import androidx.room.Dao
4 | import androidx.room.Insert
5 | import androidx.room.OnConflictStrategy.REPLACE
6 | import androidx.room.Query
7 | import com.demo.code.paging.usingRemoteSource.models.PostsKeys
8 |
9 | @Dao
10 | interface KeysDao {
11 |
12 | @Insert(onConflict = REPLACE)
13 | suspend fun savePostsKeys(postsKey: PostsKeys)
14 |
15 | @Query("SELECT * FROM postKeys ORDER BY id DESC")
16 | suspend fun getPostsKeys(): List
17 |
18 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/paging/usingRemoteSource/database/dao/PostsDao.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.paging.usingRemoteSource.database.dao
2 |
3 | import androidx.paging.PagingSource
4 | import androidx.room.Dao
5 | import androidx.room.Insert
6 | import androidx.room.OnConflictStrategy.REPLACE
7 | import androidx.room.Query
8 | import com.demo.code.paging.usingRemoteSource.models.FeedPost
9 |
10 | @Dao
11 | interface PostsDao {
12 |
13 | @Insert(onConflict = REPLACE)
14 | suspend fun savePosts(feedPosts: List)
15 |
16 | @Query("SELECT * FROM feedPosts")
17 | fun getPosts(): PagingSource
18 |
19 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/paging/usingRemoteSource/models/FeedPost.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.paging.usingRemoteSource.models
2 |
3 | import androidx.room.Entity
4 | import androidx.room.PrimaryKey
5 | import com.google.gson.annotations.SerializedName
6 |
7 | @Entity(tableName = "feedPosts")
8 | data class FeedPost(
9 | @SerializedName("name")
10 | @PrimaryKey
11 | val key: String,
12 | @SerializedName("title")
13 | val title: String,
14 | @SerializedName("score")
15 | val score: Int,
16 | @SerializedName("author")
17 | val author: String,
18 | @SerializedName("num_comments")
19 | val commentCount: Int
20 | )
21 |
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/paging/usingRemoteSource/models/PostContainer.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.paging.usingRemoteSource.models
2 |
3 | class PostContainer(val data: FeedPost)
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/paging/usingRemoteSource/models/PostsApiResponse.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.paging.usingRemoteSource.models
2 |
3 | import com.demo.code.paging.usingRemoteSource.models.PostsListing
4 |
5 |
6 | class PostsApiResponse(val data: PostsListing)
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/paging/usingRemoteSource/models/PostsKeys.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.paging.usingRemoteSource.models
2 |
3 | import androidx.room.Entity
4 | import androidx.room.PrimaryKey
5 |
6 | @Entity(tableName = "postKeys")
7 | data class PostsKeys(
8 | @PrimaryKey(autoGenerate = true)
9 | val id: Int,
10 | val after: String?,
11 | val before: String?
12 | )
13 |
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/paging/usingRemoteSource/models/PostsListing.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.paging.usingRemoteSource.models
2 |
3 | class PostsListing(val children: List, val after: String?, val before: String?)
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/paging/usingRemoteSource/networking/ApiClient.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.paging.usingRemoteSource.networking
2 |
3 | import retrofit2.Retrofit
4 | import retrofit2.converter.gson.GsonConverterFactory
5 |
6 | class ApiClient {
7 |
8 | companion object {
9 |
10 | private const val BASE_URL = "https://www.reddit.com/"
11 | private var retrofit: Retrofit? = null
12 |
13 | fun getClient(): Retrofit {
14 | when (retrofit) {
15 | null -> retrofit = Retrofit.Builder()
16 | .baseUrl(BASE_URL)
17 | .addConverterFactory(GsonConverterFactory.create())
18 | .build()
19 | }
20 | return retrofit as Retrofit
21 | }
22 |
23 | }
24 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/paging/usingRemoteSource/networking/RemoteService.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.paging.usingRemoteSource.networking
2 |
3 | import com.demo.code.paging.usingRemoteSource.models.PostsApiResponse
4 | import retrofit2.Response
5 | import retrofit2.http.GET
6 | import retrofit2.http.Query
7 |
8 | interface RemoteService {
9 |
10 | companion object {
11 | val service = RemoteService::class.java
12 | }
13 |
14 | @GET("/r/aww/hot.json")
15 | suspend fun fetchPosts(
16 | @Query("limit") loadSize: Int = 0,
17 | @Query("after") after: String? = null,
18 | @Query("before") before: String? = null
19 | ): Response
20 |
21 |
22 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/paging/usingRemoteSource/placeholder:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/app/src/main/java/com/demo/code/paging/usingRemoteSource/placeholder
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/paging/usingRemoteSource/repositories/DataMediator.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.paging.usingRemoteSource.repositories
2 |
3 | import androidx.paging.*
4 | import androidx.room.withTransaction
5 | import com.demo.code.paging.usingRemoteSource.database.LocalDatabase
6 | import com.demo.code.paging.usingRemoteSource.models.PostsKeys
7 | import com.demo.code.paging.usingRemoteSource.models.FeedPost
8 | import com.demo.code.paging.usingRemoteSource.networking.RemoteService
9 | import retrofit2.HttpException
10 | import java.io.IOException
11 |
12 | @OptIn(ExperimentalPagingApi::class)
13 | class DataMediator(
14 | private val remoteService: RemoteService,
15 | private val LocalDatabase: LocalDatabase
16 | ) : RemoteMediator() {
17 |
18 | override suspend fun load(
19 | loadType: LoadType,
20 | state: PagingState
21 | ): MediatorResult {
22 |
23 | return try {
24 |
25 | val loadKey = when(loadType){
26 | LoadType.REFRESH -> null
27 | LoadType.PREPEND -> return MediatorResult.Success(endOfPaginationReached = true)
28 | LoadType.APPEND ->{
29 | state.lastItemOrNull()
30 | ?: return MediatorResult.Success(endOfPaginationReached = true)
31 | getRedditKeys()
32 | }
33 | }
34 |
35 | val response = remoteService.fetchPosts(
36 | loadSize = state.config.pageSize,
37 | after = loadKey?.after,
38 | before = loadKey?.before
39 | )
40 |
41 | val listing = response.body()?.data
42 |
43 | val feedPosts = listing?.children?.map { it.data }
44 |
45 | if (feedPosts != null) {
46 | LocalDatabase.withTransaction {
47 | LocalDatabase.keysDao()
48 | .savePostsKeys(PostsKeys(0, listing.after, listing.before))
49 | LocalDatabase.postsDao().savePosts(feedPosts)
50 | }
51 |
52 | }
53 | MediatorResult.Success(endOfPaginationReached = listing?.after == null)
54 |
55 | } catch (exception: IOException) {
56 | MediatorResult.Error(exception)
57 | } catch (exception: HttpException) {
58 | MediatorResult.Error(exception)
59 | }
60 |
61 | }
62 |
63 | private suspend fun getRedditKeys(): PostsKeys? {
64 | return LocalDatabase.keysDao().getPostsKeys().firstOrNull()
65 | }
66 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/paging/usingRemoteSource/repositories/DataSource.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.paging.usingRemoteSource.repositories
2 |
3 | import androidx.paging.ExperimentalPagingApi
4 | import androidx.paging.PagingSource
5 | import androidx.paging.PagingState
6 | import com.demo.code.paging.usingRemoteSource.models.FeedPost
7 | import com.demo.code.paging.usingRemoteSource.networking.RemoteService
8 |
9 | @OptIn(ExperimentalPagingApi::class)
10 | class DataSource(
11 | private val service: RemoteService,
12 | ) : PagingSource() {
13 |
14 | override suspend fun load(params: LoadParams): LoadResult {
15 |
16 | try {
17 | // Load page 1 if undefined.
18 | val nextPageNumber = params.key ?: 1
19 | val response = service.fetchPosts(nextPageNumber)
20 | val data = response.body()?.data
21 | val feedPosts = response.body()?.data?.children?.map { it.data }
22 | return if (feedPosts != null) {
23 | LoadResult.Page(
24 | data = feedPosts,
25 | prevKey = null, // Only paging forward.
26 | nextKey = nextPageNumber + 1
27 | )
28 | }else{
29 | LoadResult.Error(Exception("data is null"))
30 | }
31 | }
32 | catch (e: Exception) {
33 | // Handle errors in this block
34 | return LoadResult.Error(e)
35 | }
36 | }
37 |
38 | override fun getRefreshKey(state: PagingState): Int {
39 | return state.hashCode()
40 | }
41 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/paging/usingRemoteSource/repositories/Repository.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.paging.usingRemoteSource.repositories
2 |
3 | import android.content.Context
4 | import androidx.paging.*
5 | import com.demo.code.paging.usingRemoteSource.database.LocalDatabase
6 | import com.demo.code.paging.usingRemoteSource.models.FeedPost
7 | import com.demo.code.paging.usingRemoteSource.networking.ApiClient
8 | import com.demo.code.paging.usingRemoteSource.networking.RemoteService
9 | import kotlinx.coroutines.flow.Flow
10 |
11 | class Repository(context: Context) {
12 |
13 | // Remote API reference
14 | private val apiService = ApiClient.getClient().create(RemoteService.service)
15 |
16 | /**
17 | * @return Flow of Paging data
18 | */
19 | @OptIn(ExperimentalPagingApi::class)
20 | fun fetchPosts(): Flow> {
21 | return Pager(
22 | PagingConfig(
23 | pageSize = 30,
24 | enablePlaceholders = false,
25 | prefetchDistance = 1,
26 | initialLoadSize = 30*1,
27 | )
28 | ){
29 | DataSource(apiService)
30 | }.flow
31 | }
32 |
33 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/paging/usingRemoteSource/ui/PagingFromRemoteApiActivity.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.paging.usingRemoteSource.ui
2 |
3 | import android.os.Bundle
4 | import androidx.lifecycle.ViewModelProvider
5 | import androidx.lifecycle.lifecycleScope
6 | import com.demo.code.R
7 | import com.demo.code.base.BaseActivity
8 | import com.demo.code.databinding.ActivityPagingFromRemoteApiBinding
9 | import kotlinx.coroutines.flow.collectLatest
10 | import kotlinx.coroutines.launch
11 |
12 |
13 | class PagingFromRemoteApiActivity : BaseActivity() {
14 |
15 | // Binding: View references
16 | private lateinit var binding: ActivityPagingFromRemoteApiBinding
17 |
18 | // Adapter: List of items
19 | private val adapter = RemoteApiAdapter()
20 |
21 | // viewModel reference
22 | private val remoteApiViewModel: RemoteApiViewModel by lazy {
23 | ViewModelProvider(this).get(RemoteApiViewModel.thisClass)
24 | }
25 |
26 | override fun onCreate(savedInstanceState: Bundle?) {
27 | setTheme(R.style.AppTheme)
28 | super.onCreate(savedInstanceState)
29 | binding = ActivityPagingFromRemoteApiBinding.inflate(layoutInflater)
30 | setContentView(binding.root)
31 | setupViews()
32 | fetchPosts()
33 | }
34 |
35 | private fun fetchPosts() {
36 | lifecycleScope.launch {
37 |
38 | remoteApiViewModel.fetchPosts().collectLatest { pagingData ->
39 | // We get the new data from the flow - We publish the new data to adapter
40 | adapter.submitData(pagingData)
41 | }
42 | }
43 | }
44 |
45 | private fun setupViews() {
46 | binding.apply {
47 | // Adapter: List of items
48 | rvPosts.adapter = adapter
49 | // Adapters: Header and Footer item
50 | rvPosts.adapter = adapter.withLoadStateHeaderAndFooter(
51 | // Header
52 | header = RemoteApiLoadingAdapter { adapter.retry() },
53 | // Footer
54 | footer = RemoteApiLoadingAdapter { adapter.retry() }
55 | )
56 | }
57 | }
58 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/paging/usingRemoteSource/ui/RemoteApiAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.paging.usingRemoteSource.ui
2 |
3 | import android.view.LayoutInflater
4 | import android.view.View
5 | import android.view.ViewGroup
6 | import android.widget.TextView
7 | import androidx.paging.PagingDataAdapter
8 | import androidx.recyclerview.widget.RecyclerView
9 | import com.demo.code.R
10 | import com.demo.code.paging.usingRemoteSource.models.FeedPost
11 | import com.demo.code.paging.usingRemoteSource.utils.DiffUtilCallBack
12 | import kotlinx.android.synthetic.main.adapter_row.view.*
13 |
14 | class RemoteApiAdapter :
15 | PagingDataAdapter(DiffUtilCallBack()) {
16 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RedditViewHolder {
17 | val view = LayoutInflater.from(parent.context).inflate(R.layout.adapter_row, parent, false)
18 | return RedditViewHolder(view)
19 | }
20 |
21 | override fun onBindViewHolder(holder: RedditViewHolder, position: Int) {
22 | getItem(position)?.let { holder.bindPost(it) }
23 | }
24 |
25 | class RedditViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
26 | private val titleText: TextView = itemView.title
27 |
28 | fun bindPost(feedPost: FeedPost) {
29 | with(feedPost) {
30 | titleText.text = title
31 | }
32 | }
33 | }
34 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/paging/usingRemoteSource/ui/RemoteApiLoadingAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.paging.usingRemoteSource.ui
2 |
3 | import android.view.LayoutInflater
4 | import android.view.View
5 | import android.view.ViewGroup
6 | import android.widget.Button
7 | import android.widget.ProgressBar
8 | import android.widget.TextView
9 | import androidx.core.view.isVisible
10 | import androidx.paging.LoadState
11 | import androidx.paging.LoadStateAdapter
12 | import androidx.recyclerview.widget.RecyclerView
13 | import com.demo.code.R
14 | import kotlinx.android.synthetic.main.item_loading_state.view.*
15 |
16 | class RemoteApiLoadingAdapter(private val retry: () -> Unit) :
17 | LoadStateAdapter() {
18 |
19 | override fun onBindViewHolder(holder: LoadingStateViewHolder, loadState: LoadState) {
20 | holder.bindState(loadState)
21 | }
22 |
23 | override fun onCreateViewHolder(
24 | parent: ViewGroup,
25 | loadState: LoadState
26 | ): LoadingStateViewHolder {
27 | val view = LayoutInflater.from(parent.context)
28 | .inflate(R.layout.item_loading_state, parent, false)
29 | return LoadingStateViewHolder(view, retry)
30 | }
31 |
32 |
33 | class LoadingStateViewHolder(itemView: View, retry: () -> Unit) :
34 | RecyclerView.ViewHolder(itemView) {
35 |
36 | private val tvErrorMessage: TextView = itemView.tvErrorMessage
37 | private val progressBar: ProgressBar = itemView.progress_bar
38 | private val btnRetry: Button = itemView.btnRetry
39 |
40 | init {
41 | btnRetry.setOnClickListener {
42 | retry.invoke()
43 | }
44 | }
45 |
46 |
47 | fun bindState(loadState: LoadState) {
48 | if (loadState is LoadState.Error) {
49 | tvErrorMessage.text = loadState.error.localizedMessage
50 | }
51 | progressBar.isVisible = loadState is LoadState.Loading
52 | tvErrorMessage.isVisible = loadState !is LoadState.Loading
53 | btnRetry.isVisible = loadState !is LoadState.Loading
54 | }
55 |
56 | }
57 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/paging/usingRemoteSource/ui/RemoteApiViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.paging.usingRemoteSource.ui
2 |
3 | import android.app.Application
4 | import androidx.lifecycle.AndroidViewModel
5 | import androidx.lifecycle.viewModelScope
6 | import androidx.paging.PagingData
7 | import androidx.paging.cachedIn
8 | import com.demo.code.paging.usingRemoteSource.models.FeedPost
9 | import com.demo.code.paging.usingRemoteSource.repositories.Repository
10 | import kotlinx.coroutines.flow.Flow
11 |
12 | class RemoteApiViewModel(application: Application) : AndroidViewModel(application) {
13 |
14 | companion object {
15 | val thisClass = RemoteApiViewModel::class.java
16 | }
17 |
18 | private val redditRepo = Repository(application)
19 |
20 | fun fetchPosts(): Flow> {
21 | return redditRepo.fetchPosts().cachedIn(viewModelScope)
22 | }
23 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/paging/usingRemoteSource/utils/DiffUtilCallBack.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.paging.usingRemoteSource.utils
2 |
3 | import androidx.recyclerview.widget.DiffUtil
4 | import com.demo.code.paging.usingRemoteSource.models.FeedPost
5 |
6 | class DiffUtilCallBack : DiffUtil.ItemCallback() {
7 | override fun areItemsTheSame(oldItem: FeedPost, newItem: FeedPost): Boolean {
8 | return oldItem.key == newItem.key
9 | }
10 |
11 | override fun areContentsTheSame(oldItem: FeedPost, newItem: FeedPost): Boolean {
12 | return oldItem.key == newItem.key
13 | && oldItem.score == newItem.score
14 | && oldItem.commentCount == newItem.commentCount
15 | }
16 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/utils/Constants.kt:
--------------------------------------------------------------------------------
1 | package com.demo.flow.utils
2 |
3 | object Constants {
4 | var APP_URL = "https://5e510330f2c0d300147c034c.mockapi.io/"
5 | var GENERIC_ERROR_MESSAGE = "Something went wrong"
6 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/utils/placeholder.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.utils
2 |
3 | class placeholder {
4 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/workmanager/WorkManagerActivity.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.workmanager
2 |
3 | import android.os.Bundle
4 | import com.demo.code.base.BaseActivity
5 | import com.demo.code.databinding.ActivityPagingBinding
6 | import com.demo.code.databinding.ActivityWorkManagerBinding
7 | import com.demo.code.workmanager.chainingworker.ChainingWorkerActivity
8 | import com.demo.code.workmanager.exampleone.WorkManagerExampleOneActivity
9 | import com.demo.code.workmanager.simpleworker.SimpleWorkerActivity
10 | import com.demo.extensions.intent.openActivity
11 |
12 | class WorkManagerActivity : BaseActivity() {
13 |
14 | private lateinit var binding: ActivityWorkManagerBinding
15 |
16 | override fun onCreate(savedInstanceState: Bundle?) {
17 | super.onCreate(savedInstanceState)
18 | binding = ActivityWorkManagerBinding.inflate(layoutInflater)
19 | setContentView(binding.root)
20 |
21 | binding.apply {
22 | this.simpleWorkerId.setOnClickListener {
23 | openActivity(SimpleWorkerActivity::class.java)
24 | }
25 | this.chainingWorkerId.setOnClickListener {
26 | openActivity(ChainingWorkerActivity::class.java)
27 | }
28 | this.workManagerId.setOnClickListener {
29 | openActivity(WorkManagerExampleOneActivity::class.java)
30 | }
31 | }
32 | }
33 |
34 |
35 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/workmanager/chainingworker/workers/DownloadWorker.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.workmanager.chainingworker.workers
2 |
3 | import android.content.Context
4 | import androidx.work.Worker
5 | import androidx.work.WorkerParameters
6 | import androidx.work.workDataOf
7 | import java.io.File
8 | import java.io.FileOutputStream
9 | import java.net.HttpURLConnection
10 | import java.net.URL
11 |
12 | class DownloadWorker(context: Context, workerParameters: WorkerParameters) :
13 | Worker(context, workerParameters) {
14 |
15 | override fun doWork(): Result {
16 | val imageUrl = URL("https://raw.githubusercontent.com/devrath/Sample-Data/master/Android-CleanArchitecture-Kotlin/posters/038001.jpg")
17 | val connection = imageUrl.openConnection() as HttpURLConnection
18 | connection.doInput = true
19 | connection.connect()
20 |
21 | val imagePath = "owl_image_${System.currentTimeMillis()}.jpg"
22 | val inputStream = connection.inputStream
23 | val file = File(applicationContext.externalMediaDirs.first(), imagePath)
24 |
25 | val outputStream = FileOutputStream(file)
26 | outputStream.use { output ->
27 | val buffer = ByteArray(4 * 1024)
28 |
29 | var byteCount = inputStream.read(buffer)
30 |
31 | while (byteCount > 0) {
32 | output.write(buffer, 0, byteCount)
33 |
34 | byteCount = inputStream.read(buffer)
35 | }
36 |
37 | output.flush()
38 | }
39 | val output = workDataOf("image_path" to file.absolutePath)
40 | return Result.success(output)
41 | }
42 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/workmanager/chainingworker/workers/FileClearWorker.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.workmanager.chainingworker.workers
2 |
3 | import android.content.Context
4 | import androidx.work.Worker
5 | import androidx.work.WorkerParameters
6 |
7 | class FileClearWorker(context: Context, workerParameters: WorkerParameters) :
8 | Worker(context, workerParameters) {
9 |
10 | override fun doWork(): Result {
11 | val root = applicationContext.externalMediaDirs.first()
12 |
13 | return try {
14 | root.listFiles()?.forEach { child ->
15 | if (child.isDirectory) {
16 | child.deleteRecursively()
17 | } else {
18 | child.delete()
19 | }
20 | }
21 | Result.success()
22 | } catch (error: Throwable) {
23 | error.printStackTrace()
24 | Result.failure()
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/workmanager/exampleone/workers/CleanFilesWorker.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.workmanager.exampleone.workers
2 |
3 | import android.content.Context
4 | import android.util.Log
5 | import androidx.work.Worker
6 | import androidx.work.WorkerParameters
7 | import com.demo.code.workmanager.exampleone.ImageUtils
8 |
9 | private const val LOG_TAG = "CleanFilesWorker"
10 |
11 | class CleanFilesWorker(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) {
12 |
13 | override fun doWork(): Result = try {
14 | // Sleep for debugging purposes
15 | Thread.sleep(3000)
16 | Log.d(LOG_TAG, "Cleaning files!")
17 |
18 | ImageUtils.cleanFiles(applicationContext)
19 |
20 | Log.d(LOG_TAG, "Success!")
21 | Result.success()
22 | } catch (e: Throwable) {
23 | Log.e(LOG_TAG, "Error executing work: ${e.message}", e)
24 | Result.failure()
25 | }
26 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/workmanager/exampleone/workers/CompressWorker.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.workmanager.exampleone.workers
2 |
3 | import android.content.Context
4 | import android.util.Log
5 | import androidx.work.Data
6 | import androidx.work.Worker
7 | import androidx.work.WorkerParameters
8 | import com.demo.code.workmanager.exampleone.ImageUtils
9 |
10 | private const val LOG_TAG = "CompressWorker"
11 | private const val KEY_IMAGE_PATH = "IMAGE_PATH"
12 | private const val KEY_ZIP_PATH = "ZIP_PATH"
13 |
14 | class CompressWorker(context: Context, workerParams: WorkerParameters) :
15 | Worker(context, workerParams) {
16 |
17 | override fun doWork(): Result = try {
18 | // Sleep for debugging purposes
19 | Thread.sleep(3000)
20 | Log.d(LOG_TAG, "Compressing files!")
21 |
22 | val imagePaths = inputData.keyValueMap
23 | .filter { it.key.startsWith(KEY_IMAGE_PATH) }
24 | .map { it.value as String }
25 |
26 | val zipFile = ImageUtils.createZipFile(applicationContext, imagePaths.toTypedArray())
27 |
28 | val outputData = Data.Builder()
29 | .putString(KEY_ZIP_PATH, zipFile.path)
30 | .build()
31 |
32 | Log.d(LOG_TAG, "Success!")
33 | Result.success(outputData)
34 | } catch (e: Throwable) {
35 | Log.e(LOG_TAG, "Error executing work: " + e.message, e)
36 | Result.failure()
37 | }
38 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/workmanager/exampleone/workers/FilterWorker.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.workmanager.exampleone.workers
2 |
3 | import android.content.Context
4 | import android.net.Uri
5 | import android.provider.MediaStore
6 | import android.util.Log
7 | import androidx.work.Data
8 | import androidx.work.Worker
9 | import androidx.work.WorkerParameters
10 | import com.demo.code.workmanager.exampleone.ImageUtils
11 |
12 | private const val LOG_TAG = "FilterWorker"
13 | const val KEY_IMAGE_URI = "IMAGE_URI"
14 | const val KEY_IMAGE_INDEX = "IMAGE_INDEX"
15 |
16 | private const val IMAGE_PATH_PREFIX = "IMAGE_PATH_"
17 |
18 | class FilterWorker(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) {
19 |
20 | override fun doWork(): Result = try {
21 | // Sleep for debugging purposes
22 | Thread.sleep(3000)
23 | Log.d(LOG_TAG, "Applying filter to image!")
24 |
25 | val imageUriString = inputData.getString(KEY_IMAGE_URI)
26 | val imageIndex = inputData.getInt(KEY_IMAGE_INDEX, 0)
27 |
28 | val bitmap = MediaStore.Images.Media.getBitmap(applicationContext.contentResolver, Uri.parse(imageUriString))
29 |
30 | val filteredBitmap = ImageUtils.applySepiaFilter(bitmap)
31 | val filteredImageUri = ImageUtils.writeBitmapToFile(applicationContext, filteredBitmap)
32 |
33 | val outputData =
34 | Data.Builder()
35 | .putString(IMAGE_PATH_PREFIX + imageIndex, filteredImageUri.toString())
36 | .build()
37 |
38 | Log.d(LOG_TAG, "Success!")
39 | Result.success(outputData)
40 | } catch (e: Throwable) {
41 | Log.e(LOG_TAG, "Error executing work: " + e.message, e)
42 | Result.failure()
43 | }
44 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/workmanager/exampleone/workers/UploadWorker.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.workmanager.exampleone.workers
2 |
3 | import android.content.Context
4 | import android.net.Uri
5 | import android.util.Log
6 | import androidx.work.Worker
7 | import androidx.work.WorkerParameters
8 | import com.demo.code.workmanager.exampleone.ImageUtils
9 |
10 | private const val LOG_TAG = "UploadWorker"
11 | private const val KEY_ZIP_PATH = "ZIP_PATH"
12 |
13 | class UploadWorker(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) {
14 |
15 | override fun doWork(): Result = try {
16 | // Sleep for debugging purposes
17 | Thread.sleep(3000)
18 | Log.d(LOG_TAG, "Uploading file!")
19 |
20 | val zipPath = inputData.getString(KEY_ZIP_PATH)
21 |
22 | ImageUtils.uploadFile(Uri.parse(zipPath))
23 |
24 | Log.d(LOG_TAG, "Success!")
25 | Result.success()
26 | } catch (e: Throwable) {
27 | Log.e(LOG_TAG, "Error executing work: " + e.message, e)
28 | Result.failure()
29 | }
30 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/code/workmanager/simpleworker/workers/SimpleDownloadWorker.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code.workmanager.simpleworker.workers
2 |
3 | import android.content.Context
4 | import androidx.work.Worker
5 | import androidx.work.WorkerParameters
6 | import java.io.File
7 | import java.io.FileOutputStream
8 | import java.net.HttpURLConnection
9 | import java.net.URL
10 |
11 | class SimpleDownloadWorker(context: Context, workerParameters: WorkerParameters) :
12 | Worker(context,workerParameters) {
13 | override fun doWork(): Result {
14 | val imageUrl = URL("https://raw.githubusercontent.com/devrath/Sample-Data/master/Android-CleanArchitecture-Kotlin/posters/038001.jpg")
15 | val connection = imageUrl.openConnection() as HttpURLConnection
16 | connection.doInput = true
17 | connection.connect()
18 |
19 | val imagePath = "owl_image.jpg"
20 | val inputStream = connection.inputStream
21 | val file = File(applicationContext.externalMediaDirs.first(), imagePath)
22 |
23 | val outputStream = FileOutputStream(file)
24 | outputStream.use { output ->
25 | val buffer = ByteArray(4 * 1024)
26 | var byteCount = inputStream.read(buffer)
27 | while (byteCount > 0) {
28 | output.write(buffer, 0, byteCount)
29 | byteCount = inputStream.read(buffer)
30 | }
31 | output.flush()
32 | }
33 |
34 | return Result.success()
35 | }
36 | }
--------------------------------------------------------------------------------
/app/src/main/res/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/app/src/main/res/.DS_Store
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_camera_black_48dp.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_camera_front_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_camera_rear_black_48dp.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_flash_off_black_48dp.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_comment.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_flash_on_black_48dp.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_home.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_menu_camera.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_menu_gallery.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_menu_slideshow.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_star.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_vertical_align_bottom_white_24px.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_vertical_align_top_white_24px.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/side_nav_bar.xml:
--------------------------------------------------------------------------------
1 |
3 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_bottom_navigation.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
16 |
17 |
18 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_camera_x.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
18 |
19 |
28 |
29 |
38 |
39 |
47 |
48 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_chain_worker.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_data_store.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_jetpack_selection.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
14 |
15 |
19 |
20 |
24 |
25 |
29 |
30 |
34 |
35 |
39 |
40 |
44 |
45 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_live_data_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_navigation_drawer.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
15 |
16 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_paging.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
14 |
15 |
19 |
20 |
24 |
25 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_paging_from_local_db.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_paging_from_local_remote_api.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
16 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_paging_from_remote_api.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
16 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_player.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
11 |
12 |
19 |
20 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_selection.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
15 |
16 |
20 |
21 |
25 |
26 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_simple_worker.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_two_frag_containers.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
15 |
16 |
28 |
29 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_work_manager.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
14 |
15 |
19 |
20 |
24 |
25 |
29 |
30 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_work_manager_example_one.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
20 |
21 |
32 |
33 |
40 |
41 |
52 |
53 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/adapter_row.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
18 |
19 |
26 |
27 |
33 |
34 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/app_bar_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
20 |
21 |
22 |
23 |
24 |
25 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/content_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_layout_a.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
17 |
23 |
29 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_layout_b.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
17 |
23 |
29 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_layout_c.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
17 |
23 |
29 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_layout_d.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
17 |
23 |
29 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_layout_e.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
17 |
23 |
29 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_layout_f.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
17 |
23 |
29 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_proto_data_store.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_selection_data_store.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
15 |
16 |
20 |
21 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/horizontal_paging_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_loading_state.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
20 |
30 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/list_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
18 |
19 |
23 |
24 |
32 |
33 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/list_item_movie.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
22 |
23 |
34 |
35 |
44 |
45 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/mediator_live_data_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
21 |
22 |
36 |
37 |
49 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/mutable_live_data_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
21 |
22 |
33 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/nav_header_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
22 |
23 |
29 |
30 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/selection_live_data_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
15 |
16 |
20 |
21 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/selection_paging_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
15 |
16 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/activity_main_drawer.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/bottom_menu_nav.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/navigation/data_store_nav.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
16 |
19 |
20 |
25 |
30 |
31 |
--------------------------------------------------------------------------------
/app/src/main/res/navigation/live_data_nav.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
16 |
19 |
20 |
25 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/navigation/nav_graph_a.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
12 |
15 |
16 |
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/navigation/nav_graph_b.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
12 |
15 |
18 |
21 |
22 |
27 |
32 |
37 |
38 |
--------------------------------------------------------------------------------
/app/src/main/res/navigation/nav_graph_bottom_navigation.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
16 |
17 |
18 |
23 |
26 |
27 |
28 |
33 |
34 |
39 |
42 |
43 |
44 |
49 |
50 |
53 |
54 |
55 |
60 |
61 |
--------------------------------------------------------------------------------
/app/src/main/res/navigation/nav_graph_drawer.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
16 |
17 |
18 |
23 |
26 |
27 |
28 |
33 |
34 |
39 |
42 |
43 |
44 |
49 |
50 |
53 |
54 |
55 |
60 |
61 |
--------------------------------------------------------------------------------
/app/src/main/res/navigation/paging_nav.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
16 |
17 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/values-night/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFBB86FC
4 | #FF6200EE
5 | #FF3700B3
6 | #FF03DAC5
7 | #FF018786
8 | #FF000000
9 | #FFFFFFFF
10 | #E3E2DF
11 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 10dp
5 | 16dp
6 | 16dp
7 | 8dp
8 | 176dp
9 | 16dp
10 | 16sp
11 | 50dp
12 | 50dp
13 | 10dp
14 | 200dp
15 | 100dp
16 | 8dp
17 | 32dp
18 | 50dp
19 | 20dp
20 | 16dp
21 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
17 |
30 |
31 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/app/src/test/java/com/demo/code/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.demo.code
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | buildscript {
3 | ext.gradle_version = "1.4.31"
4 | ext.kotlin_version = "1.4.31"
5 | ext.nav_version = "2.3.3"
6 | ext.protobuf_version = "0.8.12"
7 | ext.hilt_version = "2.28.3-alpha"
8 | repositories {
9 | google()
10 | jcenter()
11 | }
12 | dependencies {
13 | classpath "com.android.tools.build:gradle:$gradle_version"
14 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
15 | classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
16 | classpath "com.google.protobuf:protobuf-gradle-plugin:$protobuf_version"
17 | classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
18 | // NOTE: Do not place your application dependencies here; they belong
19 | // in the individual module build.gradle files
20 | }
21 | }
22 |
23 | allprojects {
24 | repositories {
25 | google()
26 | jcenter()
27 | }
28 | }
29 |
30 | task clean(type: Delete) {
31 | delete rootProject.buildDir
32 | }
33 |
34 | apply from: 'buildSystem/dependencies.gradle'
35 | apply from: 'buildSystem/version.gradle'
--------------------------------------------------------------------------------
/buildsystem/version.gradle:
--------------------------------------------------------------------------------
1 | ext {
2 | versions = [
3 | compileSdkVersion : 30,
4 | buildToolsVersion : "30.0.3",
5 | minSdkVersion : 21,
6 | targetSdkVersion : 30,
7 | versionCode : 1,
8 | versionName : "1.0",
9 | applicationId : "com.demo.code"
10 | ]
11 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app"s APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=true
20 | # Kotlin code style for this project: "official" or "obsolete":
21 | kotlin.code.style=official
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Mar 12 19:31:49 IST 2021
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip
7 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/images/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/images/.DS_Store
--------------------------------------------------------------------------------
/images/Logo-new.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/images/Logo-new.png
--------------------------------------------------------------------------------
/images/alltools.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/images/alltools.png
--------------------------------------------------------------------------------
/images/android-jetpack.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/images/android-jetpack.png
--------------------------------------------------------------------------------
/images/android_jetpack_lifecycle.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/images/android_jetpack_lifecycle.jpeg
--------------------------------------------------------------------------------
/images/assistant.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/images/assistant.png
--------------------------------------------------------------------------------
/images/camerax.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/images/camerax.png
--------------------------------------------------------------------------------
/images/data_source_types.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/images/data_source_types.png
--------------------------------------------------------------------------------
/images/datastore.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/images/datastore.jpeg
--------------------------------------------------------------------------------
/images/jetpacknavigation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/images/jetpacknavigation.png
--------------------------------------------------------------------------------
/images/liveData.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/images/liveData.jpeg
--------------------------------------------------------------------------------
/images/local_remote_paging.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/images/local_remote_paging.png
--------------------------------------------------------------------------------
/images/mediator_paging.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/images/mediator_paging.png
--------------------------------------------------------------------------------
/images/mobile_server.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/images/mobile_server.png
--------------------------------------------------------------------------------
/images/navigationgraph.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/images/navigationgraph.png
--------------------------------------------------------------------------------
/images/page_struct.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/images/page_struct.png
--------------------------------------------------------------------------------
/images/paging.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/images/paging.png
--------------------------------------------------------------------------------
/images/pagingBanner.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/images/pagingBanner.jpeg
--------------------------------------------------------------------------------
/images/paging_elements.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/images/paging_elements.png
--------------------------------------------------------------------------------
/images/prefdatastore.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/images/prefdatastore.jpeg
--------------------------------------------------------------------------------
/images/proposed_arch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/images/proposed_arch.png
--------------------------------------------------------------------------------
/images/protodatastore.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/images/protodatastore.jpeg
--------------------------------------------------------------------------------
/images/recyclerview.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/images/recyclerview.jpeg
--------------------------------------------------------------------------------
/images/supporting_caching.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/images/supporting_caching.png
--------------------------------------------------------------------------------
/images/types_of_work_manager.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devrath/DroidAndroidJetpack/bfa825ed41965c57a469eeb67e4b376fc8e2ab98/images/types_of_work_manager.png
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app:extensions'
2 | include ':app'
3 | rootProject.name = "code"
--------------------------------------------------------------------------------