├── .gitignore ├── .idea ├── .name ├── codeStyles │ ├── Project.xml │ └── codeStyleConfig.xml ├── compiler.xml ├── encodings.xml ├── gradle.xml ├── jarRepositories.xml ├── misc.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle.kts ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── info │ │ └── sanaebadi │ │ └── stackoverflowproject │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── info │ │ │ └── sanaebadi │ │ │ └── stackoverflowproject │ │ │ ├── di │ │ │ ├── ActivityModule.kt │ │ │ ├── ActivityScope.kt │ │ │ ├── ApplicationComponent.kt │ │ │ ├── ApplicationModule.kt │ │ │ ├── BuildersModule.kt │ │ │ ├── ViewModelKey.kt │ │ │ └── ViewModelModule.kt │ │ │ ├── executors │ │ │ └── UIThread.kt │ │ │ ├── global │ │ │ └── StackApplication.kt │ │ │ ├── mapper │ │ │ ├── UserMapperPresentation.kt │ │ │ └── base │ │ │ │ └── PresentationLayerMapper.java │ │ │ ├── model │ │ │ ├── base │ │ │ │ ├── AdapterConstants.kt │ │ │ │ └── PresentationModel.java │ │ │ └── user │ │ │ │ ├── AnswerListPresentation.kt │ │ │ │ ├── AnswerPresentation.kt │ │ │ │ ├── FavoriteByUserPresentation.kt │ │ │ │ ├── Heading.kt │ │ │ │ ├── OwnerPresentation.kt │ │ │ │ ├── QuestionListPresentation.kt │ │ │ │ ├── QuestionPresentation.kt │ │ │ │ ├── UserListModelPresentation.kt │ │ │ │ └── UserPresentation.kt │ │ │ ├── mvvm │ │ │ └── feature │ │ │ │ └── view │ │ │ │ ├── MainActivity.kt │ │ │ │ ├── adapter │ │ │ │ ├── DetailsAdapter.kt │ │ │ │ └── UserListAdapter.kt │ │ │ │ ├── delegate │ │ │ │ ├── AnswerDelegateAdapter.kt │ │ │ │ ├── HeadingDelegateAdapter.kt │ │ │ │ ├── LoadingDelegateAdapter.kt │ │ │ │ ├── QuestionDelegateAdapter.kt │ │ │ │ ├── UserDetailsDelegateAdapter.kt │ │ │ │ └── base │ │ │ │ │ └── ViewTypeDelegateAdapter.kt │ │ │ │ ├── fragment │ │ │ │ ├── DetailsFragment.kt │ │ │ │ └── UserListFragment.kt │ │ │ │ └── viewModel │ │ │ │ ├── DetailsViewModel.kt │ │ │ │ ├── UserViewModel.kt │ │ │ │ └── base │ │ │ │ ├── BasePresenter.kt │ │ │ │ ├── DetailView.kt │ │ │ │ ├── MutableViewModel.kt │ │ │ │ ├── UserListView.kt │ │ │ │ └── ViewModelFactory.kt │ │ │ └── util │ │ │ ├── AppSchedulerProvider.kt │ │ │ ├── Constants.kt │ │ │ ├── Extensions.kt │ │ │ ├── PreferencesHelper.kt │ │ │ ├── SchedulerProvider.kt │ │ │ ├── TransitionListener.kt │ │ │ └── mOnItemClickListener.kt │ └── res │ │ ├── StackOverFlowProject.zip │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ ├── ic_error.xml │ │ └── ic_launcher_background.xml │ │ ├── font │ │ ├── font_bold.ttf │ │ └── font_regular.ttf │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── fragment_details.xml │ │ ├── fragment_user_list.xml │ │ ├── list_item_answer.xml │ │ ├── list_item_heading.xml │ │ ├── list_item_loading.xml │ │ ├── list_item_question.xml │ │ ├── list_item_user.xml │ │ └── list_item_user_details.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 │ │ └── nav_graph.xml │ │ ├── transition │ │ └── shared_element_transition.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── info │ └── sanaebadi │ └── stackoverflowproject │ └── ExampleUnitTest.kt ├── build.gradle.kts ├── buildSrc ├── build.gradle.kts ├── build │ ├── classes │ │ └── kotlin │ │ │ └── main │ │ │ ├── AndroidSdk.class │ │ │ ├── BuildPlugins$Versions.class │ │ │ ├── BuildPlugins.class │ │ │ ├── DaggerLib$Versions.class │ │ │ ├── DaggerLib.class │ │ │ ├── Dependencies_Kt.class │ │ │ ├── JetPackLibraries$Versions.class │ │ │ ├── JetPackLibraries.class │ │ │ ├── Libraries$Versions.class │ │ │ ├── Libraries.class │ │ │ ├── META-INF │ │ │ └── buildSrc.kotlin_module │ │ │ ├── Networking$Versions.class │ │ │ ├── Networking.class │ │ │ ├── RXLibraries$Versions.class │ │ │ ├── RXLibraries.class │ │ │ ├── TestLibraries$Versions.class │ │ │ └── TestLibraries.class │ ├── kotlin │ │ ├── buildSrcjar-classes.txt │ │ └── compileKotlin │ │ │ ├── build-history.bin │ │ │ ├── caches-jvm │ │ │ ├── inputs │ │ │ │ ├── source-to-output.tab │ │ │ │ ├── source-to-output.tab.keystream │ │ │ │ ├── source-to-output.tab.keystream.len │ │ │ │ ├── source-to-output.tab.len │ │ │ │ ├── source-to-output.tab.values.at │ │ │ │ ├── source-to-output.tab_i │ │ │ │ └── source-to-output.tab_i.len │ │ │ ├── jvm │ │ │ │ └── kotlin │ │ │ │ │ ├── class-fq-name-to-source.tab │ │ │ │ │ ├── class-fq-name-to-source.tab.keystream │ │ │ │ │ ├── class-fq-name-to-source.tab.keystream.len │ │ │ │ │ ├── class-fq-name-to-source.tab.len │ │ │ │ │ ├── class-fq-name-to-source.tab.values.at │ │ │ │ │ ├── class-fq-name-to-source.tab_i │ │ │ │ │ ├── class-fq-name-to-source.tab_i.len │ │ │ │ │ ├── constants.tab │ │ │ │ │ ├── constants.tab.keystream │ │ │ │ │ ├── constants.tab.keystream.len │ │ │ │ │ ├── constants.tab.len │ │ │ │ │ ├── constants.tab.values.at │ │ │ │ │ ├── constants.tab_i │ │ │ │ │ ├── constants.tab_i.len │ │ │ │ │ ├── internal-name-to-source.tab │ │ │ │ │ ├── internal-name-to-source.tab.keystream │ │ │ │ │ ├── internal-name-to-source.tab.keystream.len │ │ │ │ │ ├── internal-name-to-source.tab.len │ │ │ │ │ ├── internal-name-to-source.tab.values.at │ │ │ │ │ ├── internal-name-to-source.tab_i │ │ │ │ │ ├── internal-name-to-source.tab_i.len │ │ │ │ │ ├── package-parts.tab │ │ │ │ │ ├── package-parts.tab.keystream │ │ │ │ │ ├── package-parts.tab.keystream.len │ │ │ │ │ ├── package-parts.tab.len │ │ │ │ │ ├── package-parts.tab.values.at │ │ │ │ │ ├── package-parts.tab_i │ │ │ │ │ ├── package-parts.tab_i.len │ │ │ │ │ ├── proto.tab │ │ │ │ │ ├── proto.tab.keystream │ │ │ │ │ ├── proto.tab.keystream.len │ │ │ │ │ ├── proto.tab.len │ │ │ │ │ ├── proto.tab.values.at │ │ │ │ │ ├── proto.tab_i │ │ │ │ │ ├── proto.tab_i.len │ │ │ │ │ ├── source-to-classes.tab │ │ │ │ │ ├── source-to-classes.tab.keystream │ │ │ │ │ ├── source-to-classes.tab.keystream.len │ │ │ │ │ ├── source-to-classes.tab.len │ │ │ │ │ ├── source-to-classes.tab.values.at │ │ │ │ │ ├── source-to-classes.tab_i │ │ │ │ │ └── source-to-classes.tab_i.len │ │ │ └── lookups │ │ │ │ ├── counters.tab │ │ │ │ ├── file-to-id.tab │ │ │ │ ├── file-to-id.tab.keystream │ │ │ │ ├── file-to-id.tab.keystream.len │ │ │ │ ├── file-to-id.tab.len │ │ │ │ ├── file-to-id.tab.values.at │ │ │ │ ├── file-to-id.tab_i │ │ │ │ ├── file-to-id.tab_i.len │ │ │ │ ├── id-to-file.tab │ │ │ │ ├── id-to-file.tab.keystream │ │ │ │ ├── id-to-file.tab.keystream.len │ │ │ │ ├── id-to-file.tab.len │ │ │ │ ├── id-to-file.tab.values.at │ │ │ │ ├── id-to-file.tab_i │ │ │ │ ├── id-to-file.tab_i.len │ │ │ │ ├── lookups.tab │ │ │ │ ├── lookups.tab.keystream │ │ │ │ ├── lookups.tab.keystream.len │ │ │ │ ├── lookups.tab.len │ │ │ │ ├── lookups.tab.values.at │ │ │ │ ├── lookups.tab_i │ │ │ │ └── lookups.tab_i.len │ │ │ └── last-build.bin │ ├── libs │ │ └── buildSrc.jar │ ├── pluginUnderTestMetadata │ │ └── plugin-under-test-metadata.properties │ ├── reports │ │ └── plugin-development │ │ │ └── validation-report.txt │ └── tmp │ │ └── jar │ │ └── MANIFEST.MF └── src │ └── main │ └── java │ └── Dependencies..kt ├── data ├── .gitignore ├── build.gradle.kts ├── consumer-rules.pro ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── info │ │ └── sanaebadi │ │ └── data │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ └── java │ │ └── info │ │ └── sanaebadi │ │ ├── cache │ │ └── base │ │ │ └── BaseCache.kt │ │ ├── entity │ │ ├── base │ │ │ ├── BaseEntity.kt │ │ │ ├── ListBaseEntity.kt │ │ │ └── Table.kt │ │ └── user │ │ │ ├── AnswerEntity.kt │ │ │ ├── AnswerListEntity.kt │ │ │ ├── FavoritedByUserEntity.kt │ │ │ ├── OwnerEntity.kt │ │ │ ├── QuestionEntity.kt │ │ │ ├── QuestionListEntity.kt │ │ │ ├── UserEntity.kt │ │ │ └── UserListModelEntity.kt │ │ ├── exception │ │ ├── DataException.kt │ │ └── NoDataException.kt │ │ ├── executor │ │ └── JobExecutor.kt │ │ ├── mapper │ │ ├── base │ │ │ └── DataLayerMapper.java │ │ ├── details │ │ │ ├── AnswersByUserMapper.kt │ │ │ ├── FavoritesByUserMapper.kt │ │ │ ├── QuestionByIdMapper.kt │ │ │ └── QuestionsByUserMapper.kt │ │ └── user │ │ │ └── UserMapper.kt │ │ ├── networking │ │ ├── base │ │ │ └── AbstractService.kt │ │ └── retrofit │ │ │ └── UserApiRetrofitService.kt │ │ └── repository │ │ ├── dataSource │ │ ├── base │ │ │ └── BaseDataSourceFactory.java │ │ ├── details │ │ │ ├── DetailsDataRepository.kt │ │ │ ├── DetailsDataSource.kt │ │ │ └── DetailsDataSourceFactory.kt │ │ └── user │ │ │ ├── UserDataRepository.kt │ │ │ ├── UserDataSource.kt │ │ │ └── UserDataSourceFactory.kt │ │ └── dataSourceImpl │ │ ├── DetailsOnlineDataSource.kt │ │ └── UserOnlineDataSource.kt │ └── test │ └── java │ └── info │ └── sanaebadi │ └── data │ └── ExampleUnitTest.kt ├── domain ├── .gitignore ├── build.gradle.kts └── src │ └── main │ └── java │ └── info │ └── sanaebadi │ └── domain │ ├── executor │ ├── PostExecutionThread.kt │ └── ThreadExecutor.kt │ ├── interactor │ ├── base │ │ ├── BaseCompeletableObserver.kt │ │ ├── BaseMaybeObserver.kt │ │ ├── BaseObserver.kt │ │ ├── BaseSingleObserver.kt │ │ ├── CompletableUseCase.kt │ │ ├── IObserver.kt │ │ ├── IUseCase.kt │ │ ├── MaybeUseCase.kt │ │ ├── SingleUseCase.kt │ │ └── UseCase.kt │ └── user │ │ ├── DetailsUseCase.kt │ │ └── UserUseCase.kt │ ├── model │ ├── UserDetailsModel.kt │ ├── base │ │ ├── AdapterConstants.kt │ │ ├── BaseDomainModel.kt │ │ └── ViewType.kt │ ├── details │ │ ├── AnswerViewModel.kt │ │ └── QuestionViewModel.kt │ └── user │ │ ├── Answer.kt │ │ ├── AnswerList.kt │ │ ├── FavoritedByUser.kt │ │ ├── Owner.kt │ │ ├── Question.kt │ │ ├── QuestionList.kt │ │ ├── User.kt │ │ └── UserListModel.kt │ └── repository │ ├── CacheStrategy.java │ ├── DetailsRepository.kt │ └── UserRepository.kt ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle.kts /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | StackOverFlowProject -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 23 | 24 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 29 | 30 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # StackOverFlowApi 2 | 3 | ## ScreenShots :heart_eyes: 4 | ![Frame 1](https://user-images.githubusercontent.com/26750131/94846433-ff685880-042d-11eb-9e75-2bf1e12ae6d9.png) 5 | ---- 6 | 7 | 8 | ## REFRENCE : :dizzy: 9 | 10 | [Stack Exchange API v2.2](https://api.stackexchange.com/) 11 | 12 | 13 | 14 | ------ 15 | 16 | 17 | 18 | ## Programming language : 19 | 20 | **kotlin** :fire: 21 | 22 | 23 | ----- 24 | 25 | 26 | 27 | ## Architecture and patterns: 28 | 29 | - Clean Architecture :imp: 30 | 31 | - MVVM 32 | 33 | - ... 34 | 35 | 36 | ------ 37 | 38 | 39 | 40 | 41 | ## The components used in this repository : 42 | 43 | - RX 44 | 45 | - Retrofit 46 | 47 | - OKhttp3 48 | 49 | - ViewModel 50 | 51 | - LiveData 52 | 53 | - Navigation Component 54 | 55 | - RecyclerView 56 | 57 | - Material Design 58 | 59 | - ... 60 | 61 | 62 | 63 | ------ 64 | 65 | 66 | 67 | 68 | ## The Rest Api : 69 | 70 | **BASE URL :** :point_right: https://api.stackexchange.com/ 71 | 72 | 73 | --- 74 | 75 | ## Medium Article :point_right: [Working with the StackOverFlow API!](https://medium.com/@sanaebadi97/working-with-the-stackoverflow-api-bc55d2d919b5) 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id(BuildPlugins.androidApplication) 3 | id(BuildPlugins.kotlinAndroid) 4 | id(BuildPlugins.kotlinAndroidExtensions) 5 | id(BuildPlugins.kaptPlugin) 6 | id(BuildPlugins.safeArgs) 7 | } 8 | 9 | android { 10 | compileSdkVersion(AndroidSdk.compileSdk) 11 | defaultConfig { 12 | applicationId = AndroidSdk.applicationId 13 | minSdkVersion(AndroidSdk.minSdk) 14 | targetSdkVersion(AndroidSdk.targetSdk) 15 | versionCode = 1 16 | versionName = "1.0" 17 | testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" 18 | } 19 | buildTypes { 20 | getByName("release") { 21 | isMinifyEnabled = false 22 | proguardFiles( 23 | getDefaultProguardFile("proguard-android-optimize.txt"), 24 | "proguard-rules.pro" 25 | ) 26 | } 27 | } 28 | buildFeatures{ 29 | viewBinding = true 30 | 31 | } 32 | 33 | compileOptions { 34 | sourceCompatibility = JavaVersion.VERSION_1_8 35 | targetCompatibility = JavaVersion.VERSION_1_8 36 | } 37 | // For Kotlin projects 38 | kotlinOptions { 39 | jvmTarget = "1.8" 40 | } 41 | } 42 | 43 | 44 | dependencies { 45 | 46 | implementation(project(mapOf("path" to ":data"))) 47 | api(project(mapOf("path" to ":domain"))) 48 | 49 | implementation(Libraries.kotlinStdLib) 50 | implementation(Libraries.appCompat) 51 | implementation(Libraries.ktxCore) 52 | implementation(Libraries.constraintLayout) 53 | implementation(Libraries.material) 54 | 55 | implementation(Libraries.glide) 56 | implementation(Libraries.glideCompiler) 57 | 58 | implementation(JetPackLibraries.lifecycleViewModel) 59 | implementation(JetPackLibraries.lifecycleLiveData) 60 | 61 | 62 | implementation(JetPackLibraries.navigationFragment) 63 | implementation(JetPackLibraries.navigationUi) 64 | 65 | 66 | implementation(RXLibraries.rxAndroid) 67 | implementation(RXLibraries.rxJava) 68 | 69 | implementation(DaggerLib.dagger) 70 | implementation(DaggerLib.daggerSupport) 71 | implementation("androidx.legacy:legacy-support-v4:1.0.0") 72 | kapt(DaggerLib.daggerCompiler) 73 | kapt(DaggerLib.daggerProcessor) 74 | 75 | testImplementation(TestLibraries.junit4) 76 | androidTestImplementation(TestLibraries.testRunner) 77 | androidTestImplementation(TestLibraries.espresso) 78 | implementation("androidx.core:core-ktx:+") 79 | } 80 | repositories { 81 | mavenCentral() 82 | } -------------------------------------------------------------------------------- /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/androidTest/java/info/sanaebadi/stackoverflowproject/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.stackoverflowproject 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("info.sanaebadi.stackoverflowproject", appContext.packageName) 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/java/info/sanaebadi/stackoverflowproject/di/ActivityModule.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.stackoverflowproject.di 2 | 3 | import dagger.Module 4 | 5 | @Module 6 | class ActivityModule -------------------------------------------------------------------------------- /app/src/main/java/info/sanaebadi/stackoverflowproject/di/ActivityScope.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.stackoverflowproject.di 2 | 3 | import javax.inject.Scope 4 | 5 | @Scope 6 | @Retention(AnnotationRetention.RUNTIME) 7 | annotation class ActivityScope -------------------------------------------------------------------------------- /app/src/main/java/info/sanaebadi/stackoverflowproject/di/ApplicationComponent.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.stackoverflowproject.di 2 | 3 | import dagger.BindsInstance 4 | import dagger.Component 5 | import dagger.android.AndroidInjector 6 | import dagger.android.support.AndroidSupportInjectionModule 7 | import info.sanaebadi.stackoverflowproject.global.StackApplication 8 | import javax.inject.Singleton 9 | 10 | @Singleton 11 | @Component(modules = [AndroidSupportInjectionModule::class, ApplicationModule::class, BuildersModule::class, ViewModelModule::class]) 12 | 13 | interface ApplicationComponent : AndroidInjector { 14 | @Component.Builder 15 | interface Builder { 16 | @BindsInstance 17 | fun application(application: StackApplication): Builder 18 | 19 | fun build(): ApplicationComponent 20 | } 21 | } -------------------------------------------------------------------------------- /app/src/main/java/info/sanaebadi/stackoverflowproject/di/ApplicationModule.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.stackoverflowproject.di 2 | 3 | import android.content.Context 4 | import dagger.Module 5 | import dagger.Provides 6 | import info.sanaebadi.domain.executor.PostExecutionThread 7 | import info.sanaebadi.domain.executor.ThreadExecutor 8 | import info.sanaebadi.domain.repository.DetailsRepository 9 | import info.sanaebadi.domain.repository.UserRepository 10 | import info.sanaebadi.executor.JobExecutor 11 | import info.sanaebadi.repository.dataSource.details.DetailsDataRepository 12 | import info.sanaebadi.repository.dataSource.user.UserDataRepository 13 | import info.sanaebadi.stackoverflowproject.executors.UIThread 14 | import info.sanaebadi.stackoverflowproject.global.StackApplication 15 | import info.sanaebadi.stackoverflowproject.util.AppSchedulerProvider 16 | import info.sanaebadi.stackoverflowproject.util.PreferencesHelper 17 | import info.sanaebadi.stackoverflowproject.util.SchedulerProvider 18 | import javax.inject.Singleton 19 | 20 | @Module 21 | class ApplicationModule { 22 | 23 | //TODO:DEFINE REPOSITORY AND CACHE HERE 24 | 25 | @Provides 26 | internal fun provideContext(application: StackApplication): Context { 27 | return application.applicationContext 28 | } 29 | 30 | 31 | @Provides 32 | @Singleton 33 | internal fun providesThreadExecutor(jobExecutor: JobExecutor): ThreadExecutor { 34 | return jobExecutor 35 | } 36 | 37 | @Provides 38 | @Singleton 39 | internal fun providesPostExecutionThread(uiThread: UIThread): PostExecutionThread { 40 | return uiThread 41 | } 42 | 43 | @Provides 44 | @Singleton 45 | fun provideUserRepository(userDataRepository: UserDataRepository): UserRepository { 46 | return userDataRepository 47 | } 48 | 49 | @Provides 50 | @Singleton 51 | fun provideDetailsRepository(detailsDataRepository: DetailsDataRepository): DetailsRepository { 52 | return detailsDataRepository 53 | } 54 | 55 | @Provides 56 | @Singleton 57 | fun providePreferencesHelper(context: Context) = PreferencesHelper(context) 58 | 59 | 60 | @Provides 61 | @Singleton 62 | fun provideSchedulerProvider(): SchedulerProvider = AppSchedulerProvider() 63 | 64 | } -------------------------------------------------------------------------------- /app/src/main/java/info/sanaebadi/stackoverflowproject/di/BuildersModule.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.stackoverflowproject.di 2 | 3 | import dagger.Module 4 | import dagger.android.ContributesAndroidInjector 5 | import info.sanaebadi.stackoverflowproject.mvvm.feature.view.MainActivity 6 | import info.sanaebadi.stackoverflowproject.mvvm.feature.view.fragment.DetailsFragment 7 | import info.sanaebadi.stackoverflowproject.mvvm.feature.view.fragment.UserListFragment 8 | 9 | @Module 10 | abstract class BuildersModule { 11 | 12 | @ActivityScope 13 | @ContributesAndroidInjector(modules = [ActivityModule::class]) 14 | internal abstract fun bindMainActivity(): MainActivity 15 | 16 | @ActivityScope 17 | @ContributesAndroidInjector(modules = [ActivityModule::class]) 18 | internal abstract fun bindUserListFragment(): UserListFragment 19 | 20 | @ActivityScope 21 | @ContributesAndroidInjector(modules = [ActivityModule::class]) 22 | internal abstract fun bindDetailsFragment(): DetailsFragment 23 | 24 | 25 | } -------------------------------------------------------------------------------- /app/src/main/java/info/sanaebadi/stackoverflowproject/di/ViewModelKey.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.stackoverflowproject.di 2 | 3 | import androidx.lifecycle.ViewModel 4 | import dagger.MapKey 5 | import kotlin.reflect.KClass 6 | 7 | 8 | @Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER) 9 | @kotlin.annotation.Retention(AnnotationRetention.RUNTIME) 10 | @MapKey 11 | internal annotation class ViewModelKey(val value: KClass) -------------------------------------------------------------------------------- /app/src/main/java/info/sanaebadi/stackoverflowproject/di/ViewModelModule.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.stackoverflowproject.di 2 | 3 | import androidx.lifecycle.ViewModel 4 | import androidx.lifecycle.ViewModelProvider 5 | import dagger.Binds 6 | import dagger.Module 7 | import dagger.multibindings.IntoMap 8 | import info.sanaebadi.stackoverflowproject.mvvm.feature.view.viewModel.UserViewModel 9 | import info.sanaebadi.stackoverflowproject.mvvm.feature.view.viewModel.base.ViewModelFactory 10 | import javax.inject.Singleton 11 | 12 | @Module 13 | abstract class ViewModelModule { 14 | 15 | @Binds 16 | @Singleton 17 | abstract fun bindViewModelFactory(factory: ViewModelFactory?): ViewModelProvider.Factory? 18 | 19 | @Binds 20 | @IntoMap 21 | @ViewModelKey(UserViewModel::class) 22 | abstract fun provideUserViewModel(viewModel: UserViewModel?): ViewModel? 23 | 24 | } -------------------------------------------------------------------------------- /app/src/main/java/info/sanaebadi/stackoverflowproject/executors/UIThread.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Fernando Cejas Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package info.sanaebadi.stackoverflowproject.executors 17 | 18 | 19 | import info.sanaebadi.domain.executor.PostExecutionThread 20 | import io.reactivex.Scheduler 21 | import io.reactivex.android.schedulers.AndroidSchedulers 22 | 23 | import javax.inject.Inject 24 | import javax.inject.Singleton 25 | 26 | /** 27 | * MainThread (UI Thread) implementation based on a [Scheduler] 28 | * which will execute actions on the Android UI thread 29 | */ 30 | @Singleton 31 | class UIThread @Inject 32 | internal constructor() : PostExecutionThread { 33 | 34 | override val scheduler: Scheduler 35 | get() = AndroidSchedulers.mainThread() 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/java/info/sanaebadi/stackoverflowproject/global/StackApplication.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.stackoverflowproject.global 2 | 3 | import android.app.Application 4 | import dagger.android.AndroidInjector 5 | import dagger.android.DispatchingAndroidInjector 6 | import dagger.android.HasAndroidInjector 7 | import info.sanaebadi.stackoverflowproject.di.DaggerApplicationComponent 8 | import javax.inject.Inject 9 | 10 | class StackApplication : Application(), HasAndroidInjector { 11 | 12 | @Inject 13 | lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector 14 | 15 | override fun androidInjector(): AndroidInjector { 16 | return dispatchingAndroidInjector 17 | } 18 | 19 | @Inject 20 | lateinit var fragmentInjector: DispatchingAndroidInjector 21 | 22 | 23 | override fun onCreate() { 24 | super.onCreate() 25 | initializeAppInjector() 26 | } 27 | 28 | private fun initializeAppInjector() { 29 | DaggerApplicationComponent.builder().application(this).build().inject(this) 30 | } 31 | 32 | 33 | } -------------------------------------------------------------------------------- /app/src/main/java/info/sanaebadi/stackoverflowproject/mapper/UserMapperPresentation.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.stackoverflowproject.mapper 2 | 3 | import info.sanaebadi.domain.model.user.User 4 | import info.sanaebadi.domain.model.user.UserListModel 5 | import info.sanaebadi.stackoverflowproject.mapper.base.PresentationLayerMapper 6 | import info.sanaebadi.stackoverflowproject.model.user.UserListModelPresentation 7 | import info.sanaebadi.stackoverflowproject.model.user.UserPresentation 8 | import java.util.* 9 | import javax.inject.Inject 10 | 11 | class UserMapperPresentation @Inject constructor() : 12 | PresentationLayerMapper { 13 | 14 | override fun toDomain(p: UserPresentation?): User? { 15 | return null 16 | } 17 | 18 | override fun toPresentation(d: User?): UserPresentation { 19 | return UserPresentation(d?.userId!!, d.displayName, d.reputation, d.profileImage) 20 | } 21 | 22 | fun toPresentation(userListModel: UserListModel): UserListModelPresentation { 23 | val itemPresentationList: MutableList = ArrayList() 24 | 25 | for (user: User in userListModel.items) { 26 | itemPresentationList.add(toPresentation(user)) 27 | } 28 | 29 | return UserListModelPresentation(itemPresentationList) 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /app/src/main/java/info/sanaebadi/stackoverflowproject/mapper/base/PresentationLayerMapper.java: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.stackoverflowproject.mapper.base; 2 | 3 | 4 | import info.sanaebadi.domain.model.base.BaseDomainModel; 5 | import info.sanaebadi.stackoverflowproject.model.base.PresentationModel; 6 | 7 | public interface PresentationLayerMapper

{ 8 | 9 | D toDomain(P p); 10 | 11 | P toPresentation(D d); 12 | 13 | } 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/java/info/sanaebadi/stackoverflowproject/model/base/AdapterConstants.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.stackoverflowproject.model.base 2 | 3 | object AdapterConstants { 4 | const val USER_DETAILS = 1 5 | const val HEADING = 2 6 | const val QUESTION = 3 7 | const val ANSWER = 4 8 | const val LOADING = 5 9 | } -------------------------------------------------------------------------------- /app/src/main/java/info/sanaebadi/stackoverflowproject/model/base/PresentationModel.java: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.stackoverflowproject.model.base; 2 | 3 | public interface PresentationModel { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /app/src/main/java/info/sanaebadi/stackoverflowproject/model/user/AnswerListPresentation.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.stackoverflowproject.model.user 2 | 3 | import info.sanaebadi.stackoverflowproject.model.base.PresentationModel 4 | 5 | class AnswerListPresentation(val items: List) : PresentationModel -------------------------------------------------------------------------------- /app/src/main/java/info/sanaebadi/stackoverflowproject/model/user/AnswerPresentation.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.stackoverflowproject.model.user 2 | 3 | import info.sanaebadi.stackoverflowproject.model.base.PresentationModel 4 | 5 | data class AnswerPresentation( 6 | var answerId: Long, 7 | var questionId: Long, 8 | var score: Long, 9 | var accepted: Boolean, 10 | var ownerEntity: OwnerPresentation 11 | ) : PresentationModel { 12 | 13 | constructor() : this(-1, -1, 0, false, OwnerPresentation()) 14 | } -------------------------------------------------------------------------------- /app/src/main/java/info/sanaebadi/stackoverflowproject/model/user/FavoriteByUserPresentation.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.stackoverflowproject.model.user 2 | 3 | import info.sanaebadi.stackoverflowproject.model.base.PresentationModel 4 | 5 | data class FavoriteByUserPresentation( 6 | var userId: Long, 7 | var questionIds: List 8 | ): PresentationModel { 9 | 10 | constructor() : this(-1, emptyList()) 11 | } -------------------------------------------------------------------------------- /app/src/main/java/info/sanaebadi/stackoverflowproject/model/user/Heading.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.stackoverflowproject.model.user 2 | 3 | import info.sanaebadi.domain.model.base.ViewType 4 | import info.sanaebadi.stackoverflowproject.model.base.AdapterConstants 5 | 6 | data class Heading(val title: String) : ViewType { 7 | override fun getViewType() = AdapterConstants.HEADING 8 | } -------------------------------------------------------------------------------- /app/src/main/java/info/sanaebadi/stackoverflowproject/model/user/OwnerPresentation.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.stackoverflowproject.model.user 2 | 3 | import info.sanaebadi.stackoverflowproject.model.base.PresentationModel 4 | 5 | 6 | data class OwnerPresentation(var userId: Long) : PresentationModel { 7 | 8 | constructor() : this(-1) 9 | } -------------------------------------------------------------------------------- /app/src/main/java/info/sanaebadi/stackoverflowproject/model/user/QuestionListPresentation.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.stackoverflowproject.model.user 2 | 3 | import info.sanaebadi.stackoverflowproject.model.base.PresentationModel 4 | 5 | class QuestionListPresentation(val items: List) : PresentationModel -------------------------------------------------------------------------------- /app/src/main/java/info/sanaebadi/stackoverflowproject/model/user/QuestionPresentation.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.stackoverflowproject.model.user 2 | 3 | import info.sanaebadi.stackoverflowproject.model.base.PresentationModel 4 | 5 | 6 | data class QuestionPresentation( 7 | var viewCount: Long, 8 | var score: Long, 9 | var title: String, 10 | var link: String, 11 | var questionId: Long, 12 | var ownerEntity: OwnerPresentation 13 | ) : PresentationModel { 14 | 15 | 16 | constructor() : this(0, 0, "", "", -1, OwnerPresentation()) 17 | } -------------------------------------------------------------------------------- /app/src/main/java/info/sanaebadi/stackoverflowproject/model/user/UserListModelPresentation.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.stackoverflowproject.model.user 2 | 3 | import info.sanaebadi.stackoverflowproject.model.base.PresentationModel 4 | 5 | 6 | class UserListModelPresentation(val items: MutableList) : PresentationModel -------------------------------------------------------------------------------- /app/src/main/java/info/sanaebadi/stackoverflowproject/model/user/UserPresentation.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.stackoverflowproject.model.user 2 | 3 | import android.os.Parcel 4 | import android.os.Parcelable 5 | import info.sanaebadi.domain.model.base.ViewType 6 | import info.sanaebadi.stackoverflowproject.model.base.AdapterConstants 7 | import info.sanaebadi.stackoverflowproject.model.base.PresentationModel 8 | 9 | 10 | data class UserPresentation( 11 | var userId: Long, 12 | var displayName: String, 13 | var reputation: Long, 14 | var profileImage: String 15 | ) : PresentationModel , Parcelable , ViewType { 16 | 17 | constructor(parcel: Parcel) : this( 18 | parcel.readLong(), 19 | parcel.readString()!!, 20 | parcel.readLong(), 21 | parcel.readString()!! 22 | ) { 23 | } 24 | 25 | constructor() : this(-1, "", 0, "") 26 | 27 | override fun writeToParcel(parcel: Parcel, flags: Int) { 28 | parcel.writeLong(userId) 29 | parcel.writeString(displayName) 30 | parcel.writeLong(reputation) 31 | parcel.writeString(profileImage) 32 | } 33 | 34 | override fun describeContents(): Int { 35 | return 0 36 | } 37 | 38 | companion object CREATOR : Parcelable.Creator { 39 | override fun createFromParcel(parcel: Parcel): UserPresentation { 40 | return UserPresentation(parcel) 41 | } 42 | 43 | override fun newArray(size: Int): Array { 44 | return arrayOfNulls(size) 45 | } 46 | } 47 | 48 | override fun getViewType(): Int = AdapterConstants.USER_DETAILS 49 | } -------------------------------------------------------------------------------- /app/src/main/java/info/sanaebadi/stackoverflowproject/mvvm/feature/view/adapter/DetailsAdapter.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.stackoverflowproject.mvvm.feature.view.adapter 2 | 3 | import android.view.ViewGroup 4 | import androidx.collection.SparseArrayCompat 5 | import androidx.recyclerview.widget.RecyclerView 6 | import info.sanaebadi.domain.model.base.ViewType 7 | import info.sanaebadi.stackoverflowproject.model.base.AdapterConstants 8 | import info.sanaebadi.stackoverflowproject.model.user.Heading 9 | import info.sanaebadi.stackoverflowproject.mvvm.feature.view.delegate.* 10 | import info.sanaebadi.stackoverflowproject.mvvm.feature.view.delegate.base.ViewTypeDelegateAdapter 11 | 12 | class DetailsAdapter(listener: (String) -> Unit) : RecyclerView.Adapter() { 13 | 14 | private var items: MutableList = ArrayList() 15 | private var delegateAdapters = SparseArrayCompat() 16 | 17 | private val loadingItem = object : ViewType { 18 | override fun getViewType() = AdapterConstants.LOADING 19 | } 20 | 21 | init { 22 | delegateAdapters.put(AdapterConstants.USER_DETAILS, UserDetailsDelegateAdapter()) 23 | delegateAdapters.put(AdapterConstants.HEADING, HeadingDelegateAdapter()) 24 | delegateAdapters.put(AdapterConstants.QUESTION, QuestionDelegateAdapter(listener)) 25 | delegateAdapters.put(AdapterConstants.ANSWER, AnswerDelegateAdapter(listener)) 26 | delegateAdapters.put(AdapterConstants.LOADING, LoadingDelegateAdapter()) 27 | } 28 | 29 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = 30 | delegateAdapters[viewType]!!.onCreateViewHolder(parent) 31 | 32 | override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) = 33 | delegateAdapters[getItemViewType(position)]!!.onBindViewHolder(holder, items[position]) 34 | 35 | override fun getItemCount(): Int = items.size 36 | 37 | override fun getItemViewType(position: Int): Int { 38 | return items[position].getViewType() 39 | } 40 | 41 | private fun addItems(newItems: List) { 42 | items.addAll(newItems) 43 | } 44 | 45 | fun addItem(item: ViewType) { 46 | items.add(item) 47 | } 48 | 49 | fun addLoadingItem() { 50 | items.add(loadingItem) 51 | } 52 | 53 | fun removeLoadingItem() { 54 | items.remove(loadingItem) 55 | } 56 | 57 | fun removeNonUserItems() { 58 | items.removeAll { it.getViewType() != AdapterConstants.USER_DETAILS } 59 | } 60 | 61 | fun addItemsWithHeading(items: List, headingTitle: String) { 62 | if (!items.isEmpty()) { 63 | addItem(Heading(headingTitle)) 64 | addItems(items) 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /app/src/main/java/info/sanaebadi/stackoverflowproject/mvvm/feature/view/adapter/UserListAdapter.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.stackoverflowproject.mvvm.feature.view.adapter 2 | 3 | import android.annotation.SuppressLint 4 | import android.view.LayoutInflater 5 | import android.view.ViewGroup 6 | import androidx.recyclerview.widget.RecyclerView 7 | import info.sanaebadi.stackoverflowproject.databinding.ListItemUserBinding 8 | import info.sanaebadi.stackoverflowproject.model.user.UserPresentation 9 | import info.sanaebadi.stackoverflowproject.util.isLollipopOrAbove 10 | import info.sanaebadi.stackoverflowproject.util.loadUrl 11 | import info.sanaebadi.stackoverflowproject.util.mOnItemClickListener 12 | 13 | class UserListAdapter( 14 | val listener: mOnItemClickListener, 15 | private val users: MutableList 16 | ) : RecyclerView.Adapter() { 17 | 18 | 19 | override fun getItemCount() = users.size 20 | 21 | override fun onBindViewHolder(holder: UserViewHolder, position: Int) = 22 | holder.bind(users[position]) 23 | 24 | 25 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder { 26 | val binding = 27 | ListItemUserBinding.inflate(LayoutInflater.from(parent.context), parent, false) 28 | return UserViewHolder(binding) 29 | 30 | } 31 | 32 | fun addUsers(newUsers: List) { 33 | users.addAll(newUsers) 34 | notifyDataSetChanged() 35 | } 36 | 37 | fun clearUsers() { 38 | users.clear() 39 | } 40 | 41 | inner class UserViewHolder(private val binding: ListItemUserBinding) : 42 | RecyclerView.ViewHolder(binding.root) { 43 | @SuppressLint("NewApi", "SetTextI18n") 44 | fun bind(user: UserPresentation) = 45 | with(itemView) { 46 | 47 | binding.textUserName.text = user.displayName 48 | binding.textUserReputation.text = "${user.reputation} points" 49 | binding.imageUserAvatar.loadUrl(user.profileImage) 50 | 51 | setOnClickListener { 52 | listener.onItemClick(user, binding.imageUserAvatar) 53 | } 54 | 55 | isLollipopOrAbove { 56 | binding.imageUserAvatar.transitionName = "transition${user.userId}" 57 | } 58 | 59 | } 60 | 61 | } 62 | 63 | 64 | } 65 | -------------------------------------------------------------------------------- /app/src/main/java/info/sanaebadi/stackoverflowproject/mvvm/feature/view/delegate/AnswerDelegateAdapter.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.stackoverflowproject.mvvm.feature.view.delegate 2 | 3 | import android.view.LayoutInflater 4 | import android.view.ViewGroup 5 | import androidx.recyclerview.widget.RecyclerView 6 | import info.sanaebadi.domain.model.base.ViewType 7 | import info.sanaebadi.domain.model.details.AnswerViewModel 8 | import info.sanaebadi.stackoverflowproject.databinding.ListItemAnswerBinding 9 | import info.sanaebadi.stackoverflowproject.mvvm.feature.view.delegate.base.ViewTypeDelegateAdapter 10 | 11 | class AnswerDelegateAdapter(private val listener: (String) -> Unit) : ViewTypeDelegateAdapter { 12 | override fun onCreateViewHolder(parent: ViewGroup) = 13 | AnswerViewHolder( 14 | ListItemAnswerBinding.inflate( 15 | LayoutInflater.from(parent.context), 16 | parent, 17 | false 18 | ) 19 | ) 20 | 21 | override fun onBindViewHolder(holder: RecyclerView.ViewHolder, item: ViewType) { 22 | holder as AnswerViewHolder 23 | holder.bind(item as AnswerViewModel, listener) 24 | } 25 | 26 | class AnswerViewHolder(private val binding: ListItemAnswerBinding) : 27 | RecyclerView.ViewHolder(binding.root) { 28 | fun bind(answer: AnswerViewModel, listener: (String) -> Unit) = with(itemView) { 29 | binding.score.text = "${answer.score} points" 30 | binding.questionTitle.text = answer.questionTitle 31 | 32 | setOnClickListener { listener("https://stackoverflow.com/a/${answer.answerId}") } 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /app/src/main/java/info/sanaebadi/stackoverflowproject/mvvm/feature/view/delegate/HeadingDelegateAdapter.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.stackoverflowproject.mvvm.feature.view.delegate 2 | 3 | import android.view.LayoutInflater 4 | import android.view.ViewGroup 5 | import androidx.recyclerview.widget.RecyclerView 6 | import info.sanaebadi.domain.model.base.ViewType 7 | import info.sanaebadi.stackoverflowproject.databinding.ListItemHeadingBinding 8 | import info.sanaebadi.stackoverflowproject.model.user.Heading 9 | import info.sanaebadi.stackoverflowproject.mvvm.feature.view.delegate.base.ViewTypeDelegateAdapter 10 | 11 | class HeadingDelegateAdapter : ViewTypeDelegateAdapter { 12 | override fun onCreateViewHolder(parent: ViewGroup) = 13 | HeadingViewHolder( 14 | ListItemHeadingBinding.inflate( 15 | LayoutInflater.from(parent.context), 16 | parent, 17 | false 18 | ) 19 | ) 20 | 21 | override fun onBindViewHolder(holder: RecyclerView.ViewHolder, item: ViewType) { 22 | holder as HeadingViewHolder 23 | holder.bind(item as Heading) 24 | } 25 | 26 | class HeadingViewHolder(private val binding: ListItemHeadingBinding) : 27 | RecyclerView.ViewHolder(binding.root) { 28 | fun bind(heading: Heading) = with(itemView) { 29 | binding.title.text = heading.title 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /app/src/main/java/info/sanaebadi/stackoverflowproject/mvvm/feature/view/delegate/LoadingDelegateAdapter.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.stackoverflowproject.mvvm.feature.view.delegate 2 | 3 | import android.view.LayoutInflater 4 | import android.view.ViewGroup 5 | import androidx.recyclerview.widget.RecyclerView 6 | import info.sanaebadi.domain.model.base.ViewType 7 | import info.sanaebadi.stackoverflowproject.databinding.ListItemLoadingBinding 8 | import info.sanaebadi.stackoverflowproject.mvvm.feature.view.delegate.base.ViewTypeDelegateAdapter 9 | 10 | class LoadingDelegateAdapter : ViewTypeDelegateAdapter { 11 | override fun onCreateViewHolder(parent: ViewGroup) = 12 | LoadingViewHolder( 13 | ListItemLoadingBinding.inflate( 14 | LayoutInflater.from(parent.context), 15 | parent, 16 | false 17 | ) 18 | ) 19 | 20 | override fun onBindViewHolder(holder: RecyclerView.ViewHolder, item: ViewType) { 21 | } 22 | 23 | class LoadingViewHolder(private val binding: ListItemLoadingBinding) : 24 | RecyclerView.ViewHolder(binding.root) 25 | } -------------------------------------------------------------------------------- /app/src/main/java/info/sanaebadi/stackoverflowproject/mvvm/feature/view/delegate/QuestionDelegateAdapter.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.stackoverflowproject.mvvm.feature.view.delegate 2 | 3 | import android.annotation.SuppressLint 4 | import android.view.LayoutInflater 5 | import android.view.ViewGroup 6 | import androidx.recyclerview.widget.RecyclerView 7 | import info.sanaebadi.domain.model.base.ViewType 8 | import info.sanaebadi.domain.model.details.QuestionViewModel 9 | import info.sanaebadi.stackoverflowproject.databinding.ListItemQuestionBinding 10 | import info.sanaebadi.stackoverflowproject.mvvm.feature.view.delegate.base.ViewTypeDelegateAdapter 11 | 12 | class QuestionDelegateAdapter(private val listener: (String) -> Unit) : ViewTypeDelegateAdapter { 13 | override fun onCreateViewHolder(parent: ViewGroup) = 14 | QuestionViewHolder( 15 | ListItemQuestionBinding.inflate( 16 | LayoutInflater.from(parent.context), 17 | parent, 18 | false 19 | ) 20 | ) 21 | 22 | override fun onBindViewHolder(holder: RecyclerView.ViewHolder, item: ViewType) { 23 | holder as QuestionViewHolder 24 | holder.bind(item as QuestionViewModel, listener) 25 | } 26 | 27 | class QuestionViewHolder(private val binding: ListItemQuestionBinding) : 28 | RecyclerView.ViewHolder(binding.root) { 29 | @SuppressLint("SetTextI18n") 30 | fun bind(question: QuestionViewModel, listener: (String) -> Unit) = with(itemView) { 31 | binding.title.text = question.title 32 | binding.score.text = "${question.score} points" 33 | binding.viewCount.text = "Viewed: ${question.viewCount}" 34 | 35 | setOnClickListener { listener(question.link) } 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /app/src/main/java/info/sanaebadi/stackoverflowproject/mvvm/feature/view/delegate/UserDetailsDelegateAdapter.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.stackoverflowproject.mvvm.feature.view.delegate 2 | 3 | import android.annotation.SuppressLint 4 | import android.view.LayoutInflater 5 | import android.view.ViewGroup 6 | import androidx.recyclerview.widget.RecyclerView 7 | import info.sanaebadi.domain.model.base.ViewType 8 | import info.sanaebadi.domain.model.user.User 9 | import info.sanaebadi.stackoverflowproject.databinding.ListItemUserDetailsBinding 10 | import info.sanaebadi.stackoverflowproject.model.user.UserPresentation 11 | import info.sanaebadi.stackoverflowproject.mvvm.feature.view.delegate.base.ViewTypeDelegateAdapter 12 | import info.sanaebadi.stackoverflowproject.util.isLollipopOrAbove 13 | import info.sanaebadi.stackoverflowproject.util.loadCircleImage 14 | 15 | class UserDetailsDelegateAdapter : ViewTypeDelegateAdapter { 16 | 17 | override fun onCreateViewHolder(parent: ViewGroup) = 18 | UserDetailsViewHolder( 19 | ListItemUserDetailsBinding.inflate( 20 | LayoutInflater.from(parent.context), 21 | parent, 22 | false 23 | ) 24 | ) 25 | 26 | override fun onBindViewHolder(holder: RecyclerView.ViewHolder, item: ViewType) { 27 | holder as UserDetailsViewHolder 28 | holder.bind(item as UserPresentation) 29 | } 30 | 31 | class UserDetailsViewHolder(private val binding: ListItemUserDetailsBinding) : 32 | RecyclerView.ViewHolder(binding.root) { 33 | @SuppressLint("NewApi", "SetTextI18n") 34 | fun bind(user: UserPresentation) = with(itemView) { 35 | binding.profileImage.loadCircleImage(user.profileImage) 36 | binding.textName.text = user.displayName 37 | binding.textReputation.text = "${user.reputation} points" 38 | 39 | isLollipopOrAbove { binding.profileImage.transitionName = "transition${user.userId}" } 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /app/src/main/java/info/sanaebadi/stackoverflowproject/mvvm/feature/view/delegate/base/ViewTypeDelegateAdapter.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.stackoverflowproject.mvvm.feature.view.delegate.base 2 | 3 | import android.view.ViewGroup 4 | import androidx.recyclerview.widget.RecyclerView 5 | import info.sanaebadi.domain.model.base.ViewType 6 | 7 | interface ViewTypeDelegateAdapter { 8 | fun onCreateViewHolder(parent: ViewGroup): RecyclerView.ViewHolder 9 | fun onBindViewHolder(holder: RecyclerView.ViewHolder, item: ViewType) 10 | } -------------------------------------------------------------------------------- /app/src/main/java/info/sanaebadi/stackoverflowproject/mvvm/feature/view/viewModel/DetailsViewModel.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.stackoverflowproject.mvvm.feature.view.viewModel 2 | 3 | import android.annotation.SuppressLint 4 | import info.sanaebadi.domain.interactor.user.DetailsUseCase 5 | import info.sanaebadi.stackoverflowproject.mvvm.feature.view.viewModel.base.BasePresenter 6 | import info.sanaebadi.stackoverflowproject.mvvm.feature.view.viewModel.base.DetailView 7 | import info.sanaebadi.stackoverflowproject.util.SchedulerProvider 8 | import javax.inject.Inject 9 | 10 | class DetailsViewModel @Inject constructor( 11 | private val detailsUseCase: DetailsUseCase, 12 | private val schedulerProvider: SchedulerProvider 13 | ) : BasePresenter() { 14 | 15 | @SuppressLint("CheckResult") 16 | fun getDetails(id: Long) { 17 | view?.showLoading() 18 | detailsUseCase.execute(id) 19 | .subscribeOn(schedulerProvider.ioScheduler()) 20 | .observeOn(schedulerProvider.uiScheduler()) 21 | .subscribe({ details -> 22 | view?.hideLoading() 23 | view?.showDetails(details) 24 | }, 25 | { error -> 26 | view?.hideLoading() 27 | view?.showError(error.localizedMessage!!) 28 | }) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/info/sanaebadi/stackoverflowproject/mvvm/feature/view/viewModel/UserViewModel.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.stackoverflowproject.mvvm.feature.view.viewModel 2 | 3 | import androidx.lifecycle.MutableLiveData 4 | import androidx.lifecycle.ViewModel 5 | import info.sanaebadi.domain.interactor.base.BaseSingleObserver 6 | import info.sanaebadi.domain.interactor.user.UserUseCase 7 | import info.sanaebadi.domain.model.user.UserListModel 8 | import info.sanaebadi.stackoverflowproject.mapper.UserMapperPresentation 9 | import info.sanaebadi.stackoverflowproject.model.user.UserListModelPresentation 10 | import info.sanaebadi.stackoverflowproject.mvvm.feature.view.viewModel.base.MutableViewModel 11 | import javax.inject.Inject 12 | 13 | private const val INFINITE_LOADING_OFFSET = 5 14 | 15 | class UserViewModel @Inject constructor( 16 | private val userUseCase: UserUseCase, 17 | private val mapper: UserMapperPresentation 18 | ) : ViewModel() { 19 | 20 | var userList = MutableLiveData>() 21 | 22 | fun getUserList(page: Int = 1) { 23 | val value = MutableViewModel() 24 | value.setLoading(true) 25 | userList.postValue(value) 26 | 27 | userUseCase.execute(object : BaseSingleObserver() { 28 | override fun onSuccess(t: UserListModel) { 29 | super.onSuccess(t) 30 | value.setLoading(false) 31 | value.setThrowable(null) 32 | value.setData(mapper.toPresentation(t)) 33 | userList.postValue(value) 34 | 35 | } 36 | 37 | override fun onError(e: Throwable) { 38 | super.onError(e) 39 | value.setLoading(false) 40 | value.setThrowable(e) 41 | value.setData(null) 42 | userList.postValue(value) 43 | 44 | } 45 | 46 | }, page) 47 | } 48 | 49 | fun onScrollChanged(lastVisibleItemPosition: Int, totalItemCount: Int) { 50 | if (lastVisibleItemPosition >= totalItemCount - INFINITE_LOADING_OFFSET) { 51 | getUserList() 52 | } 53 | 54 | } 55 | } -------------------------------------------------------------------------------- /app/src/main/java/info/sanaebadi/stackoverflowproject/mvvm/feature/view/viewModel/base/BasePresenter.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.stackoverflowproject.mvvm.feature.view.viewModel.base 2 | 3 | abstract class BasePresenter { 4 | 5 | var view: T? = null 6 | private set 7 | 8 | fun attachView(view: T) { 9 | this.view = view 10 | } 11 | 12 | fun detachView() { 13 | this.view = null 14 | } 15 | 16 | val isViewAttached: Boolean 17 | get() = view != null 18 | } -------------------------------------------------------------------------------- /app/src/main/java/info/sanaebadi/stackoverflowproject/mvvm/feature/view/viewModel/base/DetailView.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.stackoverflowproject.mvvm.feature.view.viewModel.base 2 | 3 | import info.sanaebadi.domain.model.UserDetailsModel 4 | 5 | 6 | interface DetailView { 7 | fun showDetails(details: UserDetailsModel) 8 | fun showError(error: String) 9 | fun showLoading() 10 | fun hideLoading() 11 | } -------------------------------------------------------------------------------- /app/src/main/java/info/sanaebadi/stackoverflowproject/mvvm/feature/view/viewModel/base/MutableViewModel.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.stackoverflowproject.mvvm.feature.view.viewModel.base 2 | 3 | 4 | open class MutableViewModel { 5 | private var loading = true 6 | private var data: T? = null 7 | private set 8 | private var throwable: Throwable? = null 9 | 10 | constructor(loading: Boolean, data: T?, throwable: Throwable?) { 11 | this.loading = loading 12 | this.data = data 13 | this.throwable = throwable 14 | } 15 | 16 | constructor() {} 17 | 18 | open fun isLoading(): Boolean { 19 | return loading 20 | } 21 | 22 | open fun setLoading(loading: Boolean) { 23 | this.loading = loading 24 | } 25 | 26 | fun setData(data: T?) { 27 | this.data = data 28 | } 29 | 30 | fun getData(): T? { 31 | return data 32 | } 33 | 34 | open fun getThrowable(): Throwable? { 35 | return throwable 36 | } 37 | 38 | open fun setThrowable(throwable: Throwable?) { 39 | this.throwable = throwable 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/java/info/sanaebadi/stackoverflowproject/mvvm/feature/view/viewModel/base/UserListView.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.stackoverflowproject.mvvm.feature.view.viewModel.base 2 | 3 | import info.sanaebadi.stackoverflowproject.model.user.UserPresentation 4 | 5 | interface UserListView { 6 | fun showLoading() 7 | fun hideLoading() 8 | fun addUsersToList(users: List) 9 | fun showEmptyListError() 10 | fun hideEmptyListError() 11 | fun showToastError() 12 | fun clearList() 13 | } -------------------------------------------------------------------------------- /app/src/main/java/info/sanaebadi/stackoverflowproject/mvvm/feature/view/viewModel/base/ViewModelFactory.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.stackoverflowproject.mvvm.feature.view.viewModel.base 2 | 3 | import androidx.lifecycle.ViewModel 4 | import androidx.lifecycle.ViewModelProvider 5 | import javax.inject.Inject 6 | import javax.inject.Provider 7 | import javax.inject.Singleton 8 | 9 | @Singleton 10 | class ViewModelFactory @Inject constructor(private val creators: MutableMap, @JvmSuppressWildcards Provider>) : 11 | ViewModelProvider.Factory { 12 | override fun create(modelClass: Class): T { 13 | var creator: Provider? = creators[modelClass] 14 | if (creator == null) { 15 | for ((key, value) in creators) { 16 | if (modelClass.isAssignableFrom(key)) { 17 | creator = value 18 | break 19 | } 20 | } 21 | } 22 | requireNotNull(creator) { "unknown model class $modelClass" } 23 | return try { 24 | creator.get() as T 25 | } catch (e: Exception) { 26 | throw RuntimeException(e) 27 | } 28 | } 29 | } 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/java/info/sanaebadi/stackoverflowproject/util/AppSchedulerProvider.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.stackoverflowproject.util 2 | 3 | import io.reactivex.Scheduler 4 | import io.reactivex.android.schedulers.AndroidSchedulers 5 | import io.reactivex.schedulers.Schedulers 6 | 7 | class AppSchedulerProvider : SchedulerProvider { 8 | override fun ioScheduler() = Schedulers.io() 9 | 10 | override fun uiScheduler(): Scheduler = AndroidSchedulers.mainThread() 11 | } -------------------------------------------------------------------------------- /app/src/main/java/info/sanaebadi/stackoverflowproject/util/Constants.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.stackoverflowproject.util 2 | 3 | object Constants { 4 | const val PLACE_APP_SHARED_PREF = "place_app_shared_pref" 5 | const val ADAPTER_POSITION = "adapter_position" 6 | const val ADAPTER_VIEW = "adapter_view" 7 | } -------------------------------------------------------------------------------- /app/src/main/java/info/sanaebadi/stackoverflowproject/util/Extensions.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.stackoverflowproject.util 2 | 3 | import android.app.Activity 4 | import android.content.Context 5 | import android.content.Context.CONNECTIVITY_SERVICE 6 | import android.net.ConnectivityManager 7 | import android.os.Build 8 | import android.view.LayoutInflater 9 | import android.view.View 10 | import android.view.ViewGroup 11 | import android.widget.ImageView 12 | import androidx.fragment.app.Fragment 13 | import com.bumptech.glide.Glide 14 | import com.bumptech.glide.request.RequestOptions 15 | import info.sanaebadi.stackoverflowproject.R 16 | import info.sanaebadi.stackoverflowproject.global.StackApplication 17 | 18 | fun ViewGroup.inflate(layoutRes: Int): View { 19 | return LayoutInflater.from(context).inflate(layoutRes, this, false) 20 | } 21 | 22 | fun ImageView.loadUrl(url: String) { 23 | Glide.with(context).load(url).apply(RequestOptions().error(R.mipmap.ic_launcher)).into(this) 24 | } 25 | 26 | fun ImageView.loadCircleImage(url: String) { 27 | Glide.with(context).load(url).apply( 28 | RequestOptions.circleCropTransform() 29 | .error(R.mipmap.ic_launcher_round) 30 | ).into(this) 31 | } 32 | 33 | fun isLollipopOrAbove(func: () -> Unit) { 34 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 35 | func() 36 | } 37 | } 38 | 39 | val Activity.placeApplication: StackApplication 40 | get() = application as StackApplication 41 | 42 | val Fragment.placeApplication: StackApplication 43 | get() = activity?.application as StackApplication 44 | 45 | fun Context.isOnline() = (getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager?) 46 | ?.activeNetworkInfo?.isConnectedOrConnecting ?: false -------------------------------------------------------------------------------- /app/src/main/java/info/sanaebadi/stackoverflowproject/util/PreferencesHelper.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.stackoverflowproject.util 2 | 3 | import android.content.Context 4 | import info.sanaebadi.stackoverflowproject.util.Constants 5 | 6 | class PreferencesHelper(private val context: Context) { 7 | 8 | fun saveInt(key: String, value: Int) { 9 | val preferences = 10 | context.getSharedPreferences(Constants.PLACE_APP_SHARED_PREF, Context.MODE_PRIVATE) 11 | val editor = preferences.edit() 12 | editor.putInt(key, value) 13 | editor.apply() 14 | } 15 | 16 | fun loadInt(key: String): Int? { 17 | val preferences = 18 | context.getSharedPreferences(Constants.PLACE_APP_SHARED_PREF, Context.MODE_PRIVATE) 19 | return preferences.getInt(key, 0) 20 | } 21 | 22 | fun saveString(key: String, value: String) { 23 | val preferences = 24 | context.getSharedPreferences(Constants.PLACE_APP_SHARED_PREF, Context.MODE_PRIVATE) 25 | val editor = preferences.edit() 26 | editor.putString(key, value) 27 | editor.apply() 28 | } 29 | 30 | fun loadString(key: String): String? { 31 | val preferences = 32 | context.getSharedPreferences(Constants.PLACE_APP_SHARED_PREF, Context.MODE_PRIVATE) 33 | return preferences.getString(key, null) 34 | } 35 | } -------------------------------------------------------------------------------- /app/src/main/java/info/sanaebadi/stackoverflowproject/util/SchedulerProvider.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.stackoverflowproject.util 2 | 3 | import io.reactivex.Scheduler 4 | 5 | interface SchedulerProvider { 6 | fun uiScheduler(): Scheduler 7 | fun ioScheduler(): Scheduler 8 | } -------------------------------------------------------------------------------- /app/src/main/java/info/sanaebadi/stackoverflowproject/util/TransitionListener.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.stackoverflowproject.util 2 | 3 | import android.annotation.SuppressLint 4 | import android.transition.Transition 5 | 6 | @SuppressLint("NewApi") 7 | open class TransitionListener : Transition.TransitionListener { 8 | override fun onTransitionEnd(p0: Transition?) { 9 | } 10 | 11 | override fun onTransitionResume(p0: Transition?) { 12 | } 13 | 14 | override fun onTransitionPause(p0: Transition?) { 15 | } 16 | 17 | override fun onTransitionCancel(p0: Transition?) { 18 | } 19 | 20 | override fun onTransitionStart(p0: Transition?) { 21 | } 22 | } -------------------------------------------------------------------------------- /app/src/main/java/info/sanaebadi/stackoverflowproject/util/mOnItemClickListener.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.stackoverflowproject.util 2 | 3 | import android.view.View 4 | import info.sanaebadi.stackoverflowproject.model.user.UserPresentation 5 | 6 | interface mOnItemClickListener { 7 | fun onItemClick(userViewModel: UserPresentation, view: View) 8 | } -------------------------------------------------------------------------------- /app/src/main/res/StackOverFlowProject.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/app/src/main/res/StackOverFlowProject.zip -------------------------------------------------------------------------------- /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_error.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/font/font_bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/app/src/main/res/font/font_bold.ttf -------------------------------------------------------------------------------- /app/src/main/res/font/font_regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/app/src/main/res/font/font_regular.ttf -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_details.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | 13 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_user_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 17 | 18 | 23 | 24 | 25 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/layout/list_item_answer.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 22 | 23 | 35 | 36 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /app/src/main/res/layout/list_item_heading.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 21 | 22 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/layout/list_item_loading.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/layout/list_item_question.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 22 | 23 | 36 | 37 | 50 | 51 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /app/src/main/res/layout/list_item_user.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 18 | 19 | 33 | 34 | 47 | 48 | -------------------------------------------------------------------------------- /app/src/main/res/layout/list_item_user_details.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 19 | 20 | 33 | 34 | 48 | -------------------------------------------------------------------------------- /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/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/navigation/nav_graph.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 16 | 17 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/transition/shared_element_transition.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #455a64 4 | #718792 5 | #1c313a 6 | #bf360c 7 | #f9683a 8 | #870000 9 | #ffffff 10 | #ECEAEA 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 2dp 5 | 4dp 6 | 8dp 7 | 12dp 8 | 16dp 9 | 20dp 10 | 24dp 11 | 32dp 12 | 48dp 13 | 64dp 14 | 15 | 16 | 8sp 17 | 10sp 18 | 12sp 19 | 14sp 20 | 16sp 21 | 18sp 22 | 20sp 23 | 20sp 24 | 24sp 25 | 28sp 26 | 64dp 27 | 128dp 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Stack Over Flow 3 | 4 | Hello blank fragment 5 | 6 | Failed to load data. Refresh to try again 7 | Error loading data 8 | 9 | Error to Connect to the Server ! Please check your Network 10 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/test/java/info/sanaebadi/stackoverflowproject/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.stackoverflowproject 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.kts: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | google() 6 | jcenter() 7 | 8 | } 9 | dependencies { 10 | classpath (BuildPlugins.androidGradlePlugin) 11 | classpath (BuildPlugins.kotlinGradlePlugin) 12 | classpath (BuildPlugins.safeArgsPlugin) 13 | // NOTE: Do not place your application dependencies here; they belong 14 | // in the individual module build.gradle files 15 | } 16 | } 17 | 18 | allprojects { 19 | repositories { 20 | google() 21 | jcenter() 22 | 23 | } 24 | } 25 | 26 | tasks.register("clean").configure { 27 | delete("build") 28 | } -------------------------------------------------------------------------------- /buildSrc/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile 2 | 3 | repositories { 4 | jcenter() 5 | } 6 | 7 | plugins { 8 | `kotlin-dsl` 9 | kotlin("jvm") version "1.4.10" 10 | } 11 | 12 | kotlinDslPluginOptions { 13 | experimentalWarning.set(false) 14 | } -------------------------------------------------------------------------------- /buildSrc/build/classes/kotlin/main/AndroidSdk.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/classes/kotlin/main/AndroidSdk.class -------------------------------------------------------------------------------- /buildSrc/build/classes/kotlin/main/BuildPlugins$Versions.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/classes/kotlin/main/BuildPlugins$Versions.class -------------------------------------------------------------------------------- /buildSrc/build/classes/kotlin/main/BuildPlugins.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/classes/kotlin/main/BuildPlugins.class -------------------------------------------------------------------------------- /buildSrc/build/classes/kotlin/main/DaggerLib$Versions.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/classes/kotlin/main/DaggerLib$Versions.class -------------------------------------------------------------------------------- /buildSrc/build/classes/kotlin/main/DaggerLib.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/classes/kotlin/main/DaggerLib.class -------------------------------------------------------------------------------- /buildSrc/build/classes/kotlin/main/Dependencies_Kt.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/classes/kotlin/main/Dependencies_Kt.class -------------------------------------------------------------------------------- /buildSrc/build/classes/kotlin/main/JetPackLibraries$Versions.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/classes/kotlin/main/JetPackLibraries$Versions.class -------------------------------------------------------------------------------- /buildSrc/build/classes/kotlin/main/JetPackLibraries.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/classes/kotlin/main/JetPackLibraries.class -------------------------------------------------------------------------------- /buildSrc/build/classes/kotlin/main/Libraries$Versions.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/classes/kotlin/main/Libraries$Versions.class -------------------------------------------------------------------------------- /buildSrc/build/classes/kotlin/main/Libraries.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/classes/kotlin/main/Libraries.class -------------------------------------------------------------------------------- /buildSrc/build/classes/kotlin/main/META-INF/buildSrc.kotlin_module: -------------------------------------------------------------------------------- 1 |  2 |  3 | Dependencies_Kt"* -------------------------------------------------------------------------------- /buildSrc/build/classes/kotlin/main/Networking$Versions.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/classes/kotlin/main/Networking$Versions.class -------------------------------------------------------------------------------- /buildSrc/build/classes/kotlin/main/Networking.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/classes/kotlin/main/Networking.class -------------------------------------------------------------------------------- /buildSrc/build/classes/kotlin/main/RXLibraries$Versions.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/classes/kotlin/main/RXLibraries$Versions.class -------------------------------------------------------------------------------- /buildSrc/build/classes/kotlin/main/RXLibraries.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/classes/kotlin/main/RXLibraries.class -------------------------------------------------------------------------------- /buildSrc/build/classes/kotlin/main/TestLibraries$Versions.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/classes/kotlin/main/TestLibraries$Versions.class -------------------------------------------------------------------------------- /buildSrc/build/classes/kotlin/main/TestLibraries.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/classes/kotlin/main/TestLibraries.class -------------------------------------------------------------------------------- /buildSrc/build/kotlin/buildSrcjar-classes.txt: -------------------------------------------------------------------------------- 1 | /home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/build/classes/kotlin/main/AndroidSdk.class:/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/build/classes/kotlin/main/BuildPlugins$Versions.class:/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/build/classes/kotlin/main/BuildPlugins.class:/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/build/classes/kotlin/main/DaggerLib$Versions.class:/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/build/classes/kotlin/main/DaggerLib.class:/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/build/classes/kotlin/main/Dependencies_Kt.class:/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/build/classes/kotlin/main/JetPackLibraries$Versions.class:/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/build/classes/kotlin/main/JetPackLibraries.class:/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/build/classes/kotlin/main/Libraries$Versions.class:/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/build/classes/kotlin/main/Libraries.class:/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/build/classes/kotlin/main/Networking$Versions.class:/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/build/classes/kotlin/main/Networking.class:/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/build/classes/kotlin/main/RXLibraries$Versions.class:/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/build/classes/kotlin/main/RXLibraries.class:/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/build/classes/kotlin/main/TestLibraries$Versions.class:/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/build/classes/kotlin/main/TestLibraries.class -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/build-history.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/kotlin/compileKotlin/build-history.bin -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.keystream: -------------------------------------------------------------------------------- 1 | j/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..kt -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.keystream.len: -------------------------------------------------------------------------------- 1 | k -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.len: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.len -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.values.at: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.values.at -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab_i: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab_i -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab_i.len: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab_i.len -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream: -------------------------------------------------------------------------------- 1 | BuildPluginsBuildPlugins.Versions 2 | AndroidSdk LibrariesLibraries.VersionsJetPackLibrariesJetPackLibraries.Versions TestLibrariesTestLibraries.Versions 3 | NetworkingNetworking.Versions RXLibrariesRXLibraries.Versions DaggerLibDaggerLib.Versions -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream.len: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream.len -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.len: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.len -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.values.at: -------------------------------------------------------------------------------- 1 | /Header Record For PersistentHashMapValueStoragekj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..kt -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i.len: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i.len -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.keystream: -------------------------------------------------------------------------------- 1 | BuildPluginsBuildPlugins$Versions 2 | AndroidSdk LibrariesLibraries$VersionsJetPackLibrariesJetPackLibraries$Versions TestLibrariesTestLibraries$Versions 3 | NetworkingNetworking$Versions RXLibrariesRXLibraries$Versions DaggerLibDaggerLib$VersionsDependencies_Kt -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.keystream.len: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.len: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.values.at: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.values.at -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab_i: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab_i -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab_i.len: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab_i.len -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream.len: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab.len: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab.values.at: -------------------------------------------------------------------------------- 1 | /Header Record For PersistentHashMapValueStoragekj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..kt -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i.len: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i.len -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/package-parts.tab: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/package-parts.tab -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/package-parts.tab.keystream: -------------------------------------------------------------------------------- 1 | Dependencies_Kt -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/package-parts.tab.keystream.len: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/package-parts.tab.len: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/package-parts.tab.len -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/package-parts.tab.values.at: -------------------------------------------------------------------------------- 1 | /Header Record For PersistentHashMapValueStorage -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/package-parts.tab_i: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/package-parts.tab_i -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/package-parts.tab_i.len: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/package-parts.tab_i.len -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.keystream: -------------------------------------------------------------------------------- 1 | BuildPluginsBuildPlugins$Versions 2 | AndroidSdk LibrariesLibraries$VersionsJetPackLibrariesJetPackLibraries$Versions TestLibrariesTestLibraries$Versions 3 | NetworkingNetworking$Versions RXLibrariesRXLibraries$Versions DaggerLibDaggerLib$VersionsDependencies_Kt.kotlin_module -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.keystream.len: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.len: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.values.at: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.values.at -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab_i: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab_i -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab_i.len: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab_i.len -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream: -------------------------------------------------------------------------------- 1 | j/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..kt -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream.len: -------------------------------------------------------------------------------- 1 | k -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab.len: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab.len -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab.values.at: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab.values.at -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab_i: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab_i -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab_i.len: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab_i.len -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/counters.tab: -------------------------------------------------------------------------------- 1 | 2 2 | 1 -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.keystream: -------------------------------------------------------------------------------- 1 | j/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..kt -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.keystream.len: -------------------------------------------------------------------------------- 1 | k -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.len: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.len -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.values.at: -------------------------------------------------------------------------------- 1 | /Header Record For PersistentHashMapValueStorage -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab_i: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab_i -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab_i.len: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab_i.len -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab.keystream: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab.keystream.len: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab.len: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab.len -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab.values.at: -------------------------------------------------------------------------------- 1 | /Header Record For PersistentHashMapValueStoragekj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..ktkj/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/src/main/java/Dependencies..kt -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab_i: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab_i -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab_i.len: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab_i.len -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.keystream: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.keystream -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.keystream.len: -------------------------------------------------------------------------------- 1 | ( -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.len: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.len -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.values.at: -------------------------------------------------------------------------------- 1 | /Header Record For PersistentHashMapValueStorage -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab_i: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab_i -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab_i.len: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab_i.len -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/last-build.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/kotlin/compileKotlin/last-build.bin -------------------------------------------------------------------------------- /buildSrc/build/libs/buildSrc.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/libs/buildSrc.jar -------------------------------------------------------------------------------- /buildSrc/build/pluginUnderTestMetadata/plugin-under-test-metadata.properties: -------------------------------------------------------------------------------- 1 | implementation-classpath=/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/build/classes/java/main\:/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/build/classes/groovy/main\:/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/build/classes/kotlin/main\:/home/sanaebadi/Pasport/and_dev/workplace/Github/StackOverFlowApii/buildSrc/build/resources/main 2 | -------------------------------------------------------------------------------- /buildSrc/build/reports/plugin-development/validation-report.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/buildSrc/build/reports/plugin-development/validation-report.txt -------------------------------------------------------------------------------- /buildSrc/build/tmp/jar/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | 3 | -------------------------------------------------------------------------------- /data/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /data/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id(BuildPlugins.androidLibrary) 3 | id(BuildPlugins.kotlinAndroid) 4 | id(BuildPlugins.kotlinAndroidExtensions) 5 | id(BuildPlugins.kaptPlugin) 6 | 7 | } 8 | android { 9 | compileSdkVersion(AndroidSdk.compileSdk) 10 | defaultConfig { 11 | minSdkVersion(AndroidSdk.minSdk) 12 | targetSdkVersion(AndroidSdk.targetSdk) 13 | versionCode = 1 14 | versionName = "1.0" 15 | testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" 16 | consumerProguardFiles("consumer-rules.pro") 17 | } 18 | 19 | buildTypes { 20 | getByName("release") { 21 | isMinifyEnabled = false 22 | proguardFiles( 23 | getDefaultProguardFile("proguard-android-optimize.txt"), 24 | "proguard-rules.pro" 25 | ) 26 | } 27 | } 28 | 29 | flavorDimensions("PlaceApp") 30 | productFlavors { 31 | create("tapsi") { 32 | setDimension("PlaceApp") 33 | buildConfigField("String", "API_BASE_URL", "\"https://api.stackexchange.com/2.2/\"") 34 | } 35 | 36 | } 37 | 38 | compileOptions { 39 | sourceCompatibility = JavaVersion.VERSION_1_8 40 | targetCompatibility = JavaVersion.VERSION_1_8 41 | } 42 | // For Kotlin projects 43 | kotlinOptions { 44 | jvmTarget = "1.8" 45 | } 46 | 47 | } 48 | 49 | 50 | dependencies { 51 | implementation(project(mapOf("path" to ":domain"))) 52 | 53 | implementation(Libraries.kotlinStdLib) 54 | implementation(Libraries.ktxCore) 55 | 56 | implementation(DaggerLib.dagger) 57 | implementation(DaggerLib.daggerSupport) 58 | kapt(DaggerLib.daggerCompiler) 59 | kapt(DaggerLib.daggerProcessor) 60 | 61 | implementation(Networking.retrofit) 62 | implementation(Networking.rxRetrofitAdapter) 63 | implementation(Networking.converterScalars) 64 | implementation(Networking.converterMoshi) 65 | api(Networking.moshi) 66 | kapt(Networking.moshiKotlin) 67 | 68 | implementation(RXLibraries.rxAndroid) 69 | implementation(RXLibraries.rxJava) 70 | 71 | testImplementation(TestLibraries.junit4) 72 | androidTestImplementation(TestLibraries.testRunner) 73 | androidTestImplementation(TestLibraries.espresso) 74 | testImplementation(TestLibraries.mockitoKotlin) 75 | 76 | implementation("com.squareup.okhttp3:logging-interceptor:4.8.1") 77 | 78 | } -------------------------------------------------------------------------------- /data/consumer-rules.pro: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/data/consumer-rules.pro -------------------------------------------------------------------------------- /data/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 -------------------------------------------------------------------------------- /data/src/androidTest/java/info/sanaebadi/data/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.data 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("info.sanaebadi.data.test", appContext.packageName) 23 | } 24 | } -------------------------------------------------------------------------------- /data/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /data/src/main/java/info/sanaebadi/cache/base/BaseCache.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.cache.base 2 | 3 | import io.reactivex.Completable 4 | import io.reactivex.Maybe 5 | 6 | interface BaseCache { 7 | 8 | fun saveData(item: T) 9 | fun getData(key: String): Maybe 10 | fun isCached(key: String): Boolean 11 | fun deleteCache(): Completable 12 | 13 | 14 | } -------------------------------------------------------------------------------- /data/src/main/java/info/sanaebadi/entity/base/BaseEntity.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.data.entity.base 2 | 3 | interface BaseEntity -------------------------------------------------------------------------------- /data/src/main/java/info/sanaebadi/entity/base/ListBaseEntity.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.entity.base 2 | 3 | import info.sanaebadi.data.entity.base.BaseEntity 4 | 5 | 6 | abstract class ListBaseEntity : BaseEntity { 7 | 8 | open var list: List = emptyList() 9 | } -------------------------------------------------------------------------------- /data/src/main/java/info/sanaebadi/entity/base/Table.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.entity.base 2 | 3 | interface Table -------------------------------------------------------------------------------- /data/src/main/java/info/sanaebadi/entity/user/AnswerEntity.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.entity.user 2 | 3 | import com.squareup.moshi.Json 4 | import com.squareup.moshi.JsonClass 5 | import info.sanaebadi.data.entity.base.BaseEntity 6 | 7 | @JsonClass(generateAdapter = true) 8 | data class AnswerEntity( 9 | @field:Json(name = "answer_id") var answerId: Long, 10 | @field:Json(name = "question_id") var questionId: Long, 11 | @field:Json(name = "score") var score: Long, 12 | @field:Json(name = "is_accepted") var accepted: Boolean, 13 | @field:Json(name = "owner") var ownerEntity: OwnerEntity 14 | ) :BaseEntity{ 15 | 16 | constructor() : this(-1, -1, 0, false, OwnerEntity()) 17 | } -------------------------------------------------------------------------------- /data/src/main/java/info/sanaebadi/entity/user/AnswerListEntity.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.entity.user 2 | 3 | import com.squareup.moshi.JsonClass 4 | 5 | 6 | @JsonClass(generateAdapter = true) 7 | class AnswerListEntity(val items: List) -------------------------------------------------------------------------------- /data/src/main/java/info/sanaebadi/entity/user/FavoritedByUserEntity.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.entity.user 2 | 3 | import com.squareup.moshi.JsonClass 4 | import info.sanaebadi.data.entity.base.BaseEntity 5 | 6 | @JsonClass(generateAdapter = true) 7 | data class FavoritedByUserEntity( 8 | var userId: Long, 9 | var questionIds: List 10 | ): BaseEntity { 11 | 12 | constructor() : this(-1, emptyList()) 13 | } -------------------------------------------------------------------------------- /data/src/main/java/info/sanaebadi/entity/user/OwnerEntity.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.entity.user 2 | 3 | import com.squareup.moshi.Json 4 | import com.squareup.moshi.JsonClass 5 | import info.sanaebadi.data.entity.base.BaseEntity 6 | 7 | @JsonClass(generateAdapter = true) 8 | data class OwnerEntity(@field:Json(name ="user_id") var userId: Long) : BaseEntity { 9 | 10 | constructor() : this(-1) 11 | } -------------------------------------------------------------------------------- /data/src/main/java/info/sanaebadi/entity/user/QuestionEntity.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.entity.user 2 | 3 | import com.squareup.moshi.Json 4 | import com.squareup.moshi.JsonClass 5 | import info.sanaebadi.data.entity.base.BaseEntity 6 | 7 | @JsonClass(generateAdapter = true) 8 | data class QuestionEntity( 9 | @field:Json(name ="view_count") var viewCount: Long, 10 | @field:Json(name ="score") var score: Long, 11 | @field:Json(name ="title") var title: String, 12 | @field:Json(name ="link") var link: String, 13 | @field:Json(name ="question_id") var questionId: Long, 14 | @field:Json(name ="owner") var ownerEntity: OwnerEntity 15 | ): BaseEntity { 16 | 17 | constructor() : this(0, 0, "", "", -1, OwnerEntity()) 18 | } -------------------------------------------------------------------------------- /data/src/main/java/info/sanaebadi/entity/user/QuestionListEntity.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.entity.user 2 | 3 | import com.squareup.moshi.JsonClass 4 | import info.sanaebadi.data.entity.base.BaseEntity 5 | 6 | @JsonClass(generateAdapter = true) 7 | class QuestionListEntity(val items: List): BaseEntity -------------------------------------------------------------------------------- /data/src/main/java/info/sanaebadi/entity/user/UserEntity.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.entity.user 2 | 3 | import com.squareup.moshi.Json 4 | import com.squareup.moshi.JsonClass 5 | import info.sanaebadi.data.entity.base.BaseEntity 6 | 7 | @JsonClass(generateAdapter = true) 8 | data class UserEntity( 9 | @field:Json(name ="user_id") var userId: Long, 10 | @field:Json(name ="display_name") var displayName: String, 11 | @field:Json(name ="reputation") var reputation: Long, 12 | @field:Json(name ="profile_image") var profileImage: String 13 | ):BaseEntity { 14 | 15 | constructor() : this(-1, "", 0, "") 16 | } -------------------------------------------------------------------------------- /data/src/main/java/info/sanaebadi/entity/user/UserListModelEntity.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.entity.user 2 | 3 | import com.squareup.moshi.JsonClass 4 | import info.sanaebadi.data.entity.base.BaseEntity 5 | 6 | @JsonClass(generateAdapter = true) 7 | class UserListModelEntity(val items: List) : BaseEntity -------------------------------------------------------------------------------- /data/src/main/java/info/sanaebadi/exception/DataException.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.exception 2 | 3 | class DataException(val code: String, override val message: String) : Exception() 4 | -------------------------------------------------------------------------------- /data/src/main/java/info/sanaebadi/exception/NoDataException.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.exception 2 | 3 | class NoDataException : Exception() 4 | -------------------------------------------------------------------------------- /data/src/main/java/info/sanaebadi/executor/JobExecutor.kt: -------------------------------------------------------------------------------- 1 | 2 | package info.sanaebadi.executor 3 | 4 | 5 | import info.sanaebadi.domain.executor.ThreadExecutor 6 | import javax.inject.Inject 7 | import javax.inject.Singleton 8 | import java.util.concurrent.LinkedBlockingQueue 9 | import java.util.concurrent.ThreadFactory 10 | import java.util.concurrent.ThreadPoolExecutor 11 | import java.util.concurrent.TimeUnit 12 | 13 | 14 | /** 15 | * Decorated [ThreadPoolExecutor] 16 | */ 17 | @Singleton 18 | class JobExecutor @Inject 19 | constructor() : ThreadExecutor { 20 | 21 | private val threadPoolExecutor: ThreadPoolExecutor 22 | 23 | init { 24 | this.threadPoolExecutor = ThreadPoolExecutor( 25 | 5, 15, 15, TimeUnit.SECONDS, 26 | LinkedBlockingQueue(), JobThreadFactory() 27 | ) 28 | 29 | 30 | } 31 | 32 | override fun execute(runnable: Runnable) { 33 | this.threadPoolExecutor.execute(runnable) 34 | } 35 | 36 | private inner class JobThreadFactory : ThreadFactory { 37 | private var counter = 0 38 | 39 | override fun newThread(runnable: Runnable): Thread { 40 | return Thread(runnable, "android_" + counter++) 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /data/src/main/java/info/sanaebadi/mapper/base/DataLayerMapper.java: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.mapper.base; 2 | 3 | 4 | import info.sanaebadi.data.entity.base.BaseEntity; 5 | import info.sanaebadi.domain.model.base.BaseDomainModel; 6 | 7 | public interface DataLayerMapper { 8 | 9 | D toDomain(E e); 10 | 11 | E toEntity(D d); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /data/src/main/java/info/sanaebadi/mapper/details/AnswersByUserMapper.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.mapper.details 2 | 3 | import info.sanaebadi.domain.model.user.Answer 4 | import info.sanaebadi.domain.model.user.AnswerList 5 | import info.sanaebadi.domain.model.user.Owner 6 | import info.sanaebadi.entity.user.AnswerEntity 7 | import info.sanaebadi.entity.user.AnswerListEntity 8 | import info.sanaebadi.mapper.base.DataLayerMapper 9 | import java.util.* 10 | import javax.inject.Inject 11 | import javax.inject.Singleton 12 | 13 | @Singleton 14 | class AnswersByUserMapper @Inject constructor() : DataLayerMapper { 15 | 16 | fun toDomain(answerListEntity: AnswerListEntity): List? { 17 | val answerList: MutableList = ArrayList() 18 | 19 | for (answer: AnswerEntity in answerListEntity.items) { 20 | answerList.add(toDomain(answer)) 21 | } 22 | return answerList 23 | } 24 | 25 | override fun toDomain(e: AnswerEntity?): Answer { 26 | 27 | val owner = e?.ownerEntity?.userId?.let { Owner(it) } 28 | 29 | return Answer(e?.answerId!!, e.questionId, e.score, e.accepted, owner!!) 30 | } 31 | 32 | override fun toEntity(d: Answer?): AnswerEntity? { 33 | return null 34 | } 35 | } -------------------------------------------------------------------------------- /data/src/main/java/info/sanaebadi/mapper/details/FavoritesByUserMapper.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.mapper.details 2 | 3 | import info.sanaebadi.domain.model.user.Owner 4 | import info.sanaebadi.domain.model.user.Question 5 | import info.sanaebadi.entity.user.QuestionEntity 6 | import info.sanaebadi.entity.user.QuestionListEntity 7 | import info.sanaebadi.mapper.base.DataLayerMapper 8 | import java.util.* 9 | import javax.inject.Inject 10 | import javax.inject.Singleton 11 | 12 | @Singleton 13 | class FavoritesByUserMapper @Inject constructor() : DataLayerMapper { 14 | 15 | fun toDomain(questionListEntity: QuestionListEntity): List { 16 | val quesList: MutableList = ArrayList() 17 | 18 | for (question: QuestionEntity in questionListEntity.items) { 19 | quesList.add(toDomain(question)) 20 | } 21 | return quesList 22 | } 23 | 24 | override fun toDomain(e: QuestionEntity?): Question { 25 | 26 | val owner = e?.ownerEntity?.userId?.let { Owner(it) } 27 | 28 | return Question( 29 | e?.viewCount!!, 30 | e.score, 31 | e.title, 32 | e.link, 33 | e.questionId, 34 | owner!! 35 | ) 36 | } 37 | 38 | override fun toEntity(d: Question?): QuestionEntity? { 39 | return null 40 | } 41 | } -------------------------------------------------------------------------------- /data/src/main/java/info/sanaebadi/mapper/details/QuestionByIdMapper.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.mapper.details 2 | 3 | import info.sanaebadi.domain.model.user.Owner 4 | import info.sanaebadi.domain.model.user.Question 5 | import info.sanaebadi.domain.model.user.QuestionList 6 | import info.sanaebadi.entity.user.QuestionEntity 7 | import info.sanaebadi.entity.user.QuestionListEntity 8 | import info.sanaebadi.mapper.base.DataLayerMapper 9 | import java.util.* 10 | import javax.inject.Inject 11 | import javax.inject.Singleton 12 | 13 | @Singleton 14 | class QuestionByIdMapper @Inject constructor() : DataLayerMapper { 15 | 16 | fun toDomain(questionListEntity: QuestionListEntity): List? { 17 | val quesList: MutableList = ArrayList() 18 | 19 | for (question: QuestionEntity in questionListEntity.items) { 20 | quesList.add(toDomain(question)) 21 | } 22 | return quesList 23 | } 24 | 25 | override fun toDomain(e: QuestionEntity?): Question { 26 | 27 | val owner = e?.ownerEntity?.userId?.let { Owner(it) } 28 | 29 | return Question( 30 | e?.viewCount!!, 31 | e.score, 32 | e.title, 33 | e.link, 34 | e.questionId, 35 | owner!! 36 | ) 37 | } 38 | 39 | override fun toEntity(d: Question?): QuestionEntity? { 40 | return null 41 | } 42 | } -------------------------------------------------------------------------------- /data/src/main/java/info/sanaebadi/mapper/details/QuestionsByUserMapper.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.mapper.details 2 | 3 | import info.sanaebadi.domain.model.user.Owner 4 | import info.sanaebadi.domain.model.user.Question 5 | import info.sanaebadi.entity.user.QuestionEntity 6 | import info.sanaebadi.entity.user.QuestionListEntity 7 | import info.sanaebadi.mapper.base.DataLayerMapper 8 | import java.util.* 9 | import javax.inject.Inject 10 | import javax.inject.Singleton 11 | 12 | @Singleton 13 | class QuestionsByUserMapper @Inject constructor() : DataLayerMapper { 14 | 15 | fun toDomain(questionListEntity: QuestionListEntity): List? { 16 | val quesList: MutableList = ArrayList() 17 | 18 | for (question: QuestionEntity in questionListEntity.items) { 19 | quesList.add(toDomain(question)) 20 | } 21 | return quesList 22 | } 23 | 24 | override fun toDomain(e: QuestionEntity?): Question { 25 | val owner = e?.ownerEntity?.userId?.let { Owner(it) } 26 | 27 | return Question( 28 | e?.viewCount!!, 29 | e.score, 30 | e.title, 31 | e.link, 32 | e.questionId, 33 | owner!! 34 | 35 | ) 36 | } 37 | 38 | override fun toEntity(d: Question?): QuestionEntity? { 39 | return null 40 | } 41 | } -------------------------------------------------------------------------------- /data/src/main/java/info/sanaebadi/mapper/user/UserMapper.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.mapper.user 2 | 3 | import info.sanaebadi.domain.model.user.User 4 | import info.sanaebadi.domain.model.user.UserListModel 5 | import info.sanaebadi.entity.user.UserEntity 6 | import info.sanaebadi.entity.user.UserListModelEntity 7 | import info.sanaebadi.mapper.base.DataLayerMapper 8 | import java.util.* 9 | import javax.inject.Inject 10 | import javax.inject.Singleton 11 | 12 | @Singleton 13 | class UserMapper @Inject constructor() : DataLayerMapper { 14 | 15 | fun toDomain(userListModelEntity: UserListModelEntity): UserListModel? { 16 | val userList: MutableList = ArrayList() 17 | 18 | for (user: UserEntity in userListModelEntity.items) { 19 | userList.add(toDomain(user)!!) 20 | } 21 | return UserListModel(userList) 22 | } 23 | 24 | 25 | override fun toDomain(e: UserEntity?): User? { 26 | return User(e?.userId!!, e.displayName, e.reputation, e.profileImage) 27 | 28 | } 29 | 30 | override fun toEntity(d: User?): UserEntity? { 31 | return null 32 | } 33 | 34 | 35 | } -------------------------------------------------------------------------------- /data/src/main/java/info/sanaebadi/networking/base/AbstractService.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.networking.base 2 | 3 | import info.sanaebadi.data.BuildConfig 4 | import io.reactivex.schedulers.Schedulers 5 | import okhttp3.OkHttpClient 6 | import okhttp3.logging.HttpLoggingInterceptor 7 | import retrofit2.Retrofit 8 | import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory 9 | import retrofit2.converter.moshi.MoshiConverterFactory 10 | import retrofit2.converter.scalars.ScalarsConverterFactory 11 | import java.util.concurrent.TimeUnit 12 | 13 | abstract class AbstractService( 14 | serviceType: Class 15 | ) { 16 | internal var service: S 17 | private var serviceType: Class? = serviceType 18 | 19 | init { 20 | service = createService(BuildConfig.API_BASE_URL) 21 | } 22 | 23 | 24 | fun setBaseUrl(baseUrl: String) { 25 | service = createService(baseUrl) 26 | } 27 | 28 | 29 | private fun createService(baseUrl: String): S { 30 | val interceptor = HttpLoggingInterceptor() 31 | interceptor.level = HttpLoggingInterceptor.Level.BODY 32 | 33 | 34 | val client = OkHttpClient.Builder() 35 | .connectTimeout(TIME_OUT_MIL_SECS, TimeUnit.SECONDS) 36 | .addInterceptor(interceptor) 37 | .build() 38 | 39 | val retrofitBuilder = Retrofit.Builder().baseUrl(baseUrl) 40 | .addConverterFactory(ScalarsConverterFactory.create()) 41 | .addConverterFactory(MoshiConverterFactory.create()) 42 | .addCallAdapterFactory(RxJava2CallAdapterFactory.createWithScheduler(Schedulers.io())) 43 | return retrofitBuilder.client(client).build().create(serviceType!!) 44 | } 45 | 46 | 47 | companion object { 48 | private const val TIME_OUT_MIL_SECS = 60L 49 | } 50 | } -------------------------------------------------------------------------------- /data/src/main/java/info/sanaebadi/networking/retrofit/UserApiRetrofitService.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.networking.retrofit 2 | 3 | import info.sanaebadi.entity.user.AnswerListEntity 4 | import info.sanaebadi.entity.user.QuestionListEntity 5 | import info.sanaebadi.entity.user.UserListModelEntity 6 | import io.reactivex.Single 7 | import retrofit2.http.GET 8 | import retrofit2.http.Path 9 | import retrofit2.http.Query 10 | 11 | interface UserApiRetrofitService { 12 | @GET("users?order=desc&sort=reputation&site=stackoverflow") 13 | fun getUsers(@Query("page") page: Int = 1): Single 14 | 15 | @GET("users/{userId}/questions?order=desc&sort=votes&site=stackoverflow") 16 | fun getQuestionsByUser(@Path("userId") userId: Long): Single 17 | 18 | @GET("users/{userId}/favorites?order=desc&sort=votes&site=stackoverflow") 19 | fun getFavoritesByUser(@Path("userId") userId: Long): Single 20 | 21 | @GET("users/{userId}/answers?order=desc&sort=votes&site=stackoverflow") 22 | fun getAnswersByUser(@Path("userId") userId: Long): Single 23 | 24 | @GET("questions/{questionIds}?order=desc&sort=activity&site=stackoverflow") 25 | fun getQuestionsById(@Path("questionIds") questionId: String): Single 26 | } -------------------------------------------------------------------------------- /data/src/main/java/info/sanaebadi/repository/dataSource/base/BaseDataSourceFactory.java: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.repository.dataSource.base; 2 | 3 | import info.sanaebadi.domain.repository.CacheStrategy; 4 | import io.reactivex.Completable; 5 | 6 | public interface BaseDataSourceFactory { 7 | T create(CacheStrategy cacheStrategy, String... params); 8 | 9 | Completable deleteCache(); 10 | } 11 | -------------------------------------------------------------------------------- /data/src/main/java/info/sanaebadi/repository/dataSource/details/DetailsDataRepository.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.repository.dataSource.details 2 | 3 | import info.sanaebadi.domain.model.user.Answer 4 | import info.sanaebadi.domain.model.user.AnswerList 5 | import info.sanaebadi.domain.model.user.Question 6 | import info.sanaebadi.domain.model.user.QuestionList 7 | import info.sanaebadi.domain.repository.CacheStrategy 8 | import info.sanaebadi.domain.repository.DetailsRepository 9 | import info.sanaebadi.mapper.details.AnswersByUserMapper 10 | import info.sanaebadi.mapper.details.FavoritesByUserMapper 11 | import info.sanaebadi.mapper.details.QuestionByIdMapper 12 | import info.sanaebadi.mapper.details.QuestionsByUserMapper 13 | import io.reactivex.Single 14 | import javax.inject.Inject 15 | 16 | class DetailsDataRepository @Inject constructor( 17 | private val detailsDataSourceFactory: DetailsDataSourceFactory, 18 | private val answersByUserMapper: AnswersByUserMapper, 19 | private val favoritesByUserMapper: FavoritesByUserMapper, 20 | private val questionsByUserMapper: QuestionsByUserMapper, 21 | private val questionByIdMapper: QuestionByIdMapper 22 | 23 | ) : DetailsRepository { 24 | override fun getQuestionsByUser(userId: Long): Single> { 25 | return detailsDataSourceFactory.create(CacheStrategy.ONLINE_FIRST) 26 | .getQuestionsByUser(userId) 27 | .map { data -> questionsByUserMapper.toDomain(data) } 28 | } 29 | 30 | override fun getAnswersByUser(userId: Long): Single> { 31 | return detailsDataSourceFactory.create(CacheStrategy.ONLINE_FIRST) 32 | .getAnswersByUser(userId) 33 | .map { data -> answersByUserMapper.toDomain(data) } 34 | } 35 | 36 | override fun getFavoritesByUser(userId: Long): Single> { 37 | return detailsDataSourceFactory.create(CacheStrategy.ONLINE_FIRST) 38 | .getFavoritesByUser(userId) 39 | .map { data -> favoritesByUserMapper.toDomain(data) } 40 | } 41 | 42 | override fun getQuestionsById(ids: List, userId: Long): Single> { 43 | return detailsDataSourceFactory.create(CacheStrategy.ONLINE_FIRST) 44 | .getQuestionsById(ids, userId) 45 | .map { data -> questionByIdMapper.toDomain(data) } 46 | } 47 | 48 | } -------------------------------------------------------------------------------- /data/src/main/java/info/sanaebadi/repository/dataSource/details/DetailsDataSource.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.repository.dataSource.details 2 | 3 | import info.sanaebadi.entity.user.AnswerListEntity 4 | import info.sanaebadi.entity.user.QuestionListEntity 5 | import io.reactivex.Single 6 | 7 | 8 | interface DetailsDataSource { 9 | fun getQuestionsByUser(userId: Long): Single 10 | fun getAnswersByUser(userId: Long): Single 11 | fun getFavoritesByUser(userId: Long): Single 12 | fun getQuestionsById(ids: List, userId: Long): Single 13 | } -------------------------------------------------------------------------------- /data/src/main/java/info/sanaebadi/repository/dataSource/details/DetailsDataSourceFactory.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.repository.dataSource.details 2 | 3 | import info.sanaebadi.domain.repository.CacheStrategy 4 | import info.sanaebadi.repository.dataSource.base.BaseDataSourceFactory 5 | import info.sanaebadi.repository.dataSourceImpl.DetailsOnlineDataSource 6 | import io.reactivex.Completable 7 | import javax.inject.Inject 8 | 9 | class DetailsDataSourceFactory @Inject constructor() : BaseDataSourceFactory { 10 | override fun create(cacheStrategy: CacheStrategy?, vararg params: String?): DetailsDataSource { 11 | return DetailsOnlineDataSource() 12 | } 13 | 14 | override fun deleteCache(): Completable? { 15 | return null 16 | } 17 | } -------------------------------------------------------------------------------- /data/src/main/java/info/sanaebadi/repository/dataSource/user/UserDataRepository.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.repository.dataSource.user 2 | 3 | import info.sanaebadi.domain.model.user.UserListModel 4 | import info.sanaebadi.domain.repository.CacheStrategy 5 | import info.sanaebadi.domain.repository.UserRepository 6 | import info.sanaebadi.mapper.user.UserMapper 7 | import io.reactivex.Single 8 | import javax.inject.Inject 9 | import javax.inject.Singleton 10 | 11 | @Singleton 12 | class UserDataRepository @Inject constructor( 13 | private val userDataSourceFactory: UserDataSourceFactory, 14 | private val userMapper: UserMapper 15 | ) : UserRepository { 16 | 17 | override fun getUsers(page: Int): Single { 18 | return userDataSourceFactory.create(CacheStrategy.ONLINE_FIRST).getUsers(page) 19 | .map { data -> userMapper.toDomain(data) } 20 | } 21 | } -------------------------------------------------------------------------------- /data/src/main/java/info/sanaebadi/repository/dataSource/user/UserDataSource.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.repository.dataSource.user 2 | 3 | import info.sanaebadi.entity.user.UserListModelEntity 4 | import io.reactivex.Single 5 | 6 | interface UserDataSource { 7 | fun getUsers(page: Int): Single 8 | } -------------------------------------------------------------------------------- /data/src/main/java/info/sanaebadi/repository/dataSource/user/UserDataSourceFactory.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.repository.dataSource.user 2 | 3 | import info.sanaebadi.domain.repository.CacheStrategy 4 | import info.sanaebadi.repository.dataSource.base.BaseDataSourceFactory 5 | import info.sanaebadi.repository.dataSourceImpl.UserOnlineDataSource 6 | import io.reactivex.Completable 7 | import javax.inject.Inject 8 | 9 | class UserDataSourceFactory @Inject constructor() : BaseDataSourceFactory { 10 | override fun create(cacheStrategy: CacheStrategy?, vararg params: String?): UserDataSource { 11 | return UserOnlineDataSource() 12 | } 13 | 14 | override fun deleteCache(): Completable? { 15 | return null 16 | } 17 | } -------------------------------------------------------------------------------- /data/src/main/java/info/sanaebadi/repository/dataSourceImpl/DetailsOnlineDataSource.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.repository.dataSourceImpl 2 | 3 | import info.sanaebadi.entity.user.AnswerListEntity 4 | import info.sanaebadi.entity.user.QuestionListEntity 5 | import info.sanaebadi.networking.base.AbstractService 6 | import info.sanaebadi.networking.retrofit.UserApiRetrofitService 7 | import info.sanaebadi.repository.dataSource.details.DetailsDataSource 8 | import io.reactivex.Single 9 | 10 | class DetailsOnlineDataSource : 11 | AbstractService(UserApiRetrofitService::class.java), DetailsDataSource { 12 | 13 | override fun getQuestionsByUser(userId: Long): Single { 14 | return service.getQuestionsByUser(userId) 15 | } 16 | 17 | override fun getAnswersByUser(userId: Long): Single { 18 | return service.getAnswersByUser(userId) 19 | } 20 | 21 | override fun getFavoritesByUser(userId: Long): Single { 22 | return service.getFavoritesByUser(userId) 23 | } 24 | 25 | override fun getQuestionsById(ids: List, userId: Long): Single { 26 | return service.getQuestionsById(ids.joinToString(separator = ";")) 27 | } 28 | 29 | 30 | } -------------------------------------------------------------------------------- /data/src/main/java/info/sanaebadi/repository/dataSourceImpl/UserOnlineDataSource.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.repository.dataSourceImpl 2 | 3 | import info.sanaebadi.entity.user.UserListModelEntity 4 | import info.sanaebadi.networking.base.AbstractService 5 | import info.sanaebadi.networking.retrofit.UserApiRetrofitService 6 | import info.sanaebadi.repository.dataSource.user.UserDataSource 7 | import io.reactivex.Single 8 | 9 | class UserOnlineDataSource : 10 | AbstractService(UserApiRetrofitService::class.java), UserDataSource { 11 | 12 | override fun getUsers(page: Int): Single { 13 | return service.getUsers(page) 14 | } 15 | 16 | } -------------------------------------------------------------------------------- /data/src/test/java/info/sanaebadi/data/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.data 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 | } -------------------------------------------------------------------------------- /domain/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /domain/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile 2 | 3 | plugins { 4 | id(BuildPlugins.javaLibraryPlugin) 5 | id(BuildPlugins.kotlinPlugin) 6 | id(BuildPlugins.kaptPlugin) 7 | } 8 | 9 | 10 | dependencies { 11 | implementation(Libraries.kotlinStdLib) 12 | implementation(RXLibraries.rxAndroid) 13 | implementation(RXLibraries.rxJava) 14 | implementation(Libraries.arrow) 15 | 16 | implementation(DaggerLib.dagger) 17 | implementation(DaggerLib.daggerSupport) 18 | kapt(DaggerLib.daggerCompiler) 19 | kapt(DaggerLib.daggerProcessor) 20 | 21 | implementation(RXLibraries.rxAndroid) 22 | implementation(RXLibraries.rxJava) 23 | implementation(RXLibraries.rxKotlin) 24 | 25 | testImplementation(TestLibraries.junit4) 26 | testImplementation(TestLibraries.mockitoKotlin) 27 | } 28 | 29 | 30 | // compile bytecode to java 8 (default is java 6) 31 | tasks.withType { 32 | kotlinOptions.jvmTarget = "1.8" 33 | } -------------------------------------------------------------------------------- /domain/src/main/java/info/sanaebadi/domain/executor/PostExecutionThread.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.domain.executor 2 | 3 | import io.reactivex.Scheduler 4 | 5 | /** 6 | * Thread abstraction created to change the execution context from any thread to any other thread. 7 | * Useful to encapsulate a UI Thread for example, since some job will be done in background, an 8 | * implementation of this interface will change context and update the UI. 9 | */ 10 | interface PostExecutionThread { 11 | val scheduler: Scheduler 12 | } -------------------------------------------------------------------------------- /domain/src/main/java/info/sanaebadi/domain/executor/ThreadExecutor.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.domain.executor 2 | 3 | 4 | import java.util.concurrent.Executor 5 | 6 | /** 7 | * Executor implementation can be based on different frameworks or techniques of asynchronous 8 | * execution, but every implementation will execute the [UseCase] out of the UI thread. 9 | */ 10 | interface ThreadExecutor : Executor 11 | -------------------------------------------------------------------------------- /domain/src/main/java/info/sanaebadi/domain/interactor/base/BaseCompeletableObserver.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.domain.interactor.base 2 | 3 | import io.reactivex.observers.DisposableCompletableObserver 4 | 5 | open class BaseCompeletableObserver : DisposableCompletableObserver(), IObserver { 6 | 7 | override fun onComplete() { 8 | 9 | } 10 | 11 | override fun onError(e: Throwable) { 12 | 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /domain/src/main/java/info/sanaebadi/domain/interactor/base/BaseMaybeObserver.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.domain.interactor.base 2 | 3 | import io.reactivex.observers.DisposableMaybeObserver 4 | 5 | open class BaseMaybeObserver : DisposableMaybeObserver(), IObserver { 6 | 7 | override fun onSuccess(t: T) { 8 | 9 | } 10 | 11 | override fun onError(e: Throwable) { 12 | 13 | } 14 | 15 | override fun onComplete() { 16 | 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /domain/src/main/java/info/sanaebadi/domain/interactor/base/BaseObserver.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Fernando Cejas Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package info.sanaebadi.domain.interactor.base 17 | 18 | import io.reactivex.observers.DisposableObserver 19 | 20 | /** 21 | * Default [DisposableObserver] base class to be used whenever you want default error handling. 22 | */ 23 | open class BaseObserver : DisposableObserver(), IObserver { 24 | override fun onNext(data: T) { 25 | // no-op by default. 26 | } 27 | 28 | override fun onComplete() { 29 | // no-op by default. 30 | } 31 | 32 | override fun onError(exception: Throwable) { 33 | // no-op by default. 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /domain/src/main/java/info/sanaebadi/domain/interactor/base/BaseSingleObserver.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.domain.interactor.base 2 | 3 | import io.reactivex.observers.DisposableSingleObserver 4 | 5 | open class BaseSingleObserver : DisposableSingleObserver(), IObserver { 6 | 7 | override fun onSuccess(t: T) { 8 | } 9 | 10 | override fun onError(e: Throwable) { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /domain/src/main/java/info/sanaebadi/domain/interactor/base/CompletableUseCase.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.domain.interactor.base 2 | 3 | import com.fernandocejas.arrow.checks.Preconditions 4 | import info.sanaebadi.domain.executor.PostExecutionThread 5 | import info.sanaebadi.domain.executor.ThreadExecutor 6 | import io.reactivex.Completable 7 | import io.reactivex.disposables.CompositeDisposable 8 | import io.reactivex.disposables.Disposable 9 | import io.reactivex.observers.DisposableCompletableObserver 10 | import io.reactivex.schedulers.Schedulers 11 | 12 | abstract class CompletableUseCase( 13 | private val threadExecutor: ThreadExecutor, 14 | private val postExecutionThread: PostExecutionThread 15 | ) : IUseCase { 16 | private val disposables: CompositeDisposable = CompositeDisposable() 17 | 18 | override fun execute(observer: DisposableCompletableObserver, params: Params) { 19 | Preconditions.checkNotNull(observer) 20 | val completable = this.buildUseCaseCompletable(params) 21 | .subscribeOn(Schedulers.from(threadExecutor)) 22 | .observeOn(postExecutionThread.scheduler) 23 | addDisposable(completable.subscribeWith(observer)) 24 | } 25 | 26 | 27 | fun dispose() { 28 | if (!disposables.isDisposed) { 29 | disposables.dispose() 30 | } 31 | } 32 | 33 | abstract fun buildUseCaseCompletable(params: Params): Completable 34 | 35 | 36 | private fun addDisposable(disposable: Disposable) { 37 | Preconditions.checkNotNull(disposable) 38 | Preconditions.checkNotNull(disposables) 39 | disposables.add(disposable) 40 | } 41 | } 42 | 43 | 44 | -------------------------------------------------------------------------------- /domain/src/main/java/info/sanaebadi/domain/interactor/base/IObserver.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.domain.interactor.base 2 | 3 | interface IObserver 4 | -------------------------------------------------------------------------------- /domain/src/main/java/info/sanaebadi/domain/interactor/base/IUseCase.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.domain.interactor.base 2 | 3 | interface IUseCase { 4 | fun execute(observer: T, params: Params) 5 | } 6 | -------------------------------------------------------------------------------- /domain/src/main/java/info/sanaebadi/domain/interactor/base/MaybeUseCase.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.domain.interactor.base 2 | 3 | import com.fernandocejas.arrow.checks.Preconditions 4 | import info.sanaebadi.domain.executor.PostExecutionThread 5 | import info.sanaebadi.domain.executor.ThreadExecutor 6 | import io.reactivex.Maybe 7 | import io.reactivex.disposables.CompositeDisposable 8 | import io.reactivex.disposables.Disposable 9 | import io.reactivex.observers.DisposableMaybeObserver 10 | import io.reactivex.schedulers.Schedulers 11 | 12 | abstract class MaybeUseCase( 13 | private val threadExecutor: ThreadExecutor, 14 | private val postExecutionThread: PostExecutionThread 15 | ) : 16 | IUseCase, Params> { 17 | private val disposables: CompositeDisposable = CompositeDisposable() 18 | 19 | override fun execute(observer: DisposableMaybeObserver, params: Params) { 20 | val maybe = this.buildUseCaseMaybe(params) 21 | .subscribeOn(Schedulers.from(threadExecutor)) 22 | .observeOn(postExecutionThread.scheduler) 23 | addDisposable(maybe.subscribeWith(observer) as Disposable) 24 | } 25 | 26 | 27 | fun dispose() { 28 | if (!disposables.isDisposed) { 29 | disposables.dispose() 30 | } 31 | } 32 | 33 | abstract fun buildUseCaseMaybe(params: Params): Maybe 34 | 35 | private fun addDisposable(disposable: Disposable) { 36 | Preconditions.checkNotNull(disposable) 37 | Preconditions.checkNotNull(disposables) 38 | disposables.add(disposable) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /domain/src/main/java/info/sanaebadi/domain/interactor/base/SingleUseCase.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.domain.interactor.base 2 | 3 | import com.fernandocejas.arrow.checks.Preconditions 4 | import info.sanaebadi.domain.executor.PostExecutionThread 5 | import info.sanaebadi.domain.executor.ThreadExecutor 6 | import io.reactivex.Single 7 | import io.reactivex.disposables.CompositeDisposable 8 | import io.reactivex.disposables.Disposable 9 | import io.reactivex.observers.DisposableSingleObserver 10 | import io.reactivex.schedulers.Schedulers 11 | 12 | abstract class SingleUseCase( 13 | private val threadExecutor: ThreadExecutor, 14 | private val postExecutionThread: PostExecutionThread 15 | ) : IUseCase, Params> { 16 | private val disposables: CompositeDisposable = CompositeDisposable() 17 | 18 | override fun execute(observer: DisposableSingleObserver, params: Params) { 19 | Preconditions.checkNotNull(observer) 20 | val single = this.buildUseCaseSingle(params) 21 | .subscribeOn(Schedulers.from(threadExecutor)) 22 | .observeOn(postExecutionThread.scheduler) 23 | addDisposable(single.subscribeWith(observer)) 24 | } 25 | 26 | 27 | fun dispose() { 28 | if (!disposables.isDisposed) { 29 | disposables.dispose() 30 | } 31 | } 32 | 33 | abstract fun buildUseCaseSingle(params: Params): Single 34 | 35 | private fun addDisposable(disposable: Disposable) { 36 | Preconditions.checkNotNull(disposable) 37 | Preconditions.checkNotNull(disposables) 38 | disposables.add(disposable) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /domain/src/main/java/info/sanaebadi/domain/interactor/base/UseCase.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.domain.interactor.base 2 | 3 | 4 | import com.fernandocejas.arrow.checks.Preconditions 5 | import info.sanaebadi.domain.executor.PostExecutionThread 6 | import info.sanaebadi.domain.executor.ThreadExecutor 7 | import io.reactivex.Observable 8 | import io.reactivex.disposables.CompositeDisposable 9 | import io.reactivex.disposables.Disposable 10 | import io.reactivex.observers.DisposableObserver 11 | import io.reactivex.schedulers.Schedulers 12 | 13 | 14 | abstract class UseCase( 15 | private val threadExecutor: ThreadExecutor, 16 | private val postExecutionThread: PostExecutionThread 17 | ) : IUseCase, Params> { 18 | private val disposables: CompositeDisposable = CompositeDisposable() 19 | 20 | abstract fun buildUseCaseObservable(params: Params): Observable 21 | 22 | 23 | override fun execute(observer: DisposableObserver, params: Params) { 24 | Preconditions.checkNotNull(observer) 25 | val observable = this.buildUseCaseObservable(params) 26 | .subscribeOn(Schedulers.from(threadExecutor)) 27 | .observeOn(postExecutionThread.scheduler) 28 | addDisposable(observable.subscribeWith(observer)) 29 | } 30 | 31 | 32 | fun dispose() { 33 | if (!disposables.isDisposed) { 34 | disposables.dispose() 35 | } 36 | } 37 | 38 | private fun addDisposable(disposable: Disposable) { 39 | Preconditions.checkNotNull(disposable) 40 | Preconditions.checkNotNull(disposables) 41 | disposables.add(disposable) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /domain/src/main/java/info/sanaebadi/domain/interactor/user/DetailsUseCase.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.domain.interactor.user 2 | 3 | import info.sanaebadi.domain.model.UserDetailsModel 4 | import info.sanaebadi.domain.model.details.AnswerViewModel 5 | import info.sanaebadi.domain.model.details.QuestionViewModel 6 | import info.sanaebadi.domain.model.user.Answer 7 | import info.sanaebadi.domain.model.user.Question 8 | import info.sanaebadi.domain.repository.DetailsRepository 9 | import io.reactivex.Single 10 | import javax.inject.Inject 11 | 12 | class DetailsUseCase @Inject constructor(private val detailsRepository: DetailsRepository) { 13 | 14 | fun execute(userId: Long): Single { 15 | return Single.zip( 16 | detailsRepository.getQuestionsByUser(userId), 17 | getTitlesForAnswers(userId), 18 | detailsRepository.getFavoritesByUser(userId), 19 | { questions, answers, favorites -> 20 | createDetailsModel(questions, answers, favorites) 21 | }) 22 | } 23 | 24 | private fun getTitlesForAnswers(userId: Long): Single> { 25 | return detailsRepository.getAnswersByUser(userId) 26 | .flatMap { answers: List -> 27 | mapAnswersToAnswerViewModels(answers, userId) 28 | } 29 | } 30 | 31 | private fun mapAnswersToAnswerViewModels( 32 | answers: List, 33 | userId: Long 34 | ): Single> { 35 | val ids = answers 36 | .map { it.questionId } 37 | 38 | val questionsById = detailsRepository.getQuestionsById(ids, userId) 39 | 40 | return questionsById 41 | .map { questions: List -> 42 | createAnswerViewModels(answers, questions) 43 | } 44 | } 45 | 46 | private fun createAnswerViewModels( 47 | answers: List, 48 | questions: List 49 | ): List { 50 | return answers.map { (answerId, questionId, score, accepted) -> 51 | val question = questions.find { it.questionId == questionId } 52 | AnswerViewModel(answerId, score, accepted, question?.title ?: "Unknown") 53 | } 54 | } 55 | 56 | private fun createDetailsModel( 57 | questions: List, 58 | answers: List, 59 | favorites: List 60 | ): UserDetailsModel { 61 | val questionViewModels = 62 | questions.map { 63 | QuestionViewModel( 64 | it.viewCount, 65 | it.score, 66 | it.title, 67 | it.link, 68 | it.questionId 69 | ) 70 | } 71 | val favoriteViewModels = 72 | favorites.map { 73 | QuestionViewModel( 74 | it.viewCount, 75 | it.score, 76 | it.title, 77 | it.link, 78 | it.questionId 79 | ) 80 | } 81 | 82 | return UserDetailsModel(questionViewModels, answers, favoriteViewModels) 83 | } 84 | 85 | } -------------------------------------------------------------------------------- /domain/src/main/java/info/sanaebadi/domain/interactor/user/UserUseCase.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.domain.interactor.user 2 | 3 | import info.sanaebadi.domain.executor.PostExecutionThread 4 | import info.sanaebadi.domain.executor.ThreadExecutor 5 | import info.sanaebadi.domain.interactor.base.SingleUseCase 6 | import info.sanaebadi.domain.model.user.UserListModel 7 | import info.sanaebadi.domain.repository.UserRepository 8 | import io.reactivex.Single 9 | import javax.inject.Inject 10 | 11 | class UserUseCase @Inject constructor( 12 | private val userRepository: UserRepository, 13 | threadExecutor: ThreadExecutor, 14 | postExecutionThread: PostExecutionThread, 15 | ) : 16 | SingleUseCase(threadExecutor, postExecutionThread) { 17 | 18 | override fun buildUseCaseSingle(page: Int): Single { 19 | return userRepository.getUsers(page) 20 | } 21 | } -------------------------------------------------------------------------------- /domain/src/main/java/info/sanaebadi/domain/model/UserDetailsModel.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.domain.model 2 | 3 | import info.sanaebadi.domain.model.base.ViewType 4 | import info.sanaebadi.domain.model.details.AnswerViewModel 5 | import info.sanaebadi.domain.model.details.QuestionViewModel 6 | 7 | data class UserDetailsModel( 8 | val questions: List, 9 | val answers: List, 10 | val favorites: List 11 | ) : ViewType { 12 | override fun getViewType(): Int { 13 | TODO("Not yet implemented") 14 | } 15 | } -------------------------------------------------------------------------------- /domain/src/main/java/info/sanaebadi/domain/model/base/AdapterConstants.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.domain.model.base 2 | 3 | object AdapterConstants { 4 | const val USER_DETAILS = 1 5 | const val HEADING = 2 6 | const val QUESTION = 3 7 | const val ANSWER = 4 8 | const val LOADING = 5 9 | } -------------------------------------------------------------------------------- /domain/src/main/java/info/sanaebadi/domain/model/base/BaseDomainModel.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.domain.model.base 2 | 3 | interface BaseDomainModel { 4 | 5 | } -------------------------------------------------------------------------------- /domain/src/main/java/info/sanaebadi/domain/model/base/ViewType.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.domain.model.base 2 | 3 | interface ViewType { 4 | fun getViewType(): Int 5 | } -------------------------------------------------------------------------------- /domain/src/main/java/info/sanaebadi/domain/model/details/AnswerViewModel.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.domain.model.details 2 | 3 | import info.sanaebadi.domain.model.base.AdapterConstants 4 | import info.sanaebadi.domain.model.base.ViewType 5 | 6 | data class AnswerViewModel( 7 | val answerId: Long, 8 | val score: Long, 9 | val accepted: Boolean, 10 | val questionTitle: String 11 | ) : ViewType { 12 | 13 | override fun getViewType() = AdapterConstants.ANSWER 14 | } -------------------------------------------------------------------------------- /domain/src/main/java/info/sanaebadi/domain/model/details/QuestionViewModel.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.domain.model.details 2 | 3 | import info.sanaebadi.domain.model.base.AdapterConstants 4 | import info.sanaebadi.domain.model.base.ViewType 5 | 6 | data class QuestionViewModel( 7 | val viewCount: Long, 8 | val score: Long, 9 | val title: String, 10 | val link: String, 11 | val questionId: Long 12 | ) : ViewType { 13 | override fun getViewType(): Int = AdapterConstants.QUESTION 14 | 15 | } -------------------------------------------------------------------------------- /domain/src/main/java/info/sanaebadi/domain/model/user/Answer.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.domain.model.user 2 | 3 | import info.sanaebadi.domain.model.base.AdapterConstants 4 | import info.sanaebadi.domain.model.base.BaseDomainModel 5 | import info.sanaebadi.domain.model.base.ViewType 6 | 7 | data class Answer( 8 | var answerId: Long, 9 | var questionId: Long, 10 | var score: Long, 11 | var accepted: Boolean, 12 | var ownerEntity: Owner 13 | ) : BaseDomainModel { 14 | 15 | constructor() : this(-1, -1, 0, false, Owner()) 16 | } 17 | -------------------------------------------------------------------------------- /domain/src/main/java/info/sanaebadi/domain/model/user/AnswerList.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.domain.model.user 2 | 3 | import info.sanaebadi.domain.model.base.BaseDomainModel 4 | 5 | class AnswerList(val items: List) :BaseDomainModel -------------------------------------------------------------------------------- /domain/src/main/java/info/sanaebadi/domain/model/user/FavoritedByUser.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.domain.model.user 2 | 3 | import info.sanaebadi.domain.model.base.BaseDomainModel 4 | 5 | data class FavoritedByUser( 6 | var userId: Long, 7 | var questionIds: List 8 | ): BaseDomainModel { 9 | 10 | constructor() : this(-1, emptyList()) 11 | } -------------------------------------------------------------------------------- /domain/src/main/java/info/sanaebadi/domain/model/user/Owner.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.domain.model.user 2 | 3 | import info.sanaebadi.domain.model.base.BaseDomainModel 4 | 5 | 6 | 7 | data class Owner(var userId: Long) : BaseDomainModel { 8 | 9 | constructor() : this(-1) 10 | } 11 | -------------------------------------------------------------------------------- /domain/src/main/java/info/sanaebadi/domain/model/user/Question.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.domain.model.user 2 | 3 | import info.sanaebadi.domain.model.base.BaseDomainModel 4 | 5 | 6 | data class Question( 7 | var viewCount: Long, 8 | var score: Long, 9 | var title: String, 10 | var link: String, 11 | var questionId: Long, 12 | var ownerEntity: Owner 13 | ) : BaseDomainModel { 14 | 15 | 16 | constructor() : this(0, 0, "", "", -1, Owner()) 17 | } -------------------------------------------------------------------------------- /domain/src/main/java/info/sanaebadi/domain/model/user/QuestionList.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.domain.model.user 2 | 3 | import info.sanaebadi.domain.model.base.BaseDomainModel 4 | 5 | class QuestionList(val items: List) : BaseDomainModel -------------------------------------------------------------------------------- /domain/src/main/java/info/sanaebadi/domain/model/user/User.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.domain.model.user 2 | 3 | import info.sanaebadi.domain.model.base.BaseDomainModel 4 | 5 | 6 | data class User( 7 | var userId: Long, 8 | var displayName: String, 9 | var reputation: Long, 10 | var profileImage: String 11 | ) : BaseDomainModel { 12 | 13 | constructor() : this(-1, "", 0, "") 14 | } -------------------------------------------------------------------------------- /domain/src/main/java/info/sanaebadi/domain/model/user/UserListModel.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.domain.model.user 2 | 3 | import info.sanaebadi.domain.model.base.BaseDomainModel 4 | 5 | 6 | class UserListModel(val items: List) : BaseDomainModel -------------------------------------------------------------------------------- /domain/src/main/java/info/sanaebadi/domain/repository/CacheStrategy.java: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.domain.repository; 2 | 3 | public enum CacheStrategy { 4 | ONLINE_FIRST, 5 | CACHE_FIRST 6 | } 7 | -------------------------------------------------------------------------------- /domain/src/main/java/info/sanaebadi/domain/repository/DetailsRepository.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.domain.repository 2 | 3 | import info.sanaebadi.domain.model.user.Answer 4 | import info.sanaebadi.domain.model.user.Question 5 | import io.reactivex.Single 6 | 7 | interface DetailsRepository { 8 | fun getQuestionsByUser(userId: Long): Single> 9 | fun getAnswersByUser(userId: Long): Single> 10 | fun getFavoritesByUser(userId: Long): Single> 11 | fun getQuestionsById(ids: List, userId: Long): Single> 12 | } -------------------------------------------------------------------------------- /domain/src/main/java/info/sanaebadi/domain/repository/UserRepository.kt: -------------------------------------------------------------------------------- 1 | package info.sanaebadi.domain.repository 2 | 3 | import info.sanaebadi.domain.model.user.UserListModel 4 | import io.reactivex.Single 5 | 6 | interface UserRepository { 7 | fun getUsers(page: Int): Single 8 | } -------------------------------------------------------------------------------- /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 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/Sanaebadi97/StackOverFlowApi/a240e4e0f29d4af06da7d80cb638e3552e074e47/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Thu Sep 17 18:44:23 IRDT 2020 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.1.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | 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 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | include(":domain") 2 | include(":data") 3 | include (":app") 4 | rootProject.name = "StackOverFlowProject" --------------------------------------------------------------------------------