├── .gitignore ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── me │ │ └── ibrahimsn │ │ └── wdevtools │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── me │ │ │ └── ibrahimsn │ │ │ └── wdevtools │ │ │ ├── BaseApplication.kt │ │ │ ├── di │ │ │ ├── AppDataModule.kt │ │ │ ├── AppDomainModule.kt │ │ │ └── AppViewModelModule.kt │ │ │ └── ui │ │ │ └── MainActivity.kt │ └── res │ │ ├── drawable │ │ └── ic_launcher_foreground.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── ic_launcher_background.xml │ │ └── strings.xml │ └── test │ └── java │ └── me │ └── ibrahimsn │ └── wdevtools │ └── ExampleUnitTest.kt ├── art ├── 1.png ├── 2.png ├── 3.png └── 4.png ├── build.gradle ├── buildSrc ├── build.gradle.kts ├── build │ ├── classes │ │ └── kotlin │ │ │ └── main │ │ │ ├── CoreLibraries.class │ │ │ ├── Libraries.class │ │ │ ├── META-INF │ │ │ └── buildSrc.kotlin_module │ │ │ ├── Modules.class │ │ │ ├── Plugins.class │ │ │ ├── SupportLibraries.class │ │ │ └── Versions.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 │ │ │ │ │ ├── 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 │ │ └── task-properties │ │ │ └── report.txt │ └── tmp │ │ └── jar │ │ └── MANIFEST.MF └── src │ └── main │ └── java │ ├── Dependencies.kt │ ├── Modules.kt │ ├── Plugins.kt │ └── Versions.kt ├── common.gradle ├── core ├── .gitignore ├── build.gradle ├── consumer-rules.pro ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── me │ │ └── ibrahimsn │ │ └── core │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── me │ │ │ └── ibrahimsn │ │ │ └── core │ │ │ ├── data │ │ │ ├── dao │ │ │ │ ├── RequestDao.kt │ │ │ │ └── WebsocketDao.kt │ │ │ ├── database │ │ │ │ ├── AppDatabase.kt │ │ │ │ └── Converters.kt │ │ │ ├── di │ │ │ │ ├── DataModule.kt │ │ │ │ ├── HttpModule.kt │ │ │ │ ├── RequestDataModule.kt │ │ │ │ ├── UriDataModule.kt │ │ │ │ └── WebsocketDataModule.kt │ │ │ ├── model │ │ │ │ ├── DataHolder.kt │ │ │ │ ├── DefaultTextWatcher.kt │ │ │ │ ├── ErrorHolder.kt │ │ │ │ └── RequestMethod.kt │ │ │ ├── repository │ │ │ │ ├── RequestRepositoryImpl.kt │ │ │ │ ├── UriRepositoryImpl.kt │ │ │ │ └── WebsocketRepositoryImpl.kt │ │ │ └── source │ │ │ │ └── DefaultPreferences.kt │ │ │ ├── domain │ │ │ ├── Constants.kt │ │ │ ├── di │ │ │ │ ├── RequestDomainModule.kt │ │ │ │ ├── UriDomainModule.kt │ │ │ │ └── WebsocketDomainModule.kt │ │ │ ├── interactor │ │ │ │ ├── Interactor.kt │ │ │ │ ├── request │ │ │ │ │ ├── DeleteRequestsInteractor.kt │ │ │ │ │ ├── GetAllRequestsInteractor.kt │ │ │ │ │ ├── MakeRequestInteractor.kt │ │ │ │ │ └── SaveOrUpdateRequestInteractor.kt │ │ │ │ ├── uri │ │ │ │ │ ├── GenerateUriInteractor.kt │ │ │ │ │ └── ParseUriParamsInteractor.kt │ │ │ │ └── websocket │ │ │ │ │ ├── ConnectWebsocketInteractor.kt │ │ │ │ │ ├── DeleteWebsocketsInteractor.kt │ │ │ │ │ ├── GetAllWebsocketsInteractor.kt │ │ │ │ │ └── SaveOrUpdateWebsocketInteractor.kt │ │ │ ├── model │ │ │ │ ├── param │ │ │ │ │ └── Param.kt │ │ │ │ ├── request │ │ │ │ │ ├── Request.kt │ │ │ │ │ └── RequestResponse.kt │ │ │ │ └── websocket │ │ │ │ │ ├── Websocket.kt │ │ │ │ │ └── WebsocketEvent.kt │ │ │ ├── repository │ │ │ │ ├── RequestRepository.kt │ │ │ │ ├── UriRepository.kt │ │ │ │ └── WebsocketRepository.kt │ │ │ └── source │ │ │ │ └── LocalDataSource.kt │ │ │ └── presentation │ │ │ ├── Constants.kt │ │ │ ├── base │ │ │ ├── BaseActivity.kt │ │ │ ├── BaseAdapter.kt │ │ │ ├── BaseFragment.kt │ │ │ ├── BasePagedAdapter.kt │ │ │ ├── BaseViewHolder.kt │ │ │ └── BaseViewModel.kt │ │ │ ├── extension │ │ │ ├── AdExt.kt │ │ │ ├── CoroutineScopeExt.kt │ │ │ ├── DateExt.kt │ │ │ ├── GsonExt.kt │ │ │ ├── LifecycleExt.kt │ │ │ ├── LiveDataExt.kt │ │ │ ├── RequestExt.kt │ │ │ ├── StringExt.kt │ │ │ ├── ViewExt.kt │ │ │ └── WebsocketExt.kt │ │ │ ├── livedata │ │ │ └── SingleLiveEvent.kt │ │ │ ├── model │ │ │ └── ConsentManager.kt │ │ │ ├── ui │ │ │ └── param │ │ │ │ └── ParamAdapter.kt │ │ │ └── view │ │ │ ├── progressButton │ │ │ └── ProgressButton.kt │ │ │ └── tabView │ │ │ ├── TabItem.kt │ │ │ ├── TabParser.kt │ │ │ └── TabView.kt │ └── res │ │ ├── drawable │ │ ├── ic_add_white_24dp.xml │ │ ├── ic_background_box.xml │ │ ├── ic_background_method.xml │ │ ├── ic_background_method_delete.xml │ │ ├── ic_background_method_get.xml │ │ ├── ic_background_method_patch.xml │ │ ├── ic_background_method_post.xml │ │ ├── ic_background_method_put.xml │ │ ├── ic_background_param_button.xml │ │ ├── ic_background_response_status_fail.xml │ │ ├── ic_background_response_status_success.xml │ │ ├── ic_background_row.xml │ │ ├── ic_close_white_18dp.xml │ │ ├── ic_close_white_20dp.xml │ │ ├── ic_close_white_24dp.xml │ │ ├── ic_delete_white_24dp.xml │ │ ├── ic_expand_less_white_24dp.xml │ │ ├── ic_expand_more_white_24dp.xml │ │ ├── ic_keyboard_arrow_right_white_18dp.xml │ │ ├── ic_send_white_20dp.xml │ │ └── ic_send_white_24dp.xml │ │ ├── font │ │ ├── lato.xml │ │ ├── lato_bold.ttf │ │ └── lato_regular.ttf │ │ ├── layout │ │ └── row_param.xml │ │ └── values │ │ ├── attrs.xml │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── me │ └── ibrahimsn │ └── core │ └── ExampleUnitTest.kt ├── feature ├── dashboard │ ├── .gitignore │ ├── build.gradle │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ └── src │ │ ├── androidTest │ │ └── java │ │ │ └── me │ │ │ └── ibrahimsn │ │ │ └── dashboard │ │ │ └── ExampleInstrumentedTest.kt │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ │ └── me │ │ │ │ └── ibrahimsn │ │ │ │ └── dashboard │ │ │ │ ├── di │ │ │ │ └── DashboardViewModelModule.kt │ │ │ │ └── presentation │ │ │ │ ├── dashboard │ │ │ │ ├── DashboardFragment.kt │ │ │ │ ├── DashboardViewModel.kt │ │ │ │ ├── RequestsAdapter.kt │ │ │ │ └── WebsocketsAdapter.kt │ │ │ │ ├── home │ │ │ │ └── HomeActivity.kt │ │ │ │ └── settings │ │ │ │ ├── SettingsActivity.kt │ │ │ │ └── SettingsFragment.kt │ │ └── res │ │ │ ├── layout │ │ │ ├── activity_home.xml │ │ │ ├── activity_settings.xml │ │ │ ├── fragment_dashboard.xml │ │ │ ├── fragment_settings.xml │ │ │ ├── row_rest.xml │ │ │ └── row_ws.xml │ │ │ ├── menu │ │ │ ├── menu_action.xml │ │ │ ├── menu_home.xml │ │ │ └── menu_tabs.xml │ │ │ ├── values │ │ │ └── strings.xml │ │ │ └── xml │ │ │ └── settings.xml │ │ └── test │ │ └── java │ │ └── me │ │ └── ibrahimsn │ │ └── dashboard │ │ └── ExampleUnitTest.kt ├── request │ ├── .gitignore │ ├── build.gradle │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ └── src │ │ ├── androidTest │ │ └── java │ │ │ └── me │ │ │ └── ibrahimsn │ │ │ └── request │ │ │ └── ExampleInstrumentedTest.kt │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ │ └── me │ │ │ │ └── ibrahimsn │ │ │ │ └── request │ │ │ │ ├── di │ │ │ │ └── RequestViewModelModule.kt │ │ │ │ └── presentation │ │ │ │ └── request │ │ │ │ ├── RequestFragment.kt │ │ │ │ └── RequestViewModel.kt │ │ └── res │ │ │ ├── layout │ │ │ └── fragment_rest.xml │ │ │ └── menu │ │ │ └── menu_request_method.xml │ │ └── test │ │ └── java │ │ └── me │ │ └── ibrahimsn │ │ └── request │ │ └── ExampleUnitTest.kt └── websocket │ ├── .gitignore │ ├── build.gradle │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ └── src │ ├── androidTest │ └── java │ │ └── me │ │ └── ibrahimsn │ │ └── websocket │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── me │ │ │ └── ibrahimsn │ │ │ └── websocket │ │ │ ├── di │ │ │ └── WebsocketViewModelModule.kt │ │ │ └── presentation │ │ │ └── websocket │ │ │ ├── WebsocketFragment.kt │ │ │ └── WebsocketViewModel.kt │ └── res │ │ └── layout │ │ └── fragment_ws.xml │ └── test │ └── java │ └── me │ └── ibrahimsn │ └── websocket │ └── ExampleUnitTest.kt ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── navigation ├── .gitignore ├── build.gradle ├── consumer-rules.pro ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── me │ │ └── ibrahimsn │ │ └── navigation │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ └── res │ │ ├── navigation │ │ └── nav_graph.xml │ │ └── values │ │ └── strings.xml │ └── test │ └── java │ └── me │ └── ibrahimsn │ └── navigation │ └── ExampleUnitTest.kt └── settings.gradle /.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 16 | /app/google-services.json 17 | /.gradle -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Web Developer Tools Android 2 | 3 | Sample Android Application - MVVM, Clean Architecture, Modularization, Repository Pattern 4 | 5 | 6 | ## Tech Stack 7 | ``` 8 | - Kotlin 9 | - MVVM 10 | - Modularization 11 | - Repository Pattern 12 | - Coroutines 13 | - Koin 14 | - Architecture Components 15 | - Navigation Component 16 | - LiveData 17 | - Paging 18 | - Kotlin DSL 19 | - OkHttp3 20 | ``` 21 | 22 | ## Screenshots 23 | 24 | 25 | 28 | 31 | 34 | 37 | 38 |
26 | 27 | 29 | 30 | 32 | 33 | 35 | 36 |
39 | 40 | 41 | ## Google Play 42 | Download Web Dev Tools from [Google Play](https://play.google.com/store/apps/details?id=me.ibrahimsn.wdevtools). 43 | 44 | 45 | ## License 46 | Licensed under [GNU AGPLv3](https://github.com/ibrahimsn98/web-dev-tools-android/blob/master/LICENSE) 47 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: Plugins.androidApplication 2 | apply from: "$rootDir/common.gradle" 3 | apply plugin: Plugins.crashlytics 4 | apply plugin: Plugins.googleServices 5 | 6 | android { 7 | defaultConfig { 8 | applicationId "me.ibrahimsn.wdevtools" 9 | } 10 | } 11 | 12 | dependencies { 13 | implementation fileTree(dir: 'libs', include: ['*.jar']) 14 | implementation CoreLibraries.kotlin 15 | 16 | implementation project(Modules.core) 17 | implementation project(Modules.navigation) 18 | 19 | implementation project(Modules.dashboard) 20 | implementation project(Modules.request) 21 | implementation project(Modules.websocket) 22 | } 23 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | 23 | -keep class com.google.firebase.** { *; } 24 | -dontwarn okhttp3.** 25 | -dontwarn okio.** 26 | -keep class com.crashlytics.sdk.android.** { *; } -------------------------------------------------------------------------------- /app/src/androidTest/java/me/ibrahimsn/wdevtools/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.wdevtools 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("me.ibrahimsn.wdevtools", appContext.packageName) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 16 | 17 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/java/me/ibrahimsn/wdevtools/BaseApplication.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.wdevtools 2 | 3 | import android.app.Application 4 | import me.ibrahimsn.core.domain.source.LocalDataSource 5 | import me.ibrahimsn.core.presentation.model.ConsentManager 6 | import me.ibrahimsn.wdevtools.di.appDataModule 7 | import me.ibrahimsn.wdevtools.di.appDomainModule 8 | import me.ibrahimsn.wdevtools.di.appViewModelModule 9 | import org.koin.android.ext.android.inject 10 | import org.koin.android.ext.koin.androidContext 11 | import org.koin.android.ext.koin.androidLogger 12 | import org.koin.core.context.startKoin 13 | 14 | class BaseApplication : Application() { 15 | 16 | private val preferences: LocalDataSource.Preferences by inject() 17 | 18 | override fun onCreate() { 19 | super.onCreate() 20 | startInject() 21 | onInject() 22 | } 23 | 24 | private fun startInject() { 25 | val appModules = appDataModule + appDomainModule + appViewModelModule 26 | startKoin { 27 | androidLogger() 28 | androidContext(this@BaseApplication) 29 | modules(appModules) 30 | } 31 | } 32 | 33 | private fun onInject() { 34 | ConsentManager.setupPreferences(preferences) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/java/me/ibrahimsn/wdevtools/di/AppDataModule.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.wdevtools.di 2 | 3 | import me.ibrahimsn.core.data.di.* 4 | 5 | val appDataModule = listOf( 6 | dataModule, 7 | httpModule, 8 | requestDataModule, 9 | websocketDataModule, 10 | uriDataModule 11 | ) 12 | -------------------------------------------------------------------------------- /app/src/main/java/me/ibrahimsn/wdevtools/di/AppDomainModule.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.wdevtools.di 2 | 3 | import me.ibrahimsn.core.domain.di.requestDomainModule 4 | import me.ibrahimsn.core.domain.di.uriDomainModule 5 | import me.ibrahimsn.core.domain.di.websocketDomainModule 6 | 7 | val appDomainModule = listOf( 8 | requestDomainModule, 9 | websocketDomainModule, 10 | uriDomainModule 11 | ) 12 | -------------------------------------------------------------------------------- /app/src/main/java/me/ibrahimsn/wdevtools/di/AppViewModelModule.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.wdevtools.di 2 | 3 | import me.ibrahimsn.dashboard.di.dashboardViewModelModule 4 | import me.ibrahimsn.request.di.requestViewModelModule 5 | import me.ibrahimsn.websocket.di.websocketViewModelModule 6 | 7 | val appViewModelModule = listOf( 8 | dashboardViewModelModule, 9 | requestViewModelModule, 10 | websocketViewModelModule 11 | ) 12 | -------------------------------------------------------------------------------- /app/src/main/java/me/ibrahimsn/wdevtools/ui/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.wdevtools.ui 2 | 3 | import android.content.Intent 4 | import android.os.Bundle 5 | import androidx.appcompat.app.AppCompatActivity 6 | import me.ibrahimsn.wdevtools.R 7 | import me.ibrahimsn.dashboard.presentation.home.HomeActivity 8 | 9 | class MainActivity : AppCompatActivity() { 10 | 11 | override fun onCreate(savedInstanceState: Bundle?) { 12 | super.onCreate(savedInstanceState) 13 | startActivity(Intent(this, HomeActivity::class.java)) 14 | finish() 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 6 | 8 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /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/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3EB63E 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Dev Tools 3 | 4 | -------------------------------------------------------------------------------- /app/src/test/java/me/ibrahimsn/wdevtools/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.wdevtools 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 | } 18 | -------------------------------------------------------------------------------- /art/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/art/1.png -------------------------------------------------------------------------------- /art/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/art/2.png -------------------------------------------------------------------------------- /art/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/art/3.png -------------------------------------------------------------------------------- /art/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/art/4.png -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | ext.kotlin_version = '1.3.72' 5 | repositories { 6 | google() 7 | jcenter() 8 | maven { url 'https://jitpack.io' } 9 | } 10 | dependencies { 11 | classpath 'com.android.tools.build:gradle:3.6.3' 12 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 13 | classpath 'com.google.gms:google-services:4.3.3' 14 | classpath 'com.google.firebase:firebase-crashlytics-gradle:2.0.0' 15 | // NOTE: Do not place your application dependencies here; they belong 16 | // in the individual module build.gradle files 17 | } 18 | } 19 | 20 | allprojects { 21 | repositories { 22 | google() 23 | jcenter() 24 | maven { url 'https://jitpack.io' } 25 | } 26 | } 27 | 28 | task clean(type: Delete) { 29 | delete rootProject.buildDir 30 | } 31 | -------------------------------------------------------------------------------- /buildSrc/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.gradle.kotlin.dsl.`kotlin-dsl` 2 | 3 | plugins { 4 | `kotlin-dsl` 5 | } 6 | 7 | repositories { 8 | jcenter() 9 | } 10 | -------------------------------------------------------------------------------- /buildSrc/build/classes/kotlin/main/CoreLibraries.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/buildSrc/build/classes/kotlin/main/CoreLibraries.class -------------------------------------------------------------------------------- /buildSrc/build/classes/kotlin/main/Libraries.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/buildSrc/build/classes/kotlin/main/Libraries.class -------------------------------------------------------------------------------- /buildSrc/build/classes/kotlin/main/META-INF/buildSrc.kotlin_module: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /buildSrc/build/classes/kotlin/main/Modules.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/buildSrc/build/classes/kotlin/main/Modules.class -------------------------------------------------------------------------------- /buildSrc/build/classes/kotlin/main/Plugins.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/buildSrc/build/classes/kotlin/main/Plugins.class -------------------------------------------------------------------------------- /buildSrc/build/classes/kotlin/main/SupportLibraries.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/buildSrc/build/classes/kotlin/main/SupportLibraries.class -------------------------------------------------------------------------------- /buildSrc/build/classes/kotlin/main/Versions.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/buildSrc/build/classes/kotlin/main/Versions.class -------------------------------------------------------------------------------- /buildSrc/build/kotlin/buildSrcjar-classes.txt: -------------------------------------------------------------------------------- 1 | /home/melianor/Android Projects/open-source/webdevtools/buildSrc/build/classes/kotlin/main/CoreLibraries.class:/home/melianor/Android Projects/open-source/webdevtools/buildSrc/build/classes/kotlin/main/Libraries.class:/home/melianor/Android Projects/open-source/webdevtools/buildSrc/build/classes/kotlin/main/Modules.class:/home/melianor/Android Projects/open-source/webdevtools/buildSrc/build/classes/kotlin/main/Plugins.class:/home/melianor/Android Projects/open-source/webdevtools/buildSrc/build/classes/kotlin/main/SupportLibraries.class:/home/melianor/Android Projects/open-source/webdevtools/buildSrc/build/classes/kotlin/main/Versions.class -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/build-history.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/buildSrc/build/kotlin/compileKotlin/build-history.bin -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/buildSrc/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.keystream: -------------------------------------------------------------------------------- 1 | Y/home/melianor/Android Projects/open-source/webdevtools/buildSrc/src/main/java/Modules.kt^/home/melianor/Android Projects/open-source/webdevtools/buildSrc/src/main/java/Dependencies.ktY/home/melianor/Android Projects/open-source/webdevtools/buildSrc/src/main/java/Plugins.ktZ/home/melianor/Android Projects/open-source/webdevtools/buildSrc/src/main/java/Versions.kt -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.keystream.len: -------------------------------------------------------------------------------- 1 | n -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.len: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/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/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/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/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/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/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/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/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/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.len: -------------------------------------------------------------------------------- 1 | B -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.len: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/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 PersistentHashMapValueStorage_^/home/melianor/Android Projects/open-source/webdevtools/buildSrc/src/main/java/Dependencies.kt_^/home/melianor/Android Projects/open-source/webdevtools/buildSrc/src/main/java/Dependencies.kt_^/home/melianor/Android Projects/open-source/webdevtools/buildSrc/src/main/java/Dependencies.ktZY/home/melianor/Android Projects/open-source/webdevtools/buildSrc/src/main/java/Modules.ktZY/home/melianor/Android Projects/open-source/webdevtools/buildSrc/src/main/java/Plugins.kt[Z/home/melianor/Android Projects/open-source/webdevtools/buildSrc/src/main/java/Versions.kt -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/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/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/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/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.keystream: -------------------------------------------------------------------------------- 1 | CoreLibrariesSupportLibraries LibrariesModulesPluginsVersions -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.keystream.len: -------------------------------------------------------------------------------- 1 | B -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.len: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.len -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.values.at: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/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/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/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/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/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/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/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 | B -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab.len: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab.len -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab.values.at: -------------------------------------------------------------------------------- 1 | /Header Record For PersistentHashMapValueStorage_^/home/melianor/Android Projects/open-source/webdevtools/buildSrc/src/main/java/Dependencies.kt_^/home/melianor/Android Projects/open-source/webdevtools/buildSrc/src/main/java/Dependencies.kt_^/home/melianor/Android Projects/open-source/webdevtools/buildSrc/src/main/java/Dependencies.ktZY/home/melianor/Android Projects/open-source/webdevtools/buildSrc/src/main/java/Modules.ktZY/home/melianor/Android Projects/open-source/webdevtools/buildSrc/src/main/java/Plugins.kt[Z/home/melianor/Android Projects/open-source/webdevtools/buildSrc/src/main/java/Versions.kt -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/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/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i.len -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.keystream: -------------------------------------------------------------------------------- 1 | CoreLibrariesSupportLibraries LibrariesModulesPluginsVersions.kotlin_module -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.keystream.len: -------------------------------------------------------------------------------- 1 | Q -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.len: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.len -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.values.at: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/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/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/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/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/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/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/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.len: -------------------------------------------------------------------------------- 1 | n -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab.len: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/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: -------------------------------------------------------------------------------- 1 | /Header Record For PersistentHashMapValueStorageModules.kotlin_module8 CoreLibrariesSupportLibraries Libraries.kotlin_modulePlugins.kotlin_moduleVersions.kotlin_module -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab_i: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/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/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab_i.len -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/counters.tab: -------------------------------------------------------------------------------- 1 | 4 2 | 0 -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.keystream: -------------------------------------------------------------------------------- 1 | Y/home/melianor/Android Projects/open-source/webdevtools/buildSrc/src/main/java/Plugins.ktY/home/melianor/Android Projects/open-source/webdevtools/buildSrc/src/main/java/Modules.kt^/home/melianor/Android Projects/open-source/webdevtools/buildSrc/src/main/java/Dependencies.ktZ/home/melianor/Android Projects/open-source/webdevtools/buildSrc/src/main/java/Versions.kt -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.keystream.len: -------------------------------------------------------------------------------- 1 | n -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.len: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/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/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/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/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/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/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/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/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/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 PersistentHashMapValueStorageZY/home/melianor/Android Projects/open-source/webdevtools/buildSrc/src/main/java/Plugins.ktZY/home/melianor/Android Projects/open-source/webdevtools/buildSrc/src/main/java/Modules.kt_^/home/melianor/Android Projects/open-source/webdevtools/buildSrc/src/main/java/Dependencies.kt[Z/home/melianor/Android Projects/open-source/webdevtools/buildSrc/src/main/java/Versions.kt -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab_i: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/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/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/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/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.keystream: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/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/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/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/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/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/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab_i.len -------------------------------------------------------------------------------- /buildSrc/build/kotlin/compileKotlin/last-build.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/buildSrc/build/kotlin/compileKotlin/last-build.bin -------------------------------------------------------------------------------- /buildSrc/build/libs/buildSrc.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/buildSrc/build/libs/buildSrc.jar -------------------------------------------------------------------------------- /buildSrc/build/pluginUnderTestMetadata/plugin-under-test-metadata.properties: -------------------------------------------------------------------------------- 1 | implementation-classpath=/home/melianor/Android Projects/open-source/webdevtools/buildSrc/build/classes/java/main\:/home/melianor/Android Projects/open-source/webdevtools/buildSrc/build/classes/groovy/main\:/home/melianor/Android Projects/open-source/webdevtools/buildSrc/build/classes/kotlin/main\:/home/melianor/Android Projects/open-source/webdevtools/buildSrc/build/resources/main 2 | -------------------------------------------------------------------------------- /buildSrc/build/reports/task-properties/report.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/buildSrc/build/reports/task-properties/report.txt -------------------------------------------------------------------------------- /buildSrc/build/tmp/jar/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | 3 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/Dependencies.kt: -------------------------------------------------------------------------------- 1 | object CoreLibraries { 2 | const val kotlin = "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${Versions.kotlinVersion}" 3 | } 4 | 5 | object SupportLibraries { 6 | const val core = "androidx.core:core-ktx:${Versions.coreVersion}" 7 | const val appCompat = "androidx.appcompat:appcompat:${Versions.appCompatVersion}" 8 | const val constraintLayout = "androidx.constraintlayout:constraintlayout:${Versions.constraintVersion}" 9 | const val preference = "androidx.preference:preference-ktx:${Versions.preferenceVersion}" 10 | } 11 | 12 | object Libraries { 13 | const val coroutinesCore = "org.jetbrains.kotlinx:kotlinx-coroutines-core:${Versions.coroutinesVersion}" 14 | const val coroutinesAndroid = "org.jetbrains.kotlinx:kotlinx-coroutines-android:${Versions.coroutinesVersion}" 15 | 16 | const val lifecycleExtensions = "androidx.lifecycle:lifecycle-extensions:${Versions.lifecycleVersion}" 17 | const val lifecycleViewModel = "androidx.lifecycle:lifecycle-viewmodel-ktx:${Versions.lifecycleVersion}" 18 | const val lifecycleCompiler = "androidx.lifecycle:lifecycle-compiler:${Versions.lifecycleVersion}" 19 | 20 | const val navigation = "androidx.navigation:navigation-fragment-ktx:${Versions.navigationVersion}" 21 | const val navigationUi = "androidx.navigation:navigation-ui-ktx:${Versions.navigationVersion}" 22 | 23 | const val koin = "org.koin:koin-core:${Versions.koinVersion}" 24 | const val koinScope = "org.koin:koin-androidx-scope:${Versions.koinVersion}" 25 | const val koinViewModel = "org.koin:koin-androidx-viewmodel:${Versions.koinVersion}" 26 | const val koinAndroidExt = "org.koin:koin-androidx-ext:${Versions.koinVersion}" 27 | 28 | const val room = "androidx.room:room-runtime:${Versions.roomVersion}" 29 | const val roomKtx = "androidx.room:room-ktx:${Versions.roomVersion}" 30 | const val roomCompiler = "androidx.room:room-compiler:${Versions.roomVersion}" 31 | 32 | const val paging = "androidx.paging:paging-runtime:${Versions.pagingVersion}" 33 | 34 | const val firebaseAnalytics = "com.google.firebase:firebase-analytics:${Versions.firebaseAnalyticsVersion}" 35 | const val firebaseCrashlytics = "com.google.firebase:firebase-crashlytics:${Versions.crashlyticsVersion}" 36 | const val firebaseAds = "com.google.android.gms:play-services-ads:${Versions.firebaseAdsVersion}" 37 | const val consent = "com.google.android.ads.consent:consent-library:${Versions.consentVersion}" 38 | 39 | const val okHttp = "com.squareup.okhttp3:okhttp:${Versions.okHttpVersion}" 40 | const val gson = "com.google.code.gson:gson:${Versions.gsonVersion}" 41 | } 42 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/Modules.kt: -------------------------------------------------------------------------------- 1 | object Modules { 2 | 3 | const val app = ":app" 4 | const val core = ":core" 5 | const val navigation = ":navigation" 6 | 7 | const val dashboard = ":feature:dashboard" 8 | const val request = ":feature:request" 9 | const val websocket = ":feature:websocket" 10 | } 11 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/Plugins.kt: -------------------------------------------------------------------------------- 1 | object Plugins { 2 | 3 | const val androidApplication = "com.android.application" 4 | const val kotlinAndroid = "kotlin-android" 5 | const val androidLibrary = "com.android.library" 6 | const val kotlinAndroidExtensions = "kotlin-android-extensions" 7 | const val kotlinKapt = "kotlin-kapt" 8 | const val crashlytics = "com.google.firebase.crashlytics" 9 | const val googleServices = "com.google.gms.google-services" 10 | } 11 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/Versions.kt: -------------------------------------------------------------------------------- 1 | object Versions { 2 | 3 | const val kotlinVersion = "1.3.71" 4 | 5 | const val coreVersion = "1.2.0" 6 | const val appCompatVersion = "1.1.0" 7 | const val constraintVersion = "1.1.3" 8 | const val preferenceVersion = "1.1.0" 9 | 10 | const val coroutinesVersion = "1.3.3" 11 | const val lifecycleVersion = "2.2.0" 12 | const val navigationVersion = "2.3.0-alpha04" 13 | const val koinVersion = "2.1.4" 14 | const val pagingVersion = "2.1.2" 15 | const val roomVersion = "2.2.5" 16 | 17 | const val firebaseAnalyticsVersion = "17.2.3" 18 | const val crashlyticsVersion = "17.0.0-beta02" 19 | const val firebaseAdsVersion = "19.1.0" 20 | const val consentVersion = "1.0.8" 21 | 22 | const val okHttpVersion = "4.6.0" 23 | const val gsonVersion = "2.8.6" 24 | } 25 | -------------------------------------------------------------------------------- /common.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: Plugins.kotlinAndroid 2 | apply plugin: Plugins.kotlinAndroidExtensions 3 | apply plugin: Plugins.kotlinKapt 4 | 5 | android { 6 | compileSdkVersion 29 7 | buildToolsVersion "29.0.2" 8 | 9 | defaultConfig { 10 | minSdkVersion 21 11 | targetSdkVersion 29 12 | versionCode 9 13 | versionName "1.0.8" 14 | 15 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 16 | } 17 | 18 | buildTypes { 19 | release { 20 | minifyEnabled true 21 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 22 | } 23 | } 24 | 25 | kotlinOptions { 26 | jvmTarget = "1.8" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /core/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /core/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: Plugins.androidLibrary 2 | apply from: "$rootDir/common.gradle" 3 | 4 | dependencies { 5 | api CoreLibraries.kotlin 6 | 7 | api SupportLibraries.core 8 | api SupportLibraries.preference 9 | api SupportLibraries.appCompat 10 | api SupportLibraries.constraintLayout 11 | 12 | api Libraries.koin 13 | api Libraries.koinViewModel 14 | api Libraries.koinScope 15 | 16 | api Libraries.lifecycleViewModel 17 | api Libraries.lifecycleExtensions 18 | kapt Libraries.lifecycleCompiler 19 | 20 | api Libraries.room 21 | api Libraries.roomKtx 22 | kapt Libraries.roomCompiler 23 | 24 | api Libraries.okHttp 25 | api Libraries.gson 26 | api Libraries.paging 27 | 28 | api Libraries.firebaseAnalytics 29 | api Libraries.firebaseCrashlytics 30 | api Libraries.firebaseAds 31 | api Libraries.consent 32 | } 33 | -------------------------------------------------------------------------------- /core/consumer-rules.pro: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/core/consumer-rules.pro -------------------------------------------------------------------------------- /core/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /core/src/androidTest/java/me/ibrahimsn/core/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core 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("me.ibrahimsn.core.test", appContext.packageName) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /core/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/data/dao/RequestDao.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.data.dao 2 | 3 | import androidx.paging.DataSource 4 | import androidx.room.* 5 | import me.ibrahimsn.core.domain.model.request.Request 6 | 7 | @Dao 8 | abstract class RequestDao { 9 | 10 | @Query("SELECT * from requests") 11 | abstract fun getAll(): DataSource.Factory 12 | 13 | @Insert(onConflict = OnConflictStrategy.IGNORE) 14 | abstract suspend fun insertAsync(request: Request): Long 15 | 16 | @Update 17 | abstract suspend fun update(request: Request) 18 | 19 | @Delete 20 | abstract suspend fun delete(request: Request) 21 | 22 | @Transaction 23 | open suspend fun insertOrUpdate(request: Request): Long? { 24 | val insert = insertAsync(request) 25 | if (insert != -1L) return insert 26 | 27 | update(request) 28 | return request.id 29 | } 30 | 31 | @Transaction 32 | open suspend fun delete(requests: List) { 33 | for (request in requests) { 34 | delete(request) 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/data/dao/WebsocketDao.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.data.dao 2 | 3 | import androidx.paging.DataSource 4 | import androidx.room.* 5 | import me.ibrahimsn.core.domain.model.websocket.Websocket 6 | 7 | @Dao 8 | abstract class WebsocketDao { 9 | 10 | @Query("SELECT * from websockets") 11 | abstract fun getAll(): DataSource.Factory 12 | 13 | @Insert(onConflict = OnConflictStrategy.IGNORE) 14 | abstract suspend fun insertAsync(websocket: Websocket): Long 15 | 16 | @Update 17 | abstract suspend fun update(websocket: Websocket) 18 | 19 | @Delete 20 | abstract suspend fun delete(websocket: Websocket) 21 | 22 | @Transaction 23 | open suspend fun insertOrUpdate(websocket: Websocket): Long? { 24 | val insert = insertAsync(websocket) 25 | if (insert != -1L) return insert 26 | 27 | update(websocket) 28 | return websocket.id 29 | } 30 | 31 | @Transaction 32 | open suspend fun delete(websockets: List) { 33 | for (websocket in websockets) { 34 | delete(websocket) 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/data/database/AppDatabase.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.data.database 2 | 3 | import android.content.Context 4 | import androidx.room.Database 5 | import androidx.room.Room 6 | import androidx.room.RoomDatabase 7 | import androidx.room.TypeConverters 8 | import me.ibrahimsn.core.data.dao.RequestDao 9 | import me.ibrahimsn.core.data.dao.WebsocketDao 10 | import me.ibrahimsn.core.domain.model.request.Request 11 | import me.ibrahimsn.core.domain.model.websocket.Websocket 12 | 13 | @Database(entities = [Request::class, Websocket::class], version = 1, exportSchema = false) 14 | @TypeConverters(Converters::class) 15 | abstract class AppDatabase : RoomDatabase() { 16 | 17 | abstract fun httpRequestDao(): RequestDao 18 | abstract fun webSocketDao(): WebsocketDao 19 | 20 | companion object { 21 | 22 | @Volatile 23 | private var INSTANCE: AppDatabase? = null 24 | 25 | fun getDatabase(context: Context): AppDatabase { 26 | 27 | val tempInstance = INSTANCE 28 | 29 | if (tempInstance != null) 30 | return tempInstance 31 | 32 | synchronized(this) { 33 | val instance = Room.databaseBuilder(context, AppDatabase::class.java, "wdevtools").build() 34 | INSTANCE = instance 35 | return instance 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/data/database/Converters.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.data.database 2 | 3 | import androidx.room.TypeConverter 4 | import me.ibrahimsn.core.data.model.RequestMethod 5 | import java.util.* 6 | 7 | class Converters { 8 | 9 | @TypeConverter 10 | fun toRequestMethod(value: Int) = enumValues()[value] 11 | 12 | @TypeConverter 13 | fun fromRequestMethod(value: RequestMethod) = value.ordinal 14 | 15 | @TypeConverter 16 | fun fromTimestamp(value: Long?): Date? { 17 | return value?.let { Date(it) } 18 | } 19 | 20 | @TypeConverter 21 | fun dateToTimestamp(date: Date?): Long? { 22 | return date?.time 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/data/di/DataModule.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.data.di 2 | 3 | import android.content.Context 4 | import android.content.SharedPreferences 5 | import me.ibrahimsn.core.data.database.AppDatabase 6 | import me.ibrahimsn.core.data.source.DefaultPreferences 7 | import me.ibrahimsn.core.domain.source.LocalDataSource 8 | import org.koin.dsl.module 9 | 10 | private const val SECRET_KEY = "t3sT_m4sT3r_k3Y" 11 | 12 | val dataModule = module { 13 | 14 | single { 15 | provideSharedPrefs(context = get()) 16 | } 17 | 18 | single { 19 | providePreferences(sharedPreferences = get()) 20 | } 21 | 22 | factory { 23 | AppDatabase.getDatabase(context = get()) 24 | } 25 | } 26 | 27 | private fun provideSharedPrefs(context: Context): SharedPreferences = context.getSharedPreferences( 28 | SECRET_KEY, Context.MODE_PRIVATE 29 | ) 30 | 31 | fun providePreferences(sharedPreferences: SharedPreferences): LocalDataSource.Preferences = 32 | DefaultPreferences(sharedPreferences) 33 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/data/di/HttpModule.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.data.di 2 | 3 | import me.ibrahimsn.core.domain.source.LocalDataSource 4 | import okhttp3.OkHttpClient 5 | import org.koin.dsl.module 6 | 7 | val httpModule = module { 8 | 9 | single { 10 | provideOkHttpClient(preferences = get()) 11 | } 12 | } 13 | 14 | private fun provideOkHttpClient(preferences: LocalDataSource.Preferences): OkHttpClient { 15 | return OkHttpClient 16 | .Builder() 17 | .followRedirects(preferences.isFollowRedirect()) 18 | .followSslRedirects(preferences.isFollowRedirect()) 19 | .build() 20 | } 21 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/data/di/RequestDataModule.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.data.di 2 | 3 | import me.ibrahimsn.core.data.database.AppDatabase 4 | import me.ibrahimsn.core.data.repository.RequestRepositoryImpl 5 | import me.ibrahimsn.core.domain.repository.RequestRepository 6 | import okhttp3.OkHttpClient 7 | import org.koin.dsl.module 8 | 9 | val requestDataModule = module { 10 | 11 | single { 12 | provideRequestRepository( 13 | okHttpClient = get(), 14 | appDatabase = get() 15 | ) 16 | } 17 | } 18 | 19 | private fun provideRequestRepository( 20 | okHttpClient: OkHttpClient, 21 | appDatabase: AppDatabase 22 | ): RequestRepository { 23 | return RequestRepositoryImpl( 24 | okHttpClient, 25 | appDatabase 26 | ) 27 | } 28 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/data/di/UriDataModule.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.data.di 2 | 3 | import me.ibrahimsn.core.data.repository.UriRepositoryImpl 4 | import me.ibrahimsn.core.domain.repository.UriRepository 5 | import org.koin.dsl.module 6 | 7 | val uriDataModule = module { 8 | 9 | single { 10 | provideUriRepository() 11 | } 12 | } 13 | 14 | private fun provideUriRepository(): UriRepository { 15 | return UriRepositoryImpl() 16 | } 17 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/data/di/WebsocketDataModule.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.data.di 2 | 3 | import me.ibrahimsn.core.data.repository.WebsocketRepositoryImpl 4 | import me.ibrahimsn.core.domain.repository.WebsocketRepository 5 | import okhttp3.OkHttpClient 6 | import org.koin.dsl.module 7 | 8 | val websocketDataModule = module { 9 | 10 | single { 11 | provideWebsocketRepository( 12 | okHttpClient = get(), 13 | appDatabase = get() 14 | ) 15 | } 16 | } 17 | 18 | private fun provideWebsocketRepository( 19 | okHttpClient: OkHttpClient, 20 | appDatabase: me.ibrahimsn.core.data.database.AppDatabase 21 | ): WebsocketRepository { 22 | return WebsocketRepositoryImpl(okHttpClient, appDatabase) 23 | } 24 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/data/model/DataHolder.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.data.model 2 | 3 | sealed class DataHolder { 4 | 5 | data class Success(val data: T?) : DataHolder() 6 | 7 | data class Error(val error: ErrorHolder) : DataHolder() 8 | 9 | object Loading : DataHolder() 10 | } 11 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/data/model/DefaultTextWatcher.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.data.model 2 | 3 | import android.text.Editable 4 | import android.text.TextWatcher 5 | 6 | interface DefaultTextWatcher : TextWatcher { 7 | 8 | override fun afterTextChanged(editable: Editable?) { 9 | 10 | } 11 | 12 | override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) { 13 | 14 | } 15 | 16 | override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) { 17 | 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/data/model/ErrorHolder.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.data.model 2 | 3 | sealed class ErrorHolder { 4 | 5 | object InvalidParamsError: ErrorHolder() 6 | object EmptyUriError: ErrorHolder() 7 | object EmptyBodyError: ErrorHolder() 8 | 9 | object InvalidUriError: ErrorHolder() 10 | object SocketClosedError: ErrorHolder() 11 | 12 | data class NetworkError(val cause: Throwable): ErrorHolder() 13 | data class SocketError(val cause: Throwable): ErrorHolder() 14 | } 15 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/data/model/RequestMethod.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.data.model 2 | 3 | import androidx.annotation.ColorRes 4 | import androidx.annotation.DrawableRes 5 | import me.ibrahimsn.core.R 6 | 7 | enum class RequestMethod( 8 | val hasBody: Boolean, 9 | @ColorRes val colorRes: Int, 10 | @DrawableRes val backgroundRes: Int, 11 | val shortName: String 12 | ) { 13 | 14 | GET( 15 | false, 16 | R.color.colorGet, 17 | R.drawable.ic_background_method_get, 18 | "GET" 19 | ), 20 | 21 | POST( 22 | true, 23 | R.color.colorPost, 24 | R.drawable.ic_background_method_post, 25 | "PST" 26 | ), 27 | 28 | PUT( 29 | true, 30 | R.color.colorPut, 31 | R.drawable.ic_background_method_put, 32 | "PUT" 33 | ), 34 | 35 | DEL( 36 | true, 37 | R.color.colorDelete, 38 | R.drawable.ic_background_method_delete, 39 | "DEL" 40 | ), 41 | 42 | PATCH( 43 | true, 44 | R.color.colorPatch, 45 | R.drawable.ic_background_method_patch, 46 | "PCH" 47 | ) 48 | } 49 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/data/repository/RequestRepositoryImpl.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.data.repository 2 | 3 | import androidx.paging.DataSource 4 | import me.ibrahimsn.core.data.database.AppDatabase 5 | import me.ibrahimsn.core.data.model.DataHolder 6 | import me.ibrahimsn.core.data.model.ErrorHolder 7 | import me.ibrahimsn.core.data.model.RequestMethod 8 | import me.ibrahimsn.core.domain.model.param.Param 9 | import me.ibrahimsn.core.domain.model.request.Request 10 | import me.ibrahimsn.core.domain.model.request.RequestResponse 11 | import me.ibrahimsn.core.domain.repository.RequestRepository 12 | import okhttp3.* 13 | import java.io.IOException 14 | import kotlin.coroutines.resume 15 | import kotlin.coroutines.suspendCoroutine 16 | 17 | class RequestRepositoryImpl ( 18 | private val okHttpClient: OkHttpClient, 19 | private val appDatabase: AppDatabase 20 | ) : RequestRepository { 21 | 22 | override suspend fun makeRequest( 23 | uri: String, 24 | method: RequestMethod, 25 | headerParams: List?, 26 | bodyParams: List? 27 | ): DataHolder { 28 | 29 | val requestBuilder = okhttp3.Request.Builder() 30 | .url(uri) 31 | var requestHeaders: Headers? = null 32 | var requestBody: RequestBody? = null 33 | 34 | headerParams?.filter { 35 | it.isActive && it.key.isNotEmpty() && it.value.isNotEmpty() 36 | }?.let { params -> 37 | if (params.isNotEmpty()) { 38 | requestHeaders = Headers.Builder().apply { 39 | params.forEach { param -> 40 | add(param.key, param.value) 41 | } 42 | }.build() 43 | } 44 | } 45 | 46 | requestHeaders?.let { 47 | requestBuilder.headers(it) 48 | } 49 | 50 | bodyParams?.filter { 51 | it.isActive && it.key.isNotEmpty() && it.value.isNotEmpty() 52 | }?.let { params -> 53 | if (params.isNotEmpty()) { 54 | requestBody = MultipartBody.Builder().setType(MultipartBody.FORM).apply { 55 | params.forEach { param -> 56 | addFormDataPart(param.key, param.value) 57 | } 58 | }.build() 59 | } 60 | } 61 | 62 | requestBuilder.method(method.name, requestBody) 63 | 64 | return suspendCoroutine { continuation -> 65 | okHttpClient.newCall(requestBuilder.build()).enqueue(object: Callback { 66 | override fun onResponse(call: Call, response: Response) { 67 | continuation.resume( 68 | DataHolder.Success( 69 | RequestResponse( 70 | status = response.isSuccessful, 71 | code = response.code, 72 | body = response.body?.string() 73 | ) 74 | ) 75 | ) 76 | } 77 | 78 | override fun onFailure(call: Call, e: IOException) { 79 | continuation.resume( 80 | DataHolder.Error(ErrorHolder.NetworkError(e)) 81 | ) 82 | } 83 | }) 84 | } 85 | } 86 | 87 | override fun getAllRequests(): DataSource.Factory { 88 | return appDatabase.httpRequestDao().getAll() 89 | } 90 | 91 | override suspend fun saveOrUpdateRequest(request: Request): DataHolder { 92 | return DataHolder.Success(appDatabase.httpRequestDao().insertOrUpdate(request)) 93 | } 94 | 95 | override suspend fun deleteRequests(requests: List): DataHolder { 96 | return DataHolder.Success(appDatabase.httpRequestDao().delete(requests)) 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/data/repository/UriRepositoryImpl.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.data.repository 2 | 3 | import android.net.Uri 4 | import me.ibrahimsn.core.data.model.DataHolder 5 | import me.ibrahimsn.core.data.model.ErrorHolder 6 | import me.ibrahimsn.core.domain.model.param.Param 7 | import me.ibrahimsn.core.domain.repository.UriRepository 8 | 9 | class UriRepositoryImpl : UriRepository { 10 | 11 | override suspend fun parseUriQueryParams(uri: String): DataHolder?> { 12 | val parsed = Uri.parse(uri) 13 | val params = mutableListOf() 14 | 15 | if (parsed.isOpaque) { 16 | return DataHolder.Error(ErrorHolder.InvalidUriError) 17 | } 18 | 19 | for (param in parsed.queryParameterNames) { 20 | parsed.getQueryParameter(param)?.let { 21 | params.add(Param(true, param, it)) 22 | } 23 | } 24 | 25 | return DataHolder.Success(params) 26 | } 27 | 28 | override suspend fun generateUri(uri: String, queryParams: List): DataHolder { 29 | val builder = Uri.parse(uri) 30 | .buildUpon() 31 | .clearQuery() 32 | 33 | for (param in queryParams.filter { 34 | it.isActive && it.key.isNotEmpty() && it.value.isNotEmpty() 35 | }) { 36 | builder.appendQueryParameter(param.key, param.value) 37 | } 38 | 39 | return DataHolder.Success(builder.build()) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/data/repository/WebsocketRepositoryImpl.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.data.repository 2 | 3 | import androidx.paging.DataSource 4 | import kotlinx.coroutines.channels.Channel 5 | import me.ibrahimsn.core.data.database.AppDatabase 6 | import me.ibrahimsn.core.data.model.DataHolder 7 | import me.ibrahimsn.core.data.model.ErrorHolder 8 | import me.ibrahimsn.core.domain.model.param.Param 9 | import me.ibrahimsn.core.domain.model.websocket.Websocket 10 | import me.ibrahimsn.core.domain.model.websocket.WebsocketEvent 11 | import me.ibrahimsn.core.domain.repository.WebsocketRepository 12 | import okhttp3.* 13 | 14 | class WebsocketRepositoryImpl ( 15 | private val okHttpClient: OkHttpClient, 16 | private val appDatabase: AppDatabase 17 | ) : WebsocketRepository { 18 | 19 | override suspend fun connectWebsocket( 20 | channel: Channel, 21 | uri: String, 22 | headerParams: List? 23 | ) { 24 | val requestBuilder = Request.Builder().url(uri) 25 | var requestHeaders: Headers? = null 26 | 27 | headerParams?.filter { 28 | it.isActive && it.key.isNotEmpty() && it.value.isNotEmpty() 29 | }?.let { params -> 30 | if (params.isNotEmpty()) { 31 | requestHeaders = Headers.Builder().apply { 32 | params.forEach { param -> 33 | add(param.key, param.value) 34 | } 35 | }.build() 36 | } 37 | } 38 | 39 | requestHeaders?.let { 40 | requestBuilder.headers(it) 41 | } 42 | 43 | okHttpClient.newWebSocket(requestBuilder.build(), object: WebSocketListener() { 44 | override fun onOpen(webSocket: WebSocket, response: Response) { 45 | super.onOpen(webSocket, response) 46 | channel.offer(WebsocketEvent.OnOpen(webSocket)) 47 | } 48 | 49 | override fun onClosed(webSocket: WebSocket, code: Int, reason: String) { 50 | super.onClosed(webSocket, code, reason) 51 | channel.offer(WebsocketEvent.OnClosed) 52 | } 53 | 54 | override fun onMessage(webSocket: WebSocket, text: String) { 55 | super.onMessage(webSocket, text) 56 | channel.offer(WebsocketEvent.OnMessage(text)) 57 | } 58 | 59 | override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) { 60 | super.onFailure(webSocket, t, response) 61 | channel.offer( 62 | WebsocketEvent.OnFailure( 63 | ErrorHolder.SocketError(t) 64 | ) 65 | ) 66 | } 67 | }) 68 | } 69 | 70 | override fun getAllWebsockets(): DataSource.Factory { 71 | return appDatabase.webSocketDao().getAll() 72 | } 73 | 74 | override suspend fun saveOrUpdateWebsocket(websocket: Websocket): DataHolder { 75 | return DataHolder.Success(appDatabase.webSocketDao().insertOrUpdate(websocket)) 76 | } 77 | 78 | override suspend fun deleteWebsockets(websocket: List): DataHolder { 79 | return DataHolder.Success(appDatabase.webSocketDao().delete(websocket)) 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/data/source/DefaultPreferences.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.data.source 2 | 3 | import android.content.SharedPreferences 4 | import me.ibrahimsn.core.domain.source.LocalDataSource 5 | import me.ibrahimsn.core.domain.source.LocalDataSource.Preferences.Companion.KEY_CONSENT_STATUS 6 | import me.ibrahimsn.core.domain.source.LocalDataSource.Preferences.Companion.KEY_FOLLOW_REDIRECT 7 | import me.ibrahimsn.core.domain.source.LocalDataSource.Preferences.Companion.KEY_HAS_CONSENT_STATUS 8 | 9 | class DefaultPreferences constructor(override val sharedPreferences: SharedPreferences) 10 | : LocalDataSource.Preferences { 11 | 12 | override fun isFollowRedirect(): Boolean = 13 | sharedPreferences.getBoolean(KEY_FOLLOW_REDIRECT, true) 14 | 15 | override fun getConsentStatus(): Boolean = 16 | sharedPreferences.getBoolean(KEY_CONSENT_STATUS, true) 17 | 18 | override fun hasConsentStatus(): Boolean = 19 | sharedPreferences.getBoolean(KEY_HAS_CONSENT_STATUS, false) 20 | 21 | override fun setConsentStatus(consentStatus: Boolean) = 22 | sharedPreferences.edit() 23 | .putBoolean(KEY_CONSENT_STATUS, consentStatus) 24 | .putBoolean(KEY_HAS_CONSENT_STATUS, true) 25 | .apply() 26 | } 27 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/domain/Constants.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.domain 2 | 3 | object Constants { 4 | 5 | const val DEFAULT_REQUEST_URI = "https://google.com" 6 | const val DEFAULT_WEBSOCKET_URI = "wss://echo.websocket.org" 7 | } 8 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/domain/di/RequestDomainModule.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.domain.di 2 | 3 | import me.ibrahimsn.core.domain.interactor.Interactor 4 | import me.ibrahimsn.core.domain.interactor.request.DeleteRequestsInteractor 5 | import me.ibrahimsn.core.domain.interactor.request.GetAllRequestsInteractor 6 | import me.ibrahimsn.core.domain.interactor.request.MakeRequestInteractor 7 | import me.ibrahimsn.core.domain.interactor.request.SaveOrUpdateRequestInteractor 8 | import me.ibrahimsn.core.domain.model.request.Request 9 | import me.ibrahimsn.core.domain.model.request.RequestResponse 10 | import me.ibrahimsn.core.domain.repository.RequestRepository 11 | import org.koin.core.qualifier.named 12 | import org.koin.dsl.module 13 | 14 | val requestDomainModule = module { 15 | 16 | factory (named(GetAllRequestsInteractor.NAME)) { 17 | provideGetAllRequestsInteractor( 18 | requestRepository = get() 19 | ) 20 | } 21 | 22 | factory (named(MakeRequestInteractor.NAME)) { 23 | provideMakeRequestInteractor( 24 | requestRepository = get() 25 | ) 26 | } 27 | 28 | factory (named(SaveOrUpdateRequestInteractor.NAME)) { 29 | provideSaveOrUpdateRequestInteractor( 30 | requestRepository = get() 31 | ) 32 | } 33 | 34 | factory (named(DeleteRequestsInteractor.NAME)) { 35 | provideDeleteRequestsInteractor( 36 | requestRepository = get() 37 | ) 38 | } 39 | } 40 | 41 | private fun provideGetAllRequestsInteractor(requestRepository: RequestRepository) 42 | : Interactor.PagingInteractor { 43 | return GetAllRequestsInteractor(requestRepository) 44 | } 45 | 46 | private fun provideMakeRequestInteractor(requestRepository: RequestRepository) 47 | : Interactor.RequestInteractor { 48 | return MakeRequestInteractor(requestRepository) 49 | } 50 | 51 | private fun provideSaveOrUpdateRequestInteractor(requestRepository: RequestRepository) 52 | : Interactor.RequestInteractor { 53 | return SaveOrUpdateRequestInteractor(requestRepository) 54 | } 55 | 56 | private fun provideDeleteRequestsInteractor(requestRepository: RequestRepository) 57 | : Interactor.RequestInteractor { 58 | return DeleteRequestsInteractor(requestRepository) 59 | } 60 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/domain/di/UriDomainModule.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.domain.di 2 | 3 | import android.net.Uri 4 | import me.ibrahimsn.core.domain.interactor.Interactor 5 | import me.ibrahimsn.core.domain.interactor.uri.GenerateUriInteractor 6 | import me.ibrahimsn.core.domain.interactor.uri.ParseUriParamsInteractor 7 | import me.ibrahimsn.core.domain.model.param.Param 8 | import me.ibrahimsn.core.domain.repository.UriRepository 9 | import org.koin.core.qualifier.named 10 | import org.koin.dsl.module 11 | 12 | val uriDomainModule = module { 13 | 14 | factory(named(GenerateUriInteractor.NAME)) { 15 | provideGenerateUriInteractor(uriRepository = get()) 16 | } 17 | 18 | factory(named(ParseUriParamsInteractor.NAME)) { 19 | provideParseUriParamsInteractor(uriRepository = get()) 20 | } 21 | } 22 | 23 | private fun provideGenerateUriInteractor(uriRepository: UriRepository) 24 | : Interactor.RequestInteractor { 25 | return GenerateUriInteractor(uriRepository) 26 | } 27 | 28 | private fun provideParseUriParamsInteractor(uriRepository: UriRepository) 29 | : Interactor.RequestInteractor?> { 30 | return ParseUriParamsInteractor(uriRepository) 31 | } 32 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/domain/di/WebsocketDomainModule.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.domain.di 2 | 3 | import me.ibrahimsn.core.domain.interactor.Interactor 4 | import me.ibrahimsn.core.domain.interactor.websocket.ConnectWebsocketInteractor 5 | import me.ibrahimsn.core.domain.interactor.websocket.DeleteWebsocketsInteractor 6 | import me.ibrahimsn.core.domain.interactor.websocket.GetAllWebsocketsInteractor 7 | import me.ibrahimsn.core.domain.interactor.websocket.SaveOrUpdateWebsocketInteractor 8 | import me.ibrahimsn.core.domain.model.websocket.Websocket 9 | import me.ibrahimsn.core.domain.model.websocket.WebsocketEvent 10 | import me.ibrahimsn.core.domain.repository.WebsocketRepository 11 | import org.koin.core.qualifier.named 12 | import org.koin.dsl.module 13 | 14 | val websocketDomainModule = module { 15 | 16 | factory (named(ConnectWebsocketInteractor.NAME)) { 17 | provideConnectWebsocketInteractor( 18 | websocketRepository = get() 19 | ) 20 | } 21 | 22 | factory (named(GetAllWebsocketsInteractor.NAME)) { 23 | provideGetAllWebsocketsInteractor( 24 | websocketRepository = get() 25 | ) 26 | } 27 | 28 | factory (named(SaveOrUpdateWebsocketInteractor.NAME)) { 29 | provideSaveOrUpdateRequestInteractor( 30 | websocketRepository = get() 31 | ) 32 | } 33 | 34 | factory (named(DeleteWebsocketsInteractor.NAME)) { 35 | provideDeleteRequestsInteractor( 36 | websocketRepository = get() 37 | ) 38 | } 39 | } 40 | 41 | private fun provideConnectWebsocketInteractor(websocketRepository: WebsocketRepository) 42 | : Interactor.ObserveInteractor{ 43 | return ConnectWebsocketInteractor(websocketRepository) 44 | } 45 | 46 | private fun provideGetAllWebsocketsInteractor(websocketRepository: WebsocketRepository) 47 | : Interactor.PagingInteractor { 48 | return GetAllWebsocketsInteractor(websocketRepository) 49 | } 50 | 51 | private fun provideSaveOrUpdateRequestInteractor(websocketRepository: WebsocketRepository) 52 | : Interactor.RequestInteractor { 53 | return SaveOrUpdateWebsocketInteractor(websocketRepository) 54 | } 55 | 56 | private fun provideDeleteRequestsInteractor(websocketRepository: WebsocketRepository) 57 | : Interactor.RequestInteractor { 58 | return DeleteWebsocketsInteractor(websocketRepository) 59 | } 60 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/domain/interactor/Interactor.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.domain.interactor 2 | 3 | import androidx.paging.DataSource 4 | import kotlinx.coroutines.channels.Channel 5 | import me.ibrahimsn.core.data.model.DataHolder 6 | 7 | interface Interactor { 8 | 9 | interface RequestInteractor : Interactor { 10 | suspend fun invoke(params: P?): DataHolder 11 | } 12 | 13 | interface RetrieveInteractor : Interactor { 14 | suspend fun invoke(): DataHolder 15 | } 16 | 17 | interface ObserveInteractor: Interactor { 18 | suspend fun invoke(channel: Channel, params: P?) 19 | } 20 | 21 | interface PagingInteractor: Interactor { 22 | fun invoke(): DataSource.Factory 23 | } 24 | 25 | abstract class Params { 26 | // marker class 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/domain/interactor/request/DeleteRequestsInteractor.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.domain.interactor.request 2 | 3 | import me.ibrahimsn.core.data.model.DataHolder 4 | import me.ibrahimsn.core.data.model.ErrorHolder 5 | import me.ibrahimsn.core.domain.interactor.Interactor 6 | import me.ibrahimsn.core.domain.model.request.Request 7 | import me.ibrahimsn.core.domain.repository.RequestRepository 8 | 9 | class DeleteRequestsInteractor (private val repository: RequestRepository) 10 | : Interactor.RequestInteractor { 11 | 12 | override suspend fun invoke(params: Params?): DataHolder { 13 | 14 | if (params == null) 15 | return DataHolder.Error(ErrorHolder.InvalidParamsError) 16 | 17 | if (params.requests == null) 18 | return DataHolder.Error(ErrorHolder.InvalidParamsError) 19 | 20 | return repository.deleteRequests(params.requests) 21 | } 22 | 23 | class Params( 24 | val requests: List? 25 | ) : Interactor.Params() 26 | 27 | companion object { 28 | const val NAME = "DeleteRequestInteractor" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/domain/interactor/request/GetAllRequestsInteractor.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.domain.interactor.request 2 | 3 | import androidx.paging.DataSource 4 | import me.ibrahimsn.core.domain.interactor.Interactor 5 | import me.ibrahimsn.core.domain.model.request.Request 6 | import me.ibrahimsn.core.domain.repository.RequestRepository 7 | 8 | class GetAllRequestsInteractor (private val repository: RequestRepository) 9 | : Interactor.PagingInteractor { 10 | 11 | override fun invoke(): DataSource.Factory { 12 | return repository.getAllRequests() 13 | } 14 | 15 | companion object { 16 | const val NAME = "GetAllRequestsInteractor" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/domain/interactor/request/MakeRequestInteractor.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.domain.interactor.request 2 | 3 | import me.ibrahimsn.core.data.model.DataHolder 4 | import me.ibrahimsn.core.data.model.ErrorHolder 5 | import me.ibrahimsn.core.data.model.RequestMethod 6 | import me.ibrahimsn.core.domain.interactor.Interactor 7 | import me.ibrahimsn.core.domain.model.param.Param 8 | import me.ibrahimsn.core.domain.model.request.RequestResponse 9 | import me.ibrahimsn.core.domain.repository.RequestRepository 10 | import me.ibrahimsn.core.presentation.extension.isValidUri 11 | 12 | class MakeRequestInteractor (private val repository: RequestRepository) 13 | : Interactor.RequestInteractor { 14 | 15 | override suspend fun invoke(params: Params?): DataHolder { 16 | 17 | if (params == null) 18 | return DataHolder.Error(ErrorHolder.InvalidParamsError) 19 | 20 | if (params.uri.isNullOrEmpty()) 21 | return DataHolder.Error(ErrorHolder.EmptyUriError) 22 | 23 | if (!params.uri.isValidUri()) 24 | return DataHolder.Error(ErrorHolder.InvalidUriError) 25 | 26 | if (params.method == null) 27 | return DataHolder.Error(ErrorHolder.InvalidParamsError) 28 | 29 | if (params.method.hasBody && params.bodyParams.isNullOrEmpty()) 30 | return DataHolder.Error(ErrorHolder.EmptyBodyError) 31 | 32 | return repository.makeRequest( 33 | uri = params.uri, 34 | method = params.method, 35 | headerParams = params.headerParams, 36 | bodyParams = params.bodyParams 37 | ) 38 | } 39 | 40 | class Params( 41 | val uri: String?, 42 | val method: RequestMethod?, 43 | val headerParams: List?, 44 | val bodyParams: List? 45 | ) : Interactor.Params() 46 | 47 | companion object { 48 | const val NAME = "MakeRequestInteractor" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/domain/interactor/request/SaveOrUpdateRequestInteractor.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.domain.interactor.request 2 | 3 | import me.ibrahimsn.core.data.model.DataHolder 4 | import me.ibrahimsn.core.data.model.ErrorHolder 5 | import me.ibrahimsn.core.domain.interactor.Interactor 6 | import me.ibrahimsn.core.domain.model.request.Request 7 | import me.ibrahimsn.core.domain.repository.RequestRepository 8 | 9 | class SaveOrUpdateRequestInteractor (private val repository: RequestRepository) 10 | : Interactor.RequestInteractor { 11 | 12 | override suspend fun invoke(params: Params?): DataHolder { 13 | 14 | if (params == null) 15 | return DataHolder.Error(ErrorHolder.InvalidParamsError) 16 | 17 | if (params.request == null) 18 | return DataHolder.Error(ErrorHolder.InvalidParamsError) 19 | 20 | return repository.saveOrUpdateRequest(params.request) 21 | } 22 | 23 | class Params( 24 | val request: Request? 25 | ) : Interactor.Params() 26 | 27 | companion object { 28 | const val NAME = "UpdateRequestInteractor" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/domain/interactor/uri/GenerateUriInteractor.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.domain.interactor.uri 2 | 3 | import android.net.Uri 4 | import me.ibrahimsn.core.data.model.DataHolder 5 | import me.ibrahimsn.core.data.model.ErrorHolder 6 | import me.ibrahimsn.core.domain.interactor.Interactor 7 | import me.ibrahimsn.core.domain.model.param.Param 8 | import me.ibrahimsn.core.domain.repository.UriRepository 9 | 10 | class GenerateUriInteractor (private val uriRepository: UriRepository) 11 | : Interactor.RequestInteractor { 12 | 13 | override suspend fun invoke(params: Params?): DataHolder { 14 | 15 | if (params == null) 16 | return DataHolder.Error(ErrorHolder.InvalidParamsError) 17 | 18 | return uriRepository.generateUri(params.uri, params.queryParams) 19 | } 20 | 21 | class Params(val uri: String, val queryParams: List) : Interactor.Params() 22 | 23 | companion object { 24 | const val NAME = "GenerateUriInteractor" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/domain/interactor/uri/ParseUriParamsInteractor.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.domain.interactor.uri 2 | 3 | import me.ibrahimsn.core.data.model.DataHolder 4 | import me.ibrahimsn.core.data.model.ErrorHolder 5 | import me.ibrahimsn.core.domain.interactor.Interactor 6 | import me.ibrahimsn.core.domain.model.param.Param 7 | import me.ibrahimsn.core.domain.repository.UriRepository 8 | 9 | class ParseUriParamsInteractor (private val uriRepository: UriRepository) 10 | : Interactor.RequestInteractor?> { 11 | 12 | override suspend fun invoke(params: Params?): DataHolder?> { 13 | 14 | if (params == null) 15 | return DataHolder.Error(ErrorHolder.InvalidParamsError) 16 | 17 | if (params.uri == null) 18 | return DataHolder.Error(ErrorHolder.EmptyUriError) 19 | 20 | return uriRepository.parseUriQueryParams(params.uri) 21 | } 22 | 23 | class Params(val uri: String?) : Interactor.Params() 24 | 25 | companion object { 26 | const val NAME = "ParseUriParamsInteractor" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/domain/interactor/websocket/ConnectWebsocketInteractor.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.domain.interactor.websocket 2 | 3 | import kotlinx.coroutines.channels.Channel 4 | import me.ibrahimsn.core.data.model.ErrorHolder 5 | import me.ibrahimsn.core.domain.interactor.Interactor 6 | import me.ibrahimsn.core.domain.model.param.Param 7 | import me.ibrahimsn.core.domain.model.websocket.WebsocketEvent 8 | import me.ibrahimsn.core.domain.repository.WebsocketRepository 9 | import me.ibrahimsn.core.presentation.extension.isValidUri 10 | 11 | class ConnectWebsocketInteractor (private val repository: WebsocketRepository) 12 | : Interactor.ObserveInteractor { 13 | 14 | override suspend fun invoke(channel: Channel, params: Params?) { 15 | 16 | if (params == null) { 17 | channel.offer(WebsocketEvent.OnFailure(ErrorHolder.InvalidParamsError)) 18 | return 19 | } 20 | 21 | if (params.uri.isNullOrEmpty()) { 22 | channel.offer(WebsocketEvent.OnFailure(ErrorHolder.EmptyUriError)) 23 | return 24 | } 25 | 26 | if (!params.uri.isValidUri()) { 27 | channel.offer(WebsocketEvent.OnFailure(ErrorHolder.InvalidUriError)) 28 | return 29 | } 30 | 31 | repository.connectWebsocket( 32 | channel = channel, 33 | uri = params.uri, 34 | headerParams = params.headerParams 35 | ) 36 | } 37 | 38 | class Params( 39 | val uri: String?, 40 | val headerParams: List? 41 | ) : Interactor.Params() 42 | 43 | companion object { 44 | const val NAME = "ConnectWebsocketInteractor" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/domain/interactor/websocket/DeleteWebsocketsInteractor.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.domain.interactor.websocket 2 | 3 | import me.ibrahimsn.core.data.model.DataHolder 4 | import me.ibrahimsn.core.data.model.ErrorHolder 5 | import me.ibrahimsn.core.domain.interactor.Interactor 6 | import me.ibrahimsn.core.domain.model.websocket.Websocket 7 | import me.ibrahimsn.core.domain.repository.WebsocketRepository 8 | 9 | class DeleteWebsocketsInteractor (private val repository: WebsocketRepository) 10 | : Interactor.RequestInteractor { 11 | 12 | override suspend fun invoke(params: Params?): DataHolder { 13 | 14 | if (params == null) 15 | return DataHolder.Error(ErrorHolder.InvalidParamsError) 16 | 17 | if (params.websockets == null) 18 | return DataHolder.Error(ErrorHolder.InvalidParamsError) 19 | 20 | return repository.deleteWebsockets(params.websockets) 21 | } 22 | 23 | class Params( 24 | val websockets: List? 25 | ) : Interactor.Params() 26 | 27 | companion object { 28 | const val NAME = "DeleteWebsocketsInteractor" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/domain/interactor/websocket/GetAllWebsocketsInteractor.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.domain.interactor.websocket 2 | 3 | import androidx.paging.DataSource 4 | import me.ibrahimsn.core.domain.interactor.Interactor 5 | import me.ibrahimsn.core.domain.model.websocket.Websocket 6 | import me.ibrahimsn.core.domain.repository.WebsocketRepository 7 | 8 | class GetAllWebsocketsInteractor (private val repository: WebsocketRepository) 9 | : Interactor.PagingInteractor { 10 | 11 | override fun invoke(): DataSource.Factory { 12 | return repository.getAllWebsockets() 13 | } 14 | 15 | companion object { 16 | const val NAME = "GetAllWebsocketsInteractor" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/domain/interactor/websocket/SaveOrUpdateWebsocketInteractor.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.domain.interactor.websocket 2 | 3 | import me.ibrahimsn.core.data.model.DataHolder 4 | import me.ibrahimsn.core.data.model.ErrorHolder 5 | import me.ibrahimsn.core.domain.interactor.Interactor 6 | import me.ibrahimsn.core.domain.model.websocket.Websocket 7 | import me.ibrahimsn.core.domain.repository.WebsocketRepository 8 | 9 | class SaveOrUpdateWebsocketInteractor (private val repository: WebsocketRepository) 10 | : Interactor.RequestInteractor { 11 | 12 | override suspend fun invoke(params: Params?): DataHolder { 13 | 14 | if (params == null) 15 | return DataHolder.Error(ErrorHolder.InvalidParamsError) 16 | 17 | if (params.websocket == null) 18 | return DataHolder.Error(ErrorHolder.InvalidParamsError) 19 | 20 | return repository.saveOrUpdateWebsocket(params.websocket) 21 | } 22 | 23 | class Params( 24 | val websocket: Websocket? 25 | ) : Interactor.Params() 26 | 27 | companion object { 28 | const val NAME = "UpdateWebsocketInteractor" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/domain/model/param/Param.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.domain.model.param 2 | 3 | import android.os.Parcelable 4 | import kotlinx.android.parcel.Parcelize 5 | 6 | @Parcelize 7 | data class Param( 8 | var isActive: Boolean, 9 | var key: String, 10 | var value: String 11 | ): Parcelable { 12 | 13 | companion object { 14 | 15 | fun newInstance(): Param { 16 | return Param(true, "", "") 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/domain/model/request/Request.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.domain.model.request 2 | 3 | import android.os.Parcelable 4 | import androidx.room.Entity 5 | import androidx.room.PrimaryKey 6 | import kotlinx.android.parcel.Parcelize 7 | import me.ibrahimsn.core.data.model.RequestMethod 8 | import java.util.* 9 | 10 | @Parcelize 11 | @Entity(tableName = "requests") 12 | data class Request( 13 | var uri: String, 14 | var headerParams: String, 15 | var bodyParams: String, 16 | var method: RequestMethod, 17 | var createdAt: Date, 18 | @PrimaryKey(autoGenerate = true) var id: Long? = null 19 | ): Parcelable { 20 | 21 | companion object { 22 | 23 | fun newInstance(uri: String): Request { 24 | return Request(uri, "", "", RequestMethod.GET, Date()) 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/domain/model/request/RequestResponse.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.domain.model.request 2 | 3 | data class RequestResponse( 4 | val status: Boolean, 5 | val code: Int, 6 | val body: String? 7 | ) 8 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/domain/model/websocket/Websocket.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.domain.model.websocket 2 | 3 | import android.os.Parcelable 4 | import androidx.room.Entity 5 | import androidx.room.PrimaryKey 6 | import kotlinx.android.parcel.Parcelize 7 | import java.util.* 8 | 9 | @Parcelize 10 | @Entity(tableName = "websockets") 11 | data class Websocket( 12 | var uri: String, 13 | var headerParams: String, 14 | var createdAt: Date, 15 | @PrimaryKey(autoGenerate = true) var id: Long? = null 16 | ): Parcelable { 17 | 18 | companion object { 19 | 20 | fun newInstance(uri: String): Websocket { 21 | return Websocket(uri, "", Date()) 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/domain/model/websocket/WebsocketEvent.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.domain.model.websocket 2 | 3 | import me.ibrahimsn.core.data.model.ErrorHolder 4 | import okhttp3.WebSocket 5 | 6 | sealed class WebsocketEvent { 7 | 8 | object OnClosed: WebsocketEvent() 9 | data class OnOpen(val websocket: WebSocket): WebsocketEvent() 10 | data class OnMessage(val text: String): WebsocketEvent() 11 | data class OnFailure(val error: ErrorHolder): WebsocketEvent() 12 | } -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/domain/repository/RequestRepository.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.domain.repository 2 | 3 | import androidx.paging.DataSource 4 | import me.ibrahimsn.core.data.model.DataHolder 5 | import me.ibrahimsn.core.data.model.RequestMethod 6 | import me.ibrahimsn.core.domain.model.param.Param 7 | import me.ibrahimsn.core.domain.model.request.Request 8 | import me.ibrahimsn.core.domain.model.request.RequestResponse 9 | 10 | interface RequestRepository { 11 | 12 | suspend fun makeRequest( 13 | uri: String, 14 | method: RequestMethod, 15 | headerParams: List?, 16 | bodyParams: List? 17 | ): DataHolder 18 | 19 | fun getAllRequests(): DataSource.Factory 20 | 21 | suspend fun saveOrUpdateRequest(request: Request): DataHolder 22 | 23 | suspend fun deleteRequests(requests: List): DataHolder 24 | } 25 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/domain/repository/UriRepository.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.domain.repository 2 | 3 | import android.net.Uri 4 | import me.ibrahimsn.core.data.model.DataHolder 5 | import me.ibrahimsn.core.domain.model.param.Param 6 | 7 | interface UriRepository { 8 | 9 | suspend fun parseUriQueryParams(uri: String): DataHolder?> 10 | 11 | suspend fun generateUri(uri: String, queryParams: List): DataHolder 12 | } 13 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/domain/repository/WebsocketRepository.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.domain.repository 2 | 3 | import androidx.paging.DataSource 4 | import kotlinx.coroutines.channels.Channel 5 | import me.ibrahimsn.core.data.model.DataHolder 6 | import me.ibrahimsn.core.domain.model.param.Param 7 | import me.ibrahimsn.core.domain.model.websocket.Websocket 8 | import me.ibrahimsn.core.domain.model.websocket.WebsocketEvent 9 | 10 | interface WebsocketRepository { 11 | 12 | suspend fun connectWebsocket( 13 | channel: Channel, 14 | uri: String, 15 | headerParams: List? 16 | ) 17 | 18 | fun getAllWebsockets(): DataSource.Factory 19 | 20 | suspend fun saveOrUpdateWebsocket(websocket: Websocket): DataHolder 21 | 22 | suspend fun deleteWebsockets(websocket: List): DataHolder 23 | } 24 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/domain/source/LocalDataSource.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.domain.source 2 | 3 | import android.content.SharedPreferences 4 | 5 | interface LocalDataSource { 6 | 7 | interface Preferences : LocalDataSource { 8 | 9 | val sharedPreferences: SharedPreferences 10 | 11 | fun isFollowRedirect(): Boolean 12 | 13 | fun getConsentStatus(): Boolean 14 | 15 | fun hasConsentStatus(): Boolean 16 | 17 | fun setConsentStatus(consentStatus: Boolean) 18 | 19 | companion object { 20 | const val KEY_FOLLOW_REDIRECT = "key_follow_redirect" 21 | const val KEY_CONSENT_STATUS = "key_consent_status" 22 | const val KEY_HAS_CONSENT_STATUS = "key_has_consent_status" 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/presentation/Constants.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.presentation 2 | 3 | object Constants { 4 | 5 | const val PUBLISHER_ID = "" 6 | const val BANNER_AD_UNIT_ID = "" 7 | const val ADMOB_TEST_DEVICE = "" 8 | const val PRIVACY_URL = "https://ibrahimsn98.github.io/web/webdevtools-privacy-policy" 9 | } 10 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/presentation/base/BaseActivity.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.presentation.base 2 | 3 | import android.os.Bundle 4 | import android.view.Menu 5 | import androidx.annotation.LayoutRes 6 | import androidx.annotation.MenuRes 7 | import androidx.annotation.StringRes 8 | import androidx.appcompat.app.AppCompatActivity 9 | import androidx.appcompat.widget.Toolbar 10 | 11 | abstract class BaseActivity : AppCompatActivity() { 12 | 13 | @LayoutRes 14 | protected abstract fun layoutRes(): Int 15 | 16 | @MenuRes 17 | protected open fun menuRes(): Int? = null 18 | 19 | @StringRes 20 | protected open fun titleRes(): Int? = null 21 | 22 | protected open fun toolbar(): Toolbar? = null 23 | 24 | protected open fun showBackButton(): Boolean = false 25 | 26 | abstract fun initView() 27 | 28 | override fun onCreate(savedInstanceState: Bundle?) { 29 | super.onCreate(savedInstanceState) 30 | setContentView(layoutRes()) 31 | 32 | toolbar()?.let { setSupportActionBar(it) } 33 | titleRes()?.let { setTitle(it) } 34 | 35 | supportActionBar?.setHomeButtonEnabled(showBackButton()) 36 | supportActionBar?.setDisplayHomeAsUpEnabled(showBackButton()) 37 | 38 | initView() 39 | } 40 | 41 | override fun onCreateOptionsMenu(menu: Menu?): Boolean { 42 | menuRes()?.let { 43 | menuInflater.inflate(it, menu) 44 | } 45 | return super.onCreateOptionsMenu(menu) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/presentation/base/BaseAdapter.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.presentation.base 2 | 3 | import androidx.recyclerview.widget.DiffUtil 4 | import androidx.recyclerview.widget.RecyclerView 5 | 6 | abstract class BaseAdapter : RecyclerView.Adapter() where VH: BaseViewHolder { 7 | 8 | protected val items = mutableListOf() 9 | 10 | abstract fun areItemsTheSame(oldItem: T, newItem: T): Boolean 11 | 12 | abstract fun areContentsTheSame(oldItem: T, newItem: T): Boolean 13 | 14 | override fun onBindViewHolder(holder: VH, position: Int) { 15 | holder.bind(items[position]) 16 | } 17 | 18 | override fun getItemCount() = items.size 19 | 20 | class DiffCallback : DiffUtil.ItemCallback() { 21 | 22 | override fun areItemsTheSame(oldItem: T, newItem: T): Boolean 23 | = areItemsTheSame(oldItem, newItem) 24 | 25 | override fun areContentsTheSame(oldItem: T, newItem: T): Boolean 26 | = areContentsTheSame(oldItem, newItem) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/presentation/base/BaseFragment.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.presentation.base 2 | 3 | import android.os.Bundle 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import androidx.annotation.LayoutRes 8 | import androidx.fragment.app.Fragment 9 | 10 | abstract class BaseFragment : Fragment() { 11 | 12 | @LayoutRes 13 | protected abstract fun layoutRes(): Int 14 | 15 | abstract fun initView() 16 | 17 | abstract fun observeData() 18 | 19 | open fun initData() { 20 | 21 | } 22 | 23 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { 24 | return layoutInflater.inflate(layoutRes(), container, false) 25 | } 26 | 27 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 28 | super.onViewCreated(view, savedInstanceState) 29 | initData() 30 | initView() 31 | observeData() 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/presentation/base/BasePagedAdapter.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.presentation.base 2 | 3 | import androidx.paging.PagedListAdapter 4 | import androidx.recyclerview.widget.DiffUtil 5 | 6 | abstract class BasePagedAdapter(diffCallback: DiffUtil.ItemCallback) 7 | : PagedListAdapter(diffCallback) where VH: BaseViewHolder { 8 | 9 | private val _selectedItems = mutableMapOf() 10 | val selectedItems: Map get() = _selectedItems 11 | 12 | abstract fun onClearSelectedItems() 13 | 14 | fun isSelectedItem(pos: Int): Boolean = _selectedItems.containsKey(pos) 15 | 16 | override fun onBindViewHolder(holder: VH, position: Int) { 17 | holder.bind(getItem(position)) 18 | } 19 | 20 | fun deselectAll() { 21 | val iterator = _selectedItems.iterator() 22 | while (iterator.hasNext()) { 23 | val selectedItem = iterator.next() 24 | if (_selectedItems.containsKey(selectedItem.key)) { 25 | notifyItemChanged(selectedItem.key) 26 | iterator.remove() 27 | } 28 | } 29 | } 30 | 31 | fun deselectItem(pos: Int) { 32 | _selectedItems.remove(pos) 33 | notifyItemChanged(pos) 34 | } 35 | 36 | fun toggleSelection(request: T?, pos: Int) { 37 | if (_selectedItems.containsKey(pos)) { 38 | _selectedItems.remove(pos) 39 | if (_selectedItems.isEmpty()) { 40 | onClearSelectedItems() 41 | } 42 | } else { 43 | request?.let { 44 | _selectedItems[pos] = it 45 | } 46 | } 47 | 48 | notifyItemChanged(pos) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/presentation/base/BaseViewHolder.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.presentation.base 2 | 3 | import android.view.View 4 | import androidx.recyclerview.widget.RecyclerView 5 | 6 | abstract class BaseViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { 7 | 8 | protected var boundItem: T? = null 9 | 10 | open fun bind(item: T?) { 11 | boundItem = item 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/presentation/base/BaseViewModel.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.presentation.base 2 | 3 | import androidx.lifecycle.ViewModel 4 | 5 | abstract class BaseViewModel : ViewModel() 6 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/presentation/extension/AdExt.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.presentation.extension 2 | 3 | import android.os.Bundle 4 | import com.google.ads.mediation.admob.AdMobAdapter 5 | import com.google.android.gms.ads.AdRequest 6 | 7 | fun AdRequest.Builder.setNonPersonalized() { 8 | this.addNetworkExtrasBundle(AdMobAdapter::class.java, Bundle().apply { 9 | putString("npa", "1") 10 | }) 11 | } 12 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/presentation/extension/CoroutineScopeExt.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.presentation.extension 2 | 3 | import kotlinx.coroutines.CoroutineScope 4 | import kotlinx.coroutines.Dispatchers 5 | import kotlinx.coroutines.launch 6 | 7 | fun CoroutineScope.io(codeBlock: suspend CoroutineScope.() -> Unit) { 8 | launch(Dispatchers.IO) { 9 | codeBlock() 10 | } 11 | } -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/presentation/extension/DateExt.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.presentation.extension 2 | 3 | import java.text.SimpleDateFormat 4 | import java.util.* 5 | 6 | fun Date?.toDateString(): String? { 7 | this?.let { 8 | return SimpleDateFormat("dd MMM hh:mm", Locale.getDefault()).format(this) 9 | } 10 | return null 11 | } -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/presentation/extension/GsonExt.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.presentation.extension 2 | 3 | import com.google.gson.Gson 4 | 5 | fun Any?.toJson(): String? { 6 | return Gson().toJson(this) 7 | } -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/presentation/extension/LifecycleExt.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.presentation.extension 2 | 3 | import android.widget.Toast 4 | import androidx.annotation.StringRes 5 | import me.ibrahimsn.core.presentation.base.BaseFragment 6 | 7 | fun BaseFragment.showToast(@StringRes textRes: Int) { 8 | this.activity?.let { 9 | Toast.makeText(it, textRes, Toast.LENGTH_SHORT).show() 10 | } 11 | } 12 | 13 | fun BaseFragment.showToast(text: String?) { 14 | this.activity?.let { 15 | Toast.makeText(it, text, Toast.LENGTH_SHORT).show() 16 | } 17 | } -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/presentation/extension/LiveDataExt.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.presentation.extension 2 | 3 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/presentation/extension/RequestExt.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.presentation.extension 2 | 3 | import com.google.gson.Gson 4 | import me.ibrahimsn.core.domain.model.param.Param 5 | import me.ibrahimsn.core.domain.model.request.Request 6 | 7 | fun Request?.getHeaderParams(): List? { 8 | this?.headerParams?.let { 9 | return Gson().fromJson(it, Array::class.java)?.toList() 10 | } 11 | 12 | return null 13 | } 14 | 15 | fun Request?.getBodyParams(): List? { 16 | this?.bodyParams?.let { 17 | return Gson().fromJson(it, Array::class.java)?.toList() 18 | } 19 | 20 | return null 21 | } -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/presentation/extension/StringExt.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.presentation.extension 2 | 3 | import okhttp3.Request 4 | 5 | fun String?.isValidUri(): Boolean { 6 | if (this.isNullOrEmpty()) return false 7 | return try { 8 | Request.Builder().url(this) 9 | true 10 | } catch (e: Exception) { 11 | false 12 | } 13 | } -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/presentation/extension/ViewExt.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.presentation.extension 2 | 3 | import android.view.View 4 | import android.widget.CheckBox 5 | import android.widget.EditText 6 | import android.widget.TextView 7 | 8 | fun View?.show() { 9 | this?.visibility = View.VISIBLE 10 | } 11 | 12 | fun View?.dismiss() { 13 | this?.visibility = View.GONE 14 | } 15 | 16 | fun View?.showIf(condition: Boolean?) { 17 | this?.visibility = if (condition == true) View.VISIBLE else View.GONE 18 | } 19 | 20 | fun EditText?.setTextSilently(text: String?) { 21 | this?.tag = "#" 22 | this?.setText(text) 23 | this?.tag = null 24 | } 25 | 26 | fun CheckBox?.setCheckedSilently(isChecked: Boolean) { 27 | this?.tag = "#" 28 | this?.isChecked = isChecked 29 | this?.tag = null 30 | } 31 | 32 | fun TextView?.postText(text: String?) { 33 | this?.post { 34 | this.text = text 35 | } 36 | } -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/presentation/extension/WebsocketExt.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.presentation.extension 2 | 3 | import com.google.gson.Gson 4 | import me.ibrahimsn.core.domain.model.param.Param 5 | import me.ibrahimsn.core.domain.model.websocket.Websocket 6 | 7 | fun Websocket?.getHeaderParams(): List? { 8 | this?.headerParams?.let { 9 | return Gson().fromJson(it, Array::class.java)?.toList() 10 | } 11 | 12 | return null 13 | } 14 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/presentation/livedata/SingleLiveEvent.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.presentation.livedata 2 | 3 | import androidx.annotation.MainThread 4 | import androidx.annotation.Nullable 5 | import androidx.lifecycle.LifecycleOwner 6 | import androidx.lifecycle.MutableLiveData 7 | import androidx.lifecycle.Observer 8 | import java.util.concurrent.atomic.AtomicBoolean 9 | 10 | class SingleLiveEvent: MutableLiveData() { 11 | 12 | private val pending = AtomicBoolean(false) 13 | 14 | @MainThread 15 | override fun observe(owner: LifecycleOwner, observer: Observer) { 16 | super.observe(owner, Observer { t -> 17 | if (pending.compareAndSet(true, false)) { 18 | observer.onChanged(t) 19 | } 20 | }) 21 | } 22 | 23 | @MainThread 24 | override fun setValue(@Nullable t: T?) { 25 | pending.set(true) 26 | super.setValue(t) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/presentation/ui/param/ParamAdapter.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.presentation.ui.param 2 | 3 | import android.view.LayoutInflater 4 | import android.view.View 5 | import android.view.ViewGroup 6 | import androidx.core.widget.addTextChangedListener 7 | import kotlinx.android.synthetic.main.row_param.view.* 8 | import me.ibrahimsn.core.R 9 | import me.ibrahimsn.core.domain.model.param.Param 10 | import me.ibrahimsn.core.presentation.base.BaseAdapter 11 | import me.ibrahimsn.core.presentation.base.BaseViewHolder 12 | import me.ibrahimsn.core.presentation.extension.setCheckedSilently 13 | import me.ibrahimsn.core.presentation.extension.setTextSilently 14 | 15 | class ParamAdapter( 16 | private val onParamsUpdatedListener: (List) -> Unit? 17 | ) : BaseAdapter() { 18 | 19 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ParamViewHolder { 20 | val view = LayoutInflater.from(parent.context).inflate(R.layout.row_param, parent, false) 21 | return ParamViewHolder(view) 22 | } 23 | 24 | fun addParam(param: Param) { 25 | items.add(param) 26 | notifyItemInserted(itemCount - 1) 27 | } 28 | 29 | fun setParams(params: List?) { 30 | params?.let { 31 | items.clear() 32 | items.addAll(params) 33 | notifyDataSetChanged() 34 | } 35 | } 36 | 37 | fun getParams(): List { 38 | return items 39 | } 40 | 41 | override fun areItemsTheSame(oldItem: Param, newItem: Param): Boolean { 42 | return oldItem.key == newItem.key 43 | } 44 | 45 | override fun areContentsTheSame(oldItem: Param, newItem: Param): Boolean { 46 | return oldItem.value == newItem.value 47 | } 48 | 49 | inner class ParamViewHolder(private val view: View) : BaseViewHolder(view) { 50 | 51 | override fun bind(item: Param?) { 52 | super.bind(item) 53 | 54 | item?.let { 55 | view.cbActive.setCheckedSilently(it.isActive) 56 | view.etKey.setTextSilently(it.key) 57 | view.etValue.setTextSilently(it.value) 58 | } 59 | } 60 | 61 | init { 62 | view.cbActive.setOnCheckedChangeListener { _, isChecked -> 63 | boundItem?.apply { 64 | if (view.cbActive.tag == null) { 65 | isActive = isChecked 66 | onParamsUpdatedListener.invoke(items) 67 | } 68 | } 69 | } 70 | 71 | // May cause memory leaks! Needs refactor 72 | view.etKey.addTextChangedListener { 73 | boundItem?.apply { 74 | if (view.etKey.tag == null) { 75 | key = it.toString() 76 | onParamsUpdatedListener.invoke(items) 77 | } 78 | } 79 | } 80 | 81 | view.etValue.addTextChangedListener { 82 | boundItem?.apply { 83 | if (view.etValue.tag == null) { 84 | value = it.toString() 85 | onParamsUpdatedListener.invoke(items) 86 | } 87 | } 88 | } 89 | 90 | view.ibRemove.setOnClickListener { 91 | boundItem?.apply { 92 | val index = items.indexOf(this) 93 | items.removeAt(index) 94 | notifyItemRemoved(index) 95 | onParamsUpdatedListener(items) 96 | } 97 | } 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/presentation/view/progressButton/ProgressButton.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.presentation.view.progressButton 2 | 3 | import android.animation.ValueAnimator 4 | import android.content.Context 5 | import android.graphics.Canvas 6 | import android.graphics.Color 7 | import android.graphics.Paint 8 | import android.graphics.RectF 9 | import android.graphics.drawable.Drawable 10 | import android.util.AttributeSet 11 | import androidx.appcompat.widget.AppCompatImageButton 12 | import me.ibrahimsn.core.R 13 | 14 | class ProgressButton : AppCompatImageButton { 15 | 16 | private val loadingStrokeWidth = 5f 17 | 18 | private var icon: Drawable? = null 19 | private var reverseIcon: Drawable? = null 20 | 21 | private var loadingAngle = 0f 22 | private val loaderRect = RectF() 23 | 24 | private var _isReversed: Boolean = false 25 | private var _isProcessing: Boolean = false 26 | 27 | private val paintProgress = Paint().apply { 28 | isAntiAlias = true 29 | style = Paint.Style.STROKE 30 | color = Color.parseColor("#01D36D") 31 | strokeWidth = loadingStrokeWidth 32 | strokeCap = Paint.Cap.ROUND 33 | } 34 | 35 | override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { 36 | super.onSizeChanged(w, h, oldw, oldh) 37 | loaderRect.set( 38 | loadingStrokeWidth, 39 | loadingStrokeWidth, 40 | width - loadingStrokeWidth, 41 | height - loadingStrokeWidth 42 | ) 43 | } 44 | 45 | constructor(context: Context) : this(context, null) 46 | constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0) 47 | constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { 48 | val typedArray = context.theme.obtainStyledAttributes(attrs, R.styleable.ProgressButton, 0, 0) 49 | icon = typedArray.getDrawable(R.styleable.ProgressButton_icon) 50 | reverseIcon = typedArray.getDrawable(R.styleable.ProgressButton_reverseIcon) 51 | typedArray.recycle() 52 | 53 | setImageDrawable(icon) 54 | } 55 | 56 | var isReversed: Boolean get() = _isReversed 57 | set(value) { 58 | _isReversed = value 59 | setImageDrawable( 60 | if (value) reverseIcon else icon 61 | ) 62 | } 63 | 64 | var isProgressing: Boolean get() = _isProcessing 65 | set(value) { 66 | _isProcessing = value 67 | isEnabled = !isProgressing 68 | 69 | if (isProgressing) { 70 | anim.start() 71 | } else { 72 | anim.end() 73 | } 74 | } 75 | 76 | private val anim = ValueAnimator.ofFloat(0f, 360f).apply { 77 | repeatMode = ValueAnimator.RESTART 78 | repeatCount = ValueAnimator.INFINITE 79 | duration = 500 80 | 81 | addUpdateListener { 82 | loadingAngle = it.animatedValue as Float 83 | invalidate() 84 | } 85 | } 86 | 87 | override fun onDraw(canvas: Canvas) { 88 | super.onDraw(canvas) 89 | 90 | if (isProgressing) { 91 | canvas.drawArc(loaderRect, loadingAngle, 35f, false, paintProgress) 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/presentation/view/tabView/TabItem.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.presentation.view.tabView 2 | 3 | import android.graphics.RectF 4 | 5 | data class TabItem( 6 | var title: String, 7 | var rect: RectF = RectF() 8 | ) 9 | -------------------------------------------------------------------------------- /core/src/main/java/me/ibrahimsn/core/presentation/view/tabView/TabParser.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core.presentation.view.tabView 2 | 3 | import android.content.Context 4 | import android.content.res.Resources 5 | import android.content.res.XmlResourceParser 6 | import androidx.annotation.XmlRes 7 | 8 | class TabParser(private val context: Context, @XmlRes res: Int) { 9 | 10 | private val parser: XmlResourceParser = context.resources.getXml(res) 11 | 12 | fun parse(): List { 13 | val items: MutableList = mutableListOf() 14 | var eventType: Int? 15 | 16 | do { 17 | eventType = parser.next() 18 | if (eventType == XmlResourceParser.START_TAG && parser.name == "item") { 19 | items.add(getTabConfig(parser)) 20 | } 21 | } while (eventType != XmlResourceParser.END_DOCUMENT) 22 | 23 | return items 24 | } 25 | 26 | private fun getTabConfig(parser: XmlResourceParser): TabItem { 27 | val attributeCount = parser.attributeCount 28 | var itemText: String? = null 29 | 30 | for (index in 0 until attributeCount) { 31 | when (parser.getAttributeName(index)) { 32 | "title" -> { 33 | itemText = try { 34 | context.getString(parser.getAttributeResourceValue(index, 0)) 35 | } catch (notFoundException: Resources.NotFoundException) { 36 | parser.getAttributeValue(index) 37 | } 38 | } 39 | } 40 | } 41 | 42 | return TabItem(itemText ?: "") 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /core/src/main/res/drawable/ic_add_white_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /core/src/main/res/drawable/ic_background_box.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /core/src/main/res/drawable/ic_background_method.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /core/src/main/res/drawable/ic_background_method_delete.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /core/src/main/res/drawable/ic_background_method_get.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /core/src/main/res/drawable/ic_background_method_patch.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /core/src/main/res/drawable/ic_background_method_post.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /core/src/main/res/drawable/ic_background_method_put.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /core/src/main/res/drawable/ic_background_param_button.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /core/src/main/res/drawable/ic_background_response_status_fail.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /core/src/main/res/drawable/ic_background_response_status_success.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /core/src/main/res/drawable/ic_background_row.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /core/src/main/res/drawable/ic_close_white_18dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /core/src/main/res/drawable/ic_close_white_20dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /core/src/main/res/drawable/ic_close_white_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /core/src/main/res/drawable/ic_delete_white_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /core/src/main/res/drawable/ic_expand_less_white_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /core/src/main/res/drawable/ic_expand_more_white_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /core/src/main/res/drawable/ic_keyboard_arrow_right_white_18dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /core/src/main/res/drawable/ic_send_white_20dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /core/src/main/res/drawable/ic_send_white_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /core/src/main/res/font/lato.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /core/src/main/res/font/lato_bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/core/src/main/res/font/lato_bold.ttf -------------------------------------------------------------------------------- /core/src/main/res/font/lato_regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/core/src/main/res/font/lato_regular.ttf -------------------------------------------------------------------------------- /core/src/main/res/layout/row_param.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 14 | 15 | 21 | 22 | 41 | 42 | 59 | 60 | 61 | 62 | 69 | 70 | -------------------------------------------------------------------------------- /core/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /core/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #15171f 5 | #15171f 6 | #3eb63e 7 | 8 | #707593 9 | 10 | #3eb63e 11 | #f5a623 12 | #4a90e2 13 | #ed4b48 14 | #9C27B0 15 | 16 | #0D3EB63E 17 | #0DF5A623 18 | #0D4A90E2 19 | #0DED4B48 20 | #0C9C27B0 21 | 22 | #15171f 23 | #1c1e28 24 | 25 | #3eb63e 26 | #ed4b48 27 | 28 | #21212B 29 | #606060 30 | 31 | #ffffff 32 | #80ffffff 33 | #16ffffff 34 | 35 | #f3f3f3 36 | #acffffff 37 | #526d76 38 | 39 | #f51f1f29 40 | 41 | -------------------------------------------------------------------------------- /core/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Invalid parameters 4 | Empty Uri 5 | Empty request body 6 | Network error 7 | Invalid Uri 8 | 9 | Query Params 10 | Header Params 11 | Body Params 12 | Response 13 | Response 14 | 15 | Enter body data… 16 | Key 17 | Value 18 | https://api.server.com 19 | wss://socket.server.com 20 | 21 | Add 22 | New 23 | Clear 24 | Clear 25 | Send 26 | 27 | Delete 28 | Settings 29 | 30 | Requests 31 | Websockets 32 | 33 | WS 34 | 35 | GET 36 | POST 37 | PUT 38 | DEL 39 | PATCH 40 | -------------------------------------------------------------------------------- /core/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 21 | 24 | 25 | 29 | 30 | 36 | 37 | 43 | 44 | -------------------------------------------------------------------------------- /core/src/test/java/me/ibrahimsn/core/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.core 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 | } 18 | -------------------------------------------------------------------------------- /feature/dashboard/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /feature/dashboard/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: Plugins.androidLibrary 2 | apply from: "$rootDir/common.gradle" 3 | 4 | dependencies { 5 | implementation(project(Modules.core)) 6 | implementation(project(Modules.navigation)) 7 | } 8 | -------------------------------------------------------------------------------- /feature/dashboard/consumer-rules.pro: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/feature/dashboard/consumer-rules.pro -------------------------------------------------------------------------------- /feature/dashboard/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /feature/dashboard/src/androidTest/java/me/ibrahimsn/dashboard/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.dashboard 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("me.ibrahimsn.dashboard.test", appContext.packageName) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /feature/dashboard/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /feature/dashboard/src/main/java/me/ibrahimsn/dashboard/di/DashboardViewModelModule.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.dashboard.di 2 | 3 | import me.ibrahimsn.core.domain.interactor.request.DeleteRequestsInteractor 4 | import me.ibrahimsn.core.domain.interactor.request.GetAllRequestsInteractor 5 | import me.ibrahimsn.core.domain.interactor.websocket.DeleteWebsocketsInteractor 6 | import me.ibrahimsn.core.domain.interactor.websocket.GetAllWebsocketsInteractor 7 | import me.ibrahimsn.dashboard.presentation.dashboard.DashboardViewModel 8 | import org.koin.androidx.viewmodel.dsl.viewModel 9 | import org.koin.core.qualifier.named 10 | import org.koin.dsl.module 11 | 12 | val dashboardViewModelModule = module { 13 | 14 | viewModel { 15 | DashboardViewModel( 16 | getAllRequestsInteractor = get(named(GetAllRequestsInteractor.NAME)), 17 | getAllWebsocketsInteractor = get(named(GetAllWebsocketsInteractor.NAME)), 18 | deleteRequestsInteractor = get(named(DeleteRequestsInteractor.NAME)), 19 | deleteWebsocketsInteractor = get(named(DeleteWebsocketsInteractor.NAME)) 20 | ) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /feature/dashboard/src/main/java/me/ibrahimsn/dashboard/presentation/dashboard/DashboardViewModel.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.dashboard.presentation.dashboard 2 | 3 | import androidx.lifecycle.viewModelScope 4 | import androidx.paging.LivePagedListBuilder 5 | import androidx.paging.PagedList 6 | import me.ibrahimsn.core.domain.interactor.Interactor 7 | import me.ibrahimsn.core.domain.interactor.request.DeleteRequestsInteractor 8 | import me.ibrahimsn.core.domain.interactor.websocket.DeleteWebsocketsInteractor 9 | import me.ibrahimsn.core.domain.model.request.Request 10 | import me.ibrahimsn.core.domain.model.websocket.Websocket 11 | import me.ibrahimsn.core.presentation.base.BaseViewModel 12 | import me.ibrahimsn.core.presentation.extension.io 13 | 14 | class DashboardViewModel( 15 | getAllRequestsInteractor: Interactor.PagingInteractor, 16 | getAllWebsocketsInteractor: Interactor.PagingInteractor, 17 | private val deleteRequestsInteractor: Interactor.RequestInteractor, 18 | private val deleteWebsocketsInteractor: Interactor.RequestInteractor 19 | ) : BaseViewModel() { 20 | 21 | private var _activeTab = 0 22 | var activeTab: Int get() = _activeTab 23 | set(value) { _activeTab = value } 24 | 25 | private val pagingConfig = PagedList.Config.Builder() 26 | .setEnablePlaceholders(false) 27 | .setPrefetchDistance(5) 28 | .setInitialLoadSizeHint(35) 29 | .setPageSize(25) 30 | .build() 31 | 32 | val pagedRequestLiveData = LivePagedListBuilder( 33 | getAllRequestsInteractor.invoke(), 34 | pagingConfig 35 | ).build() 36 | 37 | val pagedWebsocketLiveData = LivePagedListBuilder( 38 | getAllWebsocketsInteractor.invoke(), 39 | pagingConfig 40 | ).build() 41 | 42 | fun deleteRequests(requests: List?) { 43 | viewModelScope.io { 44 | deleteRequestsInteractor.invoke( 45 | DeleteRequestsInteractor.Params(requests) 46 | ) 47 | } 48 | } 49 | 50 | fun deleteWebsockets(websockets: List?) { 51 | viewModelScope.io { 52 | deleteWebsocketsInteractor.invoke( 53 | DeleteWebsocketsInteractor.Params(websockets) 54 | ) 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /feature/dashboard/src/main/java/me/ibrahimsn/dashboard/presentation/dashboard/RequestsAdapter.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.dashboard.presentation.dashboard 2 | 3 | import android.view.LayoutInflater 4 | import android.view.View 5 | import android.view.ViewGroup 6 | import androidx.core.content.ContextCompat 7 | import androidx.recyclerview.widget.DiffUtil 8 | import kotlinx.android.synthetic.main.row_rest.view.* 9 | import me.ibrahimsn.core.domain.model.request.Request 10 | import me.ibrahimsn.core.presentation.base.BasePagedAdapter 11 | import me.ibrahimsn.core.presentation.base.BaseViewHolder 12 | import me.ibrahimsn.core.presentation.extension.toDateString 13 | import me.ibrahimsn.dashboard.R 14 | 15 | class RequestsAdapter( 16 | private val onRequestClickListener: (Request?, Int) -> Unit?, 17 | private val onRequestLongClickListener: (Request?, Int) -> Unit?, 18 | private val onClearSelectedItemsListener: () -> Unit? 19 | ) : BasePagedAdapter(DiffCallback) { 20 | 21 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RequestsViewHolder { 22 | val view = LayoutInflater.from(parent.context).inflate(R.layout.row_rest, parent, false) 23 | return RequestsViewHolder(view) 24 | } 25 | 26 | override fun getItemId(position: Int): Long { 27 | return getItem(position)?.id ?: 0 28 | } 29 | 30 | override fun onClearSelectedItems() { 31 | onClearSelectedItemsListener.invoke() 32 | } 33 | 34 | inner class RequestsViewHolder (private val view: View) : BaseViewHolder(view) { 35 | 36 | init { 37 | itemView.setOnClickListener { 38 | onRequestClickListener.invoke(boundItem, adapterPosition) 39 | } 40 | 41 | itemView.setOnLongClickListener { 42 | onRequestLongClickListener.invoke(boundItem, adapterPosition) 43 | true 44 | } 45 | } 46 | 47 | override fun bind(item: Request?) { 48 | super.bind(item) 49 | 50 | view.tvUri.text = boundItem?.uri 51 | view.tvTime.text = boundItem?.createdAt.toDateString() 52 | view.textViewMethod.text = boundItem?.method?.shortName 53 | 54 | boundItem?.method?.colorRes?.let { 55 | view.textViewMethod.setTextColor( 56 | ContextCompat.getColor(itemView.context, it) 57 | ) 58 | } 59 | 60 | boundItem?.method?.backgroundRes?.let { 61 | view.textViewMethod.setBackgroundResource(it) 62 | } 63 | 64 | itemView.isSelected = isSelectedItem(adapterPosition) 65 | } 66 | } 67 | 68 | object DiffCallback : DiffUtil.ItemCallback() { 69 | 70 | override fun areItemsTheSame(oldItem: Request, newItem: Request): Boolean { 71 | return oldItem.id == newItem.id 72 | } 73 | 74 | override fun areContentsTheSame(oldItem: Request, newItem: Request): Boolean { 75 | return oldItem.uri == newItem.uri && 76 | oldItem.method == newItem.method && 77 | oldItem.headerParams == newItem.headerParams && 78 | oldItem.bodyParams == newItem.bodyParams 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /feature/dashboard/src/main/java/me/ibrahimsn/dashboard/presentation/dashboard/WebsocketsAdapter.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.dashboard.presentation.dashboard 2 | 3 | import android.view.LayoutInflater 4 | import android.view.View 5 | import android.view.ViewGroup 6 | import androidx.recyclerview.widget.DiffUtil 7 | import kotlinx.android.synthetic.main.row_ws.view.* 8 | import me.ibrahimsn.core.domain.model.websocket.Websocket 9 | import me.ibrahimsn.core.presentation.base.BasePagedAdapter 10 | import me.ibrahimsn.core.presentation.base.BaseViewHolder 11 | import me.ibrahimsn.core.presentation.extension.toDateString 12 | import me.ibrahimsn.dashboard.R 13 | 14 | class WebsocketsAdapter( 15 | private val onWebsocketClickListener: (Websocket?, Int) -> Unit?, 16 | private val onWebsocketLongClickListener: (Websocket?, Int) -> Unit?, 17 | private val onClearSelectedItemsListener: () -> Unit? 18 | ) : BasePagedAdapter(DiffCallback) { 19 | 20 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WebsocketsViewHolder { 21 | val view = LayoutInflater.from(parent.context).inflate(R.layout.row_ws, parent, false) 22 | return WebsocketsViewHolder(view) 23 | } 24 | 25 | override fun getItemId(position: Int): Long { 26 | return getItem(position)?.id ?: 0 27 | } 28 | 29 | override fun onClearSelectedItems() { 30 | onClearSelectedItemsListener.invoke() 31 | } 32 | 33 | inner class WebsocketsViewHolder (private val view: View) : BaseViewHolder(view) { 34 | 35 | init { 36 | itemView.setOnClickListener { 37 | onWebsocketClickListener.invoke(boundItem, adapterPosition) 38 | } 39 | 40 | itemView.setOnLongClickListener { 41 | onWebsocketLongClickListener.invoke(boundItem, adapterPosition) 42 | true 43 | } 44 | } 45 | 46 | override fun bind(item: Websocket?) { 47 | super.bind(item) 48 | 49 | view.tvUri.text = boundItem?.uri 50 | view.tvTime.text = boundItem?.createdAt.toDateString() 51 | 52 | itemView.isSelected = isSelectedItem(adapterPosition) 53 | } 54 | } 55 | 56 | object DiffCallback : DiffUtil.ItemCallback() { 57 | 58 | override fun areItemsTheSame(oldItem: Websocket, newItem: Websocket): Boolean { 59 | return oldItem.id == newItem.id 60 | } 61 | 62 | override fun areContentsTheSame(oldItem: Websocket, newItem: Websocket): Boolean { 63 | return oldItem == newItem 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /feature/dashboard/src/main/java/me/ibrahimsn/dashboard/presentation/home/HomeActivity.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.dashboard.presentation.home 2 | 3 | import android.content.Intent 4 | import android.util.DisplayMetrics 5 | import android.view.MenuItem 6 | import androidx.appcompat.widget.Toolbar 7 | import androidx.navigation.findNavController 8 | import androidx.navigation.ui.setupWithNavController 9 | import com.google.android.gms.ads.* 10 | import kotlinx.android.synthetic.main.activity_home.* 11 | import me.ibrahimsn.core.presentation.Constants 12 | import me.ibrahimsn.core.presentation.base.BaseActivity 13 | import me.ibrahimsn.core.presentation.extension.setNonPersonalized 14 | import me.ibrahimsn.core.presentation.model.ConsentManager 15 | import me.ibrahimsn.dashboard.R 16 | import me.ibrahimsn.dashboard.presentation.settings.SettingsActivity 17 | 18 | class HomeActivity : BaseActivity() { 19 | 20 | private lateinit var adView: AdView 21 | 22 | private val adSize: AdSize 23 | get() { 24 | val outMetrics = DisplayMetrics() 25 | windowManager.defaultDisplay.getMetrics(outMetrics) 26 | 27 | val density = outMetrics.density 28 | 29 | var adWidthPixels = adContainer.width.toFloat() 30 | if (adWidthPixels == 0f) { 31 | adWidthPixels = outMetrics.widthPixels.toFloat() 32 | } 33 | 34 | val adWidth = (adWidthPixels / density).toInt() 35 | return AdSize.getCurrentOrientationAnchoredAdaptiveBannerAdSize(this, adWidth) 36 | } 37 | 38 | override fun layoutRes() = R.layout.activity_home 39 | 40 | override fun menuRes() = R.menu.menu_home 41 | 42 | override fun toolbar(): Toolbar? = toolbar 43 | 44 | override fun showBackButton(): Boolean = true 45 | 46 | override fun initView() { 47 | toolbar.setupWithNavController(findNavController(R.id.navHost)) 48 | 49 | MobileAds.initialize(this) 50 | MobileAds.setRequestConfiguration( 51 | RequestConfiguration.Builder().setTestDeviceIds(listOf(Constants.ADMOB_TEST_DEVICE)).build() 52 | ) 53 | 54 | adView = AdView(this) 55 | adView.adUnitId = Constants.BANNER_AD_UNIT_ID 56 | adView.adSize = adSize 57 | adContainer.addView(adView) 58 | 59 | val adRequest = AdRequest.Builder() 60 | ConsentManager.getConsentStatus(this, true) { isPersonalized -> 61 | if (!isPersonalized) adRequest.setNonPersonalized() 62 | adView.loadAd(adRequest.build()) 63 | } 64 | } 65 | 66 | override fun onOptionsItemSelected(item: MenuItem): Boolean { 67 | when (item.itemId) { 68 | R.id.settings -> { 69 | startActivity(Intent(this, SettingsActivity::class.java)) 70 | } 71 | } 72 | return super.onOptionsItemSelected(item) 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /feature/dashboard/src/main/java/me/ibrahimsn/dashboard/presentation/settings/SettingsActivity.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.dashboard.presentation.settings 2 | 3 | import android.view.MenuItem 4 | import androidx.appcompat.widget.Toolbar 5 | import kotlinx.android.synthetic.main.activity_home.* 6 | import me.ibrahimsn.core.presentation.base.BaseActivity 7 | import me.ibrahimsn.dashboard.R 8 | 9 | class SettingsActivity : BaseActivity() { 10 | 11 | override fun layoutRes(): Int = R.layout.activity_settings 12 | 13 | override fun titleRes(): Int? = R.string.title_settings 14 | 15 | override fun toolbar(): Toolbar? = toolbar 16 | 17 | override fun showBackButton(): Boolean = true 18 | 19 | override fun initView() { 20 | supportFragmentManager.beginTransaction() 21 | .replace(R.id.frameLayout, SettingsFragment.newInstance()) 22 | .commit() 23 | } 24 | 25 | override fun onOptionsItemSelected(item: MenuItem): Boolean { 26 | when (item.itemId) { 27 | android.R.id.home -> { 28 | finish() 29 | } 30 | } 31 | return super.onOptionsItemSelected(item) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /feature/dashboard/src/main/java/me/ibrahimsn/dashboard/presentation/settings/SettingsFragment.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.dashboard.presentation.settings 2 | 3 | import android.content.Intent 4 | import android.net.Uri 5 | import android.os.Bundle 6 | import android.view.View 7 | import androidx.preference.Preference 8 | import androidx.preference.PreferenceFragmentCompat 9 | import androidx.preference.SwitchPreference 10 | import me.ibrahimsn.core.presentation.Constants 11 | import me.ibrahimsn.core.presentation.model.ConsentManager 12 | import me.ibrahimsn.dashboard.R 13 | 14 | class SettingsFragment : PreferenceFragmentCompat() { 15 | 16 | override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { 17 | setPreferencesFromResource(R.xml.settings, rootKey) 18 | } 19 | 20 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 21 | super.onViewCreated(view, savedInstanceState) 22 | val consentPreference = findPreference("key_consent_status_value") 23 | val privacyPreference = findPreference("key_privacy_policy") 24 | 25 | ConsentManager.getConsentStatus(context!!, false) { 26 | consentPreference?.isChecked = it 27 | } 28 | 29 | consentPreference?.setOnPreferenceChangeListener { _, newValue -> 30 | ConsentManager.setConsentStatus(context!!, newValue as Boolean) 31 | true 32 | } 33 | 34 | privacyPreference?.setOnPreferenceClickListener { 35 | startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(Constants.PRIVACY_URL))) 36 | true 37 | } 38 | } 39 | 40 | companion object { 41 | fun newInstance() = SettingsFragment() 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /feature/dashboard/src/main/res/layout/activity_home.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 14 | 15 | 23 | 24 | 29 | 30 | 31 | 32 | 42 | 43 | 48 | 49 | -------------------------------------------------------------------------------- /feature/dashboard/src/main/res/layout/activity_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 14 | 15 | 23 | 24 | 29 | 30 | 31 | 32 | 38 | 39 | -------------------------------------------------------------------------------- /feature/dashboard/src/main/res/layout/fragment_dashboard.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 24 | 25 | 32 | 33 | 37 | 38 | 39 | 40 | 48 | 49 | -------------------------------------------------------------------------------- /feature/dashboard/src/main/res/layout/fragment_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /feature/dashboard/src/main/res/layout/row_rest.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 25 | 26 | 31 | 32 | 39 | 40 | 46 | 47 | 48 | 49 | 53 | 54 | -------------------------------------------------------------------------------- /feature/dashboard/src/main/res/layout/row_ws.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 25 | 26 | 31 | 32 | 39 | 40 | 46 | 47 | 48 | 49 | 53 | 54 | -------------------------------------------------------------------------------- /feature/dashboard/src/main/res/menu/menu_action.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | -------------------------------------------------------------------------------- /feature/dashboard/src/main/res/menu/menu_home.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | -------------------------------------------------------------------------------- /feature/dashboard/src/main/res/menu/menu_tabs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /feature/dashboard/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Settings 5 | 6 | Rest Client 7 | Legal 8 | About 9 | 10 | Follow Redirect 11 | Personalized Ads 12 | Privacy Policy 13 | About 14 | 15 | Automatically follow redirects 16 | Show personalized ads 17 | Usage terms, privacy policies 18 | Web Developer Tools 2020 19 | 20 | -------------------------------------------------------------------------------- /feature/dashboard/src/main/res/xml/settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 8 | 9 | 15 | 16 | 17 | 18 | 21 | 22 | 27 | 28 | 33 | 34 | 35 | 36 | 39 | 40 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /feature/dashboard/src/test/java/me/ibrahimsn/dashboard/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.dashboard 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 | } 18 | -------------------------------------------------------------------------------- /feature/request/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /feature/request/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: Plugins.androidLibrary 2 | apply from: "$rootDir/common.gradle" 3 | 4 | dependencies { 5 | implementation(project(Modules.core)) 6 | implementation(project(Modules.navigation)) 7 | } 8 | -------------------------------------------------------------------------------- /feature/request/consumer-rules.pro: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/feature/request/consumer-rules.pro -------------------------------------------------------------------------------- /feature/request/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /feature/request/src/androidTest/java/me/ibrahimsn/request/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.request 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("me.ibrahimsn.request.test", appContext.packageName) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /feature/request/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | -------------------------------------------------------------------------------- /feature/request/src/main/java/me/ibrahimsn/request/di/RequestViewModelModule.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.request.di 2 | 3 | import me.ibrahimsn.core.domain.interactor.request.MakeRequestInteractor 4 | import me.ibrahimsn.core.domain.interactor.request.SaveOrUpdateRequestInteractor 5 | import me.ibrahimsn.core.domain.interactor.uri.GenerateUriInteractor 6 | import me.ibrahimsn.core.domain.interactor.uri.ParseUriParamsInteractor 7 | import me.ibrahimsn.request.presentation.request.RequestViewModel 8 | import org.koin.androidx.viewmodel.dsl.viewModel 9 | import org.koin.core.qualifier.named 10 | import org.koin.dsl.module 11 | 12 | val requestViewModelModule = module { 13 | 14 | viewModel { 15 | RequestViewModel( 16 | makeRequestInteractor = get(named(MakeRequestInteractor.NAME)), 17 | saveOrUpdateRequestInteractor = get(named(SaveOrUpdateRequestInteractor.NAME)), 18 | generateUriInteractor = get(named(GenerateUriInteractor.NAME)), 19 | parseUriParamsInteractor = get(named(ParseUriParamsInteractor.NAME)) 20 | ) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /feature/request/src/main/res/menu/menu_request_method.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 11 | 12 | 15 | 16 | 19 | 20 | 23 | 24 | -------------------------------------------------------------------------------- /feature/request/src/test/java/me/ibrahimsn/request/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.request 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 | } 18 | -------------------------------------------------------------------------------- /feature/websocket/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /feature/websocket/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: Plugins.androidLibrary 2 | apply from: "$rootDir/common.gradle" 3 | 4 | dependencies { 5 | implementation(project(Modules.core)) 6 | implementation(project(Modules.navigation)) 7 | } 8 | -------------------------------------------------------------------------------- /feature/websocket/consumer-rules.pro: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/feature/websocket/consumer-rules.pro -------------------------------------------------------------------------------- /feature/websocket/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /feature/websocket/src/androidTest/java/me/ibrahimsn/websocket/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.websocket 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("me.ibrahimsn.websocket.test", appContext.packageName) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /feature/websocket/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | -------------------------------------------------------------------------------- /feature/websocket/src/main/java/me/ibrahimsn/websocket/di/WebsocketViewModelModule.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.websocket.di 2 | 3 | import me.ibrahimsn.core.domain.interactor.websocket.ConnectWebsocketInteractor 4 | import me.ibrahimsn.core.domain.interactor.websocket.SaveOrUpdateWebsocketInteractor 5 | import me.ibrahimsn.websocket.presentation.websocket.WebsocketViewModel 6 | import org.koin.androidx.viewmodel.dsl.viewModel 7 | import org.koin.core.qualifier.named 8 | import org.koin.dsl.module 9 | 10 | val websocketViewModelModule = module { 11 | 12 | viewModel { 13 | WebsocketViewModel( 14 | connectWebsocketInteractor = get(named(ConnectWebsocketInteractor.NAME)), 15 | saveOrUpdateWebsocketInteractor = get(named(SaveOrUpdateWebsocketInteractor.NAME)) 16 | ) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /feature/websocket/src/test/java/me/ibrahimsn/websocket/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.websocket 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 | } 18 | -------------------------------------------------------------------------------- /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=-Xmx1536m 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 22 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Mar 20 20:30:59 EET 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-5.6.4-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 | -------------------------------------------------------------------------------- /navigation/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /navigation/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: Plugins.androidLibrary 2 | apply from: "$rootDir/common.gradle" 3 | 4 | dependencies { 5 | api Libraries.navigation 6 | api Libraries.navigationUi 7 | } 8 | -------------------------------------------------------------------------------- /navigation/consumer-rules.pro: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibrahimsn98/web-dev-tools-android/41074c267a41358af53801bd2979bba062fe8310/navigation/consumer-rules.pro -------------------------------------------------------------------------------- /navigation/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /navigation/src/androidTest/java/me/ibrahimsn/navigation/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.navigation 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("me.ibrahimsn.navigation.test", appContext.packageName) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /navigation/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | -------------------------------------------------------------------------------- /navigation/src/main/res/navigation/nav_graph.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 10 | 13 | 16 | 17 | 18 | 21 | 24 | 25 | 26 | 27 | 31 | 32 | 36 | 37 | -------------------------------------------------------------------------------- /navigation/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Dashboard 4 | Request 5 | Websocket 6 | -------------------------------------------------------------------------------- /navigation/src/test/java/me/ibrahimsn/navigation/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package me.ibrahimsn.navigation 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 | } 18 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name='webdevtools' 2 | include Modules.app 3 | include Modules.core 4 | include Modules.dashboard 5 | include Modules.request 6 | include Modules.websocket 7 | include Modules.navigation 8 | --------------------------------------------------------------------------------