├── .github
├── FUNDING.yml
└── workflows
│ └── ci.yml
├── .gitignore
├── LICENSE
├── README.md
├── android
├── annotation
│ ├── .gitignore
│ ├── build.gradle.kts
│ └── src
│ │ └── main
│ │ └── kotlin
│ │ └── com
│ │ └── bael
│ │ └── dads
│ │ └── annotation
│ │ └── RenderWith.kt
├── app
│ ├── .gitignore
│ ├── build.gradle.kts
│ ├── proguard-rules.pro
│ └── src
│ │ ├── debug
│ │ ├── AndroidManifest.xml
│ │ ├── google-services.json
│ │ ├── kotlin
│ │ │ └── com
│ │ │ │ └── bael
│ │ │ │ └── dads
│ │ │ │ └── DadsDebugApplication.kt
│ │ └── res
│ │ │ └── values
│ │ │ └── strings.xml
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── kotlin
│ │ │ └── com
│ │ │ │ └── bael
│ │ │ │ └── dads
│ │ │ │ ├── DadsApplication.kt
│ │ │ │ ├── activity
│ │ │ │ └── MainActivity.kt
│ │ │ │ └── di
│ │ │ │ └── module
│ │ │ │ └── MainActivityModule.kt
│ │ └── res
│ │ │ ├── drawable
│ │ │ └── ic_launcher_foreground.xml
│ │ │ ├── font
│ │ │ └── product_sans.ttf
│ │ │ ├── layout
│ │ │ └── activity_main.xml
│ │ │ ├── mipmap-anydpi-v26
│ │ │ ├── ic_launcher.xml
│ │ │ └── ic_launcher_round.xml
│ │ │ ├── values-night
│ │ │ └── styles.xml
│ │ │ ├── values
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ │ │ └── xml
│ │ │ └── provider_paths.xml
│ │ └── release
│ │ ├── AndroidManifest.xml
│ │ ├── google-services.enc
│ │ └── kotlin
│ │ └── com
│ │ └── bael
│ │ └── dads
│ │ └── DadsReleaseApplication.kt
├── feature
│ └── home
│ │ ├── .gitignore
│ │ ├── build.gradle.kts
│ │ ├── consumer-rules.pro
│ │ ├── proguard-rules.pro
│ │ └── src
│ │ ├── androidTest
│ │ └── kotlin
│ │ │ └── com
│ │ │ └── bael
│ │ │ └── dads
│ │ │ └── feature
│ │ │ └── home
│ │ │ ├── screen
│ │ │ ├── home
│ │ │ │ └── UITest.kt
│ │ │ └── seen
│ │ │ │ └── UITest.kt
│ │ │ ├── sheet
│ │ │ ├── detail
│ │ │ │ └── UITest.kt
│ │ │ ├── settings
│ │ │ │ └── UITest.kt
│ │ │ └── sharepreview
│ │ │ │ └── UITest.kt
│ │ │ └── worker
│ │ │ ├── FetchDadJokeFeedWorkerTest.kt
│ │ │ └── factory
│ │ │ └── FakeFetchDadJokeFeedWorkerFactory.kt
│ │ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── assets
│ │ └── anim_reminder.json
│ │ ├── kotlin
│ │ └── com
│ │ │ └── bael
│ │ │ └── dads
│ │ │ └── feature
│ │ │ └── home
│ │ │ ├── adapter
│ │ │ ├── DadJokeFeedAdapter.kt
│ │ │ ├── SeenDadJokeAdapter.kt
│ │ │ ├── cell
│ │ │ │ ├── DadJokeFeedCell.kt
│ │ │ │ └── SeenDadJokeCell.kt
│ │ │ └── diffcallback
│ │ │ │ └── DadJokeDiffCallback.kt
│ │ │ ├── animation
│ │ │ └── Animation.kt
│ │ │ ├── di
│ │ │ └── module
│ │ │ │ ├── screen
│ │ │ │ ├── FeedScreenModule.kt
│ │ │ │ ├── HomeScreenModule.kt
│ │ │ │ └── SeenScreenModule.kt
│ │ │ │ └── sheet
│ │ │ │ ├── DetailSheetModule.kt
│ │ │ │ ├── SettingsSheetModule.kt
│ │ │ │ └── SharePreviewSheetModule.kt
│ │ │ ├── notification
│ │ │ ├── NewFeedReminderNotification.kt
│ │ │ └── factory
│ │ │ │ └── NewFeedReminderNotificationFactory.kt
│ │ │ ├── screen
│ │ │ ├── feed
│ │ │ │ ├── Event.kt
│ │ │ │ ├── Renderer.kt
│ │ │ │ ├── State.kt
│ │ │ │ ├── UI.kt
│ │ │ │ └── ViewModel.kt
│ │ │ ├── home
│ │ │ │ ├── Event.kt
│ │ │ │ ├── Renderer.kt
│ │ │ │ ├── State.kt
│ │ │ │ ├── UI.kt
│ │ │ │ └── ViewModel.kt
│ │ │ └── seen
│ │ │ │ ├── Event.kt
│ │ │ │ ├── Renderer.kt
│ │ │ │ ├── State.kt
│ │ │ │ ├── UI.kt
│ │ │ │ └── ViewModel.kt
│ │ │ ├── sheet
│ │ │ ├── detail
│ │ │ │ ├── Event.kt
│ │ │ │ ├── Renderer.kt
│ │ │ │ ├── State.kt
│ │ │ │ ├── UI.kt
│ │ │ │ └── ViewModel.kt
│ │ │ ├── settings
│ │ │ │ ├── Event.kt
│ │ │ │ ├── Renderer.kt
│ │ │ │ ├── State.kt
│ │ │ │ ├── UI.kt
│ │ │ │ └── ViewModel.kt
│ │ │ └── sharepreview
│ │ │ │ ├── Event.kt
│ │ │ │ ├── Renderer.kt
│ │ │ │ ├── State.kt
│ │ │ │ ├── UI.kt
│ │ │ │ └── ViewModel.kt
│ │ │ └── worker
│ │ │ └── FetchDadJokeFeedWorker.kt
│ │ └── res
│ │ ├── drawable
│ │ ├── bg_border.xml
│ │ ├── bg_round.xml
│ │ ├── ic_clear.xml
│ │ ├── ic_feed.xml
│ │ ├── ic_like.xml
│ │ ├── ic_like_outline.xml
│ │ ├── ic_logo.xml
│ │ ├── ic_no_internet.xml
│ │ ├── ic_search.xml
│ │ ├── ic_seen.xml
│ │ ├── ic_settings.xml
│ │ └── ic_share.xml
│ │ ├── layout
│ │ ├── cell_feed.xml
│ │ ├── cell_seen.xml
│ │ ├── item_group_settings.xml
│ │ ├── item_menu.xml
│ │ ├── item_setting.xml
│ │ ├── screen_feed.xml
│ │ ├── screen_home.xml
│ │ ├── screen_seen.xml
│ │ ├── sheet_detail.xml
│ │ ├── sheet_settings.xml
│ │ ├── sheet_share_preview.xml
│ │ └── toolbar_home.xml
│ │ ├── navigation
│ │ └── nav_graph.xml
│ │ ├── values
│ │ └── strings.xml
│ │ └── xml
│ │ ├── scene_favorite_menu.xml
│ │ └── scene_feed.xml
├── library
│ ├── instrumentation
│ │ ├── .gitignore
│ │ ├── build.gradle.kts
│ │ ├── consumer-rules.pro
│ │ ├── proguard-rules.pro
│ │ └── src
│ │ │ └── main
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── kotlin
│ │ │ └── com
│ │ │ │ └── bael
│ │ │ │ └── dads
│ │ │ │ └── library
│ │ │ │ └── instrumentation
│ │ │ │ ├── activity
│ │ │ │ └── MainTestActivity.kt
│ │ │ │ ├── di
│ │ │ │ └── module
│ │ │ │ │ └── MainTestActivityModule.kt
│ │ │ │ ├── fragment
│ │ │ │ ├── BaseFragmentTest.kt
│ │ │ │ └── FragmentExt.kt
│ │ │ │ ├── matcher
│ │ │ │ └── MatcherParams.kt
│ │ │ │ ├── runner
│ │ │ │ └── HiltTestRunner.kt
│ │ │ │ ├── sheet
│ │ │ │ └── BaseSheetTest.kt
│ │ │ │ ├── ui
│ │ │ │ └── BaseUITest.kt
│ │ │ │ └── worker
│ │ │ │ └── BaseWorkerTest.kt
│ │ │ └── res
│ │ │ └── values
│ │ │ └── styles.xml
│ ├── preference
│ │ ├── .gitignore
│ │ ├── build.gradle.kts
│ │ ├── consumer-rules.pro
│ │ ├── proguard-rules.pro
│ │ └── src
│ │ │ └── main
│ │ │ ├── AndroidManifest.xml
│ │ │ └── kotlin
│ │ │ └── com
│ │ │ └── bael
│ │ │ └── dads
│ │ │ └── library
│ │ │ └── preference
│ │ │ ├── DataStorePreference.kt
│ │ │ ├── Preference.kt
│ │ │ └── di
│ │ │ └── module
│ │ │ └── PreferenceModule.kt
│ ├── preference_test
│ │ ├── .gitignore
│ │ ├── build.gradle.kts
│ │ ├── consumer-rules.pro
│ │ ├── proguard-rules.pro
│ │ └── src
│ │ │ └── main
│ │ │ ├── AndroidManifest.xml
│ │ │ └── kotlin
│ │ │ └── com
│ │ │ └── bael
│ │ │ └── dads
│ │ │ └── library
│ │ │ └── preference
│ │ │ └── test
│ │ │ ├── FakePreference.kt
│ │ │ └── di
│ │ │ └── module
│ │ │ └── PreferenceTestModule.kt
│ ├── presentation
│ │ ├── .gitignore
│ │ ├── build.gradle.kts
│ │ ├── consumer-rules.pro
│ │ ├── proguard-rules.pro
│ │ └── src
│ │ │ └── main
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── assets
│ │ │ ├── anim_empty.json
│ │ │ ├── anim_error.json
│ │ │ ├── anim_loading.json
│ │ │ └── anim_no_internet.json
│ │ │ ├── kotlin
│ │ │ └── com
│ │ │ │ └── bael
│ │ │ │ └── dads
│ │ │ │ └── library
│ │ │ │ └── presentation
│ │ │ │ ├── di
│ │ │ │ └── qualifier
│ │ │ │ │ └── ActivityNameQualifier.kt
│ │ │ │ ├── event
│ │ │ │ └── EventStore.kt
│ │ │ │ ├── ext
│ │ │ │ ├── ContextExt.kt
│ │ │ │ ├── DrawableExt.kt
│ │ │ │ ├── FragmentExt.kt
│ │ │ │ ├── SoftKeyboardExt.kt
│ │ │ │ ├── StateExt.kt
│ │ │ │ └── StringExt.kt
│ │ │ │ ├── fragment
│ │ │ │ └── BaseFragment.kt
│ │ │ │ ├── notification
│ │ │ │ ├── NotificationConfiguration.kt
│ │ │ │ └── NotificationPublisher.kt
│ │ │ │ ├── renderer
│ │ │ │ ├── BaseRenderExecutor.kt
│ │ │ │ ├── BaseRenderer.kt
│ │ │ │ └── RendererInitializer.kt
│ │ │ │ ├── sheet
│ │ │ │ └── BaseSheet.kt
│ │ │ │ ├── state
│ │ │ │ ├── BaseState.kt
│ │ │ │ └── StateStore.kt
│ │ │ │ ├── store
│ │ │ │ └── Store.kt
│ │ │ │ ├── viewmodel
│ │ │ │ └── BaseViewModel.kt
│ │ │ │ └── widget
│ │ │ │ ├── animation
│ │ │ │ └── Animation.kt
│ │ │ │ ├── listener
│ │ │ │ ├── OnPageSnapListener.kt
│ │ │ │ └── OnTextChangedListener.kt
│ │ │ │ ├── recyclerview
│ │ │ │ └── adapter
│ │ │ │ │ ├── BaseAdapter.kt
│ │ │ │ │ ├── BaseListAdapter.kt
│ │ │ │ │ ├── LiveListAdapter.kt
│ │ │ │ │ ├── ResponseStateAdapter.kt
│ │ │ │ │ ├── SingleItemAdapter.kt
│ │ │ │ │ ├── cell
│ │ │ │ │ ├── BaseCell.kt
│ │ │ │ │ └── ResponseStateCell.kt
│ │ │ │ │ └── data
│ │ │ │ │ └── ResponseState.kt
│ │ │ │ ├── tab
│ │ │ │ ├── adapter
│ │ │ │ │ └── BottomTabAdapter.kt
│ │ │ │ └── data
│ │ │ │ │ └── BottomTab.kt
│ │ │ │ └── viewpager
│ │ │ │ ├── NestedScrollableHost.kt
│ │ │ │ ├── adapter
│ │ │ │ └── ScreenPagerAdapter.kt
│ │ │ │ └── transformer
│ │ │ │ └── StackTransformer.kt
│ │ │ └── res
│ │ │ ├── drawable
│ │ │ ├── bg_circle.xml
│ │ │ └── bg_sheet.xml
│ │ │ ├── layout
│ │ │ ├── item_bottom_tab.xml
│ │ │ └── item_response_state.xml
│ │ │ ├── values-night
│ │ │ └── styles.xml
│ │ │ ├── values
│ │ │ ├── colors.xml
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ │ │ └── xml
│ │ │ └── scene_bottom_tab.xml
│ ├── threading
│ │ ├── .gitignore
│ │ ├── build.gradle.kts
│ │ ├── consumer-rules.pro
│ │ ├── proguard-rules.pro
│ │ └── src
│ │ │ └── main
│ │ │ ├── AndroidManifest.xml
│ │ │ └── kotlin
│ │ │ └── com
│ │ │ └── bael
│ │ │ └── dads
│ │ │ └── library
│ │ │ └── threading
│ │ │ ├── DefaultThread.kt
│ │ │ ├── Thread.kt
│ │ │ └── di
│ │ │ └── module
│ │ │ └── ThreadingModule.kt
│ ├── threading_test
│ │ ├── .gitignore
│ │ ├── build.gradle.kts
│ │ ├── consumer-rules.pro
│ │ ├── proguard-rules.pro
│ │ └── src
│ │ │ └── main
│ │ │ ├── AndroidManifest.xml
│ │ │ └── kotlin
│ │ │ └── com
│ │ │ └── bael
│ │ │ └── dads
│ │ │ └── library
│ │ │ └── threading
│ │ │ └── test
│ │ │ ├── FakeThread.kt
│ │ │ └── di
│ │ │ └── module
│ │ │ └── ThreadingTestModule.kt
│ └── worker
│ │ ├── .gitignore
│ │ ├── build.gradle.kts
│ │ ├── consumer-rules.pro
│ │ ├── proguard-rules.pro
│ │ └── src
│ │ └── main
│ │ ├── AndroidManifest.xml
│ │ └── kotlin
│ │ └── com
│ │ └── bael
│ │ └── dads
│ │ └── library
│ │ └── worker
│ │ ├── BaseWorker.kt
│ │ ├── di
│ │ ├── entry
│ │ │ └── EntryPoint.kt
│ │ └── module
│ │ │ └── WorkerModule.kt
│ │ ├── factory
│ │ └── NoOpWorkerFactory.kt
│ │ └── initializer
│ │ └── WorkManagerInitializer.kt
└── processor
│ ├── .gitignore
│ ├── build.gradle.kts
│ └── src
│ └── main
│ └── kotlin
│ └── com
│ └── bael
│ └── dads
│ └── processor
│ ├── ext
│ ├── AnnotationMirrorExt.kt
│ ├── ClassNameExt.kt
│ ├── ElementExt.kt
│ ├── NameExt.kt
│ └── TypeElementExt.kt
│ ├── generator
│ ├── BaseGenerator.kt
│ ├── render
│ │ ├── RenderGenerator.kt
│ │ └── file
│ │ │ ├── DefaultRendererInitializerFile.kt
│ │ │ └── RenderExecutorFile.kt
│ └── util
│ │ └── CustomEquals.kt
│ └── logger
│ └── Logger.kt
├── assets
├── architecture.png
├── demo.gif
├── graphql.png
├── kmm.png
├── logo.png
├── mad_scorecard.png
└── playstore.png
├── build.gradle.kts
├── buildSrc
├── build.gradle.kts
├── buildSrc
│ ├── build.gradle.kts
│ └── src
│ │ └── main
│ │ └── kotlin
│ │ ├── Application.kt
│ │ ├── Library.kt
│ │ ├── Plugin.kt
│ │ └── Version.kt
└── src
│ └── main
│ └── kotlin
│ └── plugin
│ ├── android
│ ├── AppModulePlugin.kt
│ ├── FeatureModulePlugin.kt
│ └── LibraryModulePlugin.kt
│ ├── shared
│ ├── DataModulePlugin.kt
│ ├── DomainModulePlugin.kt
│ └── SharedModulePlugin.kt
│ └── test
│ └── JacocoTestReportPlugin.kt
├── data
├── database
│ ├── .gitignore
│ ├── build.gradle.kts
│ ├── consumer-rules.pro
│ ├── proguard-rules.pro
│ └── src
│ │ ├── androidMain
│ │ ├── AndroidManifest.xml
│ │ └── kotlin
│ │ │ └── com
│ │ │ └── bael
│ │ │ └── dads
│ │ │ └── data
│ │ │ └── database
│ │ │ └── di
│ │ │ └── module
│ │ │ ├── DatabaseModule.kt
│ │ │ └── repository
│ │ │ └── RepositoryModule.kt
│ │ └── commonMain
│ │ ├── kotlin
│ │ └── com
│ │ │ └── bael
│ │ │ └── dads
│ │ │ └── data
│ │ │ └── database
│ │ │ ├── constant
│ │ │ └── Database.kt
│ │ │ └── repository
│ │ │ ├── DadJokeRepository.kt
│ │ │ ├── DefaultDadJokeRepository.kt
│ │ │ ├── DefaultRemoteMetaRepository.kt
│ │ │ └── RemoteMetaRepository.kt
│ │ └── sqldelight
│ │ └── com
│ │ └── bael
│ │ └── dads
│ │ └── data
│ │ └── database
│ │ └── entity
│ │ ├── DadJoke.sq
│ │ └── RemoteMeta.sq
├── database_test
│ ├── .gitignore
│ ├── build.gradle.kts
│ ├── consumer-rules.pro
│ ├── proguard-rules.pro
│ └── src
│ │ └── androidMain
│ │ ├── AndroidManifest.xml
│ │ └── kotlin
│ │ └── com
│ │ └── bael
│ │ └── dads
│ │ └── data
│ │ └── database
│ │ └── test
│ │ └── di
│ │ └── module
│ │ └── DatabaseTestModule.kt
├── remote
│ ├── .gitignore
│ ├── build.gradle.kts
│ ├── consumer-rules.pro
│ ├── proguard-rules.pro
│ └── src
│ │ ├── androidMain
│ │ ├── AndroidManifest.xml
│ │ └── kotlin
│ │ │ └── com
│ │ │ └── bael
│ │ │ └── dads
│ │ │ └── data
│ │ │ └── remote
│ │ │ ├── di
│ │ │ └── module
│ │ │ │ ├── client
│ │ │ │ └── ApolloClientModule.kt
│ │ │ │ ├── interceptor
│ │ │ │ └── InterceptorModule.kt
│ │ │ │ ├── mapper
│ │ │ │ ├── ListMapperModule.kt
│ │ │ │ ├── MapperModule.kt
│ │ │ │ └── ResultMapperModule.kt
│ │ │ │ └── service
│ │ │ │ └── ServiceModule.kt
│ │ │ └── network
│ │ │ └── Network.kt
│ │ └── commonMain
│ │ ├── graphql
│ │ └── com
│ │ │ └── bael
│ │ │ └── dads
│ │ │ └── data
│ │ │ └── remote
│ │ │ ├── fragment
│ │ │ └── DadJokeFragment.graphql
│ │ │ └── query
│ │ │ └── DadJokesQuery.graphql
│ │ └── kotlin
│ │ └── com
│ │ └── bael
│ │ └── dads
│ │ └── data
│ │ └── remote
│ │ ├── constant
│ │ └── Server.kt
│ │ ├── interceptor
│ │ └── NetworkInterceptor.kt
│ │ ├── mapper
│ │ ├── DadJokeMapper.kt
│ │ └── DadJokesResponseMapper.kt
│ │ ├── model
│ │ └── DadJoke.kt
│ │ ├── network
│ │ └── Network.kt
│ │ ├── response
│ │ └── DadJokesResponse.kt
│ │ └── service
│ │ ├── BaseApolloService.kt
│ │ ├── DadsApolloService.kt
│ │ └── DadsService.kt
└── remote_test
│ ├── .gitignore
│ ├── build.gradle.kts
│ ├── consumer-rules.pro
│ ├── proguard-rules.pro
│ └── src
│ ├── androidMain
│ ├── AndroidManifest.xml
│ └── kotlin
│ │ └── com
│ │ └── bael
│ │ └── dads
│ │ └── data
│ │ └── remote
│ │ └── test
│ │ └── di
│ │ └── module
│ │ └── service
│ │ └── ServiceTestModule.kt
│ └── commonMain
│ └── kotlin
│ └── com
│ └── bael
│ └── dads
│ └── data
│ └── remote
│ └── test
│ └── service
│ ├── FakeBaseService.kt
│ ├── FakeDadsService.kt
│ └── RemoteService.kt
├── domain
└── home
│ ├── .gitignore
│ ├── build.gradle.kts
│ ├── consumer-rules.pro
│ ├── proguard-rules.pro
│ └── src
│ ├── androidMain
│ ├── AndroidManifest.xml
│ └── kotlin
│ │ └── com
│ │ └── bael
│ │ └── dads
│ │ └── domain
│ │ └── home
│ │ ├── di
│ │ └── module
│ │ │ ├── mapper
│ │ │ ├── ListMapperModule.kt
│ │ │ └── MapperModule.kt
│ │ │ └── usecase
│ │ │ └── UseCaseModule.kt
│ │ └── model
│ │ └── DadJoke.kt
│ └── commonMain
│ └── kotlin
│ └── com
│ └── bael
│ └── dads
│ └── domain
│ └── home
│ ├── interactor
│ ├── FavorDadJokeInteractor.kt
│ ├── LoadDadJokeFeedInteractor.kt
│ ├── LoadDadJokeInteractor.kt
│ ├── LoadFavoredDadJokeInteractor.kt
│ ├── LoadSeenDadJokeInteractor.kt
│ ├── ObserveDadJokeInteractor.kt
│ └── SetDadJokeSeenInteractor.kt
│ ├── mapper
│ ├── DadJokeDBMapper.kt
│ ├── DadJokeRemoteMapper.kt
│ └── RemoteMetaMapper.kt
│ ├── model
│ └── DadJoke.kt
│ └── usecase
│ ├── FavorDadJokeUseCase.kt
│ ├── LoadDadJokeFeedUseCase.kt
│ ├── LoadDadJokeUseCase.kt
│ ├── LoadFavoredDadJokeUseCase.kt
│ ├── LoadSeenDadJokeUseCase.kt
│ ├── ObserveDadJokeUseCase.kt
│ └── SetDadJokeSeenUseCase.kt
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── keys.properties
├── settings.gradle.kts
└── shared
├── .gitignore
├── build.gradle.kts
├── consumer-rules.pro
├── proguard-rules.pro
└── src
├── androidMain
├── AndroidManifest.xml
└── kotlin
│ └── com
│ └── bael
│ └── dads
│ └── shared
│ └── response
│ └── Response.kt
└── commonMain
└── kotlin
└── com
└── bael
└── dads
└── shared
├── exception
└── NoNetworkException.kt
├── ext
└── ListExt.kt
├── mapper
├── ListMapper.kt
├── Mapper.kt
└── ResultMapper.kt
├── response
└── Response.kt
└── time
└── DateTime.kt
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | custom: ["https://www.buymeacoffee.com/ErickSumargo"]
2 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 | on:
3 | pull_request:
4 | push:
5 | branches:
6 | - main
7 | jobs:
8 | initialize:
9 | runs-on: macos-latest
10 | steps:
11 | - name: Checkout repository
12 | uses: actions/checkout@v2
13 | - name: Setup GraphQL
14 | run: ./gradlew downloadApolloSchema --endpoint="https://dads-engine.herokuapp.com" --schema="data/remote/src/commonMain/graphql/com/bael/dads/data/remote/schema.json"
15 | - name: Cache GraphQL setup
16 | uses: actions/cache@v2
17 | with:
18 | path: data/remote/src/commonMain/graphql/com/bael/dads/data/remote
19 | key: ${{ github.sha }}
20 | build:
21 | runs-on: macos-latest
22 | needs: initialize
23 | steps:
24 | - name: Checkout repository
25 | uses: actions/checkout@v2
26 | - name: Cache GraphQL setup
27 | uses: actions/cache@v2
28 | with:
29 | path: data/remote/src/commonMain/graphql/com/bael/dads/data/remote
30 | key: ${{ github.sha }}
31 | - name: Build application
32 | run: ./gradlew assembleDebug --stacktrace
33 | test:
34 | runs-on: macos-latest
35 | needs: build
36 | steps:
37 | - name: Checkout repository
38 | uses: actions/checkout@v2
39 | - name: Cache GraphQL setup
40 | uses: actions/cache@v2
41 | with:
42 | path: data/remote/src/commonMain/graphql/com/bael/dads/data/remote
43 | key: ${{ github.sha }}
44 | - name: Test application
45 | uses: reactivecircus/android-emulator-runner@v2
46 | with:
47 | api-level: 29
48 | script: ./gradlew jacocoTestReport --stacktrace
49 | - name: Upload JaCoCo report
50 | uses: codecov/codecov-action@v1
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle/
2 | .idea/
3 | build/
4 | captures/
5 |
6 | *.aab
7 | *.apk
8 | *.cxx
9 | *.DS_Store
10 | *.externalNativeBuild
11 | *.iml
12 | *.jks
13 | *.pepk
14 | local.properties
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 ErickSumargo
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/android/annotation/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/android/annotation/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id("kotlin")
3 | }
4 |
--------------------------------------------------------------------------------
/android/annotation/src/main/kotlin/com/bael/dads/annotation/RenderWith.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.annotation
2 |
3 | import kotlin.annotation.AnnotationRetention.SOURCE
4 | import kotlin.annotation.AnnotationTarget.CLASS
5 | import kotlin.reflect.KClass
6 |
7 | /**
8 | * Created by ErickSumargo on 01/01/21.
9 | */
10 |
11 | @Target(CLASS)
12 | @Retention(SOURCE)
13 | @MustBeDocumented
14 | annotation class RenderWith(val state: KClass<*>)
15 |
--------------------------------------------------------------------------------
/android/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | /release
3 | /src/release/google-services.json
--------------------------------------------------------------------------------
/android/app/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import Library.AndroidX.hiltCompiler
2 | import Library.AndroidX.hiltNavigation
3 | import Library.AndroidX.hiltWork
4 | import Library.AndroidX.navigationFragment
5 | import Library.AndroidX.navigationUi
6 | import Library.AndroidX.work
7 | import Library.Apollo.apolloKotlin
8 | import Library.Google.dagger
9 | import Library.Google.daggerCompiler
10 | import Library.Google.firebaseBom
11 | import Library.Square.leakCanary
12 | import Library.Google.firebaseAnalytics as analytics
13 | import Library.Google.firebaseCrashlytics as crashlytics
14 |
15 | plugins {
16 | id("androidApp")
17 | }
18 |
19 | dependencies {
20 | // AndroidX
21 | implementation(hiltNavigation)
22 | implementation(hiltWork)
23 | kapt(hiltCompiler)
24 |
25 | implementation(navigationFragment)
26 | implementation(navigationUi)
27 |
28 | implementation(work)
29 |
30 | // Apollo
31 | implementation(apolloKotlin)
32 |
33 | // Google
34 | implementation(dagger)
35 | kapt(daggerCompiler)
36 |
37 | implementation(platform(firebaseBom))
38 | implementation(analytics)
39 | implementation(crashlytics)
40 |
41 | // Square
42 | debugImplementation(leakCanary)
43 | }
44 |
45 | dependencies {
46 | // Shared
47 | implementation(project(":shared"))
48 |
49 | // Data
50 | implementation(project(":data:database"))
51 | implementation(project(":data:remote"))
52 |
53 | // Domain
54 | implementation(project(":domain:home"))
55 | implementation(project(":shared"))
56 |
57 | // Feature
58 | implementation(project(":android:feature:home"))
59 |
60 | // Library
61 | implementation(project(":android:library:preference"))
62 | implementation(project(":android:library:presentation"))
63 | implementation(project(":android:library:threading"))
64 | implementation(project(":android:library:worker"))
65 | }
66 |
--------------------------------------------------------------------------------
/android/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # ProGuard Configuration file
2 | #
3 | # See http://proguard.sourceforge.net/index.html#manual/usage.html
4 |
5 | # Firebase Crashlytics
6 | -keepattributes SourceFile,LineNumberTable
7 | -keep public class * extends java.lang.Exception
8 | -keep class com.google.firebase.crashlytics.** { *; }
9 | -dontwarn com.google.firebase.crashlytics.**
10 |
11 | # Jetpack - Navigation Component
12 | -keep class androidx.navigation.fragment.NavHostFragment
13 |
--------------------------------------------------------------------------------
/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/android/app/src/debug/google-services.json:
--------------------------------------------------------------------------------
1 | {
2 | "project_info": {
3 | "project_number": "",
4 | "project_id": "",
5 | "storage_bucket": ""
6 | },
7 | "client": [
8 | {
9 | "client_info": {
10 | "mobilesdk_app_id": "1:0123456789:android:abcdefghijklmnopqrstuvwxyz",
11 | "android_client_info": {
12 | "package_name": "com.bael.dads.debug"
13 | }
14 | },
15 | "oauth_client": [
16 | {
17 | "client_id": "",
18 | "client_type": 1,
19 | "android_info": {
20 | "package_name": "com.bael.dads.debug",
21 | "certificate_hash": ""
22 | }
23 | },
24 | {
25 | "client_id": "",
26 | "client_type": 3
27 | }
28 | ],
29 | "api_key": [
30 | {
31 | "current_key": ""
32 | }
33 | ],
34 | "services": {
35 | "appinvite_service": {
36 | "other_platform_oauth_client": [
37 | {
38 | "client_id": "",
39 | "client_type": 3
40 | }
41 | ]
42 | }
43 | }
44 | }
45 | ],
46 | "configuration_version": "1"
47 | }
--------------------------------------------------------------------------------
/android/app/src/debug/kotlin/com/bael/dads/DadsDebugApplication.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads
2 |
3 | import android.os.StrictMode.ThreadPolicy
4 | import android.os.StrictMode.VmPolicy
5 | import android.os.StrictMode.setThreadPolicy
6 | import android.os.StrictMode.setVmPolicy
7 | import dagger.hilt.android.HiltAndroidApp
8 |
9 | /**
10 | * Created by ErickSumargo on 01/01/21.
11 | */
12 |
13 | @HiltAndroidApp
14 | internal class DadsDebugApplication : DadsApplication() {
15 |
16 | override fun onCreate() {
17 | super.onCreate()
18 | setStrictMode()
19 | }
20 |
21 | private fun setStrictMode() {
22 | setThreadPolicy(
23 | ThreadPolicy.Builder()
24 | .detectAll()
25 | .penaltyLog()
26 | .build()
27 | )
28 |
29 | setVmPolicy(
30 | VmPolicy.Builder()
31 | .detectAll()
32 | .penaltyLog()
33 | .build()
34 | )
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/android/app/src/debug/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Dads (Debug)
4 |
5 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
13 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
28 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/android/app/src/main/kotlin/com/bael/dads/DadsApplication.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads
2 |
3 | import android.app.Application
4 | import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_NO
5 | import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_YES
6 | import androidx.appcompat.app.AppCompatDelegate.setDefaultNightMode
7 | import com.bael.dads.library.preference.Preference
8 | import kotlinx.coroutines.runBlocking
9 | import javax.inject.Inject
10 |
11 | /**
12 | * Created by ErickSumargo on 01/01/21.
13 | */
14 |
15 | abstract class DadsApplication : Application() {
16 | @Inject
17 | lateinit var preference: Preference
18 |
19 | override fun onCreate() {
20 | super.onCreate()
21 | setTheme()
22 | }
23 |
24 | private fun setTheme() {
25 | runBlocking {
26 | val isNightTheme = preference.read(
27 | key = NIGHT_THEME_PREFERENCE,
28 | defaultValue = false
29 | )
30 | setDefaultNightMode(MODE_NIGHT_YES.takeIf { isNightTheme } ?: MODE_NIGHT_NO)
31 | }
32 | }
33 |
34 | private companion object {
35 | const val NIGHT_THEME_PREFERENCE: String = "night_theme"
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/android/app/src/main/kotlin/com/bael/dads/activity/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.activity
2 |
3 | import android.os.Bundle
4 | import androidx.appcompat.app.AppCompatActivity
5 | import com.bael.dads.databinding.ActivityMainBinding
6 | import dagger.hilt.android.AndroidEntryPoint
7 |
8 | /**
9 | * Created by ErickSumargo on 01/01/21.
10 | */
11 |
12 | @AndroidEntryPoint
13 | internal class MainActivity : AppCompatActivity() {
14 |
15 | override fun onCreate(savedInstanceState: Bundle?) {
16 | super.onCreate(savedInstanceState)
17 | ActivityMainBinding.inflate(layoutInflater).also { viewBinding ->
18 | setContentView(viewBinding.root)
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/android/app/src/main/kotlin/com/bael/dads/di/module/MainActivityModule.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.di.module
2 |
3 | import com.bael.dads.activity.MainActivity
4 | import com.bael.dads.library.presentation.di.qualifier.ActivityNameQualifier
5 | import com.bael.dads.library.presentation.di.qualifier.ActivityNameQualifier.Companion.ACTIVITY_MAIN
6 | import dagger.Module
7 | import dagger.Provides
8 | import dagger.hilt.InstallIn
9 | import dagger.hilt.components.SingletonComponent
10 | import javax.inject.Singleton
11 |
12 | /**
13 | * Created by stef_ang on 24/04/21.
14 | */
15 |
16 | @Module
17 | @InstallIn(SingletonComponent::class)
18 | internal class MainActivityModule {
19 |
20 | @Provides
21 | @Singleton
22 | @ActivityNameQualifier(name = ACTIVITY_MAIN)
23 | fun provideMainActivityName(): String {
24 | return MainActivity::class.java.name
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/android/app/src/main/res/font/product_sans.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErickSumargo/Dads/8eb44894518e23f535a69cbe0207ad034f6a282f/android/app/src/main/res/font/product_sans.ttf
--------------------------------------------------------------------------------
/android/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Dads
4 |
5 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
31 |
32 |
33 |
36 |
37 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/android/app/src/main/res/xml/provider_paths.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
--------------------------------------------------------------------------------
/android/app/src/release/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/android/app/src/release/google-services.enc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErickSumargo/Dads/8eb44894518e23f535a69cbe0207ad034f6a282f/android/app/src/release/google-services.enc
--------------------------------------------------------------------------------
/android/app/src/release/kotlin/com/bael/dads/DadsReleaseApplication.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads
2 |
3 | import dagger.hilt.android.HiltAndroidApp
4 |
5 | /**
6 | * Created by ErickSumargo on 01/01/21.
7 | */
8 |
9 | @HiltAndroidApp
10 | internal class DadsReleaseApplication : DadsApplication()
11 |
--------------------------------------------------------------------------------
/android/feature/home/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/android/feature/home/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import Library.Airbnb.lottie
2 | import Library.AndroidX.constraintLayout
3 | import Library.AndroidX.swipeRefreshLayout
4 | import Library.AndroidX.viewPager2
5 | import Library.AndroidX.work
6 |
7 | plugins {
8 | id("androidFeature")
9 | }
10 |
11 | dependencies {
12 | // AndroidX
13 | implementation(constraintLayout)
14 | implementation(swipeRefreshLayout)
15 | implementation(viewPager2)
16 | implementation(work)
17 |
18 | // Airbnb
19 | implementation(lottie)
20 | }
21 |
22 | dependencies {
23 | // Shared
24 | implementation(project(":shared"))
25 |
26 | // Data
27 | androidTestImplementation(project(":data:database"))
28 | androidTestImplementation(project(":data:database_test"))
29 |
30 | androidTestImplementation(project(":data:remote"))
31 | androidTestImplementation(project(":data:remote_test"))
32 |
33 | // Domain
34 | implementation(project(":domain:home"))
35 |
36 | // Library
37 | implementation(project(":android:library:preference"))
38 | androidTestImplementation(project(":android:library:preference_test"))
39 |
40 | implementation(project(":android:library:worker"))
41 | }
42 |
--------------------------------------------------------------------------------
/android/feature/home/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErickSumargo/Dads/8eb44894518e23f535a69cbe0207ad034f6a282f/android/feature/home/consumer-rules.pro
--------------------------------------------------------------------------------
/android/feature/home/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.kts.
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
--------------------------------------------------------------------------------
/android/feature/home/src/androidTest/kotlin/com/bael/dads/feature/home/screen/home/UITest.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.feature.home.screen.home
2 |
3 | import com.bael.dads.feature.home.R
4 | import com.bael.dads.library.instrumentation.fragment.BaseFragmentTest
5 | import com.bael.dads.library.instrumentation.matcher.MatcherParams
6 | import com.bael.dads.library.presentation.ext.readText
7 | import dagger.hilt.android.testing.HiltAndroidTest
8 | import org.junit.Test
9 |
10 | /**
11 | * Created by ErickSumargo on 01/04/21.
12 | */
13 |
14 | @HiltAndroidTest
15 | internal class UITest : BaseFragmentTest() {
16 |
17 | override fun setupTest() {}
18 |
19 | @Test
20 | fun whenScreenDisplayed_contentShouldShow() {
21 | runTest {
22 | // when
23 | launch(graphResId = R.navigation.nav_graph)
24 |
25 | // then
26 | assertViewDisplayed(
27 | params = MatcherParams(
28 | id = R.id.logoIcon
29 | )
30 | )
31 | assertViewDisplayed(
32 | params = MatcherParams(
33 | id = R.id.settingsIcon
34 | )
35 | )
36 | assertViewDisplayed(
37 | params = MatcherParams(
38 | text = context.readText(resId = R.string.feed)
39 | )
40 | )
41 | assertViewDisplayed(
42 | params = MatcherParams(
43 | text = context.readText(resId = R.string.seen)
44 | )
45 | )
46 | }
47 | }
48 |
49 | override fun clearTest() {}
50 | }
51 |
--------------------------------------------------------------------------------
/android/feature/home/src/androidTest/kotlin/com/bael/dads/feature/home/sheet/sharepreview/UITest.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.feature.home.sheet.sharepreview
2 |
3 | import androidx.core.os.bundleOf
4 | import com.bael.dads.domain.home.model.DadJoke
5 | import com.bael.dads.library.instrumentation.matcher.MatcherParams
6 | import com.bael.dads.library.instrumentation.sheet.BaseSheetTest
7 | import com.bael.dads.shared.time.DateTime.now
8 | import dagger.hilt.android.testing.HiltAndroidTest
9 | import org.junit.Test
10 |
11 | /**
12 | * Created by ErickSumargo on 01/05/21.
13 | */
14 |
15 | @HiltAndroidTest
16 | internal class UITest : BaseSheetTest() {
17 |
18 | override fun setupTest() {}
19 |
20 | @Test
21 | fun whenSheetDisplayed_shareMaterialShouldShow() {
22 | runTest {
23 | // given
24 | val dadJoke = DadJoke(
25 | id = 1,
26 | setup = "Setup 1",
27 | punchline = "Punchline 1",
28 | favored = false,
29 | seen = false,
30 | updatedAt = now
31 | )
32 |
33 | // when
34 | launch(args = bundleOf("dadJoke" to dadJoke))
35 |
36 | // then
37 | assertViewDisplayed(
38 | params = MatcherParams(
39 | text = "Setup 1"
40 | )
41 | )
42 | assertViewDisplayed(
43 | params = MatcherParams(
44 | text = "Punchline 1"
45 | )
46 | )
47 | }
48 | }
49 |
50 | override fun clearTest() {}
51 | }
52 |
--------------------------------------------------------------------------------
/android/feature/home/src/androidTest/kotlin/com/bael/dads/feature/home/worker/factory/FakeFetchDadJokeFeedWorkerFactory.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.feature.home.worker.factory
2 |
3 | import android.content.Context
4 | import androidx.work.ListenableWorker
5 | import androidx.work.WorkerFactory
6 | import androidx.work.WorkerParameters
7 | import com.bael.dads.domain.home.usecase.LoadDadJokeFeedUseCase
8 | import com.bael.dads.domain.home.usecase.LoadDadJokeUseCase
9 | import com.bael.dads.feature.home.notification.factory.NewFeedReminderNotificationFactory
10 | import com.bael.dads.feature.home.worker.FetchDadJokeFeedWorker
11 | import com.bael.dads.library.preference.Preference
12 | import com.bael.dads.library.presentation.notification.NotificationPublisher
13 | import javax.inject.Inject
14 | import javax.inject.Singleton
15 |
16 | /**
17 | * Created by ErickSumargo on 15/05/21.
18 | */
19 |
20 | @Singleton
21 | internal class FakeFetchDadJokeFeedWorkerFactory @Inject constructor(
22 | private val loadDadJokeUseCase: LoadDadJokeUseCase,
23 | private val loadDadJokeFeedUseCase: LoadDadJokeFeedUseCase,
24 | private val preference: Preference,
25 | private val notificationPublisher: NotificationPublisher,
26 | private val newFeedReminderNotificationFactory: NewFeedReminderNotificationFactory
27 | ) : WorkerFactory() {
28 |
29 | override fun createWorker(
30 | appContext: Context,
31 | workerClassName: String,
32 | workerParameters: WorkerParameters
33 | ): ListenableWorker {
34 | return FetchDadJokeFeedWorker(
35 | appContext,
36 | workerParameters,
37 | loadDadJokeUseCase,
38 | loadDadJokeFeedUseCase,
39 | preference,
40 | notificationPublisher,
41 | newFeedReminderNotificationFactory
42 | )
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/kotlin/com/bael/dads/feature/home/adapter/DadJokeFeedAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.feature.home.adapter
2 |
3 | import android.view.LayoutInflater
4 | import android.view.ViewGroup
5 | import androidx.lifecycle.LifecycleOwner
6 | import com.bael.dads.feature.home.adapter.cell.DadJokeFeedCell
7 | import com.bael.dads.feature.home.adapter.diffcallback.DadJokeDiffCallback
8 | import com.bael.dads.feature.home.databinding.CellFeedBinding.inflate
9 | import com.bael.dads.domain.home.model.DadJoke
10 | import com.bael.dads.library.presentation.widget.recyclerview.adapter.LiveListAdapter
11 |
12 | /**
13 | * Created by ErickSumargo on 01/01/21.
14 | */
15 |
16 | internal class DadJokeFeedAdapter(
17 | diffCallback: DadJokeDiffCallback,
18 | lifecycleOwner: LifecycleOwner,
19 | private val onClickLikeListener: (DadJoke, Boolean) -> Unit,
20 | private val onClickShareListener: (DadJoke) -> Unit,
21 | private val onReachEndOfItemsListener: (DadJoke) -> Unit,
22 | private val onObserveItemListener: suspend (DadJoke) -> Unit
23 | ) : LiveListAdapter(diffCallback, lifecycleOwner) {
24 | private val transitionCache: MutableMap = mutableMapOf()
25 |
26 | override fun createCell(
27 | inflater: LayoutInflater,
28 | viewGroup: ViewGroup
29 | ): DadJokeFeedCell {
30 | val viewBinding = inflate(inflater, viewGroup, false)
31 | return DadJokeFeedCell(
32 | viewBinding,
33 | transitionCache,
34 | onClickLikeListener,
35 | onClickShareListener
36 | )
37 | }
38 |
39 | override fun onReachEndOfItems(item: DadJoke) {
40 | onReachEndOfItemsListener(item)
41 | }
42 |
43 | override fun getItemKey(item: DadJoke): Int {
44 | return item.id
45 | }
46 |
47 | override suspend fun observeItem(item: DadJoke) {
48 | onObserveItemListener(item)
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/kotlin/com/bael/dads/feature/home/adapter/SeenDadJokeAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.feature.home.adapter
2 |
3 | import android.view.LayoutInflater
4 | import android.view.ViewGroup
5 | import androidx.lifecycle.LifecycleOwner
6 | import com.bael.dads.feature.home.adapter.cell.SeenDadJokeCell
7 | import com.bael.dads.feature.home.adapter.diffcallback.DadJokeDiffCallback
8 | import com.bael.dads.feature.home.databinding.CellSeenBinding.inflate
9 | import com.bael.dads.domain.home.model.DadJoke
10 | import com.bael.dads.library.presentation.widget.recyclerview.adapter.LiveListAdapter
11 |
12 | /**
13 | * Created by ErickSumargo on 01/01/21.
14 | */
15 |
16 | internal class SeenDadJokeAdapter(
17 | diffCallback: DadJokeDiffCallback,
18 | lifecycleOwner: LifecycleOwner,
19 | private val onClickItemListener: (DadJoke) -> Unit,
20 | private val onReachEndOfItemsListener: (DadJoke) -> Unit,
21 | private val onObserveItemListener: suspend (DadJoke) -> Unit
22 | ) : LiveListAdapter(diffCallback, lifecycleOwner) {
23 |
24 | override fun createCell(
25 | inflater: LayoutInflater,
26 | viewGroup: ViewGroup
27 | ): SeenDadJokeCell {
28 | val viewBinding = inflate(inflater, viewGroup, false)
29 | val cellHeight = viewGroup.height / 2
30 |
31 | return SeenDadJokeCell(viewBinding, cellHeight, onClickItemListener)
32 | }
33 |
34 | override fun getItemKey(item: DadJoke): Int {
35 | return item.id
36 | }
37 |
38 | override fun onReachEndOfItems(item: DadJoke) {
39 | onReachEndOfItemsListener(item)
40 | }
41 |
42 | override suspend fun observeItem(item: DadJoke) {
43 | onObserveItemListener(item)
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/kotlin/com/bael/dads/feature/home/adapter/cell/SeenDadJokeCell.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.feature.home.adapter.cell
2 |
3 | import com.bael.dads.feature.home.databinding.CellSeenBinding
4 | import com.bael.dads.domain.home.model.DadJoke
5 | import com.bael.dads.library.presentation.ext.toRichText
6 | import com.bael.dads.library.presentation.widget.recyclerview.adapter.cell.BaseCell
7 |
8 | /**
9 | * Created by ErickSumargo on 01/01/21.
10 | */
11 |
12 | internal class SeenDadJokeCell(
13 | viewBinding: CellSeenBinding,
14 | private val cellHeight: Int,
15 | private val onClickItemListener: (DadJoke) -> Unit
16 | ) : BaseCell(viewBinding) {
17 |
18 | override fun render(state: DadJoke) {
19 | renderContent(state)
20 | renderSetup(state)
21 | }
22 |
23 | private fun renderContent(state: DadJoke) {
24 | viewBinding.contentLayout.also { layout ->
25 | layout.minHeight = cellHeight
26 |
27 | layout.setOnClickListener {
28 | onClickItemListener(state)
29 | }
30 | }
31 | }
32 |
33 | private fun renderSetup(state: DadJoke) {
34 | viewBinding.setupText.also { view ->
35 | view.text = state.setup.toRichText()
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/kotlin/com/bael/dads/feature/home/adapter/diffcallback/DadJokeDiffCallback.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.feature.home.adapter.diffcallback
2 |
3 | import androidx.recyclerview.widget.DiffUtil.ItemCallback
4 | import com.bael.dads.domain.home.model.DadJoke
5 |
6 | /**
7 | * Created by ErickSumargo on 01/01/21.
8 | */
9 |
10 | internal class DadJokeDiffCallback : ItemCallback() {
11 |
12 | override fun areItemsTheSame(
13 | oldItem: DadJoke,
14 | newItem: DadJoke
15 | ): Boolean {
16 | return oldItem.id == newItem.id
17 | }
18 |
19 | override fun areContentsTheSame(
20 | oldItem: DadJoke,
21 | newItem: DadJoke
22 | ): Boolean {
23 | return oldItem == newItem
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/kotlin/com/bael/dads/feature/home/animation/Animation.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.feature.home.animation
2 |
3 | /**
4 | * Created by ErickSumargo on 01/01/21.
5 | */
6 |
7 | internal val reminder: String
8 | get() = "anim_reminder.json"
9 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/kotlin/com/bael/dads/feature/home/di/module/screen/FeedScreenModule.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.feature.home.di.module.screen
2 |
3 | import com.bael.dads.feature.home.screen.feed.DefaultRendererInitializer
4 | import com.bael.dads.feature.home.screen.feed.Renderer
5 | import com.bael.dads.feature.home.screen.feed.State
6 | import com.bael.dads.feature.home.screen.feed.ViewModel
7 | import com.bael.dads.library.presentation.renderer.RendererInitializer
8 | import dagger.Binds
9 | import dagger.Module
10 | import dagger.Provides
11 | import dagger.hilt.InstallIn
12 | import dagger.hilt.android.components.FragmentComponent
13 | import dagger.hilt.android.components.ViewModelComponent
14 |
15 | /**
16 | * Created by ErickSumargo on 01/01/21.
17 | */
18 |
19 | @Module
20 | @InstallIn(value = [ViewModelComponent::class, FragmentComponent::class])
21 | internal interface FeedScreenModule {
22 |
23 | @Binds
24 | fun bindRendererInitializer(
25 | rendererInitializer: DefaultRendererInitializer
26 | ): RendererInitializer
27 |
28 | companion object {
29 |
30 | @Provides
31 | fun provideState(): State {
32 | return State(responses = listOf())
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/kotlin/com/bael/dads/feature/home/di/module/screen/SeenScreenModule.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.feature.home.di.module.screen
2 |
3 | import com.bael.dads.feature.home.screen.seen.DefaultRendererInitializer
4 | import com.bael.dads.feature.home.screen.seen.Renderer
5 | import com.bael.dads.feature.home.screen.seen.State
6 | import com.bael.dads.feature.home.screen.seen.ViewModel
7 | import com.bael.dads.library.presentation.renderer.RendererInitializer
8 | import dagger.Binds
9 | import dagger.Module
10 | import dagger.Provides
11 | import dagger.hilt.InstallIn
12 | import dagger.hilt.android.components.FragmentComponent
13 | import dagger.hilt.android.components.ViewModelComponent
14 |
15 | /**
16 | * Created by ErickSumargo on 01/01/21.
17 | */
18 |
19 | @Module
20 | @InstallIn(value = [ViewModelComponent::class, FragmentComponent::class])
21 | internal interface SeenScreenModule {
22 |
23 | @Binds
24 | fun bindRendererInitializer(
25 | rendererInitializer: DefaultRendererInitializer
26 | ): RendererInitializer
27 |
28 | companion object {
29 |
30 | @Provides
31 | fun provideState(): State {
32 | return State(
33 | isFavoriteFilterActivated = false,
34 | responses = listOf()
35 | )
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/kotlin/com/bael/dads/feature/home/di/module/sheet/DetailSheetModule.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.feature.home.di.module.sheet
2 |
3 | import com.bael.dads.feature.home.sheet.detail.DefaultRendererInitializer
4 | import com.bael.dads.feature.home.sheet.detail.Renderer
5 | import com.bael.dads.feature.home.sheet.detail.State
6 | import com.bael.dads.feature.home.sheet.detail.ViewModel
7 | import com.bael.dads.library.presentation.renderer.RendererInitializer
8 | import dagger.Binds
9 | import dagger.Module
10 | import dagger.Provides
11 | import dagger.hilt.InstallIn
12 | import dagger.hilt.android.components.FragmentComponent
13 | import dagger.hilt.android.components.ViewModelComponent
14 |
15 | /**
16 | * Created by ErickSumargo on 01/01/21.
17 | */
18 |
19 | @Module
20 | @InstallIn(value = [ViewModelComponent::class, FragmentComponent::class])
21 | internal interface DetailSheetModule {
22 |
23 | @Binds
24 | fun bindRendererInitializer(
25 | rendererInitializer: DefaultRendererInitializer
26 | ): RendererInitializer
27 |
28 | companion object {
29 |
30 | @Provides
31 | fun provideState(): State {
32 | return State(dadJoke = null)
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/kotlin/com/bael/dads/feature/home/di/module/sheet/SettingsSheetModule.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.feature.home.di.module.sheet
2 |
3 | import com.bael.dads.feature.home.sheet.settings.DefaultRendererInitializer
4 | import com.bael.dads.feature.home.sheet.settings.Renderer
5 | import com.bael.dads.feature.home.sheet.settings.State
6 | import com.bael.dads.feature.home.sheet.settings.ViewModel
7 | import com.bael.dads.library.presentation.renderer.RendererInitializer
8 | import dagger.Binds
9 | import dagger.Module
10 | import dagger.Provides
11 | import dagger.hilt.InstallIn
12 | import dagger.hilt.android.components.FragmentComponent
13 | import dagger.hilt.android.components.ViewModelComponent
14 |
15 | /**
16 | * Created by ErickSumargo on 01/01/21.
17 | */
18 |
19 | @Module
20 | @InstallIn(value = [ViewModelComponent::class, FragmentComponent::class])
21 | internal interface SettingsSheetModule {
22 |
23 | @Binds
24 | fun bindRendererInitializer(
25 | rendererInitializer: DefaultRendererInitializer
26 | ): RendererInitializer
27 |
28 | companion object {
29 |
30 | @Provides
31 | fun provideState(): State {
32 | return State()
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/kotlin/com/bael/dads/feature/home/di/module/sheet/SharePreviewSheetModule.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.feature.home.di.module.sheet
2 |
3 | import com.bael.dads.feature.home.sheet.sharepreview.DefaultRendererInitializer
4 | import com.bael.dads.feature.home.sheet.sharepreview.Renderer
5 | import com.bael.dads.feature.home.sheet.sharepreview.State
6 | import com.bael.dads.feature.home.sheet.sharepreview.ViewModel
7 | import com.bael.dads.library.presentation.renderer.RendererInitializer
8 | import dagger.Binds
9 | import dagger.Module
10 | import dagger.Provides
11 | import dagger.hilt.InstallIn
12 | import dagger.hilt.android.components.FragmentComponent
13 | import dagger.hilt.android.components.ViewModelComponent
14 |
15 | /**
16 | * Created by ErickSumargo on 01/01/21.
17 | */
18 |
19 | @Module
20 | @InstallIn(value = [ViewModelComponent::class, FragmentComponent::class])
21 | internal interface SharePreviewSheetModule {
22 |
23 | @Binds
24 | fun bindRendererInitializer(
25 | rendererInitializer: DefaultRendererInitializer
26 | ): RendererInitializer
27 |
28 | companion object {
29 |
30 | @Provides
31 | fun provideState(): State {
32 | return State(dadJoke = null)
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/kotlin/com/bael/dads/feature/home/notification/factory/NewFeedReminderNotificationFactory.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.feature.home.notification.factory
2 |
3 | import com.bael.dads.domain.home.model.DadJoke
4 | import com.bael.dads.feature.home.notification.NewFeedReminderNotification
5 | import dagger.assisted.AssistedFactory
6 |
7 | /**
8 | * Created by stef_ang on 24/04/21.
9 | */
10 |
11 | @AssistedFactory
12 | internal interface NewFeedReminderNotificationFactory {
13 |
14 | fun create(dadJokes: List): NewFeedReminderNotification
15 | }
16 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/kotlin/com/bael/dads/feature/home/screen/feed/Event.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.feature.home.screen.feed
2 |
3 | /**
4 | * Created by ErickSumargo on 01/04/21.
5 | */
6 |
7 | internal sealed class Event
8 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/kotlin/com/bael/dads/feature/home/screen/feed/Renderer.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.feature.home.screen.feed
2 |
3 | import com.bael.dads.annotation.RenderWith
4 | import com.bael.dads.domain.home.model.DadJoke
5 | import com.bael.dads.library.presentation.renderer.BaseRenderer
6 | import com.bael.dads.shared.response.Response
7 |
8 | /**
9 | * Created by ErickSumargo on 01/01/21.
10 | */
11 |
12 | @RenderWith(State::class)
13 | internal interface Renderer : BaseRenderer {
14 |
15 | fun renderDadJokeFeed(responses: List>>)
16 | }
17 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/kotlin/com/bael/dads/feature/home/screen/feed/State.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.feature.home.screen.feed
2 |
3 | import com.bael.dads.domain.home.model.DadJoke
4 | import com.bael.dads.library.presentation.state.BaseState
5 | import com.bael.dads.shared.response.Response
6 |
7 | /**
8 | * Created by ErickSumargo on 01/01/21.
9 | */
10 |
11 | internal data class State(
12 | val responses: List>>
13 | ) : BaseState()
14 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/kotlin/com/bael/dads/feature/home/screen/home/Event.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.feature.home.screen.home
2 |
3 | /**
4 | * Created by ErickSumargo on 01/04/21.
5 | */
6 |
7 | internal sealed class Event
8 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/kotlin/com/bael/dads/feature/home/screen/home/Renderer.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.feature.home.screen.home
2 |
3 | import com.bael.dads.annotation.RenderWith
4 | import com.bael.dads.library.presentation.renderer.BaseRenderer
5 |
6 | /**
7 | * Created by ErickSumargo on 01/01/21.
8 | */
9 |
10 | @RenderWith(State::class)
11 | internal interface Renderer : BaseRenderer
12 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/kotlin/com/bael/dads/feature/home/screen/home/State.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.feature.home.screen.home
2 |
3 | import com.bael.dads.library.presentation.state.BaseState
4 |
5 | /**
6 | * Created by ErickSumargo on 01/01/21.
7 | */
8 |
9 | internal data class State(
10 | val query: String
11 | ) : BaseState()
12 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/kotlin/com/bael/dads/feature/home/screen/home/ViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.feature.home.screen.home
2 |
3 | import androidx.lifecycle.SavedStateHandle
4 | import com.bael.dads.library.presentation.ext.reduce
5 | import com.bael.dads.library.presentation.viewmodel.BaseViewModel
6 | import dagger.hilt.android.lifecycle.HiltViewModel
7 | import kotlinx.coroutines.flow.MutableStateFlow
8 | import javax.inject.Inject
9 |
10 | /**
11 | * Created by ErickSumargo on 01/01/21.
12 | */
13 |
14 | @HiltViewModel
15 | internal class ViewModel @Inject constructor(
16 | initState: State,
17 | savedStateHandle: SavedStateHandle
18 | ) : BaseViewModel(initState, savedStateHandle) {
19 | val queryFlow: MutableStateFlow = MutableStateFlow(state.query)
20 |
21 | fun submitQuery(query: String) {
22 | queryFlow.value = query
23 | renderQuery(query)
24 | }
25 |
26 | private fun renderQuery(query: String) {
27 | val newState = state.reduce {
28 | copy(query = query)
29 | }
30 | render(newState)
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/kotlin/com/bael/dads/feature/home/screen/seen/Event.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.feature.home.screen.seen
2 |
3 | /**
4 | * Created by ErickSumargo on 01/04/21.
5 | */
6 |
7 | internal sealed class Event
8 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/kotlin/com/bael/dads/feature/home/screen/seen/Renderer.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.feature.home.screen.seen
2 |
3 | import com.bael.dads.annotation.RenderWith
4 | import com.bael.dads.domain.home.model.DadJoke
5 | import com.bael.dads.library.presentation.renderer.BaseRenderer
6 | import com.bael.dads.shared.response.Response
7 |
8 | /**
9 | * Created by ErickSumargo on 01/01/21.
10 | */
11 |
12 | @RenderWith(State::class)
13 | internal interface Renderer : BaseRenderer {
14 |
15 | fun renderSeenDadJoke(responses: List>>)
16 |
17 | fun renderFavoriteFilter(isFavoriteFilterActivated: Boolean)
18 | }
19 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/kotlin/com/bael/dads/feature/home/screen/seen/State.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.feature.home.screen.seen
2 |
3 | import com.bael.dads.domain.home.model.DadJoke
4 | import com.bael.dads.library.presentation.state.BaseState
5 | import com.bael.dads.shared.response.Response
6 |
7 | /**
8 | * Created by ErickSumargo on 01/01/21.
9 | */
10 |
11 | internal data class State(
12 | val responses: List>>,
13 | val isFavoriteFilterActivated: Boolean,
14 | ) : BaseState()
15 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/kotlin/com/bael/dads/feature/home/sheet/detail/Event.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.feature.home.sheet.detail
2 |
3 | /**
4 | * Created by ErickSumargo on 01/04/21.
5 | */
6 |
7 | sealed class Event
8 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/kotlin/com/bael/dads/feature/home/sheet/detail/Renderer.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.feature.home.sheet.detail
2 |
3 | import com.bael.dads.annotation.RenderWith
4 | import com.bael.dads.domain.home.model.DadJoke
5 | import com.bael.dads.library.presentation.renderer.BaseRenderer
6 |
7 | /**
8 | * Created by ErickSumargo on 01/01/21.
9 | */
10 |
11 | @RenderWith(State::class)
12 | internal interface Renderer : BaseRenderer {
13 |
14 | fun renderDetail(dadJoke: DadJoke?)
15 | }
16 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/kotlin/com/bael/dads/feature/home/sheet/detail/State.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.feature.home.sheet.detail
2 |
3 | import com.bael.dads.domain.home.model.DadJoke
4 | import com.bael.dads.library.presentation.state.BaseState
5 |
6 | /**
7 | * Created by ErickSumargo on 01/01/21.
8 | */
9 |
10 | internal data class State(
11 | val dadJoke: DadJoke?
12 | ) : BaseState()
13 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/kotlin/com/bael/dads/feature/home/sheet/detail/ViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.feature.home.sheet.detail
2 |
3 | import androidx.lifecycle.SavedStateHandle
4 | import com.bael.dads.domain.home.model.DadJoke
5 | import com.bael.dads.library.presentation.ext.reduce
6 | import com.bael.dads.library.presentation.viewmodel.BaseViewModel
7 | import dagger.hilt.android.lifecycle.HiltViewModel
8 | import javax.inject.Inject
9 |
10 | /**
11 | * Created by ErickSumargo on 01/01/21.
12 | */
13 |
14 | @HiltViewModel
15 | internal class ViewModel @Inject constructor(
16 | initState: State,
17 | savedStateHandle: SavedStateHandle
18 | ) : BaseViewModel(initState, savedStateHandle) {
19 | val dadJoke: DadJoke?
20 | get() = state.dadJoke
21 |
22 | fun receiveDadJoke() {
23 | val newState = state.reduce {
24 | copy(dadJoke = savedStateHandle.get("dadJoke"))
25 | }
26 | render(newState)
27 | }
28 |
29 | fun favorDadJoke(favored: Boolean) {
30 | val newState = state.reduce {
31 | copy(dadJoke = dadJoke?.copy(favored = favored))
32 | }
33 | render(newState)
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/kotlin/com/bael/dads/feature/home/sheet/settings/Event.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.feature.home.sheet.settings
2 |
3 | /**
4 | * Created by ErickSumargo on 01/04/21.
5 | */
6 |
7 | internal sealed class Event
8 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/kotlin/com/bael/dads/feature/home/sheet/settings/Renderer.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.feature.home.sheet.settings
2 |
3 | import com.bael.dads.annotation.RenderWith
4 | import com.bael.dads.library.presentation.renderer.BaseRenderer
5 |
6 | /**
7 | * Created by ErickSumargo on 01/01/21.
8 | */
9 |
10 | @RenderWith(State::class)
11 | internal interface Renderer : BaseRenderer
12 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/kotlin/com/bael/dads/feature/home/sheet/settings/State.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.feature.home.sheet.settings
2 |
3 | import com.bael.dads.library.presentation.state.BaseState
4 |
5 | /**
6 | * Created by ErickSumargo on 01/01/21.
7 | */
8 |
9 | internal class State : BaseState()
10 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/kotlin/com/bael/dads/feature/home/sheet/settings/ViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.feature.home.sheet.settings
2 |
3 | import androidx.lifecycle.SavedStateHandle
4 | import com.bael.dads.library.presentation.viewmodel.BaseViewModel
5 | import dagger.hilt.android.lifecycle.HiltViewModel
6 | import javax.inject.Inject
7 |
8 | /**
9 | * Created by ErickSumargo on 01/01/21.
10 | */
11 |
12 | @HiltViewModel
13 | internal class ViewModel @Inject constructor(
14 | initState: State,
15 | savedStateHandle: SavedStateHandle
16 | ) : BaseViewModel(initState, savedStateHandle)
17 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/kotlin/com/bael/dads/feature/home/sheet/sharepreview/Event.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.feature.home.sheet.sharepreview
2 |
3 | /**
4 | * Created by ErickSumargo on 01/04/21.
5 | */
6 |
7 | sealed class Event
8 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/kotlin/com/bael/dads/feature/home/sheet/sharepreview/Renderer.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.feature.home.sheet.sharepreview
2 |
3 | import com.bael.dads.annotation.RenderWith
4 | import com.bael.dads.domain.home.model.DadJoke
5 | import com.bael.dads.library.presentation.renderer.BaseRenderer
6 |
7 | /**
8 | * Created by ErickSumargo on 01/01/21.
9 | */
10 |
11 | @RenderWith(State::class)
12 | internal interface Renderer : BaseRenderer {
13 |
14 | fun renderPreview(dadJoke: DadJoke?)
15 | }
16 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/kotlin/com/bael/dads/feature/home/sheet/sharepreview/State.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.feature.home.sheet.sharepreview
2 |
3 | import com.bael.dads.domain.home.model.DadJoke
4 | import com.bael.dads.library.presentation.state.BaseState
5 |
6 | /**
7 | * Created by ErickSumargo on 01/01/21.
8 | */
9 |
10 | internal data class State(
11 | val dadJoke: DadJoke?
12 | ) : BaseState()
13 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/kotlin/com/bael/dads/feature/home/sheet/sharepreview/ViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.feature.home.sheet.sharepreview
2 |
3 | import androidx.lifecycle.SavedStateHandle
4 | import com.bael.dads.library.presentation.ext.reduce
5 | import com.bael.dads.library.presentation.viewmodel.BaseViewModel
6 | import dagger.hilt.android.lifecycle.HiltViewModel
7 | import javax.inject.Inject
8 |
9 | /**
10 | * Created by ErickSumargo on 01/01/21.
11 | */
12 |
13 | @HiltViewModel
14 | internal class ViewModel @Inject constructor(
15 | initState: State,
16 | savedStateHandle: SavedStateHandle
17 | ) : BaseViewModel(initState, savedStateHandle) {
18 |
19 | fun receiveDadJoke() {
20 | val newState = state.reduce {
21 | copy(dadJoke = savedStateHandle.get("dadJoke"))
22 | }
23 | render(newState)
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/res/drawable/bg_border.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/res/drawable/bg_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/res/drawable/ic_clear.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/res/drawable/ic_feed.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/res/drawable/ic_like.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/res/drawable/ic_like_outline.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/res/drawable/ic_no_internet.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/res/drawable/ic_search.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/res/drawable/ic_seen.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
13 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/res/drawable/ic_settings.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
15 |
16 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/res/drawable/ic_share.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/res/layout/cell_seen.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
17 |
18 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/res/layout/item_group_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
18 |
19 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/res/layout/item_setting.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
18 |
19 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/res/layout/screen_feed.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
16 |
17 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/res/layout/sheet_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
17 |
18 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/res/navigation/nav_graph.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
12 |
13 |
17 |
18 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/android/feature/home/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Dads
4 |
5 | Logo
6 | Find joke
7 | Search
8 | Clear
9 | Settings
10 |
11 | Notification
12 | New feed available reminder
13 | New feed available
14 | %1$s new feed recently added
15 | Theme
16 | Night mode
17 |
18 | Feed
19 | Seen
20 |
21 | Like
22 | Dislike
23 | Share
24 | Preview
25 |
26 | Wow you hit the end! We\'ll notify back as soon the latest avails. Stay tuned!
27 | Hmm no joke found. Different keyword perhaps?
28 |
29 | Favorite filter
30 | Filter favorite only
31 |
32 |
--------------------------------------------------------------------------------
/android/library/instrumentation/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/android/library/instrumentation/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import Library.AndroidX.appCompat
2 | import Library.AndroidX.archTesting
3 | import Library.AndroidX.espresso
4 | import Library.AndroidX.fragment
5 | import Library.AndroidX.fragmentTesting
6 | import Library.AndroidX.navigationTesting
7 | import Library.AndroidX.runner
8 | import Library.AndroidX.uiAutomator
9 | import Library.AndroidX.workTesting
10 | import Library.Google.daggerTesting
11 | import Library.Google.material
12 | import Library.Google.truth
13 | import Library.KotlinX.coroutinesTest
14 |
15 | plugins {
16 | id("androidLibrary")
17 | }
18 |
19 | dependencies {
20 | // AndroidX
21 | implementation(appCompat)
22 | implementation(archTesting)
23 | implementation(espresso)
24 | implementation(fragment)
25 | implementation(fragmentTesting)
26 | implementation(navigationTesting)
27 | implementation(runner)
28 | implementation(uiAutomator)
29 | implementation(workTesting)
30 |
31 | // Google
32 | implementation(daggerTesting)
33 | implementation(material)
34 | implementation(truth)
35 |
36 | // KotlinX
37 | implementation(coroutinesTest)
38 | }
39 |
40 | dependencies {
41 | // Library
42 | implementation(project(":android:library:presentation"))
43 | implementation(project(":android:library:threading"))
44 | implementation(project(":android:library:worker"))
45 | }
46 |
--------------------------------------------------------------------------------
/android/library/instrumentation/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErickSumargo/Dads/8eb44894518e23f535a69cbe0207ad034f6a282f/android/library/instrumentation/consumer-rules.pro
--------------------------------------------------------------------------------
/android/library/instrumentation/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.kts.
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
--------------------------------------------------------------------------------
/android/library/instrumentation/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/android/library/instrumentation/src/main/kotlin/com/bael/dads/library/instrumentation/activity/MainTestActivity.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.library.instrumentation.activity
2 |
3 | import androidx.appcompat.app.AppCompatActivity
4 | import dagger.hilt.android.AndroidEntryPoint
5 |
6 | /**
7 | * Created by ErickSumargo on 01/04/21.
8 | */
9 |
10 | @AndroidEntryPoint
11 | class MainTestActivity : AppCompatActivity()
12 |
--------------------------------------------------------------------------------
/android/library/instrumentation/src/main/kotlin/com/bael/dads/library/instrumentation/di/module/MainTestActivityModule.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.library.instrumentation.di.module
2 |
3 | import com.bael.dads.library.instrumentation.activity.MainTestActivity
4 | import com.bael.dads.library.presentation.di.qualifier.ActivityNameQualifier
5 | import com.bael.dads.library.presentation.di.qualifier.ActivityNameQualifier.Companion.ACTIVITY_MAIN
6 | import dagger.Module
7 | import dagger.Provides
8 | import dagger.hilt.InstallIn
9 | import dagger.hilt.components.SingletonComponent
10 | import javax.inject.Singleton
11 |
12 | /**
13 | * Created by stef_ang on 26/04/21.
14 | */
15 |
16 | @Module
17 | @InstallIn(SingletonComponent::class)
18 | internal class MainTestActivityModule {
19 |
20 | @Provides
21 | @Singleton
22 | @ActivityNameQualifier(name = ACTIVITY_MAIN)
23 | fun provideMainTestActivityName(): String {
24 | return MainTestActivity::class.java.name
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/android/library/instrumentation/src/main/kotlin/com/bael/dads/library/instrumentation/matcher/MatcherParams.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.library.instrumentation.matcher
2 |
3 | /**
4 | * Created by ErickSumargo on 15/05/21.
5 | */
6 |
7 | data class MatcherParams(
8 | val id: Int = -1,
9 | val text: String = "",
10 | val parent: MatcherParams? = null,
11 | val sibling: MatcherParams? = null
12 | )
13 |
--------------------------------------------------------------------------------
/android/library/instrumentation/src/main/kotlin/com/bael/dads/library/instrumentation/runner/HiltTestRunner.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.library.instrumentation.runner
2 |
3 | import android.app.Application
4 | import android.content.Context
5 | import androidx.test.runner.AndroidJUnitRunner
6 | import dagger.hilt.android.testing.HiltTestApplication
7 |
8 | /**
9 | * Created by ErickSumargo on 01/01/21.
10 | */
11 |
12 | class HiltTestRunner : AndroidJUnitRunner() {
13 |
14 | override fun newApplication(
15 | cl: ClassLoader?,
16 | className: String?,
17 | context: Context?
18 | ): Application {
19 | return super.newApplication(cl, HiltTestApplication::class.java.name, context)
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/android/library/instrumentation/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/library/preference/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/android/library/preference/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import Library.AndroidX.dataStore
2 |
3 | plugins {
4 | id("androidLibrary")
5 | }
6 |
7 | dependencies {
8 | // AndroidX
9 | implementation(dataStore)
10 | }
11 |
12 | dependencies {
13 | // Library
14 | implementation(project(":android:library:threading"))
15 | }
16 |
--------------------------------------------------------------------------------
/android/library/preference/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErickSumargo/Dads/8eb44894518e23f535a69cbe0207ad034f6a282f/android/library/preference/consumer-rules.pro
--------------------------------------------------------------------------------
/android/library/preference/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.kts.
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
--------------------------------------------------------------------------------
/android/library/preference/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/android/library/preference/src/main/kotlin/com/bael/dads/library/preference/Preference.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.library.preference
2 |
3 | /**
4 | * Created by ErickSumargo on 01/01/21.
5 | */
6 |
7 | interface Preference {
8 |
9 | suspend fun read(key: String, defaultValue: T): T
10 |
11 | suspend fun write(key: String, value: T)
12 | }
13 |
--------------------------------------------------------------------------------
/android/library/preference/src/main/kotlin/com/bael/dads/library/preference/di/module/PreferenceModule.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.library.preference.di.module
2 |
3 | import com.bael.dads.library.preference.DataStorePreference
4 | import com.bael.dads.library.preference.Preference
5 | import dagger.Binds
6 | import dagger.Module
7 | import dagger.hilt.InstallIn
8 | import dagger.hilt.components.SingletonComponent
9 | import javax.inject.Singleton
10 |
11 | /**
12 | * Created by ErickSumargo on 01/01/21.
13 | */
14 |
15 | @Module
16 | @InstallIn(SingletonComponent::class)
17 | interface PreferenceModule {
18 |
19 | @Binds
20 | @Singleton
21 | fun bindPreferenceStore(preference: DataStorePreference): Preference
22 | }
23 |
--------------------------------------------------------------------------------
/android/library/preference_test/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/android/library/preference_test/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import Library.Google.daggerTesting
2 |
3 | plugins {
4 | id("androidLibrary")
5 | }
6 |
7 | dependencies {
8 | // Google
9 | implementation(daggerTesting)
10 | }
11 |
12 | dependencies {
13 | // Library
14 | implementation(project(":android:library:preference"))
15 | }
16 |
--------------------------------------------------------------------------------
/android/library/preference_test/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErickSumargo/Dads/8eb44894518e23f535a69cbe0207ad034f6a282f/android/library/preference_test/consumer-rules.pro
--------------------------------------------------------------------------------
/android/library/preference_test/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.kts.
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
--------------------------------------------------------------------------------
/android/library/preference_test/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/android/library/preference_test/src/main/kotlin/com/bael/dads/library/preference/test/FakePreference.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("UNCHECKED_CAST")
2 |
3 | package com.bael.dads.library.preference.test
4 |
5 | import com.bael.dads.library.preference.Preference
6 | import javax.inject.Inject
7 |
8 | /**
9 | * Created by ErickSumargo on 01/04/21.
10 | */
11 |
12 | internal class FakePreference @Inject constructor() : Preference {
13 | private val container: MutableMap = HashMap()
14 |
15 | override suspend fun read(key: String, defaultValue: T): T {
16 | return container[key] as T ?: defaultValue
17 | }
18 |
19 | override suspend fun write(key: String, value: T) {
20 | container[key] = value as Any
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/android/library/preference_test/src/main/kotlin/com/bael/dads/library/preference/test/di/module/PreferenceTestModule.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.library.preference.test.di.module
2 |
3 | import com.bael.dads.library.preference.Preference
4 | import com.bael.dads.library.preference.di.module.PreferenceModule
5 | import com.bael.dads.library.preference.test.FakePreference
6 | import dagger.Binds
7 | import dagger.Module
8 | import dagger.hilt.components.SingletonComponent
9 | import dagger.hilt.testing.TestInstallIn
10 | import javax.inject.Singleton
11 |
12 | /**
13 | * Created by ErickSumargo on 01/04/21.
14 | */
15 |
16 | @Module
17 | @TestInstallIn(
18 | components = [SingletonComponent::class],
19 | replaces = [PreferenceModule::class]
20 | )
21 | internal interface PreferenceTestModule {
22 |
23 | @Binds
24 | @Singleton
25 | fun bindPreference(preference: FakePreference): Preference
26 | }
27 |
--------------------------------------------------------------------------------
/android/library/presentation/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/android/library/presentation/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import Library.Airbnb.lottie
2 | import Library.AndroidX.constraintLayout
3 | import Library.AndroidX.fragment
4 | import Library.AndroidX.lifecycle
5 | import Library.AndroidX.lifecycleViewModelSavedState
6 | import Library.AndroidX.navigationFragment
7 | import Library.AndroidX.navigationUi
8 | import Library.AndroidX.recyclerView
9 | import Library.AndroidX.viewPager2
10 | import Library.Google.material
11 |
12 | plugins {
13 | id("androidLibrary")
14 | }
15 |
16 | android {
17 | buildFeatures.apply {
18 | viewBinding = true
19 | }
20 | }
21 |
22 | dependencies {
23 | // AndroidX
24 | implementation(constraintLayout)
25 | implementation(fragment)
26 | implementation(lifecycle)
27 | implementation(lifecycleViewModelSavedState)
28 | implementation(navigationFragment)
29 | implementation(navigationUi)
30 | implementation(recyclerView)
31 | implementation(viewPager2)
32 |
33 | // Airbnb
34 | implementation(lottie)
35 |
36 | // Google
37 | implementation(material)
38 | }
39 |
40 | dependencies {
41 | // Shared
42 | implementation(project(":shared"))
43 |
44 | // Library
45 | implementation(project(":android:library:threading"))
46 | }
47 |
--------------------------------------------------------------------------------
/android/library/presentation/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErickSumargo/Dads/8eb44894518e23f535a69cbe0207ad034f6a282f/android/library/presentation/consumer-rules.pro
--------------------------------------------------------------------------------
/android/library/presentation/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.kts.
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
--------------------------------------------------------------------------------
/android/library/presentation/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/android/library/presentation/src/main/kotlin/com/bael/dads/library/presentation/di/qualifier/ActivityNameQualifier.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.library.presentation.di.qualifier
2 |
3 | import javax.inject.Qualifier
4 |
5 | /**
6 | * Created by stef_ang on 24/04/21.
7 | */
8 |
9 | @Qualifier
10 | @Retention(AnnotationRetention.BINARY)
11 | annotation class ActivityNameQualifier(val name: String) {
12 |
13 | companion object {
14 | const val ACTIVITY_MAIN: String = "main"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/android/library/presentation/src/main/kotlin/com/bael/dads/library/presentation/event/EventStore.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("UNCHECKED_CAST")
2 |
3 | package com.bael.dads.library.presentation.event
4 |
5 | import com.bael.dads.library.presentation.store.Store
6 | import kotlinx.coroutines.flow.MutableStateFlow
7 |
8 | /**
9 | * Created by ErickSumargo on 01/04/21.
10 | */
11 |
12 | internal class EventStore : Store {
13 | override val stateFlow: MutableStateFlow = MutableStateFlow(value = null as E)
14 |
15 | override fun process(state: E) {
16 | stateFlow.value = state
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/android/library/presentation/src/main/kotlin/com/bael/dads/library/presentation/ext/ContextExt.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.library.presentation.ext
2 |
3 | import android.content.Context
4 | import android.graphics.drawable.Drawable
5 | import androidx.annotation.DrawableRes
6 | import androidx.annotation.StringRes
7 |
8 | /**
9 | * Created by ErickSumargo on 01/01/21.
10 | */
11 |
12 | fun Context.readDrawable(@DrawableRes resId: Int): Drawable {
13 | return drawable(resId)
14 | }
15 |
16 | fun Context.readText(@StringRes resId: Int, vararg formatArgs: Any): String {
17 | return getString(resId, *formatArgs)
18 | }
19 |
--------------------------------------------------------------------------------
/android/library/presentation/src/main/kotlin/com/bael/dads/library/presentation/ext/DrawableExt.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.library.presentation.ext
2 |
3 | import android.content.Context
4 | import android.graphics.drawable.ColorDrawable
5 | import android.graphics.drawable.Drawable
6 | import androidx.annotation.DrawableRes
7 | import androidx.core.content.ContextCompat.getDrawable
8 |
9 | /**
10 | * Created by ErickSumargo on 01/01/21.
11 | */
12 |
13 | fun Context.drawable(@DrawableRes resId: Int): Drawable {
14 | val drawable = getDrawable(this, resId)
15 | return drawable ?: ColorDrawable()
16 | }
17 |
--------------------------------------------------------------------------------
/android/library/presentation/src/main/kotlin/com/bael/dads/library/presentation/ext/FragmentExt.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.library.presentation.ext
2 |
3 | import android.graphics.drawable.Drawable
4 | import androidx.annotation.DrawableRes
5 | import androidx.annotation.StringRes
6 | import androidx.fragment.app.Fragment
7 |
8 | /**
9 | * Created by ErickSumargo on 01/01/21.
10 | */
11 |
12 | val Fragment.screenHeight: Int
13 | get() = activity?.resources?.displayMetrics?.heightPixels ?: 0
14 |
15 | fun Fragment.readDrawable(@DrawableRes resId: Int): Drawable {
16 | return requireContext().readDrawable(resId)
17 | }
18 |
19 | fun Fragment.readText(@StringRes resId: Int, vararg formatArgs: Any): String {
20 | return requireContext().readText(resId, formatArgs)
21 | }
22 |
--------------------------------------------------------------------------------
/android/library/presentation/src/main/kotlin/com/bael/dads/library/presentation/ext/SoftKeyboardExt.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.library.presentation.ext
2 |
3 | import android.content.Context.INPUT_METHOD_SERVICE
4 | import android.view.View
5 | import android.view.inputmethod.InputMethodManager
6 | import android.view.inputmethod.InputMethodManager.SHOW_FORCED
7 |
8 | /**
9 | * Created by ErickSumargo on 01/01/21.
10 | */
11 |
12 | fun View.showSoftKeyboard() {
13 | val imm = context.getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
14 | imm.toggleSoftInputFromWindow(windowToken, SHOW_FORCED, 0)
15 | }
16 |
17 | fun View.hideSoftKeyboard() {
18 | val imm = context.getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
19 | imm.hideSoftInputFromWindow(windowToken, 0)
20 | }
--------------------------------------------------------------------------------
/android/library/presentation/src/main/kotlin/com/bael/dads/library/presentation/ext/StateExt.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.library.presentation.ext
2 |
3 | import com.bael.dads.library.presentation.state.BaseState
4 |
5 | /**
6 | * Created by ErickSumargo on 01/01/21.
7 | */
8 |
9 | fun S.reduce(reduceState: S.() -> S): S {
10 | return reduceState()
11 | }
12 |
--------------------------------------------------------------------------------
/android/library/presentation/src/main/kotlin/com/bael/dads/library/presentation/ext/StringExt.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("DEPRECATION")
2 |
3 | package com.bael.dads.library.presentation.ext
4 |
5 | import android.os.Build.VERSION.SDK_INT
6 | import android.os.Build.VERSION_CODES.N
7 | import android.text.Html.FROM_HTML_MODE_LEGACY
8 | import android.text.Html.fromHtml
9 | import android.text.Spanned
10 |
11 | /**
12 | * Created by ErickSumargo on 01/01/21.
13 | */
14 |
15 | fun String?.toRichText(): Spanned {
16 | val source = this.orEmpty()
17 |
18 | return if (SDK_INT >= N) fromHtml(source, FROM_HTML_MODE_LEGACY)
19 | else fromHtml(source)
20 | }
21 |
--------------------------------------------------------------------------------
/android/library/presentation/src/main/kotlin/com/bael/dads/library/presentation/notification/NotificationConfiguration.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.library.presentation.notification
2 |
3 | import android.app.Notification
4 | import androidx.core.app.NotificationCompat.Builder
5 |
6 | /**
7 | * Created by ErickSumargo on 01/01/21.
8 | */
9 |
10 | interface NotificationConfiguration {
11 | val id: Int
12 |
13 | val category: String
14 |
15 | val importance: Int
16 |
17 | fun createTemplate(templateBuilder: Builder): Notification
18 | }
19 |
--------------------------------------------------------------------------------
/android/library/presentation/src/main/kotlin/com/bael/dads/library/presentation/notification/NotificationPublisher.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.library.presentation.notification
2 |
3 | import android.app.Notification
4 | import android.app.NotificationChannel
5 | import android.app.NotificationManager
6 | import android.content.Context
7 | import android.content.Context.NOTIFICATION_SERVICE
8 | import android.os.Build.VERSION.SDK_INT
9 | import android.os.Build.VERSION_CODES.O
10 | import androidx.core.app.NotificationCompat.Builder
11 | import dagger.hilt.android.qualifiers.ApplicationContext
12 | import javax.inject.Inject
13 | import javax.inject.Singleton
14 |
15 | /**
16 | * Created by ErickSumargo on 01/01/21.
17 | */
18 |
19 | @Singleton
20 | class NotificationPublisher @Inject constructor(
21 | @ApplicationContext private val context: Context
22 | ) {
23 | private val notificationManager: NotificationManager by lazy {
24 | context.getSystemService(NOTIFICATION_SERVICE) as NotificationManager
25 | }
26 |
27 | fun publish(configuration: NotificationConfiguration) {
28 | val channel = createChannel(configuration)
29 | channel?.let(notificationManager::createNotificationChannel)
30 |
31 | val template = createTemplate(configuration)
32 | notificationManager.notify(configuration.id, template)
33 | }
34 |
35 | private fun createChannel(configuration: NotificationConfiguration): NotificationChannel? {
36 | if (SDK_INT < O) return null
37 | return NotificationChannel(
38 | context.packageName,
39 | configuration.category,
40 | configuration.importance
41 | )
42 | }
43 |
44 | private fun createTemplate(configuration: NotificationConfiguration): Notification {
45 | return configuration.createTemplate(
46 | templateBuilder = Builder(context, context.packageName)
47 | )
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/android/library/presentation/src/main/kotlin/com/bael/dads/library/presentation/renderer/BaseRenderExecutor.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("UNCHECKED_CAST")
2 |
3 | package com.bael.dads.library.presentation.renderer
4 |
5 | import androidx.lifecycle.Lifecycle.State.RESUMED
6 | import androidx.lifecycle.flowWithLifecycle
7 | import androidx.lifecycle.lifecycleScope
8 | import com.bael.dads.library.presentation.viewmodel.BaseViewModel
9 | import kotlinx.coroutines.flow.launchIn
10 | import kotlinx.coroutines.flow.scan
11 |
12 | /**
13 | * Created by ErickSumargo on 01/01/21.
14 | */
15 |
16 | abstract class BaseRenderExecutor(
17 | renderer: BaseRenderer,
18 | private val viewModel: BaseViewModel
19 | ) : BaseRenderer by renderer {
20 |
21 | fun observeState() {
22 | viewModel.stateFlow
23 | .flowWithLifecycle(lifecycle, minActiveState = RESUMED)
24 | .scan(null as S, ::dispatch)
25 | .launchIn(scope = lifecycleScope)
26 | }
27 |
28 | private fun dispatch(oldState: S?, newState: S): S {
29 | render(oldState, newState)
30 | return newState
31 | }
32 |
33 | protected abstract fun render(oldState: S?, newState: S)
34 | }
35 |
--------------------------------------------------------------------------------
/android/library/presentation/src/main/kotlin/com/bael/dads/library/presentation/renderer/BaseRenderer.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.library.presentation.renderer
2 |
3 | import androidx.lifecycle.LifecycleOwner
4 |
5 | /**
6 | * Created by ErickSumargo on 01/01/21.
7 | */
8 |
9 | interface BaseRenderer : LifecycleOwner
10 |
--------------------------------------------------------------------------------
/android/library/presentation/src/main/kotlin/com/bael/dads/library/presentation/renderer/RendererInitializer.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.library.presentation.renderer
2 |
3 | /**
4 | * Created by ErickSumargo on 01/01/21.
5 | */
6 |
7 | interface RendererInitializer {
8 |
9 | fun init(renderer: R, viewModel: VM)
10 | }
11 |
--------------------------------------------------------------------------------
/android/library/presentation/src/main/kotlin/com/bael/dads/library/presentation/state/BaseState.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.library.presentation.state
2 |
3 | import java.io.Serializable
4 |
5 | /**
6 | * Created by ErickSumargo on 01/01/21.
7 | */
8 |
9 | abstract class BaseState : Serializable
10 |
--------------------------------------------------------------------------------
/android/library/presentation/src/main/kotlin/com/bael/dads/library/presentation/state/StateStore.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.library.presentation.state
2 |
3 | import com.bael.dads.library.presentation.store.Store
4 | import kotlinx.coroutines.flow.MutableStateFlow
5 |
6 | /**
7 | * Created by ErickSumargo on 01/01/21.
8 | */
9 |
10 | internal class StateStore(initState: S) : Store {
11 | override val stateFlow: MutableStateFlow = MutableStateFlow(value = initState)
12 |
13 | override fun process(state: S) {
14 | stateFlow.value = state
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/android/library/presentation/src/main/kotlin/com/bael/dads/library/presentation/store/Store.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.library.presentation.store
2 |
3 | import kotlinx.coroutines.flow.Flow
4 |
5 | /**
6 | * Created by ErickSumargo on 01/01/21.
7 | */
8 |
9 | internal interface Store {
10 | val stateFlow: Flow
11 |
12 | fun process(state: S)
13 | }
14 |
--------------------------------------------------------------------------------
/android/library/presentation/src/main/kotlin/com/bael/dads/library/presentation/widget/animation/Animation.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.library.presentation.widget.animation
2 |
3 | /**
4 | * Created by ErickSumargo on 01/01/21.
5 | */
6 |
7 | val loading: String
8 | get() = "anim_loading.json"
9 |
10 | val error: String
11 | get() = "anim_error.json"
12 |
13 | val noInternet: String
14 | get() = "anim_no_internet.json"
15 |
16 | val empty: String
17 | get() = "anim_empty.json"
18 |
--------------------------------------------------------------------------------
/android/library/presentation/src/main/kotlin/com/bael/dads/library/presentation/widget/listener/OnPageSnapListener.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.library.presentation.widget.listener
2 |
3 | import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback
4 |
5 | /**
6 | * Created by ErickSumargo on 01/01/21.
7 | */
8 |
9 | class OnPageSnapListener(
10 | private val callback: (Int) -> Unit
11 | ) : OnPageChangeCallback() {
12 | private var previousPosition: Int = -1
13 |
14 | override fun onPageSelected(position: Int) {
15 | super.onPageSelected(position)
16 | if (position != previousPosition) {
17 | callback(previousPosition)
18 | }
19 | previousPosition = position
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/android/library/presentation/src/main/kotlin/com/bael/dads/library/presentation/widget/listener/OnTextChangedListener.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.library.presentation.widget.listener
2 |
3 | import android.text.Editable
4 | import android.text.TextWatcher
5 |
6 | /**
7 | * Created by ErickSumargo on 01/01/21.
8 | */
9 |
10 | class OnTextChangedListener(
11 | private val callback: (String) -> Unit
12 | ) : TextWatcher {
13 |
14 | override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
15 |
16 | override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
17 |
18 | override fun afterTextChanged(editor: Editable?) {
19 | callback(editor?.toString().orEmpty())
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/android/library/presentation/src/main/kotlin/com/bael/dads/library/presentation/widget/recyclerview/adapter/BaseAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.library.presentation.widget.recyclerview.adapter
2 |
3 | import android.view.LayoutInflater
4 | import android.view.LayoutInflater.from
5 | import android.view.ViewGroup
6 | import androidx.recyclerview.widget.RecyclerView.Adapter
7 | import com.bael.dads.library.presentation.widget.recyclerview.adapter.cell.BaseCell
8 |
9 | /**
10 | * Created by ErickSumargo on 01/01/21.
11 | */
12 |
13 | abstract class BaseAdapter> : Adapter() {
14 |
15 | override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): C {
16 | val inflater = from(viewGroup.context)
17 | return createCell(inflater, viewGroup)
18 | }
19 |
20 | override fun onBindViewHolder(cell: C, position: Int) {
21 | bindCell(cell)
22 | }
23 |
24 | abstract fun createCell(inflater: LayoutInflater, viewGroup: ViewGroup): C
25 |
26 | abstract fun bindCell(cell: C)
27 | }
28 |
--------------------------------------------------------------------------------
/android/library/presentation/src/main/kotlin/com/bael/dads/library/presentation/widget/recyclerview/adapter/BaseListAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.library.presentation.widget.recyclerview.adapter
2 |
3 | import android.view.LayoutInflater
4 | import android.view.LayoutInflater.from
5 | import android.view.ViewGroup
6 | import androidx.recyclerview.widget.DiffUtil.ItemCallback
7 | import androidx.recyclerview.widget.ListAdapter
8 | import com.bael.dads.library.presentation.widget.recyclerview.adapter.cell.BaseCell
9 |
10 | /**
11 | * Created by ErickSumargo on 01/01/21.
12 | */
13 |
14 | abstract class BaseListAdapter>(
15 | diffCallback: ItemCallback
16 | ) : ListAdapter(diffCallback) {
17 |
18 | override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): C {
19 | val inflater = from(viewGroup.context)
20 | return createCell(inflater, viewGroup)
21 | }
22 |
23 | override fun onBindViewHolder(cell: C, position: Int) {
24 | val item = getItem(position)
25 |
26 | cell.cacheItem(item)
27 | cell.render(item)
28 |
29 | if (position < itemCount - 1) return
30 | onReachEndOfItems(item)
31 | }
32 |
33 | abstract fun createCell(inflater: LayoutInflater, viewGroup: ViewGroup): C
34 |
35 | abstract fun onReachEndOfItems(item: I)
36 |
37 | fun getItemAt(position: Int): I? {
38 | return if (position < 0 || position >= itemCount) null
39 | else getItem(position)
40 | }
41 |
42 | fun lastItem(): I? {
43 | return getItemAt(position = itemCount - 1)
44 | }
45 |
46 | fun clearData() {
47 | submitList(listOf())
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/android/library/presentation/src/main/kotlin/com/bael/dads/library/presentation/widget/recyclerview/adapter/LiveListAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.library.presentation.widget.recyclerview.adapter
2 |
3 | import androidx.lifecycle.LifecycleOwner
4 | import androidx.lifecycle.lifecycleScope
5 | import androidx.recyclerview.widget.DiffUtil.ItemCallback
6 | import com.bael.dads.library.presentation.widget.recyclerview.adapter.cell.BaseCell
7 | import kotlinx.coroutines.Job
8 |
9 | /**
10 | * Created by ErickSumargo on 01/01/21.
11 | */
12 |
13 | abstract class LiveListAdapter>(
14 | diffCallback: ItemCallback,
15 | private val lifecycleOwner: LifecycleOwner
16 | ) : BaseListAdapter(diffCallback),
17 | LifecycleOwner by lifecycleOwner {
18 | private val observers: MutableMap = mutableMapOf()
19 |
20 | override fun onViewAttachedToWindow(cell: C) {
21 | super.onViewAttachedToWindow(cell)
22 |
23 | val item = cell.itemCache
24 | val key = getItemKey(item)
25 |
26 | observers[key] = lifecycleScope.launchWhenResumed {
27 | observeItem(item)
28 | }
29 | }
30 |
31 | abstract fun getItemKey(item: I): Any
32 |
33 | abstract suspend fun observeItem(item: I)
34 |
35 | override fun onViewDetachedFromWindow(cell: C) {
36 | val item = cell.itemCache
37 | val key = getItemKey(item)
38 |
39 | observers[key]?.cancel()
40 | super.onViewDetachedFromWindow(cell)
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/android/library/presentation/src/main/kotlin/com/bael/dads/library/presentation/widget/recyclerview/adapter/ResponseStateAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.library.presentation.widget.recyclerview.adapter
2 |
3 | import android.view.LayoutInflater
4 | import android.view.View
5 | import android.view.ViewGroup
6 | import com.bael.dads.library.presentation.databinding.ItemResponseStateBinding.inflate
7 | import com.bael.dads.library.presentation.widget.recyclerview.adapter.cell.ResponseStateCell
8 | import com.bael.dads.library.presentation.widget.recyclerview.adapter.data.ResponseState
9 |
10 | /**
11 | * Created by ErickSumargo on 01/01/21.
12 | */
13 |
14 | class ResponseStateAdapter(
15 | private val state: ResponseState,
16 | private val onClickActionListener: ((View) -> Unit)? = null
17 | ) : SingleItemAdapter() {
18 |
19 | override fun createCell(
20 | inflater: LayoutInflater,
21 | viewGroup: ViewGroup
22 | ): ResponseStateCell {
23 | val viewBinding = inflate(inflater, viewGroup, false)
24 | return ResponseStateCell(viewBinding, onClickActionListener)
25 | }
26 |
27 | override fun bindCell(cell: ResponseStateCell) {
28 | cell.render(state)
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/android/library/presentation/src/main/kotlin/com/bael/dads/library/presentation/widget/recyclerview/adapter/SingleItemAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.library.presentation.widget.recyclerview.adapter
2 |
3 | import com.bael.dads.library.presentation.widget.recyclerview.adapter.cell.BaseCell
4 |
5 | /**
6 | * Created by ErickSumargo on 01/01/21.
7 | */
8 |
9 | abstract class SingleItemAdapter> : BaseAdapter() {
10 |
11 | override fun getItemCount(): Int = 1
12 | }
13 |
--------------------------------------------------------------------------------
/android/library/presentation/src/main/kotlin/com/bael/dads/library/presentation/widget/recyclerview/adapter/cell/BaseCell.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.library.presentation.widget.recyclerview.adapter.cell
2 |
3 | import android.content.Context
4 | import androidx.recyclerview.widget.RecyclerView.ViewHolder
5 | import androidx.viewbinding.ViewBinding
6 |
7 | /**
8 | * Created by ErickSumargo on 01/01/21.
9 | */
10 |
11 | abstract class BaseCell(
12 | protected val viewBinding: VB
13 | ) : ViewHolder(viewBinding.root) {
14 | val context: Context
15 | get() = viewBinding.root.context
16 |
17 | internal lateinit var itemCache: I
18 | private set
19 |
20 | internal fun cacheItem(item: I) {
21 | itemCache = item
22 | }
23 |
24 | abstract fun render(state: I)
25 | }
26 |
--------------------------------------------------------------------------------
/android/library/presentation/src/main/kotlin/com/bael/dads/library/presentation/widget/recyclerview/adapter/data/ResponseState.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.library.presentation.widget.recyclerview.adapter.data
2 |
3 |
4 | /**
5 | * Created by ErickSumargo on 01/01/21.
6 | */
7 |
8 | data class ResponseState(
9 | val animation: AnimationProperty? = null,
10 | val description: String = "",
11 | val actionText: String = ""
12 | ) {
13 | data class AnimationProperty(
14 | val resource: String,
15 | val playLoop: Boolean
16 | )
17 | }
18 |
--------------------------------------------------------------------------------
/android/library/presentation/src/main/kotlin/com/bael/dads/library/presentation/widget/tab/data/BottomTab.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.library.presentation.widget.tab.data
2 |
3 | import android.graphics.drawable.Drawable
4 |
5 | /**
6 | * Created by ErickSumargo on 01/01/21.
7 | */
8 |
9 | data class BottomTab(
10 | val icon: Drawable,
11 | val name: String
12 | )
13 |
--------------------------------------------------------------------------------
/android/library/presentation/src/main/kotlin/com/bael/dads/library/presentation/widget/viewpager/adapter/ScreenPagerAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.library.presentation.widget.viewpager.adapter
2 |
3 | import androidx.fragment.app.Fragment
4 | import androidx.fragment.app.FragmentManager
5 | import androidx.lifecycle.Lifecycle
6 | import androidx.viewpager2.adapter.FragmentStateAdapter
7 |
8 | /**
9 | * Created by ErickSumargo on 01/01/21.
10 | */
11 |
12 | class ScreenPagerAdapter(
13 | fragmentManager: FragmentManager,
14 | lifecycle: Lifecycle,
15 | private val screens: List<() -> Fragment>
16 | ) : FragmentStateAdapter(fragmentManager, lifecycle) {
17 |
18 | override fun getItemCount() = screens.size
19 |
20 | override fun createFragment(position: Int): Fragment {
21 | return screens[position]()
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/android/library/presentation/src/main/kotlin/com/bael/dads/library/presentation/widget/viewpager/transformer/StackTransformer.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.library.presentation.widget.viewpager.transformer
2 |
3 | import android.view.View
4 | import androidx.core.view.ViewCompat.setElevation
5 | import androidx.viewpager2.widget.ViewPager2.PageTransformer
6 | import kotlin.math.abs
7 |
8 | /**
9 | * Created by ErickSumargo on 01/01/21.
10 | */
11 |
12 | class StackTransformer(private val stackLimit: Int) : PageTransformer {
13 |
14 | override fun transformPage(page: View, position: Float) {
15 | val alphaFactor = -ALPHA_FACTOR * position + ALPHA
16 | val scaleFactor = -SCALE_FACTOR * position + SCALE
17 |
18 | when {
19 | position <= 0f -> {
20 | page.alpha = ALPHA + position
21 | page.scaleX = SCALE
22 | page.scaleY = SCALE
23 | page.translationX = TRANSLATION_X
24 | }
25 | position <= stackLimit - 1 -> {
26 | page.alpha = alphaFactor
27 | page.scaleX = scaleFactor
28 | page.scaleY = scaleFactor
29 | page.translationX = -(page.width / TRANSLATION_FACTOR) * position
30 | }
31 | else -> {
32 | page.alpha = ALPHA
33 | page.scaleX = SCALE
34 | page.scaleY = SCALE
35 | page.translationX = TRANSLATION_X
36 | }
37 | }
38 | setElevation(page, -abs(position))
39 | }
40 |
41 | private companion object {
42 | const val ALPHA = 1f
43 | const val ALPHA_FACTOR = 0f
44 |
45 | const val SCALE: Float = 1f
46 | const val SCALE_FACTOR: Float = .1f
47 |
48 | const val TRANSLATION_X = 0f
49 | const val TRANSLATION_FACTOR = 1.1f
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/android/library/presentation/src/main/res/drawable/bg_circle.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/library/presentation/src/main/res/drawable/bg_sheet.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/android/library/presentation/src/main/res/layout/item_bottom_tab.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
16 |
17 |
25 |
26 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/android/library/presentation/src/main/res/values-night/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
19 |
20 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/android/library/presentation/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #404552
4 | #515868
5 |
6 | #A1A9B3
7 | #686d75
8 | #D6D6D6
9 | #F1F2F5
10 |
11 | #EF3A25
12 |
13 | #01AAC8
14 |
15 | #FFFFFF
16 |
17 |
--------------------------------------------------------------------------------
/android/library/presentation/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Icon
4 |
5 | Hmm, is your connection fine there?
6 | Oops! There\'s a temporary issue with the service. Would you please,
7 | Try again
8 |
9 |
--------------------------------------------------------------------------------
/android/library/presentation/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
19 |
20 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/android/library/threading/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/android/library/threading/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id("androidLibrary")
3 | }
4 |
--------------------------------------------------------------------------------
/android/library/threading/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErickSumargo/Dads/8eb44894518e23f535a69cbe0207ad034f6a282f/android/library/threading/consumer-rules.pro
--------------------------------------------------------------------------------
/android/library/threading/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.kts.
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
--------------------------------------------------------------------------------
/android/library/threading/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/android/library/threading/src/main/kotlin/com/bael/dads/library/threading/DefaultThread.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.library.threading
2 |
3 | import kotlinx.coroutines.CoroutineDispatcher
4 | import kotlinx.coroutines.Dispatchers.Default
5 | import kotlinx.coroutines.Dispatchers.IO
6 | import kotlinx.coroutines.Dispatchers.Main
7 | import javax.inject.Inject
8 |
9 | /**
10 | * Created by ErickSumargo on 01/01/21.
11 | */
12 |
13 | class DefaultThread @Inject constructor() : Thread {
14 | override val main: CoroutineDispatcher
15 | get() = Main
16 |
17 | override val default: CoroutineDispatcher
18 | get() = Default
19 |
20 | override val io: CoroutineDispatcher
21 | get() = IO
22 |
23 | override fun reset() {}
24 | }
25 |
--------------------------------------------------------------------------------
/android/library/threading/src/main/kotlin/com/bael/dads/library/threading/Thread.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.library.threading
2 |
3 | import kotlinx.coroutines.CoroutineDispatcher
4 |
5 | /**
6 | * Created by ErickSumargo on 01/01/21.
7 | */
8 |
9 | interface Thread {
10 | val main: CoroutineDispatcher
11 |
12 | val default: CoroutineDispatcher
13 |
14 | val io: CoroutineDispatcher
15 |
16 | fun reset()
17 | }
18 |
--------------------------------------------------------------------------------
/android/library/threading/src/main/kotlin/com/bael/dads/library/threading/di/module/ThreadingModule.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.library.threading.di.module
2 |
3 | import com.bael.dads.library.threading.DefaultThread
4 | import com.bael.dads.library.threading.Thread
5 | import dagger.Binds
6 | import dagger.Module
7 | import dagger.hilt.InstallIn
8 | import dagger.hilt.components.SingletonComponent
9 | import javax.inject.Singleton
10 |
11 | /**
12 | * Created by ErickSumargo on 01/01/21.
13 | */
14 |
15 | @Module
16 | @InstallIn(SingletonComponent::class)
17 | interface ThreadingModule {
18 |
19 | @Binds
20 | @Singleton
21 | fun bindThread(thread: DefaultThread): Thread
22 | }
23 |
--------------------------------------------------------------------------------
/android/library/threading_test/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/android/library/threading_test/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import Library.Google.daggerTesting
2 | import Library.KotlinX.coroutinesTest
3 |
4 | plugins {
5 | id("androidLibrary")
6 | }
7 |
8 | dependencies {
9 | // Google
10 | implementation(daggerTesting)
11 |
12 | // KotlinX
13 | implementation(coroutinesTest)
14 | }
15 |
16 | dependencies {
17 | // Library
18 | implementation(project(":android:library:threading"))
19 | }
20 |
--------------------------------------------------------------------------------
/android/library/threading_test/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErickSumargo/Dads/8eb44894518e23f535a69cbe0207ad034f6a282f/android/library/threading_test/consumer-rules.pro
--------------------------------------------------------------------------------
/android/library/threading_test/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.kts.
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
--------------------------------------------------------------------------------
/android/library/threading_test/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/android/library/threading_test/src/main/kotlin/com/bael/dads/library/threading/test/FakeThread.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.library.threading.test
2 |
3 | import com.bael.dads.library.threading.Thread
4 | import kotlinx.coroutines.CoroutineDispatcher
5 | import kotlinx.coroutines.test.TestCoroutineDispatcher
6 | import javax.inject.Inject
7 |
8 | /**
9 | * Created by ErickSumargo on 01/04/21.
10 | */
11 |
12 | internal class FakeThread @Inject constructor() : Thread {
13 | private val testDispatcher: TestCoroutineDispatcher = TestCoroutineDispatcher()
14 |
15 | override val main: CoroutineDispatcher
16 | get() = testDispatcher
17 |
18 | override val default: CoroutineDispatcher
19 | get() = testDispatcher
20 |
21 | override val io: CoroutineDispatcher
22 | get() = testDispatcher
23 |
24 | override fun reset() {
25 | testDispatcher.cleanupTestCoroutines()
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/android/library/threading_test/src/main/kotlin/com/bael/dads/library/threading/test/di/module/ThreadingTestModule.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.library.threading.test.di.module
2 |
3 | import com.bael.dads.library.threading.Thread
4 | import com.bael.dads.library.threading.di.module.ThreadingModule
5 | import com.bael.dads.library.threading.test.FakeThread
6 | import dagger.Binds
7 | import dagger.Module
8 | import dagger.hilt.components.SingletonComponent
9 | import dagger.hilt.testing.TestInstallIn
10 | import javax.inject.Singleton
11 |
12 | /**
13 | * Created by ErickSumargo on 01/04/21.
14 | */
15 |
16 | @Module
17 | @TestInstallIn(
18 | components = [SingletonComponent::class],
19 | replaces = [ThreadingModule::class]
20 | )
21 | internal interface ThreadingTestModule {
22 |
23 | @Binds
24 | @Singleton
25 | fun bindThread(thread: FakeThread): Thread
26 | }
27 |
--------------------------------------------------------------------------------
/android/library/worker/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/android/library/worker/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import Library.AndroidX.hiltWork
2 | import Library.AndroidX.startup
3 | import Library.AndroidX.work
4 |
5 | plugins {
6 | id("androidLibrary")
7 | }
8 |
9 | dependencies {
10 | // AndroidX
11 | implementation(hiltWork)
12 | implementation(startup)
13 | implementation(work)
14 | }
15 |
--------------------------------------------------------------------------------
/android/library/worker/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErickSumargo/Dads/8eb44894518e23f535a69cbe0207ad034f6a282f/android/library/worker/consumer-rules.pro
--------------------------------------------------------------------------------
/android/library/worker/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.kts.
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
--------------------------------------------------------------------------------
/android/library/worker/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
11 |
12 |
17 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/android/library/worker/src/main/kotlin/com/bael/dads/library/worker/BaseWorker.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.library.worker
2 |
3 | import android.content.Context
4 | import androidx.work.CoroutineWorker
5 | import androidx.work.WorkManager
6 | import androidx.work.WorkerParameters
7 | import javax.inject.Inject
8 |
9 | /**
10 | * Created by ErickSumargo on 01/01/21.
11 | */
12 |
13 | abstract class BaseWorker constructor(
14 | appContext: Context,
15 | params: WorkerParameters
16 | ) : CoroutineWorker(appContext, params) {
17 | @Inject
18 | lateinit var workManager: WorkManager
19 |
20 | protected fun cancelWork() {
21 | workManager.cancelWorkById(id)
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/android/library/worker/src/main/kotlin/com/bael/dads/library/worker/di/entry/EntryPoint.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.library.worker.di.entry
2 |
3 | import androidx.hilt.work.HiltWorkerFactory
4 | import dagger.hilt.EntryPoint
5 | import dagger.hilt.InstallIn
6 | import dagger.hilt.components.SingletonComponent
7 |
8 | /**
9 | * Created by ErickSumargo on 01/01/21.
10 | */
11 |
12 | @EntryPoint
13 | @InstallIn(SingletonComponent::class)
14 | internal interface EntryPoint {
15 |
16 | fun accessWorkerFactory(): HiltWorkerFactory
17 | }
18 |
--------------------------------------------------------------------------------
/android/library/worker/src/main/kotlin/com/bael/dads/library/worker/di/module/WorkerModule.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.library.worker.di.module
2 |
3 | import android.content.Context
4 | import androidx.work.WorkManager
5 | import dagger.Module
6 | import dagger.Provides
7 | import dagger.hilt.InstallIn
8 | import dagger.hilt.android.qualifiers.ApplicationContext
9 | import dagger.hilt.components.SingletonComponent
10 | import javax.inject.Singleton
11 |
12 | /**
13 | * Created by ErickSumargo on 01/01/21.
14 | */
15 |
16 | @Module
17 | @InstallIn(SingletonComponent::class)
18 | internal object WorkerModule {
19 |
20 | @Provides
21 | @Singleton
22 | fun provideWorkManager(@ApplicationContext context: Context): WorkManager {
23 | return WorkManager.getInstance(context)
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/android/library/worker/src/main/kotlin/com/bael/dads/library/worker/factory/NoOpWorkerFactory.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.library.worker.factory
2 |
3 | import android.content.Context
4 | import androidx.work.ListenableWorker
5 | import androidx.work.WorkerFactory
6 | import androidx.work.WorkerParameters
7 |
8 | /**
9 | * Created by ErickSumargo on 01/01/21.
10 | */
11 |
12 | internal class NoOpWorkerFactory : WorkerFactory() {
13 |
14 | override fun createWorker(
15 | appContext: Context,
16 | workerClassName: String,
17 | workerParameters: WorkerParameters
18 | ): ListenableWorker? {
19 | TODO("Not yet implemented")
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/android/processor/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/android/processor/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import Library.Google.autoService
2 | import Library.JavaX.inject
3 | import Library.Square.javaPoet
4 |
5 | plugins {
6 | id("kotlin")
7 | kotlin("kapt")
8 | }
9 |
10 | dependencies {
11 | // Google
12 | implementation(autoService)
13 | kapt(autoService)
14 |
15 | // JavaX
16 | implementation(inject)
17 |
18 | // Square
19 | implementation(javaPoet)
20 | }
21 |
22 | dependencies {
23 | // Internal
24 | implementation(project(":android:annotation"))
25 | }
26 |
--------------------------------------------------------------------------------
/android/processor/src/main/kotlin/com/bael/dads/processor/ext/AnnotationMirrorExt.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.processor.ext
2 |
3 | import javax.lang.model.element.AnnotationMirror
4 | import javax.lang.model.element.Element
5 | import javax.lang.model.element.TypeElement
6 | import javax.lang.model.type.TypeMirror
7 | import javax.lang.model.util.Types
8 | import kotlin.reflect.KProperty
9 |
10 | /**
11 | * Created by ErickSumargo on 01/01/21.
12 | */
13 |
14 | fun AnnotationMirror.toElement(): Element {
15 | return annotationType.asElement()
16 | }
17 |
18 | fun AnnotationMirror.parameterOf(typeUtils: Types, parameter: KProperty<*>): TypeElement? {
19 | val typeMirror = elementValues?.entries?.firstOrNull { (element, _) ->
20 | element.simpleName.toString() == parameter.name
21 | }?.value?.value as? TypeMirror
22 | return typeUtils.asElement(typeMirror) as TypeElement
23 | }
24 |
--------------------------------------------------------------------------------
/android/processor/src/main/kotlin/com/bael/dads/processor/ext/ClassNameExt.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.processor.ext
2 |
3 | import com.squareup.javapoet.ClassName
4 |
5 | /**
6 | * Created by ErickSumargo on 01/01/21.
7 | */
8 |
9 | val ClassName.varName: String
10 | get() = simpleName().let { name ->
11 | name[0].toLowerCase() + name.substring(1, name.length)
12 | }
13 |
--------------------------------------------------------------------------------
/android/processor/src/main/kotlin/com/bael/dads/processor/ext/ElementExt.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.processor.ext
2 |
3 | import javax.lang.model.element.AnnotationMirror
4 | import javax.lang.model.element.Element
5 | import javax.lang.model.element.ElementKind
6 | import javax.lang.model.element.TypeElement
7 | import kotlin.reflect.KClass
8 |
9 | /**
10 | * Created by ErickSumargo on 01/01/21.
11 | */
12 |
13 | fun Element.annotationOf(annotation: KClass<*>): AnnotationMirror? {
14 | return annotationMirrors.find { annotationMirror ->
15 | val typeElement = annotationMirror.toElement() as TypeElement
16 | typeElement.qualifiedName.toString() == annotation.java.name
17 | }
18 | }
19 |
20 | fun Element.members(kind: ElementKind): List {
21 | return enclosedElements?.filter { element ->
22 | element.kind == kind
23 | }.orEmpty()
24 | }
25 |
26 | val Element.isNullable: Boolean
27 | get() = annotationMirrors.any { annotationMirror ->
28 | annotationMirror.toElement().simpleName.endsWith("Nullable")
29 | }
30 |
--------------------------------------------------------------------------------
/android/processor/src/main/kotlin/com/bael/dads/processor/ext/NameExt.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.processor.ext
2 |
3 | import javax.lang.model.element.Name
4 |
5 | /**
6 | * Created by ErickSumargo on 01/01/21.
7 | */
8 |
9 | fun Name.toGetter(): String {
10 | return toString().let { name ->
11 | if (name.take(2) == "is") "$name()"
12 | else "get${name.capitalize()}()"
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/android/processor/src/main/kotlin/com/bael/dads/processor/ext/TypeElementExt.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.processor.ext
2 |
3 | import com.squareup.javapoet.TypeName
4 | import javax.lang.model.element.ElementKind.FIELD
5 | import javax.lang.model.element.ExecutableElement
6 | import javax.lang.model.element.Name
7 | import javax.lang.model.element.TypeElement
8 |
9 | /**
10 | * Created by ErickSumargo on 01/01/21.
11 | */
12 |
13 | val TypeElement.fields: Map
14 | get() = members(kind = FIELD).associate { field ->
15 | field.simpleName to TypeName.get(field.asType())
16 | }
17 |
18 | val TypeElement.methods: List
19 | get() = enclosedElements.map { element ->
20 | val method = element as? ExecutableElement
21 | method ?: return emptyList()
22 | method
23 | }
24 |
--------------------------------------------------------------------------------
/android/processor/src/main/kotlin/com/bael/dads/processor/logger/Logger.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.processor.logger
2 |
3 | import javax.annotation.processing.Messager
4 | import javax.tools.Diagnostic.Kind.ERROR
5 |
6 | /**
7 | * Created by ErickSumargo on 01/01/21.
8 | */
9 |
10 | internal class Logger(messager: Messager) : Messager by messager {
11 |
12 | fun error(message: String) {
13 | printMessage(ERROR, message)
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/assets/architecture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErickSumargo/Dads/8eb44894518e23f535a69cbe0207ad034f6a282f/assets/architecture.png
--------------------------------------------------------------------------------
/assets/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErickSumargo/Dads/8eb44894518e23f535a69cbe0207ad034f6a282f/assets/demo.gif
--------------------------------------------------------------------------------
/assets/graphql.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErickSumargo/Dads/8eb44894518e23f535a69cbe0207ad034f6a282f/assets/graphql.png
--------------------------------------------------------------------------------
/assets/kmm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErickSumargo/Dads/8eb44894518e23f535a69cbe0207ad034f6a282f/assets/kmm.png
--------------------------------------------------------------------------------
/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErickSumargo/Dads/8eb44894518e23f535a69cbe0207ad034f6a282f/assets/logo.png
--------------------------------------------------------------------------------
/assets/mad_scorecard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErickSumargo/Dads/8eb44894518e23f535a69cbe0207ad034f6a282f/assets/mad_scorecard.png
--------------------------------------------------------------------------------
/assets/playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErickSumargo/Dads/8eb44894518e23f535a69cbe0207ad034f6a282f/assets/playstore.png
--------------------------------------------------------------------------------
/build.gradle.kts:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | allprojects {
4 | repositories {
5 | google()
6 | mavenCentral()
7 | maven {
8 | setUrl("https://www.jetbrains.com/intellij-repository/releases")
9 | setUrl("https://jetbrains.bintray.com/intellij-third-party-dependencies")
10 | }
11 | }
12 | }
13 |
14 | tasks.register("clean", Delete::class) {
15 | delete(rootProject.buildDir)
16 | }
17 |
--------------------------------------------------------------------------------
/buildSrc/buildSrc/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | `kotlin-dsl`
3 | }
4 |
5 | repositories {
6 | mavenCentral()
7 | }
8 |
--------------------------------------------------------------------------------
/buildSrc/buildSrc/src/main/kotlin/Application.kt:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by ErickSumargo on 15/04/21.
3 | */
4 |
5 | object Application {
6 | const val id: String = "com.bael.dads"
7 |
8 | const val versionCode: Int = 2
9 |
10 | const val versionName: String = "1.1"
11 |
12 | const val compileSdk: Int = 30
13 |
14 | const val targetSdk: Int = 30
15 |
16 | const val minSdk: Int = 23
17 | }
18 |
--------------------------------------------------------------------------------
/buildSrc/buildSrc/src/main/kotlin/Plugin.kt:
--------------------------------------------------------------------------------
1 | import Version.Android.gradle as androidGradleVersion
2 | import Version.Apollo.apollo as apolloVersion
3 | import Version.Google.dagger as daggerVersion
4 | import Version.Google.firebaseCrashlytics as firebaseCrashlyticsVersion
5 | import Version.Google.gms as gmsVersion
6 | import Version.KotlinX.kotlin as kotlinVersion
7 | import Version.Square.sqlDelight as sqlDelightVersion
8 |
9 | /**
10 | * Created by ErickSumargo on 15/04/21.
11 | */
12 |
13 | object Plugin {
14 |
15 | object Android {
16 | val gradle: String
17 | get() = "com.android.tools.build:gradle:$androidGradleVersion"
18 | }
19 |
20 | object Apollo {
21 | val apollo: String
22 | get() = "com.apollographql.apollo:apollo-gradle-plugin:$apolloVersion"
23 | }
24 |
25 | object Google {
26 | val firebaseCrashlytics: String
27 | get() = "com.google.firebase:firebase-crashlytics-gradle:$firebaseCrashlyticsVersion"
28 |
29 | val dagger: String
30 | get() = "com.google.dagger:hilt-android-gradle-plugin:$daggerVersion"
31 |
32 | val gms: String
33 | get() = "com.google.gms:google-services:$gmsVersion"
34 | }
35 |
36 | object KotlinX {
37 | val kotlin: String
38 | get() = "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
39 | }
40 |
41 | object Square {
42 | val sqlDelight: String
43 | get() = "com.squareup.sqldelight:gradle-plugin:$sqlDelightVersion"
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/buildSrc/src/main/kotlin/plugin/shared/DataModulePlugin.kt:
--------------------------------------------------------------------------------
1 | package plugin.shared
2 |
3 | /**
4 | * Created by ErickSumargo on 01/05/21.
5 | */
6 |
7 | class DataModulePlugin : SharedModulePlugin()
8 |
--------------------------------------------------------------------------------
/buildSrc/src/main/kotlin/plugin/shared/DomainModulePlugin.kt:
--------------------------------------------------------------------------------
1 | package plugin.shared
2 |
3 | /**
4 | * Created by ErickSumargo on 15/04/21.
5 | */
6 |
7 | class DomainModulePlugin : SharedModulePlugin()
8 |
--------------------------------------------------------------------------------
/data/database/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | *.db
--------------------------------------------------------------------------------
/data/database/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import Library.Square.sqlDelightAndroidDriver
2 | import Library.Square.sqlDelightCoroutines
3 |
4 | plugins {
5 | id("data")
6 | id("com.squareup.sqldelight")
7 | }
8 |
9 | kotlin {
10 | sourceSets {
11 | val commonMain by getting {
12 | dependencies {
13 | // Square
14 | implementation(sqlDelightCoroutines)
15 | }
16 |
17 | dependencies {
18 | // Shared
19 | implementation(project(":shared"))
20 | }
21 | }
22 |
23 | val androidMain by getting {
24 | dependencies {
25 | // Square
26 | implementation(sqlDelightAndroidDriver)
27 | }
28 | }
29 | }
30 | }
31 |
32 | sqldelight {
33 | database("DadsDatabase") {
34 | packageName = "${Application.id}.data.database"
35 | schemaOutputDirectory = file("schemas")
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/data/database/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErickSumargo/Dads/8eb44894518e23f535a69cbe0207ad034f6a282f/data/database/consumer-rules.pro
--------------------------------------------------------------------------------
/data/database/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.kts.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/data/database/src/androidMain/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/data/database/src/androidMain/kotlin/com/bael/dads/data/database/di/module/DatabaseModule.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.data.database.di.module
2 |
3 | import android.content.Context
4 | import com.bael.dads.data.database.DadsDatabase
5 | import com.bael.dads.data.database.constant.Database.name
6 | import com.bael.dads.data.database.constant.Database.schema
7 | import com.squareup.sqldelight.android.AndroidSqliteDriver
8 | import dagger.Module
9 | import dagger.Provides
10 | import dagger.hilt.InstallIn
11 | import dagger.hilt.android.qualifiers.ApplicationContext
12 | import dagger.hilt.components.SingletonComponent
13 | import javax.inject.Singleton
14 |
15 | /**
16 | * Created by ErickSumargo on 01/01/21.
17 | */
18 |
19 | @Module
20 | @InstallIn(SingletonComponent::class)
21 | object DatabaseModule {
22 |
23 | @Provides
24 | @Singleton
25 | fun provideDadsDatabase(@ApplicationContext context: Context): DadsDatabase {
26 | val driver = AndroidSqliteDriver(schema, context, name)
27 | return DadsDatabase(driver)
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/data/database/src/androidMain/kotlin/com/bael/dads/data/database/di/module/repository/RepositoryModule.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.data.database.di.module.repository
2 |
3 | import com.bael.dads.data.database.DadsDatabase
4 | import com.bael.dads.data.database.repository.DadJokeRepository
5 | import com.bael.dads.data.database.repository.DefaultDadJokeRepository
6 | import com.bael.dads.data.database.repository.DefaultRemoteMetaRepository
7 | import com.bael.dads.data.database.repository.RemoteMetaRepository
8 | import dagger.Module
9 | import dagger.Provides
10 | import dagger.hilt.InstallIn
11 | import dagger.hilt.components.SingletonComponent
12 | import javax.inject.Singleton
13 |
14 | /**
15 | * Created by ErickSumargo on 01/04/21.
16 | */
17 |
18 | @Module
19 | @InstallIn(SingletonComponent::class)
20 | internal object RepositoryModule {
21 |
22 | @Provides
23 | @Singleton
24 | fun provideDadJokeRepository(database: DadsDatabase): DadJokeRepository {
25 | return DefaultDadJokeRepository(database)
26 | }
27 |
28 | @Provides
29 | @Singleton
30 | fun provideRemoteMetaRepository(database: DadsDatabase): RemoteMetaRepository {
31 | return DefaultRemoteMetaRepository(database)
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/data/database/src/commonMain/kotlin/com/bael/dads/data/database/constant/Database.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.data.database.constant
2 |
3 | import com.squareup.sqldelight.db.SqlDriver.Schema
4 | import com.bael.dads.data.database.DadsDatabase.Companion.Schema as DadsDatabaseSchema
5 |
6 | /**
7 | * Created by ErickSumargo on 01/05/21.
8 | */
9 |
10 | internal object Database {
11 | const val name: String = "dads.db"
12 |
13 | val schema: Schema
14 | get() = DadsDatabaseSchema
15 | }
16 |
--------------------------------------------------------------------------------
/data/database/src/commonMain/kotlin/com/bael/dads/data/database/repository/DadJokeRepository.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.data.database.repository
2 |
3 | import com.bael.dads.data.database.entity.DadJoke
4 | import kotlinx.coroutines.flow.Flow
5 |
6 | /**
7 | * Created by ErickSumargo on 01/04/21.
8 | */
9 |
10 | interface DadJokeRepository {
11 |
12 | suspend fun insertDadJokes(dadJokes: List)
13 |
14 | suspend fun loadDadJokeFeed(id: Int, limit: Int): List
15 |
16 | suspend fun loadSeenDadJoke(term: String, cursor: Int, limit: Int): List
17 |
18 | suspend fun loadFavoredDadJoke(term: String, cursor: Long, limit: Int): List
19 |
20 | suspend fun loadDadJoke(id: Int): DadJoke?
21 |
22 | suspend fun loadLatestDadJoke(): DadJoke?
23 |
24 | suspend fun observeDadJoke(id: Int): Flow
25 |
26 | suspend fun setDadJokeSeen(id: Int): Int
27 |
28 | suspend fun favorDadJoke(id: Int, favored: Boolean): Int
29 |
30 | suspend fun deleteAllDadJokes(): Int
31 | }
32 |
--------------------------------------------------------------------------------
/data/database/src/commonMain/kotlin/com/bael/dads/data/database/repository/DefaultRemoteMetaRepository.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.data.database.repository
2 |
3 | import com.bael.dads.data.database.DadsDatabase
4 | import com.bael.dads.data.database.entity.RemoteMeta
5 |
6 | /**
7 | * Created by ErickSumargo on 01/04/21.
8 | */
9 |
10 | internal class DefaultRemoteMetaRepository(database: DadsDatabase) :
11 | RemoteMetaRepository,
12 | DadsDatabase by database {
13 |
14 | override suspend fun loadRemoteMeta(): RemoteMeta? {
15 | return remoteMetaQueries.loadRemoteMeta()
16 | .executeAsOneOrNull()
17 | }
18 |
19 | override suspend fun insertRemoteMeta(remoteMeta: RemoteMeta): Int {
20 | remoteMetaQueries.insertRemoteMeta(cursor = remoteMeta.cursor)
21 | return 1
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/data/database/src/commonMain/kotlin/com/bael/dads/data/database/repository/RemoteMetaRepository.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.data.database.repository
2 |
3 | import com.bael.dads.data.database.entity.RemoteMeta
4 |
5 | /**
6 | * Created by ErickSumargo on 01/04/21.
7 | */
8 |
9 | interface RemoteMetaRepository {
10 |
11 | suspend fun loadRemoteMeta(): RemoteMeta?
12 |
13 | suspend fun insertRemoteMeta(remoteMeta: RemoteMeta): Int
14 | }
15 |
--------------------------------------------------------------------------------
/data/database/src/commonMain/sqldelight/com/bael/dads/data/database/entity/DadJoke.sq:
--------------------------------------------------------------------------------
1 | CREATE TABLE dadJoke (
2 | id INTEGER AS Int PRIMARY KEY AUTOINCREMENT,
3 | jokeId TEXT NOT NULL,
4 | setup TEXT NOT NULL,
5 | punchline TEXT NOT NULL,
6 | favored INTEGER AS Boolean NOT NULL,
7 | seen INTEGER AS Boolean NOT NULL,
8 | createdAt INTEGER NOT NULL,
9 | updatedAt INTEGER NOT NULL
10 | );
11 |
12 | insertDadJoke:
13 | INSERT INTO dadJoke (jokeId, setup, punchline, favored, seen, createdAt, updatedAt)
14 | VALUES (?, ?, ?, ?, ?, ?, ?);
15 |
16 | loadDadJokeFeed:
17 | SELECT * FROM dadJoke WHERE id > :id AND seen == 0 LIMIT :limit;
18 |
19 | loadSeenDadJoke:
20 | SELECT * FROM dadJoke WHERE id < :cursor AND setup LIKE '%' || :term || '%' AND seen ORDER BY id DESC LIMIT :limit;
21 |
22 | loadFavoredDadJoke:
23 | SELECT * FROM dadJoke WHERE updatedAt < :updatedAt AND setup LIKE '%' || :term || '%' AND favored ORDER BY updatedAt DESC LIMIT :limit;
24 |
25 | loadDadJoke:
26 | SELECT * FROM dadJoke WHERE id = :id;
27 |
28 | loadLatestDadJoke:
29 | SELECT * FROM dadJoke ORDER BY id DESC LIMIT 1;
30 |
31 | observeDadJoke:
32 | SELECT * FROM dadJoke WHERE id = :id;
33 |
34 | setDadJokeSeen:
35 | UPDATE dadJoke SET seen = 1, updatedAt = :updatedAt WHERE id = :id;
36 |
37 | favorDadJoke:
38 | UPDATE dadJoke SET favored = :favored, updatedAt = :updatedAt WHERE id = :id;
39 |
40 | deleteAllDadJokes:
41 | DELETE FROM dadJoke;
42 |
--------------------------------------------------------------------------------
/data/database/src/commonMain/sqldelight/com/bael/dads/data/database/entity/RemoteMeta.sq:
--------------------------------------------------------------------------------
1 | CREATE TABLE remoteMeta (
2 | id INTEGER AS Int PRIMARY KEY AUTOINCREMENT,
3 | cursor TEXT
4 | );
5 |
6 | loadRemoteMeta:
7 | SELECT * FROM remoteMeta ORDER BY id DESC LIMIT 1;
8 |
9 | insertRemoteMeta:
10 | INSERT INTO remoteMeta (cursor)
11 | VALUES (?);
12 |
--------------------------------------------------------------------------------
/data/database_test/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/data/database_test/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import Library.Google.daggerTesting
2 | import Library.Square.sqlDelightAndroidDriver
3 |
4 | plugins {
5 | id("data")
6 | }
7 |
8 | kotlin {
9 | sourceSets {
10 | val commonMain by getting {
11 | dependencies {
12 | // Data
13 | implementation(project(":data:database"))
14 | }
15 | }
16 |
17 | val androidMain by getting {
18 | dependencies {
19 | // Google
20 | implementation(daggerTesting)
21 |
22 | // Square
23 | implementation(sqlDelightAndroidDriver)
24 | }
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/data/database_test/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErickSumargo/Dads/8eb44894518e23f535a69cbe0207ad034f6a282f/data/database_test/consumer-rules.pro
--------------------------------------------------------------------------------
/data/database_test/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.kts.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/data/database_test/src/androidMain/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/data/database_test/src/androidMain/kotlin/com/bael/dads/data/database/test/di/module/DatabaseTestModule.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.data.database.test.di.module
2 |
3 | import android.content.Context
4 | import com.bael.dads.data.database.DadsDatabase
5 | import com.bael.dads.data.database.di.module.DatabaseModule
6 | import com.squareup.sqldelight.android.AndroidSqliteDriver
7 | import dagger.Module
8 | import dagger.Provides
9 | import dagger.hilt.android.qualifiers.ApplicationContext
10 | import dagger.hilt.components.SingletonComponent
11 | import dagger.hilt.testing.TestInstallIn
12 | import javax.inject.Singleton
13 | import com.bael.dads.data.database.DadsDatabase.Companion.Schema as DadsTestSchema
14 |
15 | /**
16 | * Created by ErickSumargo on 01/01/21.
17 | */
18 |
19 | @Module
20 | @TestInstallIn(
21 | components = [SingletonComponent::class],
22 | replaces = [DatabaseModule::class]
23 | )
24 | internal object DatabaseTestModule {
25 |
26 | /**
27 | * SqlDelight current version doesn't support in-memory database for
28 | * Android's instrumentation testing requirement.
29 | *
30 | * Workaround is to create persistent database as production one.
31 | */
32 | @Provides
33 | @Singleton
34 | fun provideDadsDatabase(@ApplicationContext context: Context): DadsDatabase {
35 | val driver = AndroidSqliteDriver(schema = DadsTestSchema, context, name = "dads_test.db")
36 | return DadsDatabase(driver)
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/data/remote/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | schema.json
--------------------------------------------------------------------------------
/data/remote/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import Library.Apollo.apolloKotlin
2 |
3 | plugins {
4 | id("data")
5 | id("com.apollographql.apollo")
6 | id("com.google.secrets_gradle_plugin") version Version.Google.secrets
7 | }
8 |
9 | kotlin {
10 | sourceSets {
11 | all {
12 | languageSettings.apply {
13 | useExperimentalAnnotation("com.apollographql.apollo.api.ApolloExperimental")
14 | }
15 | }
16 |
17 | val commonMain by getting {
18 | dependencies {
19 | // Apollo
20 | implementation(apolloKotlin)
21 | }
22 |
23 | dependencies {
24 | // Shared
25 | implementation(project(":shared"))
26 | }
27 | }
28 |
29 | val androidMain by getting
30 | }
31 | }
32 |
33 | apollo {
34 | generateKotlinModels.set(true)
35 | }
36 |
37 | secrets {
38 | propertiesFileName = "keys.properties"
39 | }
40 |
--------------------------------------------------------------------------------
/data/remote/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErickSumargo/Dads/8eb44894518e23f535a69cbe0207ad034f6a282f/data/remote/consumer-rules.pro
--------------------------------------------------------------------------------
/data/remote/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.kts.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/data/remote/src/androidMain/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/data/remote/src/androidMain/kotlin/com/bael/dads/data/remote/di/module/client/ApolloClientModule.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.data.remote.di.module.client
2 |
3 | import com.apollographql.apollo.ApolloClient
4 | import com.apollographql.apollo.network.http.ApolloHttpNetworkTransport
5 | import com.bael.dads.data.remote.BuildConfig.JWT
6 | import com.bael.dads.data.remote.constant.Server.url
7 | import com.bael.dads.data.remote.interceptor.NetworkInterceptor
8 | import dagger.Module
9 | import dagger.Provides
10 | import dagger.hilt.InstallIn
11 | import dagger.hilt.components.SingletonComponent
12 | import javax.inject.Singleton
13 |
14 | /**
15 | * Created by ErickSumargo on 01/05/21.
16 | */
17 |
18 | @Module
19 | @InstallIn(SingletonComponent::class)
20 | internal object ApolloClientModule {
21 |
22 | @Provides
23 | @Singleton
24 | fun provideApolloClient(networkInterceptor: NetworkInterceptor): ApolloClient {
25 | return ApolloClient(
26 | networkTransport = ApolloHttpNetworkTransport(
27 | serverUrl = url,
28 | headers = mapOf(
29 | "Accept" to "application/json",
30 | "Authorization" to "Bearer $JWT"
31 | )
32 | ),
33 | interceptors = listOf(
34 | networkInterceptor
35 | )
36 | )
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/data/remote/src/androidMain/kotlin/com/bael/dads/data/remote/di/module/interceptor/InterceptorModule.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.data.remote.di.module.interceptor
2 |
3 | import com.bael.dads.data.remote.interceptor.NetworkInterceptor
4 | import com.bael.dads.data.remote.network.Network
5 | import dagger.Module
6 | import dagger.Provides
7 | import dagger.hilt.InstallIn
8 | import dagger.hilt.components.SingletonComponent
9 | import javax.inject.Singleton
10 |
11 | /**
12 | * Created by ErickSumargo on 01/05/21.
13 | */
14 |
15 | @Module
16 | @InstallIn(SingletonComponent::class)
17 | internal object InterceptorModule {
18 |
19 | @Provides
20 | @Singleton
21 | fun provideNetworkInterceptor(network: Network): NetworkInterceptor {
22 | return NetworkInterceptor(network)
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/data/remote/src/androidMain/kotlin/com/bael/dads/data/remote/di/module/mapper/ListMapperModule.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.data.remote.di.module.mapper
2 |
3 | import com.bael.dads.data.remote.model.DadJoke
4 | import com.bael.dads.shared.mapper.ListMapper
5 | import com.bael.dads.shared.mapper.Mapper
6 | import dagger.Module
7 | import dagger.Provides
8 | import dagger.hilt.InstallIn
9 | import dagger.hilt.components.SingletonComponent
10 | import javax.inject.Singleton
11 | import com.bael.dads.data.remote.query.DadJokesQuery.Joke as DadJokeQL
12 |
13 | /**
14 | * Created by ErickSumargo on 01/05/21.
15 | */
16 |
17 | @Module
18 | @InstallIn(SingletonComponent::class)
19 | internal object ListMapperModule {
20 |
21 | @Provides
22 | @Singleton
23 | fun provideDadJokeListMapper(
24 | mapper: Mapper
25 | ): ListMapper {
26 | return ListMapper(mapper)
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/data/remote/src/androidMain/kotlin/com/bael/dads/data/remote/di/module/mapper/MapperModule.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.data.remote.di.module.mapper
2 |
3 | import com.bael.dads.data.remote.mapper.DadJokeMapper
4 | import com.bael.dads.data.remote.mapper.DadJokesResponseMapper
5 | import com.bael.dads.data.remote.model.DadJoke
6 | import com.bael.dads.data.remote.response.DadJokesResponse
7 | import com.bael.dads.shared.mapper.ListMapper
8 | import com.bael.dads.shared.mapper.Mapper
9 | import dagger.Module
10 | import dagger.Provides
11 | import dagger.hilt.InstallIn
12 | import dagger.hilt.components.SingletonComponent
13 | import javax.inject.Singleton
14 | import com.bael.dads.data.remote.query.DadJokesQuery.Data as DadJokesQueryData
15 | import com.bael.dads.data.remote.query.DadJokesQuery.Joke as DadJokeQL
16 |
17 | /**
18 | * Created by ErickSumargo on 01/01/21.
19 | */
20 |
21 | @Module
22 | @InstallIn(SingletonComponent::class)
23 | internal object MapperModule {
24 |
25 | @Provides
26 | @Singleton
27 | fun provideDadJokeMapper(): Mapper {
28 | return DadJokeMapper()
29 | }
30 |
31 | @Provides
32 | @Singleton
33 | fun provideDadJokesResponseMapper(
34 | listMapper: ListMapper
35 | ): Mapper {
36 | return DadJokesResponseMapper(listMapper)
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/data/remote/src/androidMain/kotlin/com/bael/dads/data/remote/di/module/mapper/ResultMapperModule.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.data.remote.di.module.mapper
2 |
3 | import com.bael.dads.data.remote.model.DadJoke
4 | import com.bael.dads.data.remote.response.DadJokesResponse
5 | import com.bael.dads.shared.mapper.Mapper
6 | import com.bael.dads.shared.mapper.ResultMapper
7 | import dagger.Module
8 | import dagger.Provides
9 | import dagger.hilt.InstallIn
10 | import dagger.hilt.components.SingletonComponent
11 | import javax.inject.Singleton
12 | import com.bael.dads.data.remote.query.DadJokesQuery.Data as DadJokesQueryData
13 | import com.bael.dads.data.remote.query.DadJokesQuery.Joke as DadJokeQL
14 |
15 | /**
16 | * Created by ErickSumargo on 01/05/21.
17 | */
18 |
19 | @Module
20 | @InstallIn(SingletonComponent::class)
21 | internal object ResultMapperModule {
22 |
23 | @Provides
24 | @Singleton
25 | fun provideDadJokeResultMapper(
26 | mapper: Mapper
27 | ): ResultMapper {
28 | return ResultMapper(mapper)
29 | }
30 |
31 | @Provides
32 | @Singleton
33 | fun provideDadJokeResponseResultMapper(
34 | mapper: Mapper
35 | ): ResultMapper {
36 | return ResultMapper(mapper)
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/data/remote/src/androidMain/kotlin/com/bael/dads/data/remote/di/module/service/ServiceModule.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.data.remote.di.module.service
2 |
3 | import com.apollographql.apollo.ApolloClient
4 | import com.bael.dads.data.remote.response.DadJokesResponse
5 | import com.bael.dads.data.remote.service.DadsApolloService
6 | import com.bael.dads.data.remote.service.DadsService
7 | import com.bael.dads.shared.mapper.ResultMapper
8 | import dagger.Module
9 | import dagger.Provides
10 | import dagger.hilt.InstallIn
11 | import dagger.hilt.components.SingletonComponent
12 | import javax.inject.Singleton
13 | import com.bael.dads.data.remote.query.DadJokesQuery.Data as DadJokesQueryData
14 |
15 | /**
16 | * Created by ErickSumargo on 01/01/21.
17 | */
18 |
19 | @Module
20 | @InstallIn(SingletonComponent::class)
21 | object ServiceModule {
22 |
23 | @Provides
24 | @Singleton
25 | fun provideDadsService(
26 | client: ApolloClient,
27 | mapper: ResultMapper
28 | ): DadsService {
29 | return DadsApolloService(client, mapper)
30 | }
31 | }
--------------------------------------------------------------------------------
/data/remote/src/androidMain/kotlin/com/bael/dads/data/remote/network/Network.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("DEPRECATION", "RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS")
2 |
3 | package com.bael.dads.data.remote.network
4 |
5 | import android.content.Context
6 | import android.content.Context.CONNECTIVITY_SERVICE
7 | import android.net.ConnectivityManager
8 | import android.net.ConnectivityManager.TYPE_MOBILE
9 | import android.net.ConnectivityManager.TYPE_WIFI
10 | import android.net.NetworkInfo
11 | import android.net.NetworkInfo.State.CONNECTED
12 | import dagger.hilt.android.qualifiers.ApplicationContext
13 | import javax.inject.Inject
14 |
15 | /**
16 | * Created by ErickSumargo on 01/01/21.
17 | */
18 |
19 | actual class Network @Inject constructor(@ApplicationContext context: Context) {
20 | actual val isConnected: Boolean
21 | get() = isNetworkConnected(TYPE_MOBILE) || isNetworkConnected(TYPE_WIFI)
22 |
23 | private val connectivityManager: ConnectivityManager by lazy {
24 | context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
25 | }
26 |
27 | private fun isNetworkConnected(networkType: Int): Boolean {
28 | return networkInfo(networkType) == CONNECTED
29 | }
30 |
31 | private fun networkInfo(type: Int): NetworkInfo.State? {
32 | return connectivityManager.getNetworkInfo(type)?.state
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/data/remote/src/commonMain/graphql/com/bael/dads/data/remote/fragment/DadJokeFragment.graphql:
--------------------------------------------------------------------------------
1 | fragment DadJokeFragment on DadJoke {
2 | id
3 | setup
4 | punchline
5 | }
6 |
--------------------------------------------------------------------------------
/data/remote/src/commonMain/graphql/com/bael/dads/data/remote/query/DadJokesQuery.graphql:
--------------------------------------------------------------------------------
1 | query DadJokes($cursor: String, $limit: Int) {
2 | dadJokes(
3 | cursor: $cursor
4 | limit: $limit
5 | ) {
6 | jokes {
7 | ...DadJokeFragment
8 | }
9 | cursor
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/data/remote/src/commonMain/kotlin/com/bael/dads/data/remote/constant/Server.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.data.remote.constant
2 |
3 | /**
4 | * Created by ErickSumargo on 01/05/21.
5 | */
6 |
7 | internal object Server {
8 | const val url: String = "https://dads-engine.herokuapp.com/"
9 | }
10 |
--------------------------------------------------------------------------------
/data/remote/src/commonMain/kotlin/com/bael/dads/data/remote/interceptor/NetworkInterceptor.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.data.remote.interceptor
2 |
3 | import com.apollographql.apollo.api.Operation
4 | import com.apollographql.apollo.interceptor.ApolloInterceptorChain
5 | import com.apollographql.apollo.interceptor.ApolloRequest
6 | import com.apollographql.apollo.interceptor.ApolloRequestInterceptor
7 | import com.apollographql.apollo.interceptor.ApolloResponse
8 | import com.bael.dads.data.remote.network.Network
9 | import com.bael.dads.shared.exception.NoNetworkException
10 | import kotlinx.coroutines.flow.Flow
11 |
12 | /**
13 | * Created by ErickSumargo on 01/05/21.
14 | */
15 |
16 | internal class NetworkInterceptor(private val network: Network) : ApolloRequestInterceptor {
17 |
18 | override fun intercept(
19 | request: ApolloRequest,
20 | chain: ApolloInterceptorChain
21 | ): Flow> {
22 | if (!network.isConnected) throw NoNetworkException()
23 | return chain.proceed(request)
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/data/remote/src/commonMain/kotlin/com/bael/dads/data/remote/mapper/DadJokeMapper.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.data.remote.mapper
2 |
3 | import com.bael.dads.data.remote.model.DadJoke
4 | import com.bael.dads.shared.mapper.Mapper
5 | import com.bael.dads.data.remote.query.DadJokesQuery.Joke as DadJokeQL
6 |
7 | /**
8 | * Created by ErickSumargo on 01/01/21.
9 | */
10 |
11 | internal class DadJokeMapper : Mapper {
12 |
13 | override fun map(data: DadJokeQL): DadJoke {
14 | return data.fragments.dadJokeFragment.let { fragment ->
15 | DadJoke(
16 | id = fragment.id,
17 | setup = fragment.setup,
18 | punchline = fragment.punchline
19 | )
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/data/remote/src/commonMain/kotlin/com/bael/dads/data/remote/mapper/DadJokesResponseMapper.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.data.remote.mapper
2 |
3 | import com.bael.dads.data.remote.model.DadJoke
4 | import com.bael.dads.data.remote.response.DadJokesResponse
5 | import com.bael.dads.shared.mapper.ListMapper
6 | import com.bael.dads.shared.mapper.Mapper
7 | import com.bael.dads.data.remote.query.DadJokesQuery.Data as DadJokesQueryData
8 | import com.bael.dads.data.remote.query.DadJokesQuery.Joke as DadJokeQL
9 |
10 | /**
11 | * Created by ErickSumargo on 01/01/21.
12 | */
13 |
14 | internal class DadJokesResponseMapper(
15 | private val dadJokesMapper: ListMapper,
16 | ) : Mapper {
17 |
18 | override fun map(data: DadJokesQueryData): DadJokesResponse {
19 | return DadJokesResponse(
20 | dadJokes = dadJokesMapper.map(data.dadJokes.jokes),
21 | cursor = data.dadJokes.cursor
22 | )
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/data/remote/src/commonMain/kotlin/com/bael/dads/data/remote/model/DadJoke.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.data.remote.model
2 |
3 | /**
4 | * Created by ErickSumargo on 01/01/21.
5 | */
6 |
7 | data class DadJoke(
8 | val id: String,
9 | val setup: String,
10 | val punchline: String
11 | )
12 |
--------------------------------------------------------------------------------
/data/remote/src/commonMain/kotlin/com/bael/dads/data/remote/network/Network.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.data.remote.network
2 |
3 | /**
4 | * Created by ErickSumargo on 01/01/21.
5 | */
6 |
7 | expect class Network {
8 | val isConnected: Boolean
9 | }
10 |
--------------------------------------------------------------------------------
/data/remote/src/commonMain/kotlin/com/bael/dads/data/remote/response/DadJokesResponse.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.data.remote.response
2 |
3 | import com.bael.dads.data.remote.model.DadJoke
4 |
5 | /**
6 | * Created by ErickSumargo on 01/01/21.
7 | */
8 |
9 | data class DadJokesResponse(
10 | val dadJokes: List,
11 | val cursor: String?
12 | )
13 |
--------------------------------------------------------------------------------
/data/remote/src/commonMain/kotlin/com/bael/dads/data/remote/service/BaseApolloService.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.data.remote.service
2 |
3 | import com.apollographql.apollo.ApolloClient
4 | import com.apollographql.apollo.api.Operation.Data
5 | import com.apollographql.apollo.api.Operation.Variables
6 | import com.apollographql.apollo.api.Query
7 | import kotlinx.coroutines.flow.first
8 |
9 | /**
10 | * Created by ErickSumargo on 01/01/21.
11 | */
12 |
13 | internal abstract class BaseApolloService(private val client: ApolloClient) {
14 |
15 | protected suspend fun query(script: Query): Result {
16 | return runCatching {
17 | val response = client.query(script).execute().first()
18 | if (response.hasErrors()) {
19 | throw Exception(response.errors!![0].message)
20 | }
21 | response.data!!
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/data/remote/src/commonMain/kotlin/com/bael/dads/data/remote/service/DadsApolloService.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.data.remote.service
2 |
3 | import com.apollographql.apollo.ApolloClient
4 | import com.apollographql.apollo.api.Input.Companion.fromNullable
5 | import com.bael.dads.data.remote.query.DadJokesQuery
6 | import com.bael.dads.data.remote.response.DadJokesResponse
7 | import com.bael.dads.shared.mapper.ResultMapper
8 | import com.bael.dads.data.remote.query.DadJokesQuery.Data as DadJokesQueryData
9 |
10 | /**
11 | * Created by ErickSumargo on 01/01/21.
12 | */
13 |
14 | internal class DadsApolloService(
15 | client: ApolloClient,
16 | private val mapper: ResultMapper
17 | ) : BaseApolloService(client),
18 | DadsService {
19 |
20 | override suspend fun fetchDadJokes(cursor: String?, limit: Int): Result {
21 | return query(
22 | script = DadJokesQuery(
23 | cursor = fromNullable(cursor),
24 | limit = fromNullable(limit)
25 | )
26 | ).let(mapper::map)
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/data/remote/src/commonMain/kotlin/com/bael/dads/data/remote/service/DadsService.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.data.remote.service
2 |
3 | import com.bael.dads.data.remote.response.DadJokesResponse
4 |
5 | /**
6 | * Created by ErickSumargo on 01/01/21.
7 | */
8 |
9 | interface DadsService {
10 |
11 | suspend fun fetchDadJokes(cursor: String?, limit: Int): Result
12 | }
13 |
--------------------------------------------------------------------------------
/data/remote_test/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/data/remote_test/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import Library.Google.daggerTesting
2 |
3 | plugins {
4 | id("data")
5 | }
6 |
7 | kotlin {
8 | sourceSets {
9 | val commonMain by getting {
10 | dependencies {
11 | // Shared
12 | implementation(project(":shared"))
13 |
14 | // Data
15 | implementation(project(":data:remote"))
16 | }
17 | }
18 |
19 | val androidMain by getting {
20 | dependencies {
21 | // Google
22 | implementation(daggerTesting)
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/data/remote_test/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErickSumargo/Dads/8eb44894518e23f535a69cbe0207ad034f6a282f/data/remote_test/consumer-rules.pro
--------------------------------------------------------------------------------
/data/remote_test/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.kts.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/data/remote_test/src/androidMain/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/data/remote_test/src/androidMain/kotlin/com/bael/dads/data/remote/test/di/module/service/ServiceTestModule.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("UNCHECKED_CAST")
2 |
3 | package com.bael.dads.data.remote.test.di.module.service
4 |
5 | import com.bael.dads.data.remote.di.module.service.ServiceModule
6 | import com.bael.dads.data.remote.response.DadJokesResponse
7 | import com.bael.dads.data.remote.service.DadsService
8 | import com.bael.dads.data.remote.test.service.FakeDadsService
9 | import com.bael.dads.data.remote.test.service.RemoteService
10 | import dagger.Module
11 | import dagger.Provides
12 | import dagger.hilt.components.SingletonComponent
13 | import dagger.hilt.testing.TestInstallIn
14 | import javax.inject.Singleton
15 |
16 | /**
17 | * Created by ErickSumargo on 01/01/21.
18 | */
19 |
20 | @Module
21 | @TestInstallIn(
22 | components = [SingletonComponent::class],
23 | replaces = [ServiceModule::class]
24 | )
25 | internal object ServiceTestModule {
26 |
27 | @Provides
28 | @Singleton
29 | fun provideDadsService(): DadsService {
30 | return FakeDadsService()
31 | }
32 |
33 | @Provides
34 | @Singleton
35 | fun provideFakeDadsService(service: DadsService): RemoteService {
36 | return service as RemoteService
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/data/remote_test/src/commonMain/kotlin/com/bael/dads/data/remote/test/service/FakeBaseService.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.data.remote.test.service
2 |
3 | import com.bael.dads.shared.response.Response
4 | import com.bael.dads.shared.response.Response.Error
5 | import com.bael.dads.shared.response.Response.Success
6 | import kotlin.Result.Companion.failure
7 | import kotlin.Result.Companion.success
8 |
9 | /**
10 | * Created by ErickSumargo on 01/01/21.
11 | */
12 |
13 | internal abstract class FakeBaseService : RemoteService {
14 | private var responses: Array> = arrayOf()
15 |
16 | private var count: Int = 0
17 |
18 | protected val result: Result
19 | get() {
20 | return when (val response = responses[count++]) {
21 | is Error -> failure(response.error as Throwable)
22 | is Success -> success(response.data)
23 | else -> failure(Exception("Connection error"))
24 | }
25 | }
26 |
27 | override fun submitResponses(vararg responses: Response) {
28 | this.responses = responses
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/data/remote_test/src/commonMain/kotlin/com/bael/dads/data/remote/test/service/FakeDadsService.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.data.remote.test.service
2 |
3 | import com.bael.dads.data.remote.response.DadJokesResponse
4 | import com.bael.dads.data.remote.service.DadsService
5 |
6 | /**
7 | * Created by ErickSumargo on 01/01/21.
8 | */
9 |
10 | internal class FakeDadsService :
11 | FakeBaseService(),
12 | DadsService {
13 |
14 | override suspend fun fetchDadJokes(cursor: String?, limit: Int): Result {
15 | return result
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/data/remote_test/src/commonMain/kotlin/com/bael/dads/data/remote/test/service/RemoteService.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.data.remote.test.service
2 |
3 | import com.bael.dads.shared.response.Response
4 |
5 | /**
6 | * Created by ErickSumargo on 01/01/21.
7 | */
8 |
9 | interface RemoteService {
10 |
11 | fun submitResponses(vararg responses: Response)
12 | }
13 |
--------------------------------------------------------------------------------
/domain/home/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/domain/home/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id("domain")
3 | }
4 |
5 | kotlin {
6 | sourceSets {
7 | val commonMain by getting {
8 | dependencies {
9 | // Shared
10 | implementation(project(":shared"))
11 |
12 | // Data
13 | implementation(project(":data:database"))
14 | implementation(project(":data:remote"))
15 | }
16 | }
17 |
18 | val androidMain by getting
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/domain/home/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErickSumargo/Dads/8eb44894518e23f535a69cbe0207ad034f6a282f/domain/home/consumer-rules.pro
--------------------------------------------------------------------------------
/domain/home/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.kts.
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
--------------------------------------------------------------------------------
/domain/home/src/androidMain/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/domain/home/src/androidMain/kotlin/com/bael/dads/domain/home/di/module/mapper/ListMapperModule.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.domain.home.di.module.mapper
2 |
3 | import com.bael.dads.shared.mapper.ListMapper
4 | import com.bael.dads.shared.mapper.Mapper
5 | import dagger.Module
6 | import dagger.Provides
7 | import dagger.hilt.InstallIn
8 | import dagger.hilt.components.SingletonComponent
9 | import javax.inject.Singleton
10 | import com.bael.dads.data.database.entity.DadJoke as DadJokeDB
11 | import com.bael.dads.data.remote.model.DadJoke as DadJokeRemote
12 |
13 | /**
14 | * Created by ErickSumargo on 01/05/21.
15 | */
16 |
17 | @Module
18 | @InstallIn(SingletonComponent::class)
19 | internal object ListMapperModule {
20 |
21 | @Provides
22 | @Singleton
23 | fun provideDadJokesRemoteMapper(
24 | mapper: Mapper
25 | ): ListMapper {
26 | return ListMapper(mapper)
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/domain/home/src/androidMain/kotlin/com/bael/dads/domain/home/di/module/mapper/MapperModule.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.domain.home.di.module.mapper
2 |
3 | import com.bael.dads.data.database.entity.RemoteMeta
4 | import com.bael.dads.data.remote.response.DadJokesResponse
5 | import com.bael.dads.domain.home.mapper.DadJokeDBMapper
6 | import com.bael.dads.domain.home.mapper.DadJokeRemoteMapper
7 | import com.bael.dads.domain.home.mapper.RemoteMetaMapper
8 | import com.bael.dads.domain.home.model.DadJoke
9 | import com.bael.dads.shared.mapper.Mapper
10 | import dagger.Module
11 | import dagger.Provides
12 | import dagger.hilt.InstallIn
13 | import dagger.hilt.components.SingletonComponent
14 | import javax.inject.Singleton
15 | import com.bael.dads.data.database.entity.DadJoke as DadJokeDB
16 | import com.bael.dads.data.remote.model.DadJoke as DadJokeRemote
17 |
18 | /**
19 | * Created by ErickSumargo on 01/01/21.
20 | */
21 |
22 | @Module
23 | @InstallIn(SingletonComponent::class)
24 | internal object MapperModule {
25 |
26 | @Provides
27 | @Singleton
28 | fun provideDadJokeRemoteMapper(): Mapper {
29 | return DadJokeRemoteMapper()
30 | }
31 |
32 | @Provides
33 | @Singleton
34 | fun provideDadJokeDBMapper(): Mapper {
35 | return DadJokeDBMapper()
36 | }
37 |
38 | @Provides
39 | @Singleton
40 | fun provideRemoteMetaMapper(): Mapper {
41 | return RemoteMetaMapper()
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/domain/home/src/androidMain/kotlin/com/bael/dads/domain/home/model/DadJoke.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.domain.home.model
2 |
3 | import java.io.Serializable
4 |
5 | /**
6 | * Created by ErickSumargo on 01/05/21.
7 | */
8 |
9 | actual data class DadJoke actual constructor(
10 | val id: Int,
11 | val setup: String,
12 | val punchline: String,
13 | val favored: Boolean,
14 | val seen: Boolean,
15 | val updatedAt: Long
16 | ) : Serializable
17 |
--------------------------------------------------------------------------------
/domain/home/src/commonMain/kotlin/com/bael/dads/domain/home/interactor/FavorDadJokeInteractor.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.domain.home.interactor
2 |
3 | import com.bael.dads.data.database.repository.DadJokeRepository
4 | import com.bael.dads.domain.home.model.DadJoke
5 | import com.bael.dads.domain.home.usecase.FavorDadJokeUseCase
6 | import kotlinx.coroutines.flow.Flow
7 | import kotlinx.coroutines.flow.flow
8 |
9 | /**
10 | * Created by ErickSumargo on 01/04/21.
11 | */
12 |
13 | internal class FavorDadJokeInteractor(
14 | private val repository: DadJokeRepository
15 | ) : FavorDadJokeUseCase {
16 |
17 | override fun invoke(dadJoke: DadJoke, favored: Boolean): Flow {
18 | return flow {
19 | val updates = repository.favorDadJoke(
20 | id = dadJoke.id,
21 | favored = favored
22 | )
23 | emit(updates > 0)
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/domain/home/src/commonMain/kotlin/com/bael/dads/domain/home/interactor/LoadDadJokeInteractor.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.domain.home.interactor
2 |
3 | import com.bael.dads.data.database.repository.DadJokeRepository
4 | import com.bael.dads.domain.home.model.DadJoke
5 | import com.bael.dads.domain.home.usecase.LoadDadJokeUseCase
6 | import com.bael.dads.shared.mapper.Mapper
7 | import com.bael.dads.shared.response.Response
8 | import com.bael.dads.shared.response.Response.Loading
9 | import com.bael.dads.shared.response.Response.Success
10 | import kotlinx.coroutines.flow.Flow
11 | import kotlinx.coroutines.flow.flow
12 | import com.bael.dads.data.database.entity.DadJoke as DadJokeDB
13 |
14 | /**
15 | * Created by ErickSumargo on 01/04/21.
16 | */
17 |
18 | internal class LoadDadJokeInteractor(
19 | private val repository: DadJokeRepository,
20 | private val mapper: Mapper
21 | ) : LoadDadJokeUseCase {
22 |
23 | override fun invoke(id: Int): Flow> {
24 | return flow {
25 | emit(Loading)
26 |
27 | repository.loadDadJoke(id)
28 | ?.let(mapper::map)
29 | ?.let(::Success)
30 | ?.also { response ->
31 | emit(response)
32 | }
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/domain/home/src/commonMain/kotlin/com/bael/dads/domain/home/interactor/LoadFavoredDadJokeInteractor.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.domain.home.interactor
2 |
3 | import com.bael.dads.data.database.repository.DadJokeRepository
4 | import com.bael.dads.domain.home.model.DadJoke
5 | import com.bael.dads.domain.home.usecase.LoadFavoredDadJokeUseCase
6 | import com.bael.dads.shared.mapper.Mapper
7 | import com.bael.dads.shared.response.Response
8 | import com.bael.dads.shared.response.Response.Empty
9 | import com.bael.dads.shared.response.Response.Loading
10 | import com.bael.dads.shared.response.Response.Success
11 | import com.bael.dads.shared.time.DateTime.now
12 | import kotlinx.coroutines.flow.Flow
13 | import kotlinx.coroutines.flow.flow
14 | import com.bael.dads.data.database.entity.DadJoke as DadJokeDB
15 |
16 | /**
17 | * Created by ErickSumargo on 01/04/21.
18 | */
19 |
20 | internal class LoadFavoredDadJokeInteractor(
21 | private val repository: DadJokeRepository,
22 | private val mapper: Mapper
23 | ) : LoadFavoredDadJokeUseCase {
24 |
25 | override fun invoke(term: String, cursor: DadJoke?, limit: Int): Flow>> {
26 | return flow {
27 | emit(Loading)
28 |
29 | val dadJokes = loadFavoredDadJokeDB(term, cursor, limit)
30 | if (dadJokes.isEmpty()) {
31 | emit(Empty)
32 | } else {
33 | emit(Success(data = dadJokes))
34 | }
35 | }
36 | }
37 |
38 | private suspend fun loadFavoredDadJokeDB(
39 | term: String,
40 | cursor: DadJoke?,
41 | limit: Int
42 | ): List {
43 | return repository.loadFavoredDadJoke(term, cursor = cursor?.updatedAt ?: now, limit)
44 | .map(mapper::map)
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/domain/home/src/commonMain/kotlin/com/bael/dads/domain/home/interactor/LoadSeenDadJokeInteractor.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.domain.home.interactor
2 |
3 | import com.bael.dads.data.database.repository.DadJokeRepository
4 | import com.bael.dads.domain.home.model.DadJoke
5 | import com.bael.dads.domain.home.usecase.LoadSeenDadJokeUseCase
6 | import com.bael.dads.shared.mapper.Mapper
7 | import com.bael.dads.shared.response.Response
8 | import com.bael.dads.shared.response.Response.Empty
9 | import com.bael.dads.shared.response.Response.Loading
10 | import com.bael.dads.shared.response.Response.Success
11 | import kotlinx.coroutines.flow.Flow
12 | import kotlinx.coroutines.flow.flow
13 | import com.bael.dads.data.database.entity.DadJoke as DadJokeDB
14 |
15 | /**
16 | * Created by ErickSumargo on 01/04/21.
17 | */
18 |
19 | internal class LoadSeenDadJokeInteractor(
20 | private val repository: DadJokeRepository,
21 | private val mapper: Mapper
22 | ) : LoadSeenDadJokeUseCase {
23 |
24 | override fun invoke(term: String, cursor: DadJoke?, limit: Int): Flow>> {
25 | return flow {
26 | emit(Loading)
27 |
28 | val dadJokes = loadSeenDadJokeDB(term, cursor, limit)
29 | if (dadJokes.isEmpty()) {
30 | emit(Empty)
31 | } else {
32 | emit(Success(data = dadJokes))
33 | }
34 | }
35 | }
36 |
37 | private suspend fun loadSeenDadJokeDB(
38 | term: String,
39 | cursor: DadJoke?,
40 | limit: Int
41 | ): List {
42 | return repository.loadSeenDadJoke(
43 | term = term,
44 | cursor = cursor?.id ?: (repository.loadLatestDadJoke()?.id ?: 0) + 1,
45 | limit = limit
46 | ).map(mapper::map)
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/domain/home/src/commonMain/kotlin/com/bael/dads/domain/home/interactor/ObserveDadJokeInteractor.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.domain.home.interactor
2 |
3 | import com.bael.dads.data.database.repository.DadJokeRepository
4 | import com.bael.dads.domain.home.model.DadJoke
5 | import com.bael.dads.domain.home.usecase.ObserveDadJokeUseCase
6 | import com.bael.dads.shared.mapper.Mapper
7 | import com.bael.dads.shared.response.Response
8 | import com.bael.dads.shared.response.Response.Success
9 | import kotlinx.coroutines.flow.Flow
10 | import kotlinx.coroutines.flow.distinctUntilChanged
11 | import kotlinx.coroutines.flow.filterNotNull
12 | import kotlinx.coroutines.flow.map
13 | import com.bael.dads.data.database.entity.DadJoke as DadJokeDB
14 |
15 | /**
16 | * Created by ErickSumargo on 01/04/21.
17 | */
18 |
19 | internal class ObserveDadJokeInteractor(
20 | private val repository: DadJokeRepository,
21 | private val mapper: Mapper
22 | ) : ObserveDadJokeUseCase {
23 |
24 | override suspend fun invoke(dadJoke: DadJoke): Flow> {
25 | return repository.observeDadJoke(id = dadJoke.id)
26 | .filterNotNull()
27 | .map(mapper::map)
28 | .distinctUntilChanged()
29 | .map(::Success)
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/domain/home/src/commonMain/kotlin/com/bael/dads/domain/home/interactor/SetDadJokeSeenInteractor.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.domain.home.interactor
2 |
3 | import com.bael.dads.data.database.repository.DadJokeRepository
4 | import com.bael.dads.domain.home.model.DadJoke
5 | import com.bael.dads.domain.home.usecase.SetDadJokeSeenUseCase
6 | import kotlinx.coroutines.flow.Flow
7 | import kotlinx.coroutines.flow.flow
8 |
9 | /**
10 | * Created by ErickSumargo on 01/04/21.
11 | */
12 |
13 | internal class SetDadJokeSeenInteractor(
14 | private val repository: DadJokeRepository
15 | ) : SetDadJokeSeenUseCase {
16 |
17 | override fun invoke(dadJoke: DadJoke): Flow {
18 | return flow {
19 | val updates = repository.setDadJokeSeen(id = dadJoke.id)
20 | emit(updates > 0)
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/domain/home/src/commonMain/kotlin/com/bael/dads/domain/home/mapper/DadJokeDBMapper.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.domain.home.mapper
2 |
3 | import com.bael.dads.domain.home.model.DadJoke
4 | import com.bael.dads.shared.mapper.Mapper
5 | import com.bael.dads.data.database.entity.DadJoke as DadJokeDB
6 |
7 | /**
8 | * Created by ErickSumargo on 01/01/21.
9 | */
10 |
11 | internal class DadJokeDBMapper : Mapper {
12 |
13 | override fun map(data: DadJokeDB): DadJoke {
14 | return DadJoke(
15 | id = data.id,
16 | setup = data.setup,
17 | punchline = data.punchline,
18 | favored = data.favored,
19 | seen = data.seen,
20 | updatedAt = data.updatedAt
21 | )
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/domain/home/src/commonMain/kotlin/com/bael/dads/domain/home/mapper/DadJokeRemoteMapper.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.domain.home.mapper
2 |
3 | import com.bael.dads.shared.mapper.Mapper
4 | import com.bael.dads.shared.time.DateTime.now
5 | import com.bael.dads.data.database.entity.DadJoke as DadJokeDB
6 | import com.bael.dads.data.remote.model.DadJoke as DadJokeRemote
7 |
8 | /**
9 | * Created by ErickSumargo on 01/01/21.
10 | */
11 |
12 | internal class DadJokeRemoteMapper : Mapper {
13 |
14 | override fun map(data: DadJokeRemote): DadJokeDB {
15 | return DadJokeDB(
16 | id = 0, // to be overridden by auto-increment key
17 | jokeId = data.id,
18 | setup = data.setup,
19 | punchline = data.punchline,
20 | favored = false,
21 | seen = false,
22 | createdAt = now,
23 | updatedAt = now
24 | )
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/domain/home/src/commonMain/kotlin/com/bael/dads/domain/home/mapper/RemoteMetaMapper.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.domain.home.mapper
2 |
3 | import com.bael.dads.data.database.entity.RemoteMeta
4 | import com.bael.dads.data.remote.response.DadJokesResponse
5 | import com.bael.dads.shared.mapper.Mapper
6 |
7 | /**
8 | * Created by ErickSumargo on 01/01/21.
9 | */
10 |
11 | internal class RemoteMetaMapper : Mapper {
12 |
13 | override fun map(data: DadJokesResponse): RemoteMeta {
14 | return RemoteMeta(
15 | id = 0, // to be overridden by auto-increment key
16 | cursor = data.cursor
17 | )
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/domain/home/src/commonMain/kotlin/com/bael/dads/domain/home/model/DadJoke.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.domain.home.model
2 |
3 | /**
4 | * Created by ErickSumargo on 01/01/21.
5 | */
6 |
7 | expect class DadJoke(
8 | id: Int,
9 | setup: String,
10 | punchline: String,
11 | favored: Boolean,
12 | seen: Boolean,
13 | updatedAt: Long
14 | )
15 |
--------------------------------------------------------------------------------
/domain/home/src/commonMain/kotlin/com/bael/dads/domain/home/usecase/FavorDadJokeUseCase.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.domain.home.usecase
2 |
3 | import com.bael.dads.domain.home.model.DadJoke
4 | import kotlinx.coroutines.flow.Flow
5 |
6 | /**
7 | * Created by ErickSumargo on 01/04/21.
8 | */
9 |
10 | interface FavorDadJokeUseCase {
11 |
12 | operator fun invoke(dadJoke: DadJoke, favored: Boolean): Flow
13 | }
14 |
--------------------------------------------------------------------------------
/domain/home/src/commonMain/kotlin/com/bael/dads/domain/home/usecase/LoadDadJokeFeedUseCase.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.domain.home.usecase
2 |
3 | import com.bael.dads.domain.home.model.DadJoke
4 | import com.bael.dads.shared.response.Response
5 | import kotlinx.coroutines.flow.Flow
6 |
7 | /**
8 | * Created by ErickSumargo on 01/04/21.
9 | */
10 |
11 | interface LoadDadJokeFeedUseCase {
12 |
13 | operator fun invoke(cursor: DadJoke?, limit: Int): Flow>>
14 | }
15 |
--------------------------------------------------------------------------------
/domain/home/src/commonMain/kotlin/com/bael/dads/domain/home/usecase/LoadDadJokeUseCase.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.domain.home.usecase
2 |
3 | import com.bael.dads.domain.home.model.DadJoke
4 | import com.bael.dads.shared.response.Response
5 | import kotlinx.coroutines.flow.Flow
6 |
7 | /**
8 | * Created by ErickSumargo on 01/04/21.
9 | */
10 |
11 | interface LoadDadJokeUseCase {
12 |
13 | operator fun invoke(id: Int): Flow>
14 | }
15 |
--------------------------------------------------------------------------------
/domain/home/src/commonMain/kotlin/com/bael/dads/domain/home/usecase/LoadFavoredDadJokeUseCase.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.domain.home.usecase
2 |
3 | import com.bael.dads.domain.home.model.DadJoke
4 | import com.bael.dads.shared.response.Response
5 | import kotlinx.coroutines.flow.Flow
6 |
7 | /**
8 | * Created by ErickSumargo on 01/04/21.
9 | */
10 |
11 | interface LoadFavoredDadJokeUseCase {
12 |
13 | operator fun invoke(term: String, cursor: DadJoke?, limit: Int): Flow>>
14 | }
15 |
--------------------------------------------------------------------------------
/domain/home/src/commonMain/kotlin/com/bael/dads/domain/home/usecase/LoadSeenDadJokeUseCase.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.domain.home.usecase
2 |
3 | import com.bael.dads.domain.home.model.DadJoke
4 | import com.bael.dads.shared.response.Response
5 | import kotlinx.coroutines.flow.Flow
6 |
7 | /**
8 | * Created by ErickSumargo on 01/04/21.
9 | */
10 |
11 | interface LoadSeenDadJokeUseCase {
12 |
13 | operator fun invoke(term: String, cursor: DadJoke?, limit: Int): Flow>>
14 | }
15 |
--------------------------------------------------------------------------------
/domain/home/src/commonMain/kotlin/com/bael/dads/domain/home/usecase/ObserveDadJokeUseCase.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.domain.home.usecase
2 |
3 | import com.bael.dads.domain.home.model.DadJoke
4 | import com.bael.dads.shared.response.Response
5 | import kotlinx.coroutines.flow.Flow
6 |
7 | /**
8 | * Created by ErickSumargo on 01/04/21.
9 | */
10 |
11 | interface ObserveDadJokeUseCase {
12 |
13 | suspend operator fun invoke(dadJoke: DadJoke): Flow>
14 | }
15 |
--------------------------------------------------------------------------------
/domain/home/src/commonMain/kotlin/com/bael/dads/domain/home/usecase/SetDadJokeSeenUseCase.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.domain.home.usecase
2 |
3 | import com.bael.dads.domain.home.model.DadJoke
4 | import kotlinx.coroutines.flow.Flow
5 |
6 | /**
7 | * Created by ErickSumargo on 01/04/21.
8 | */
9 |
10 | interface SetDadJokeSeenUseCase {
11 |
12 | operator fun invoke(dadJoke: DadJoke): Flow
13 | }
14 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app"s APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=false
20 | # Kotlin code style for this project: "official" or "obsolete":
21 | kotlin.code.style=official
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErickSumargo/Dads/8eb44894518e23f535a69cbe0207ad034f6a282f/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Dec 28 09:16:22 WIB 2020
2 | distributionBase=GRADLE_USER_HOME
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-bin.zip
4 | distributionPath=wrapper/dists
5 | zipStorePath=wrapper/dists
6 | zipStoreBase=GRADLE_USER_HOME
7 |
--------------------------------------------------------------------------------
/keys.properties:
--------------------------------------------------------------------------------
1 | JWT=""
--------------------------------------------------------------------------------
/shared/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/shared/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id("shared")
3 | }
4 |
--------------------------------------------------------------------------------
/shared/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErickSumargo/Dads/8eb44894518e23f535a69cbe0207ad034f6a282f/shared/consumer-rules.pro
--------------------------------------------------------------------------------
/shared/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.kts.
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
--------------------------------------------------------------------------------
/shared/src/androidMain/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/shared/src/androidMain/kotlin/com/bael/dads/shared/response/Response.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.shared.response
2 |
3 | import java.io.Serializable
4 |
5 | /**
6 | * Created by ErickSumargo on 01/05/21.
7 | */
8 |
9 | actual sealed class Response : Serializable {
10 |
11 | actual object Loading : Response()
12 |
13 | actual data class Error actual constructor(
14 | val error: Exception
15 | ) : Response()
16 |
17 | actual object Empty : Response()
18 |
19 | actual data class Success actual constructor(
20 | val data: T
21 | ) : Response()
22 | }
23 |
--------------------------------------------------------------------------------
/shared/src/commonMain/kotlin/com/bael/dads/shared/exception/NoNetworkException.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.shared.exception
2 |
3 | /**
4 | * Created by ErickSumargo on 01/01/21.
5 | */
6 |
7 | class NoNetworkException : Exception()
8 |
--------------------------------------------------------------------------------
/shared/src/commonMain/kotlin/com/bael/dads/shared/ext/ListExt.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.shared.ext
2 |
3 | import com.bael.dads.shared.response.Response
4 | import com.bael.dads.shared.response.Response.Success
5 |
6 | /**
7 | * Created by ErickSumargo on 01/01/21.
8 | */
9 |
10 | fun List>.findSuccess(): Success? {
11 | return firstOrNull { it is Success } as? Success
12 | }
13 |
--------------------------------------------------------------------------------
/shared/src/commonMain/kotlin/com/bael/dads/shared/mapper/ListMapper.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.shared.mapper
2 |
3 | /**
4 | * Created by ErickSumargo on 01/01/21.
5 | */
6 |
7 | class ListMapper(
8 | private val mapper: Mapper
9 | ) : Mapper, List> {
10 |
11 | override fun map(data: List): List {
12 | return data.map(mapper::map)
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/shared/src/commonMain/kotlin/com/bael/dads/shared/mapper/Mapper.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.shared.mapper
2 |
3 | /**
4 | * Created by ErickSumargo on 01/01/21.
5 | */
6 |
7 | interface Mapper {
8 |
9 | fun map(data: I): O
10 | }
11 |
--------------------------------------------------------------------------------
/shared/src/commonMain/kotlin/com/bael/dads/shared/mapper/ResultMapper.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.shared.mapper
2 |
3 | /**
4 | * Created by ErickSumargo on 01/01/21.
5 | */
6 |
7 | class ResultMapper(
8 | private val mapper: Mapper
9 | ) : Mapper, Result> {
10 |
11 | override fun map(data: Result): Result {
12 | return data.map(mapper::map)
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/shared/src/commonMain/kotlin/com/bael/dads/shared/response/Response.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.shared.response
2 |
3 | /**
4 | * Created by ErickSumargo on 01/01/21.
5 | */
6 |
7 | expect sealed class Response {
8 |
9 | object Loading : Response
10 |
11 | class Error(error: Exception) : Response
12 |
13 | object Empty : Response
14 |
15 | class Success(data: T) : Response
16 | }
17 |
--------------------------------------------------------------------------------
/shared/src/commonMain/kotlin/com/bael/dads/shared/time/DateTime.kt:
--------------------------------------------------------------------------------
1 | package com.bael.dads.shared.time
2 |
3 | import kotlinx.datetime.Clock.System.now
4 |
5 | /**
6 | * Created by ErickSumargo on 01/05/21.
7 | */
8 |
9 | object DateTime {
10 | val now: Long
11 | get() = now().toEpochMilliseconds()
12 | }
13 |
--------------------------------------------------------------------------------