├── .circleci
└── config.yml
├── .gitignore
├── LICENSE
├── README.md
├── app
├── .gitignore
├── build.gradle
├── fabric.properties
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── nstudiosappdev
│ │ └── stocker
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── ic_launcher-web.png
│ ├── java
│ │ └── com
│ │ │ └── nstudiosappdev
│ │ │ └── stocker
│ │ │ ├── StockerApp.kt
│ │ │ ├── injection
│ │ │ ├── components
│ │ │ │ └── AppComponent.kt
│ │ │ └── modules
│ │ │ │ ├── ActivityModule.kt
│ │ │ │ ├── ApplicationModule.kt
│ │ │ │ ├── DataModule.kt
│ │ │ │ ├── DomainModule.kt
│ │ │ │ └── ViewModelModule.kt
│ │ │ └── ui
│ │ │ └── SplashActivity.kt
│ └── res
│ │ ├── drawable
│ │ └── ic_splash.png
│ │ ├── layout
│ │ └── activity_splash.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── values-tr-rTR
│ │ └── strings.xml
│ │ ├── values-tr
│ │ └── strings.xml
│ │ └── values
│ │ ├── colors.xml
│ │ ├── ic_launcher_background.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── nstudiosappdev
│ └── stocker
│ └── ExampleUnitTest.kt
├── art
├── App0.jpg
├── App1.jpg
├── App2.jpg
├── App3.jpg
├── App4.jpg
└── AppGif.gif
├── base
├── core
│ ├── .gitignore
│ ├── build.gradle
│ ├── proguard-rules.pro
│ └── src
│ │ ├── androidTest
│ │ └── java
│ │ │ └── com
│ │ │ └── nstudiosappdev
│ │ │ └── core
│ │ │ └── ExampleInstrumentedTest.java
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── nstudiosappdev
│ │ │ │ └── core
│ │ │ │ ├── application
│ │ │ │ ├── CoreApplication.kt
│ │ │ │ └── CoreApplicationImpl.kt
│ │ │ │ ├── coroutines
│ │ │ │ ├── AsyncManager.kt
│ │ │ │ ├── CoroutineExt.kt
│ │ │ │ ├── CoroutineManager.kt
│ │ │ │ ├── DefaultAsyncManager.kt
│ │ │ │ ├── DefaultCoroutinesManager.kt
│ │ │ │ ├── DefaultDispatcherProvider.kt
│ │ │ │ └── DispatcherProvider.kt
│ │ │ │ ├── date
│ │ │ │ ├── DateTimeConstants.kt
│ │ │ │ ├── DateTimeConverter.kt
│ │ │ │ └── DefaultDateTimeConverter.kt
│ │ │ │ ├── error
│ │ │ │ ├── DefaultErrorFactory.kt
│ │ │ │ ├── Error.kt
│ │ │ │ ├── ErrorFactory.kt
│ │ │ │ └── StatusError.kt
│ │ │ │ ├── injection
│ │ │ │ ├── Injectable.kt
│ │ │ │ ├── modules
│ │ │ │ │ ├── CoreModule.kt
│ │ │ │ │ ├── CoroutineDispatcherModule.kt
│ │ │ │ │ ├── CoroutineManagerModule.kt
│ │ │ │ │ └── ErrorFactoryModule.kt
│ │ │ │ ├── qualifiers
│ │ │ │ │ ├── ForActivity.kt
│ │ │ │ │ └── ForApplication.kt
│ │ │ │ └── scope
│ │ │ │ │ ├── ActivityScope.kt
│ │ │ │ │ └── FragmentScope.kt
│ │ │ │ ├── model
│ │ │ │ ├── BaseRepository.kt
│ │ │ │ └── DataHolder.kt
│ │ │ │ ├── preconditions
│ │ │ │ ├── AndroidPreConditions.kt
│ │ │ │ ├── DefaultAndroidPreConditions.kt
│ │ │ │ └── ThreadPreconditions.kt
│ │ │ │ └── util
│ │ │ │ └── SharedPrefUtil.kt
│ │ └── res
│ │ │ ├── values-tr-rTR
│ │ │ └── strings.xml
│ │ │ ├── values-tr
│ │ │ └── strings.xml
│ │ │ └── values
│ │ │ └── strings.xml
│ │ └── test
│ │ └── java
│ │ └── com
│ │ └── nstudiosappdev
│ │ └── core
│ │ └── ExampleUnitTest.java
├── core_data
│ ├── .gitignore
│ ├── build.gradle
│ ├── proguard-rules.pro
│ └── src
│ │ ├── androidTest
│ │ └── java
│ │ │ └── com
│ │ │ └── nstudiosappdev
│ │ │ └── core
│ │ │ └── data
│ │ │ └── ExampleInstrumentedTest.java
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── nstudiosappdev
│ │ │ │ └── core
│ │ │ │ └── data
│ │ │ │ ├── adapter
│ │ │ │ ├── ApiCallAdapter.kt
│ │ │ │ └── CallAdapter.kt
│ │ │ │ ├── api
│ │ │ │ ├── ApiConstants.kt
│ │ │ │ ├── interceptor
│ │ │ │ │ └── DefaultRequestInterceptor.kt
│ │ │ │ └── response
│ │ │ │ │ └── ApiResponse.kt
│ │ │ │ ├── datasource
│ │ │ │ ├── BaseDataSource.kt
│ │ │ │ └── DataSource.kt
│ │ │ │ ├── db
│ │ │ │ ├── Db.kt
│ │ │ │ ├── Migrations.kt
│ │ │ │ ├── StockerDb.kt
│ │ │ │ ├── dao
│ │ │ │ │ └── CurrenciesDao.kt
│ │ │ │ └── entity
│ │ │ │ │ ├── CurrenciesEntity.kt
│ │ │ │ │ ├── DbEntity.kt
│ │ │ │ │ └── DbEntityMapper.kt
│ │ │ │ └── modules
│ │ │ │ ├── ApiModule.kt
│ │ │ │ ├── CoreDataModule.kt
│ │ │ │ └── DbModule.kt
│ │ └── res
│ │ │ └── values
│ │ │ └── strings.xml
│ │ └── test
│ │ └── java
│ │ └── com
│ │ └── nstudiosappdev
│ │ └── core
│ │ └── data
│ │ └── ExampleUnitTest.java
├── core_domain
│ ├── .gitignore
│ ├── build.gradle
│ ├── proguard-rules.pro
│ └── src
│ │ ├── androidTest
│ │ └── java
│ │ │ └── com
│ │ │ └── nstudiosappdev
│ │ │ └── core
│ │ │ └── domain
│ │ │ └── ExampleInstrumentedTest.java
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── nstudiosappdev
│ │ │ │ └── core
│ │ │ │ └── domain
│ │ │ │ ├── BaseInteractor.kt
│ │ │ │ └── DeferredInteractor.kt
│ │ └── res
│ │ │ └── values
│ │ │ └── strings.xml
│ │ └── test
│ │ └── java
│ │ └── com
│ │ └── nstudiosappdev
│ │ └── core
│ │ └── domain
│ │ └── ExampleUnitTest.java
├── core_presentation
│ ├── .gitignore
│ ├── build.gradle
│ ├── proguard-rules.pro
│ └── src
│ │ ├── androidTest
│ │ └── java
│ │ │ └── com
│ │ │ └── nstudiosappdev
│ │ │ └── core
│ │ │ └── presentation
│ │ │ └── ExampleInstrumentedTest.java
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ │ └── com.nstudiosappdev.core.presentation
│ │ │ │ ├── Constants.kt
│ │ │ │ ├── TabProvider.kt
│ │ │ │ ├── base
│ │ │ │ ├── BaseActivity.kt
│ │ │ │ ├── BaseFragment.kt
│ │ │ │ ├── BaseInjectionActivity.kt
│ │ │ │ ├── BaseInjectionFragment.kt
│ │ │ │ ├── BaseView.kt
│ │ │ │ ├── BaseViewModelFragment.kt
│ │ │ │ └── ContentView.kt
│ │ │ │ ├── entity
│ │ │ │ ├── ViewEntity.kt
│ │ │ │ └── ViewEntityMapper.kt
│ │ │ │ ├── enums
│ │ │ │ └── DialogType.kt
│ │ │ │ ├── extensions
│ │ │ │ ├── AlertDialogExt.kt
│ │ │ │ ├── ContextExt.kt
│ │ │ │ ├── FragmentManagerExt.kt
│ │ │ │ ├── RecyclerViewExt.kt
│ │ │ │ └── StringExt.kt
│ │ │ │ ├── factory
│ │ │ │ ├── DefaultIntentFactory.kt
│ │ │ │ └── IntentFactory.kt
│ │ │ │ ├── livedata
│ │ │ │ ├── LiveDataExt.kt
│ │ │ │ └── SingleLiveData.kt
│ │ │ │ ├── navigation
│ │ │ │ └── UiNavigation.kt
│ │ │ │ ├── recyclerview
│ │ │ │ ├── DefaultDisplayItemComparator.kt
│ │ │ │ ├── DiffAdapter.kt
│ │ │ │ ├── DiffUtilImpl.kt
│ │ │ │ ├── DisplayItem.kt
│ │ │ │ ├── DisplayItemComparator.kt
│ │ │ │ ├── DisplayItemListMapper.kt
│ │ │ │ ├── RecyclerViewAdapter.kt
│ │ │ │ ├── SelectableItem.kt
│ │ │ │ ├── SelectionAdapter.kt
│ │ │ │ ├── ViewHolder.kt
│ │ │ │ ├── ViewHolderBinder.kt
│ │ │ │ └── ViewHolderFactory.kt
│ │ │ │ ├── util
│ │ │ │ └── PermissionUtil.kt
│ │ │ │ ├── viewmodel
│ │ │ │ ├── BaseViewModel.kt
│ │ │ │ ├── ViewModelKey.kt
│ │ │ │ └── VmFactory.kt
│ │ │ │ └── widget
│ │ │ │ └── CustomAlertDialog.kt
│ │ └── res
│ │ │ ├── drawable
│ │ │ ├── disable_primary_button.xml
│ │ │ ├── disable_secondary_button.xml
│ │ │ ├── edit_text_underline.xml
│ │ │ ├── ic_launcher_background.xml
│ │ │ ├── primary_button_background.xml
│ │ │ ├── ripple_primary_button_background.xml
│ │ │ ├── ripple_primary_button_background_pressed.xml
│ │ │ ├── ripple_second_button_background.xml
│ │ │ ├── ripple_second_button_background_pressed.xml
│ │ │ └── secondary_button_background.xml
│ │ │ ├── font
│ │ │ ├── roboto_black.ttf
│ │ │ ├── roboto_bold.ttf
│ │ │ ├── roboto_light.ttf
│ │ │ ├── roboto_medium.ttf
│ │ │ └── roboto_regular.ttf
│ │ │ ├── layout
│ │ │ ├── custom_alert_dialog_view.xml
│ │ │ └── toolbar_default.xml
│ │ │ ├── raw
│ │ │ └── not_found.json
│ │ │ ├── values-tr-rTR
│ │ │ └── strings.xml
│ │ │ ├── values-tr
│ │ │ └── strings.xml
│ │ │ └── values
│ │ │ ├── colors.xml
│ │ │ ├── dimens.xml
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ │ └── test
│ │ └── java
│ │ └── com
│ │ └── nstudiosappdev
│ │ └── core
│ │ └── presentation
│ │ └── ExampleUnitTest.java
└── navigation
│ ├── .gitignore
│ ├── build.gradle
│ ├── proguard-rules.pro
│ └── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── nstudiosappdev
│ │ └── stocker
│ │ └── navigation
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com.nstudiosappdev.navigation
│ │ │ ├── FragmentLoader.kt
│ │ │ ├── IntentLoader.kt
│ │ │ ├── Loader.kt
│ │ │ ├── features
│ │ │ ├── BottomNavigation.kt
│ │ │ ├── Currencies.kt
│ │ │ ├── Feature.kt
│ │ │ ├── Main.kt
│ │ │ └── Portfolio.kt
│ │ │ └── navigation
│ │ │ ├── DefaultNavigationController.kt
│ │ │ └── NavigationController.kt
│ └── res
│ │ └── values
│ │ └── strings.xml
│ └── test
│ └── java
│ └── com
│ └── nstudiosappdev
│ └── stocker
│ └── navigation
│ └── ExampleUnitTest.java
├── build.gradle
├── buildSrc
├── build.gradle.kts
└── src
│ └── main
│ └── java
│ ├── Config.kt
│ ├── Dependencies.kt
│ ├── Modules.kt
│ ├── Paths.kt
│ ├── Plugins.kt
│ └── Versions.kt
├── common-android-library.gradle
├── common.gradle
├── dashboard
├── dashboard_data
│ ├── .gitignore
│ ├── build.gradle
│ ├── consumer-rules.pro
│ ├── proguard-rules.pro
│ └── src
│ │ ├── androidTest
│ │ └── java
│ │ │ └── com
│ │ │ └── nstudiosappdev
│ │ │ └── stocker
│ │ │ └── dashboard
│ │ │ └── data
│ │ │ └── ExampleInstrumentedTest.kt
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── nstudiosappdev
│ │ │ │ └── stocker
│ │ │ │ └── dashboard
│ │ │ │ └── data
│ │ │ │ ├── CurrenciesDataModule.kt
│ │ │ │ ├── CurrenciesDbEntityMapper.kt
│ │ │ │ ├── CurrenciesLocalDataSource.kt
│ │ │ │ ├── CurrenciesRemoteDataSource.kt
│ │ │ │ ├── CurrenciesRepositoryImpl.kt
│ │ │ │ └── CurrenciesServices.kt
│ │ └── res
│ │ │ └── values
│ │ │ └── strings.xml
│ │ └── test
│ │ └── java
│ │ └── com
│ │ └── nstudiosappdev
│ │ └── stocker
│ │ └── dashboard
│ │ └── data
│ │ └── ExampleUnitTest.kt
├── dashboard_domain
│ ├── .gitignore
│ ├── build.gradle
│ ├── consumer-rules.pro
│ ├── proguard-rules.pro
│ └── src
│ │ ├── androidTest
│ │ └── java
│ │ │ └── com
│ │ │ └── nstudiosappdev
│ │ │ └── stocker
│ │ │ └── dashboard
│ │ │ └── domain
│ │ │ └── ExampleInstrumentedTest.kt
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── nstudiosappdev
│ │ │ │ └── stocker
│ │ │ │ └── dashboard
│ │ │ │ └── domain
│ │ │ │ ├── CurrenciesDomainModule.kt
│ │ │ │ ├── CurrenciesRepository.kt
│ │ │ │ ├── CurrenciesRequest.kt
│ │ │ │ ├── Currency.kt
│ │ │ │ ├── CurrencyStatus.kt
│ │ │ │ ├── DeleteCurrencyInteractor.kt
│ │ │ │ ├── GetCurrenciesInteractor.kt
│ │ │ │ ├── GetSavedCurrenciesInteractor.kt
│ │ │ │ ├── GetSavedCurrencyInteractor.kt
│ │ │ │ └── SaveCurrencyInteractor.kt
│ │ └── res
│ │ │ └── values
│ │ │ └── strings.xml
│ │ └── test
│ │ └── java
│ │ └── com
│ │ └── nstudiosappdev
│ │ └── stocker
│ │ └── dashboard
│ │ └── domain
│ │ └── ExampleUnitTest.kt
└── dashboard_presentation
│ ├── .gitignore
│ ├── build.gradle
│ ├── consumer-rules.pro
│ ├── proguard-rules.pro
│ └── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── nstudiosappdev
│ │ └── stocker
│ │ └── presentation
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── nstudiosappdev
│ │ │ └── stocker
│ │ │ └── dashboard
│ │ │ └── presentation
│ │ │ ├── CurrenciesListMapper.kt
│ │ │ ├── CurrenciesOrderingStyle.kt
│ │ │ ├── CurrenciesPresentationModule.kt
│ │ │ ├── CurrenciesViewEntity.kt
│ │ │ ├── CurrenciesViewEntityMapper.kt
│ │ │ ├── CurrenciesViewHolder.kt
│ │ │ ├── CurrenciesViewModelModule.kt
│ │ │ ├── DashboardActivity.kt
│ │ │ ├── DashboardActivityModule.kt
│ │ │ ├── DashboardPresentationConstants.kt
│ │ │ ├── bottom
│ │ │ └── BottomNavigationFragment.kt
│ │ │ ├── liveCurrencies
│ │ │ ├── LiveCurrenciesFragment.kt
│ │ │ ├── LiveCurrenciesFragmentModule.kt
│ │ │ ├── LiveCurrenciesMainFragment.kt
│ │ │ ├── LiveCurrenciesPagerAdapter.kt
│ │ │ └── LiveCurrenciesViewModel.kt
│ │ │ └── portfolio
│ │ │ ├── PortfolioFragment.kt
│ │ │ ├── PortfolioFragmentModule.kt
│ │ │ ├── PortfolioMainFragment.kt
│ │ │ ├── PortfolioPagerAdapter.kt
│ │ │ └── PortfolioViewModel.kt
│ └── res
│ │ ├── drawable
│ │ ├── ic_dollar.png
│ │ └── ic_portfolio.png
│ │ ├── layout
│ │ ├── activity_main.xml
│ │ ├── content_home.xml
│ │ ├── fragment_bottom_navigation.xml
│ │ ├── fragment_currencies.xml
│ │ ├── fragment_dashboard.xml
│ │ ├── fragment_portfolio.xml
│ │ └── item_currency.xml
│ │ ├── menu
│ │ └── menu_bottom_navigation.xml
│ │ ├── values-tr-rTR
│ │ └── strings.xml
│ │ ├── values-tr
│ │ └── strings.xml
│ │ └── values
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── nstudiosappdev
│ └── stocker
│ └── presentation
│ └── ExampleUnitTest.kt
├── default-detekt-config.yml
├── detekt.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── ktlint.gradle
└── settings.gradle
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | jobs:
3 | build:
4 | working_directory: ~/code
5 | docker:
6 | - image: circleci/android:api-28
7 | environment:
8 | JVM_OPTS: -Xmx3200m
9 | steps:
10 | - checkout
11 | - restore_cache:
12 | key: jars-{{ checksum "build.gradle" }}-{{ checksum "app/build.gradle" }}
13 | # - run:
14 | # name: Chmod permissions #if permission for Gradlew Dependencies fail, use this.
15 | # command: sudo chmod +x ./gradlew
16 | - run:
17 | name: Download Dependencies
18 | command: ./gradlew androidDependencies
19 | - save_cache:
20 | paths:
21 | - ~/.gradle
22 | key: jars-{{ checksum "build.gradle" }}-{{ checksum "app/build.gradle" }}
23 | - run:
24 | name: Run Tests
25 | command: ./gradlew lint test
26 | - store_artifacts:
27 | path: app/build/reports
28 | destination: reports
29 | - store_test_results:
30 | path: app/build/test-results
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | /.idea/navEditor.xml
9 | /.idea/assetWizardSettings.xml
10 | .DS_Store
11 | /build
12 | /captures
13 | .externalNativeBuild
14 | # Windows thumbnail db
15 | Thumbs.db
16 |
17 | # OSX files
18 | .DS_Store
19 |
20 | # built application files
21 | *.apk
22 | *.ap_
23 |
24 | # files for the dex VM
25 | *.dex
26 |
27 | # Java class files
28 | *.class
29 |
30 | # generated files
31 | bin/
32 | gen/
33 | build/
34 |
35 | # Local configuration file (sdk path, etc)
36 | local.properties
37 |
38 | # Eclipse project files
39 | .classpath
40 | .project
41 |
42 | # Android Studio
43 | .idea
44 | .gradle
45 | /*/local.properties
46 | /*/out
47 | /*/*/build
48 | build
49 | /*/*/production
50 | *.iml
51 | *.iws
52 | *.ipr
53 | *~
54 | *.swp
55 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 harrunisk
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 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | /.idea/navEditor.xml
9 | /.idea/assetWizardSettings.xml
10 | .DS_Store
11 | /build
12 | /captures
13 | .externalNativeBuild
14 | # Windows thumbnail db
15 | Thumbs.db
16 |
17 | # OSX files
18 | .DS_Store
19 |
20 | # built application files
21 | *.apk
22 | *.ap_
23 |
24 | # files for the dex VM
25 | *.dex
26 |
27 | # Java class files
28 | *.class
29 |
30 | # generated files
31 | bin/
32 | gen/
33 | build/
34 |
35 | # Local configuration file (sdk path, etc)
36 | local.properties
37 |
38 | # Eclipse project files
39 | .classpath
40 | .project
41 |
42 | # Android Studio
43 | .idea
44 | .gradle
45 | /*/local.properties
46 | /*/out
47 | /*/*/build
48 | build
49 | /*/*/production
50 | *.iml
51 | *.iws
52 | *.ipr
53 | *~
54 | *.swp
55 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: Plugins.androidApplication
2 | apply from: "$rootDir/common.gradle"
3 |
4 | android {
5 | flavorDimensions Dimensions.default
6 | productFlavors {
7 | prod {
8 | // empty
9 | }
10 |
11 | dev {
12 | applicationIdSuffix Dev.applicationIdSuffix
13 | versionNameSuffix Dev.versionNameSuffix
14 | }
15 | }
16 | }
17 |
18 | dependencies {
19 | implementation project(Modules.navigation)
20 | implementation project(Modules.core)
21 | implementation project(Modules.corePresentation)
22 | implementation project(Modules.coreDomain)
23 | implementation project(Modules.coreData)
24 |
25 | implementation project(Modules.dashboardPresentation)
26 | implementation project(Modules.dashboardDomain)
27 | implementation project(Modules.dashboardData)
28 |
29 | // Support Libraries
30 | implementation SupportLibraries.appCompat
31 |
32 | // Testing
33 | testImplementation TestLibraries.jUnit
34 | androidTestImplementation TestLibraries.runner
35 | androidTestImplementation TestLibraries.espressoCore
36 | androidTestImplementation TestLibraries.androidTestImplementation
37 | }
--------------------------------------------------------------------------------
/app/fabric.properties:
--------------------------------------------------------------------------------
1 | apiKey = 6e5fcdb8423e2edef042653349f5c3df00d34cf5
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/nstudiosappdev/stocker/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.stocker
2 |
3 | import androidx.test.InstrumentationRegistry
4 | import androidx.test.runner.AndroidJUnit4
5 | import org.junit.Assert.*
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | /**
10 | * Instrumented test, which will execute on an Android device.
11 | *
12 | * See [testing documentation](http://d.android.com/tools/testing).
13 | */
14 | @RunWith(AndroidJUnit4::class)
15 | class ExampleInstrumentedTest {
16 | @Test
17 | fun useAppContext() {
18 | // Context of the app under test.
19 | val appContext = InstrumentationRegistry.getTargetContext()
20 | assertEquals("com.example.stocker", appContext.packageName)
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
20 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harrunisk/Stocker/dca907383ca09c86c6a81b06820ef7ace3e45a5c/app/src/main/ic_launcher-web.png
--------------------------------------------------------------------------------
/app/src/main/java/com/nstudiosappdev/stocker/StockerApp.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.stocker
2 |
3 | import android.app.Activity
4 | import android.app.Application
5 | import com.crashlytics.android.Crashlytics
6 | import com.nstudiosappdev.stocker.injection.components.DaggerAppComponent
7 | import dagger.android.DispatchingAndroidInjector
8 | import dagger.android.HasActivityInjector
9 | import io.fabric.sdk.android.Fabric
10 | import javax.inject.Inject
11 |
12 | class StockerApp : Application(), HasActivityInjector {
13 |
14 | @Inject
15 | lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector
16 |
17 | override fun onCreate() {
18 | super.onCreate()
19 | Fabric.with(this, Crashlytics())
20 | DaggerAppComponent.builder()
21 | .application(this)
22 | .build()
23 | .inject(this)
24 | }
25 |
26 | override fun activityInjector() = dispatchingAndroidInjector
27 | }
28 |
--------------------------------------------------------------------------------
/app/src/main/java/com/nstudiosappdev/stocker/injection/components/AppComponent.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.stocker.injection.components
2 |
3 | import com.nstudiosappdev.stocker.StockerApp
4 | import com.nstudiosappdev.stocker.injection.modules.*
5 | import com.nstudiosappdev.stocker.injection.modules.ActivityModule
6 | import com.nstudiosappdev.stocker.injection.modules.DataModule
7 | import com.nstudiosappdev.stocker.injection.modules.DomainModule
8 | import com.nstudiosappdev.stocker.injection.modules.ViewModelModule
9 | import dagger.BindsInstance
10 | import dagger.Component
11 | import dagger.android.AndroidInjectionModule
12 | import dagger.android.support.AndroidSupportInjectionModule
13 | import javax.inject.Singleton
14 |
15 | @Singleton
16 | @Component(
17 | modules = [
18 | AndroidSupportInjectionModule::class,
19 | AndroidInjectionModule::class,
20 | ApplicationModule::class,
21 | ActivityModule::class,
22 | DomainModule::class,
23 | DataModule::class,
24 | ViewModelModule::class]
25 | )
26 | interface AppComponent {
27 |
28 | @Component.Builder
29 | interface Builder {
30 | @BindsInstance
31 | fun application(application: StockerApp): Builder
32 |
33 | fun build(): AppComponent
34 | }
35 |
36 | fun inject(application: StockerApp)
37 | }
38 |
--------------------------------------------------------------------------------
/app/src/main/java/com/nstudiosappdev/stocker/injection/modules/ActivityModule.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.stocker.injection.modules
2 |
3 | import com.nstudiosappdev.core.injection.scope.ActivityScope
4 | import com.nstudiosappdev.stocker.dashboard.presentation.DashboardActivityModule
5 | import com.nstudiosappdev.stocker.ui.SplashActivity
6 | import dagger.Module
7 | import dagger.android.ContributesAndroidInjector
8 |
9 | @Module(
10 | includes = [DashboardActivityModule::class]
11 | )
12 | abstract class ActivityModule {
13 | @ContributesAndroidInjector
14 | @ActivityScope
15 | abstract fun contributeSplashActivityInjector(): SplashActivity
16 | }
17 |
--------------------------------------------------------------------------------
/app/src/main/java/com/nstudiosappdev/stocker/injection/modules/ApplicationModule.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.stocker.injection.modules
2 |
3 | import android.content.Context
4 | import com.nstudiosappdev.core.injection.modules.CoreModule
5 | import com.nstudiosappdev.core.presentation.factory.DefaultIntentFactory
6 | import com.nstudiosappdev.core.presentation.factory.IntentFactory
7 | import com.nstudiosappdev.stocker.StockerApp
8 | import dagger.Module
9 | import dagger.Provides
10 | import java.lang.ref.WeakReference
11 | import javax.inject.Singleton
12 |
13 | @Module(
14 | includes = [CoreModule::class]
15 | )
16 | class ApplicationModule {
17 |
18 | @Provides
19 | fun provideApplicationContext(app: StockerApp): Context {
20 | return app.applicationContext
21 | }
22 |
23 | @Provides
24 | @Singleton
25 | fun provideIntentFactory(context: Context): IntentFactory =
26 | DefaultIntentFactory(WeakReference(context))
27 | }
28 |
--------------------------------------------------------------------------------
/app/src/main/java/com/nstudiosappdev/stocker/injection/modules/DataModule.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.stocker.injection.modules
2 |
3 | import com.nstudiosappdev.core.data.modules.CoreDataModule
4 | import com.nstudiosappdev.stocker.dashboard.data.CurrenciesDataModule
5 | import dagger.Module
6 |
7 | @Module(
8 | includes = [CoreDataModule::class,
9 | CurrenciesDataModule::class]
10 | )
11 | internal abstract class DataModule
12 |
--------------------------------------------------------------------------------
/app/src/main/java/com/nstudiosappdev/stocker/injection/modules/DomainModule.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.stocker.injection.modules
2 |
3 | import com.nstudiosappdev.stocker.dashboard.domain.CurrenciesDomainModule
4 | import dagger.Module
5 |
6 | @Module(
7 | includes = [CurrenciesDomainModule::class]
8 | )
9 | internal abstract class DomainModule
10 |
--------------------------------------------------------------------------------
/app/src/main/java/com/nstudiosappdev/stocker/injection/modules/ViewModelModule.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.stocker.injection.modules
2 |
3 | import androidx.lifecycle.ViewModelProvider
4 | import com.nstudiosappdev.core.presentation.viewmodel.VmFactory
5 | import com.nstudiosappdev.stocker.dashboard.presentation.CurrenciesViewModelModule
6 | import dagger.Binds
7 | import dagger.Module
8 |
9 | @Module(
10 | includes = [CurrenciesViewModelModule::class]
11 | )
12 |
13 | internal abstract class ViewModelModule {
14 | @Binds
15 | abstract fun bindViewModelFactory(vmFactory: VmFactory): ViewModelProvider.Factory
16 | }
17 |
--------------------------------------------------------------------------------
/app/src/main/java/com/nstudiosappdev/stocker/ui/SplashActivity.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.stocker.ui
2 |
3 | import android.os.Bundle
4 | import android.os.Handler
5 | import com.nstudiosappdev.core.presentation.base.BaseInjectionActivity
6 | import com.nstudiosappdev.navigation.navigation.DefaultNavigationController
7 | import com.nstudiosappdev.navigation.navigation.NavigationController
8 | import com.nstudiosappdev.stocker.R
9 | import java.lang.ref.WeakReference
10 |
11 | class SplashActivity : BaseInjectionActivity() {
12 |
13 | private lateinit var navigationController: NavigationController
14 |
15 | override fun getLayoutRes(): Int = R.layout.activity_splash
16 |
17 | override fun onCreate(savedInstanceState: Bundle?) {
18 | super.onCreate(savedInstanceState)
19 | this.navigationController = DefaultNavigationController(WeakReference(this))
20 |
21 | Handler().postDelayed({
22 |
23 | navigationController.navigateToMain()
24 | }, SPLASH_TIME_OUT)
25 | }
26 |
27 | companion object {
28 | const val SPLASH_TIME_OUT = 1000L
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harrunisk/Stocker/dca907383ca09c86c6a81b06820ef7ace3e45a5c/app/src/main/res/drawable/ic_splash.png
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_splash.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
20 |
21 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harrunisk/Stocker/dca907383ca09c86c6a81b06820ef7ace3e45a5c/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harrunisk/Stocker/dca907383ca09c86c6a81b06820ef7ace3e45a5c/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harrunisk/Stocker/dca907383ca09c86c6a81b06820ef7ace3e45a5c/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harrunisk/Stocker/dca907383ca09c86c6a81b06820ef7ace3e45a5c/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harrunisk/Stocker/dca907383ca09c86c6a81b06820ef7ace3e45a5c/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harrunisk/Stocker/dca907383ca09c86c6a81b06820ef7ace3e45a5c/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harrunisk/Stocker/dca907383ca09c86c6a81b06820ef7ace3e45a5c/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harrunisk/Stocker/dca907383ca09c86c6a81b06820ef7ace3e45a5c/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harrunisk/Stocker/dca907383ca09c86c6a81b06820ef7ace3e45a5c/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harrunisk/Stocker/dca907383ca09c86c6a81b06820ef7ace3e45a5c/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harrunisk/Stocker/dca907383ca09c86c6a81b06820ef7ace3e45a5c/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harrunisk/Stocker/dca907383ca09c86c6a81b06820ef7ace3e45a5c/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harrunisk/Stocker/dca907383ca09c86c6a81b06820ef7ace3e45a5c/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harrunisk/Stocker/dca907383ca09c86c6a81b06820ef7ace3e45a5c/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harrunisk/Stocker/dca907383ca09c86c6a81b06820ef7ace3e45a5c/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values-tr-rTR/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Banka Döviz Kurları
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values-tr/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Banka Döviz Kurları
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #252525
4 | #252525
5 | #BBDEFB
6 | #4CAF50
7 | #212121
8 | #757575
9 | #FFFFFF
10 | #BDBDBD
11 | #cccccc
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Stocker
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/test/java/com/nstudiosappdev/stocker/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.stocker
2 |
3 | import org.junit.Assert.*
4 | import org.junit.Test
5 |
6 | /**
7 | * Example local unit test, which will execute on the development machine (host).
8 | *
9 | * See [testing documentation](http://d.android.com/tools/testing).
10 | */
11 | class ExampleUnitTest {
12 | @Test
13 | fun addition_isCorrect() {
14 | assertEquals(4, 2 + 2)
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/art/App0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harrunisk/Stocker/dca907383ca09c86c6a81b06820ef7ace3e45a5c/art/App0.jpg
--------------------------------------------------------------------------------
/art/App1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harrunisk/Stocker/dca907383ca09c86c6a81b06820ef7ace3e45a5c/art/App1.jpg
--------------------------------------------------------------------------------
/art/App2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harrunisk/Stocker/dca907383ca09c86c6a81b06820ef7ace3e45a5c/art/App2.jpg
--------------------------------------------------------------------------------
/art/App3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harrunisk/Stocker/dca907383ca09c86c6a81b06820ef7ace3e45a5c/art/App3.jpg
--------------------------------------------------------------------------------
/art/App4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harrunisk/Stocker/dca907383ca09c86c6a81b06820ef7ace3e45a5c/art/App4.jpg
--------------------------------------------------------------------------------
/art/AppGif.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harrunisk/Stocker/dca907383ca09c86c6a81b06820ef7ace3e45a5c/art/AppGif.gif
--------------------------------------------------------------------------------
/base/core/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/base/core/build.gradle:
--------------------------------------------------------------------------------
1 | apply from: "$rootDir/common-android-library.gradle"
2 | dependencies {
3 | api Libraries.coroutinesCore
4 | api Libraries.coroutinesAndroid
5 |
6 | // Dagger2
7 | api Libraries.dagger2AndroidSupport
8 |
9 | // Gson
10 | api Libraries.gson
11 |
12 | // Test
13 | api TestLibraries.jUnit
14 | api TestLibraries.espressoCore
15 | api TestLibraries.runner
16 | api TestLibraries.androidTestImplementation
17 | }
--------------------------------------------------------------------------------
/base/core/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/base/core/src/androidTest/java/com/nstudiosappdev/core/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core;
2 |
3 | import android.content.Context;
4 |
5 | import androidx.test.ext.junit.runners.AndroidJUnit4;
6 | import androidx.test.platform.app.InstrumentationRegistry;
7 |
8 | import org.junit.Test;
9 | import org.junit.runner.RunWith;
10 |
11 | import static org.junit.Assert.assertEquals;
12 |
13 | /**
14 | * Instrumented test, which will execute on an Android device.
15 | *
16 | * @see Testing documentation
17 | */
18 | @RunWith(AndroidJUnit4.class)
19 | public class ExampleInstrumentedTest {
20 | @Test
21 | public void useAppContext() {
22 | // Context of the app under test.
23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
24 |
25 | assertEquals("com.nstudiosappdev.core.test", appContext.getPackageName());
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/base/core/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/base/core/src/main/java/com/nstudiosappdev/core/application/CoreApplication.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.application
2 |
3 | import com.nstudiosappdev.core.injection.Injectable
4 | import dagger.android.HasActivityInjector
5 |
6 | interface CoreApplication : Injectable, HasActivityInjector
7 |
--------------------------------------------------------------------------------
/base/core/src/main/java/com/nstudiosappdev/core/application/CoreApplicationImpl.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.application
2 |
3 | import android.app.Activity
4 | import android.app.Application
5 | import dagger.android.AndroidInjector
6 | import dagger.android.DispatchingAndroidInjector
7 | import javax.inject.Inject
8 |
9 | abstract class CoreApplicationImpl : Application(), CoreApplication {
10 | @Inject
11 | lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector
12 |
13 | override fun inject() {
14 | // override if needed
15 | }
16 |
17 | override fun onCreate() {
18 | super.onCreate()
19 | inject()
20 | }
21 |
22 | override fun activityInjector(): AndroidInjector = dispatchingAndroidInjector
23 | }
24 |
--------------------------------------------------------------------------------
/base/core/src/main/java/com/nstudiosappdev/core/coroutines/AsyncManager.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.coroutines
2 |
3 | import kotlinx.coroutines.CoroutineScope
4 | import kotlinx.coroutines.Deferred
5 |
6 | interface AsyncManager : CoroutineScope {
7 |
8 | suspend fun handleAsync(block: suspend CoroutineScope.() -> T): Deferred
9 |
10 | suspend fun handleAsyncAwait(block: suspend CoroutineScope.() -> T): T
11 |
12 | fun cancelAllAsync()
13 |
14 | fun destroy()
15 | }
16 |
--------------------------------------------------------------------------------
/base/core/src/main/java/com/nstudiosappdev/core/coroutines/CoroutineExt.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.coroutines
2 |
3 | import kotlinx.coroutines.CancellationException
4 | import kotlinx.coroutines.CoroutineScope
5 |
6 | suspend fun CoroutineScope.tryCatch(
7 | tryBlock: suspend CoroutineScope.() -> Unit,
8 | catchBlock: suspend CoroutineScope.(Throwable) -> Unit,
9 | handleCancellationExceptionManually: Boolean = false
10 | ) {
11 | try {
12 | tryBlock()
13 | } catch (e: Throwable) {
14 | if (e !is CancellationException || handleCancellationExceptionManually) {
15 | catchBlock(e)
16 | } else {
17 | throw e
18 | }
19 | }
20 | }
21 |
22 | suspend fun CoroutineScope.tryCatchFinally(
23 | tryBlock: suspend CoroutineScope.() -> Unit,
24 | catchBlock: suspend CoroutineScope.(Throwable) -> Unit,
25 | finallyBlock: suspend CoroutineScope.() -> Unit,
26 | handleCancellationExceptionManually: Boolean = false
27 | ) {
28 | var caughtThrowable: Throwable? = null
29 |
30 | try {
31 | tryBlock()
32 | } catch (e: Throwable) {
33 | if (e !is CancellationException || handleCancellationExceptionManually) {
34 | catchBlock(e)
35 | } else {
36 | caughtThrowable = e
37 | }
38 | } finally {
39 | if (caughtThrowable is CancellationException && !handleCancellationExceptionManually) {
40 | throw caughtThrowable
41 | } else {
42 | finallyBlock()
43 | }
44 | }
45 | }
46 |
47 | suspend fun CoroutineScope.tryFinally(
48 | tryBlock: suspend CoroutineScope.() -> Unit,
49 | finallyBlock: suspend CoroutineScope.() -> Unit,
50 | supressCancellationException: Boolean = false
51 | ) {
52 | var caughtThrowable: Throwable? = null
53 |
54 | try {
55 | tryBlock()
56 | } catch (e: CancellationException) {
57 | if (!supressCancellationException) {
58 | caughtThrowable = e
59 | }
60 | } finally {
61 | if (caughtThrowable is CancellationException && !supressCancellationException) {
62 | throw caughtThrowable
63 | } else {
64 | finallyBlock()
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/base/core/src/main/java/com/nstudiosappdev/core/coroutines/CoroutineManager.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.coroutines
2 |
3 | import kotlinx.coroutines.CoroutineScope
4 |
5 | interface CoroutineManager : CoroutineScope {
6 |
7 | fun handleLaunch(execution: suspend CoroutineScope.() -> Unit)
8 |
9 | fun handleLaunch(
10 | execution: suspend CoroutineScope.() -> Unit,
11 | error: suspend CoroutineScope.(Throwable) -> Unit,
12 | handleCancellationExceptionManually: Boolean = false
13 | )
14 |
15 | fun handleLaunch(
16 | execution: suspend CoroutineScope.() -> Unit,
17 | error: suspend CoroutineScope.(Throwable) -> Unit,
18 | final: suspend CoroutineScope.() -> Unit,
19 | handleCancellationExceptionManually: Boolean = false
20 | )
21 |
22 | fun handleLaunch(
23 | execution: suspend CoroutineScope.() -> Unit,
24 | final: suspend CoroutineScope.() -> Unit,
25 | supressCancellationException: Boolean = false
26 | )
27 |
28 | fun cancelAllCoroutines()
29 |
30 | fun destroy()
31 | }
32 |
--------------------------------------------------------------------------------
/base/core/src/main/java/com/nstudiosappdev/core/coroutines/DefaultAsyncManager.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.coroutines
2 |
3 | import androidx.annotation.CallSuper
4 | import kotlin.coroutines.CoroutineContext
5 | import kotlinx.coroutines.CoroutineScope
6 | import kotlinx.coroutines.Deferred
7 | import kotlinx.coroutines.async
8 |
9 | class DefaultAsyncManager(
10 | override val coroutineContext: CoroutineContext
11 | ) : AsyncManager {
12 |
13 | private val deferredObjects: MutableList> by lazy {
14 | mutableListOf>()
15 | }
16 |
17 | @CallSuper
18 | @Synchronized
19 | override suspend fun handleAsync(block: suspend CoroutineScope.() -> T): Deferred {
20 | val deferred: Deferred = async { block() }
21 | deferredObjects.add(deferred)
22 | deferred.invokeOnCompletion { deferredObjects.remove(deferred) }
23 | return deferred
24 | }
25 |
26 | @CallSuper
27 | @Synchronized
28 | override suspend fun handleAsyncAwait(block: suspend CoroutineScope.() -> T): T {
29 | return handleAsync(block).await()
30 | }
31 |
32 | @CallSuper
33 | @Synchronized
34 | override fun cancelAllAsync() {
35 | val deferredObjectsSize = deferredObjects.size
36 | if (deferredObjectsSize > 0) {
37 | for (i in deferredObjectsSize - 1 downTo 0) {
38 | deferredObjects[i].cancel()
39 | }
40 | }
41 | }
42 |
43 | @CallSuper
44 | @Synchronized
45 | override fun destroy() {
46 | cancelAllAsync()
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/base/core/src/main/java/com/nstudiosappdev/core/coroutines/DefaultCoroutinesManager.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.coroutines
2 |
3 | import kotlin.coroutines.CoroutineContext
4 | import kotlinx.coroutines.CoroutineScope
5 | import kotlinx.coroutines.Job
6 | import kotlinx.coroutines.launch
7 |
8 | class DefaultCoroutinesManager(override val coroutineContext: CoroutineContext) : CoroutineManager {
9 |
10 | private val coroutinesJobs: MutableList by lazy {
11 | mutableListOf()
12 | }
13 |
14 | override fun handleLaunch(execution: suspend CoroutineScope.() -> Unit) {
15 | val job: Job = launch { execution() }
16 | coroutinesJobs.add(job)
17 | job.invokeOnCompletion { coroutinesJobs.remove(job) }
18 | }
19 |
20 | @Synchronized
21 | override fun handleLaunch(
22 | execution: suspend CoroutineScope.() -> Unit,
23 | error: suspend CoroutineScope.(Throwable) -> Unit,
24 | handleCancellationExceptionManually: Boolean
25 | ) {
26 | launch { tryCatch(execution, error, handleCancellationExceptionManually) }
27 | }
28 |
29 | @Synchronized
30 | override fun handleLaunch(
31 | execution: suspend CoroutineScope.() -> Unit,
32 | error: suspend CoroutineScope.(Throwable) -> Unit,
33 | final: suspend CoroutineScope.() -> Unit,
34 | handleCancellationExceptionManually: Boolean
35 | ) {
36 | launch { tryCatchFinally(execution, error, final, handleCancellationExceptionManually) }
37 | }
38 |
39 | @Synchronized
40 | override fun handleLaunch(
41 | execution: suspend CoroutineScope.() -> Unit,
42 | final: suspend CoroutineScope.() -> Unit,
43 | supressCancellationException: Boolean
44 | ) {
45 | launch { tryFinally(execution, final, supressCancellationException) }
46 | }
47 |
48 | @Synchronized
49 | override fun cancelAllCoroutines() {
50 | val coroutineJobsSize = coroutinesJobs.size
51 |
52 | if (coroutineJobsSize > 0) {
53 | for (i in coroutineJobsSize - 1 downTo 0) {
54 | coroutinesJobs[i].cancel()
55 | }
56 | }
57 | }
58 |
59 | @Synchronized
60 | override fun destroy() {
61 | cancelAllCoroutines()
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/base/core/src/main/java/com/nstudiosappdev/core/coroutines/DefaultDispatcherProvider.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.coroutines
2 |
3 | import kotlinx.coroutines.Dispatchers
4 |
5 | class DefaultDispatcherProvider : DispatcherProvider {
6 |
7 | private val main = Dispatchers.Main
8 | private val ui = Dispatchers.Main
9 | private val io = Dispatchers.IO
10 | private val default = Dispatchers.Default
11 |
12 | override fun main() = main
13 |
14 | override fun ui() = ui
15 |
16 | override fun io() = io
17 |
18 | override fun default() = default
19 | }
20 |
--------------------------------------------------------------------------------
/base/core/src/main/java/com/nstudiosappdev/core/coroutines/DispatcherProvider.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.coroutines
2 |
3 | import kotlin.coroutines.CoroutineContext
4 |
5 | interface DispatcherProvider {
6 | fun main(): CoroutineContext
7 |
8 | fun ui(): CoroutineContext
9 |
10 | fun io(): CoroutineContext
11 |
12 | fun default(): CoroutineContext
13 | }
14 |
--------------------------------------------------------------------------------
/base/core/src/main/java/com/nstudiosappdev/core/date/DateTimeConstants.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.date
2 |
3 | class DateTimeConstants {
4 | companion object {
5 | const val DEFAULT_DATE_FORMAT = "dd MM yyyy"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/base/core/src/main/java/com/nstudiosappdev/core/date/DateTimeConverter.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.date
2 |
3 | interface DateTimeConverter {
4 |
5 | fun convertLongToDate(
6 | dateTime: Long,
7 | dateFormat: String = DateTimeConstants.DEFAULT_DATE_FORMAT
8 | ): String
9 |
10 | fun convertCurrentDateToLong(): Long
11 | }
12 |
--------------------------------------------------------------------------------
/base/core/src/main/java/com/nstudiosappdev/core/date/DefaultDateTimeConverter.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.date
2 |
3 | import java.text.SimpleDateFormat
4 | import java.util.*
5 |
6 | class DefaultDateTimeConverter : DateTimeConverter {
7 |
8 | override fun convertLongToDate(dateTime: Long, dateFormat: String): String {
9 | val sdf = SimpleDateFormat(dateFormat)
10 | val date = Date(dateTime)
11 | return sdf.format(date)
12 | }
13 |
14 | override fun convertCurrentDateToLong(): Long = Date().time
15 | }
16 |
--------------------------------------------------------------------------------
/base/core/src/main/java/com/nstudiosappdev/core/error/DefaultErrorFactory.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.error
2 |
3 | import android.content.Context
4 | import com.nstudiosappdev.core.R
5 | import javax.inject.Inject
6 |
7 | class DefaultErrorFactory @Inject constructor(
8 | override val context: Context
9 | ) : ErrorFactory {
10 |
11 | override fun createApiError(code: String, messages: String) =
12 | Error.ApiError(code, messages)
13 |
14 | override fun createApiError(statusError: StatusError): Error {
15 | if (statusError.code == null) {
16 | return createUnknownError()
17 | }
18 |
19 | val message = statusError.message ?: context.getString(R.string.text_error)
20 | return createApiError(statusError.code, message)
21 | }
22 |
23 | override fun createErrors(errors: List?): Error {
24 | val safeErrorList = ArrayList()
25 | if (errors != null && errors.isNotEmpty()) {
26 | for (statusError in errors) {
27 | val apiError = createApiError(statusError)
28 | safeErrorList.add(apiError)
29 | }
30 | }
31 |
32 | return Error.ApiErrors(safeErrorList)
33 | }
34 |
35 | override fun createUnknownError(): Error =
36 | Error.UnknownError(context.getString(R.string.text_error))
37 |
38 | override fun createErrorFromThrowable(t: Throwable) =
39 | Error.ExceptionalError(message = t.localizedMessage)
40 |
41 | override fun createInvalidResponseError() =
42 | Error.InvalidResponseError(context.getString(R.string.text_invalid_response))
43 |
44 | override fun createUnHandledStateError() = Error.UnhandledStateError()
45 |
46 | override fun createInvalidInteractorRequestError() = Error.InvalidInteractorRequestError()
47 |
48 | override fun createAuthenticationError() = Error.AuthenticationError()
49 |
50 | override fun emptyCacheResultError() = Error.EmptyCacheResult()
51 |
52 | override fun createConnectionError() = Error.ConnectionError()
53 |
54 | override fun createBusinessError(code: Int, message: String?) = Error.BusinessError()
55 | }
56 |
--------------------------------------------------------------------------------
/base/core/src/main/java/com/nstudiosappdev/core/error/Error.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.error
2 |
3 | sealed class Error {
4 |
5 | data class UnknownError(val message: String) : Error()
6 |
7 | data class ApiError(val code: String, val message: String) : Error()
8 |
9 | data class ApiErrors(val errors: List) : Error()
10 |
11 | data class BusinessError(val code: Int = 1, val message: String? = null) : Error()
12 |
13 | data class InvalidResponseError(val message: String) : Error()
14 |
15 | data class ExceptionalError(val message: String?) : Error()
16 |
17 | class ConnectionError : Error() {
18 | override fun equals(other: Any?): Boolean {
19 | return this === other
20 | }
21 |
22 | override fun hashCode(): Int {
23 | return System.identityHashCode(this)
24 | }
25 | }
26 |
27 | class EmptyCacheResult : Error() {
28 | override fun equals(other: Any?): Boolean {
29 | return this === other
30 | }
31 |
32 | override fun hashCode(): Int {
33 | return System.identityHashCode(this)
34 | }
35 | }
36 |
37 | class UnhandledStateError : Error() {
38 | override fun equals(other: Any?): Boolean {
39 | return this === other
40 | }
41 |
42 | override fun hashCode(): Int {
43 | return System.identityHashCode(this)
44 | }
45 | }
46 |
47 | class AuthenticationError : Error() {
48 | override fun equals(other: Any?): Boolean {
49 | return this === other
50 | }
51 |
52 | override fun hashCode(): Int {
53 | return System.identityHashCode(this)
54 | }
55 | }
56 |
57 | class InvalidInteractorRequestError : Error() {
58 | override fun equals(other: Any?): Boolean {
59 | return this === other
60 | }
61 |
62 | override fun hashCode(): Int {
63 | return System.identityHashCode(this)
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/base/core/src/main/java/com/nstudiosappdev/core/error/ErrorFactory.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.error
2 |
3 | import android.content.Context
4 |
5 | interface ErrorFactory {
6 |
7 | val context: Context
8 |
9 | fun createUnknownError(): Error
10 |
11 | fun createApiError(statusError: StatusError): Error
12 |
13 | fun createApiError(code: String, messages: String): Error
14 |
15 | fun createErrors(errors: List?): Error
16 |
17 | fun createErrorFromThrowable(t: Throwable): Error
18 |
19 | fun createInvalidResponseError(): Error
20 |
21 | fun createUnHandledStateError(): Error
22 |
23 | fun createInvalidInteractorRequestError(): Error
24 |
25 | fun createAuthenticationError(): Error
26 |
27 | fun emptyCacheResultError(): Error
28 |
29 | fun createConnectionError(): Error
30 |
31 | fun createBusinessError(code: Int = 1, message: String? = null): Error
32 | }
33 |
--------------------------------------------------------------------------------
/base/core/src/main/java/com/nstudiosappdev/core/error/StatusError.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.error
2 |
3 | import com.google.gson.annotations.SerializedName
4 |
5 | data class StatusError(@SerializedName("code") val code: String?, @SerializedName("message") val message: String?)
6 |
--------------------------------------------------------------------------------
/base/core/src/main/java/com/nstudiosappdev/core/injection/Injectable.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.injection
2 |
3 | interface Injectable {
4 | fun inject()
5 | }
6 |
--------------------------------------------------------------------------------
/base/core/src/main/java/com/nstudiosappdev/core/injection/modules/CoreModule.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.injection.modules
2 |
3 | import com.nstudiosappdev.core.date.DateTimeConverter
4 | import com.nstudiosappdev.core.date.DefaultDateTimeConverter
5 | import com.nstudiosappdev.core.preconditions.AndroidPreConditions
6 | import com.nstudiosappdev.core.preconditions.DefaultAndroidPreConditions
7 | import dagger.Module
8 | import dagger.Provides
9 | import javax.inject.Singleton
10 |
11 | @Module(
12 | includes = [CoroutineManagerModule::class,
13 | CoroutineDispatcherModule::class,
14 | ErrorFactoryModule::class]
15 | )
16 | class CoreModule {
17 |
18 | @Provides
19 | @Singleton
20 | fun provideAndroidPreConditions(): AndroidPreConditions = DefaultAndroidPreConditions()
21 |
22 | @Provides
23 | @Singleton
24 | fun provideDateTimeConverter(): DateTimeConverter = DefaultDateTimeConverter()
25 | }
26 |
--------------------------------------------------------------------------------
/base/core/src/main/java/com/nstudiosappdev/core/injection/modules/CoroutineDispatcherModule.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.injection.modules
2 |
3 | import com.nstudiosappdev.core.coroutines.DefaultDispatcherProvider
4 | import com.nstudiosappdev.core.coroutines.DispatcherProvider
5 | import dagger.Module
6 | import dagger.Provides
7 | import javax.inject.Singleton
8 |
9 | @Module
10 | class CoroutineDispatcherModule {
11 |
12 | @Provides
13 | @Singleton
14 | fun provideDefaultDispatcher(): DispatcherProvider = DefaultDispatcherProvider()
15 | }
16 |
--------------------------------------------------------------------------------
/base/core/src/main/java/com/nstudiosappdev/core/injection/modules/CoroutineManagerModule.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.injection.modules
2 |
3 | import com.nstudiosappdev.core.coroutines.*
4 | import dagger.Module
5 | import dagger.Provides
6 | import javax.inject.Named
7 | import javax.inject.Singleton
8 |
9 | @Module
10 | class CoroutineManagerModule {
11 |
12 | @Provides
13 | @Singleton
14 | @Named(AM_NAME_INTERACTOR)
15 | fun provideAsyncManagerForInteractors(dispatcherProvider: DispatcherProvider): AsyncManager =
16 | DefaultAsyncManager(dispatcherProvider.default())
17 |
18 | @Provides
19 | @Singleton
20 | @Named(AM_NAME_REPOSITORY)
21 | fun provideAsyncManagerForRepositories(dispatcherProvider: DispatcherProvider): AsyncManager =
22 | DefaultAsyncManager(dispatcherProvider.io())
23 |
24 | @Provides
25 | @Singleton
26 | @Named(AM_NAME_REMOTE_DATA_SOURCE)
27 | fun provideAsyncManagerForRemoteDataSource(dispatcherProvider: DispatcherProvider): AsyncManager =
28 | DefaultAsyncManager(dispatcherProvider.io())
29 |
30 | @Provides
31 | @Singleton
32 | @Named(CM_VIEWMODEL)
33 | fun provideCoroutineManagerForViewModel(dispatcherProvider: DispatcherProvider): CoroutineManager =
34 | DefaultCoroutinesManager(dispatcherProvider.ui())
35 |
36 | companion object {
37 | const val AM_NAME_INTERACTOR = "am_interactor"
38 | const val AM_NAME_REPOSITORY = "am_repository"
39 | const val CM_VIEWMODEL = "cm_viewmodel"
40 | const val AM_NAME_REMOTE_DATA_SOURCE = "am_remote_datasource"
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/base/core/src/main/java/com/nstudiosappdev/core/injection/modules/ErrorFactoryModule.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.injection.modules
2 |
3 | import android.content.Context
4 | import com.nstudiosappdev.core.error.DefaultErrorFactory
5 | import com.nstudiosappdev.core.error.ErrorFactory
6 | import dagger.Module
7 | import dagger.Provides
8 | import javax.inject.Singleton
9 |
10 | @Module
11 | class ErrorFactoryModule {
12 |
13 | @Provides
14 | @Singleton
15 | internal fun provideErrorFactory(context: Context): ErrorFactory =
16 | DefaultErrorFactory(context.applicationContext)
17 | }
18 |
--------------------------------------------------------------------------------
/base/core/src/main/java/com/nstudiosappdev/core/injection/qualifiers/ForActivity.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.injection.qualifiers
2 |
3 | import javax.inject.Qualifier
4 |
5 | @Qualifier
6 | @Retention(AnnotationRetention.RUNTIME)
7 | annotation class ForActivity
8 |
--------------------------------------------------------------------------------
/base/core/src/main/java/com/nstudiosappdev/core/injection/qualifiers/ForApplication.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.injection.qualifiers
2 |
3 | import javax.inject.Qualifier
4 |
5 | @Qualifier
6 | @Retention(AnnotationRetention.RUNTIME)
7 | annotation class ForApplication
8 |
--------------------------------------------------------------------------------
/base/core/src/main/java/com/nstudiosappdev/core/injection/scope/ActivityScope.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.injection.scope
2 |
3 | import javax.inject.Scope
4 |
5 | @Scope
6 | @Retention(AnnotationRetention.RUNTIME)
7 | annotation class ActivityScope
8 |
--------------------------------------------------------------------------------
/base/core/src/main/java/com/nstudiosappdev/core/injection/scope/FragmentScope.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.injection.scope
2 |
3 | import javax.inject.Scope
4 |
5 | @Scope
6 | @Retention(AnnotationRetention.RUNTIME)
7 | annotation class FragmentScope
8 |
--------------------------------------------------------------------------------
/base/core/src/main/java/com/nstudiosappdev/core/model/BaseRepository.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.model
2 |
3 | interface BaseRepository {
4 | fun dropRepo()
5 | }
6 |
--------------------------------------------------------------------------------
/base/core/src/main/java/com/nstudiosappdev/core/model/DataHolder.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.model
2 |
3 | import com.nstudiosappdev.core.error.Error
4 |
5 | sealed class DataHolder {
6 |
7 | data class Success(val data: T) : DataHolder()
8 |
9 | data class Fail(val e: Error) : DataHolder()
10 |
11 | object Loading : DataHolder()
12 | }
13 |
--------------------------------------------------------------------------------
/base/core/src/main/java/com/nstudiosappdev/core/preconditions/AndroidPreConditions.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.preconditions
2 |
3 | interface AndroidPreConditions {
4 | fun assertMainThread()
5 |
6 | fun assertUiThread()
7 |
8 | fun assertWorkerThread()
9 | }
10 |
--------------------------------------------------------------------------------
/base/core/src/main/java/com/nstudiosappdev/core/preconditions/DefaultAndroidPreConditions.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.preconditions
2 |
3 | class DefaultAndroidPreConditions : AndroidPreConditions {
4 | override fun assertMainThread() {
5 | check(Thread.currentThread().isMainThread()) { "This code must be executed in main thread!" }
6 | }
7 |
8 | override fun assertUiThread() {
9 | check(Thread.currentThread().isMainThread()) { "This code must be executed in ui thread!" }
10 | }
11 |
12 | override fun assertWorkerThread() {
13 | check(!Thread.currentThread().isMainThread()) { "This code must be executed in ui thread!" }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/base/core/src/main/java/com/nstudiosappdev/core/preconditions/ThreadPreconditions.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.preconditions
2 |
3 | import android.os.Looper
4 |
5 | fun Thread.isMainThread() = Looper.getMainLooper().thread == this
6 |
7 | fun Thread.assertMainThread() = this.isMainThread()
8 |
9 | fun Thread.assertUiThread() = this.isMainThread()
10 |
11 | fun Thread.assertWorkerThread() = !this.isMainThread()
12 |
--------------------------------------------------------------------------------
/base/core/src/main/java/com/nstudiosappdev/core/util/SharedPrefUtil.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.util
2 |
3 | import android.content.Context
4 | import android.content.SharedPreferences
5 |
6 | object SharedPrefUtil {
7 |
8 | private const val MASTER_KEY = "[Stocker!]"
9 |
10 | private fun getSharedPref(context: Context): SharedPreferences {
11 | return context.getSharedPreferences(MASTER_KEY, Context.MODE_PRIVATE)
12 | }
13 |
14 | /**
15 | * Put Methods
16 | */
17 |
18 | fun put(context: Context, key: String, value: String?) {
19 | getSharedPref(context).edit().putString(key, value).apply()
20 | }
21 |
22 | fun put(context: Context, key: String, value: Boolean) {
23 | getSharedPref(context).edit().putBoolean(key, value).apply()
24 | }
25 |
26 | fun put(context: Context, key: String, value: Long) {
27 | getSharedPref(context).edit().putLong(key, value).apply()
28 | }
29 |
30 | /**
31 | * Get Methods
32 | */
33 |
34 | fun get(context: Context, key: String, defaultVal: String?): String? {
35 | return getSharedPref(context).getString(key, defaultVal)
36 | }
37 |
38 | fun get(context: Context, key: String, defaultVal: Boolean): Boolean {
39 | return getSharedPref(context).getBoolean(key, defaultVal)
40 | }
41 |
42 | fun get(context: Context, key: String, defaultVal: Long): Long {
43 | return getSharedPref(context).getLong(key, defaultVal)
44 | }
45 |
46 | /**
47 | * Clear methods
48 | */
49 |
50 | fun clearData(context: Context) {
51 | getSharedPref(context).edit().clear().apply()
52 | }
53 |
54 | fun remove(context: Context, key: String) {
55 | getSharedPref(context).edit().remove(key).apply()
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/base/core/src/main/res/values-tr-rTR/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Banka Döviz Kurları
4 | Bir hata oluştu.
5 | Geçersiz yanıt.
6 |
--------------------------------------------------------------------------------
/base/core/src/main/res/values-tr/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Banka Döviz Kurları
4 | Bir hata oluştu.
5 | Geçersiz yanıt.
6 |
--------------------------------------------------------------------------------
/base/core/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Stocker
3 | An error occurred.
4 | Invalid response.
5 |
6 |
--------------------------------------------------------------------------------
/base/core/src/test/java/com/nstudiosappdev/core/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/base/core_data/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/base/core_data/build.gradle:
--------------------------------------------------------------------------------
1 | apply from: "$rootDir/common-android-library.gradle"
2 | dependencies {
3 | api project(Modules.core)
4 |
5 | // RETROFIT
6 | api Libraries.retrofit
7 | api Libraries.logInterceptor
8 | api Libraries.okHttp
9 | api Libraries.retrofitCoroutineAdapter
10 | api Libraries.room
11 | }
--------------------------------------------------------------------------------
/base/core_data/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/base/core_data/src/androidTest/java/com/nstudiosappdev/core/data/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.data;
2 |
3 | import android.content.Context;
4 | import androidx.test.ext.junit.runners.AndroidJUnit4;
5 | import androidx.test.platform.app.InstrumentationRegistry;
6 | import org.junit.Test;
7 | import org.junit.runner.RunWith;
8 |
9 | import static org.junit.Assert.*;
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * @see Testing documentation
15 | */
16 | @RunWith(AndroidJUnit4.class)
17 | public class ExampleInstrumentedTest {
18 | @Test
19 | public void useAppContext() {
20 | // Context of the app under test.
21 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
22 |
23 | assertEquals("com.nstudiosappdev.core.data.test", appContext.getPackageName());
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/base/core_data/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/base/core_data/src/main/java/com/nstudiosappdev/core/data/adapter/ApiCallAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.data.adapter
2 |
3 | import com.nstudiosappdev.core.data.api.response.ApiResponse
4 | import com.nstudiosappdev.core.error.ErrorFactory
5 | import com.nstudiosappdev.core.model.DataHolder
6 | import javax.inject.Inject
7 | import kotlinx.coroutines.Deferred
8 |
9 | class ApiCallAdapter @Inject constructor(private val errorFactory: ErrorFactory) :
10 | CallAdapter {
11 |
12 | override suspend fun adapt(apiCall: Deferred>): DataHolder {
13 | val apiResult = apiCall.await()
14 |
15 | if (apiResult.data == null) {
16 | return DataHolder.Fail(errorFactory.createInvalidResponseError())
17 | }
18 |
19 | return DataHolder.Success(apiResult.data)
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/base/core_data/src/main/java/com/nstudiosappdev/core/data/adapter/CallAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.data.adapter
2 |
3 | import com.nstudiosappdev.core.data.api.response.ApiResponse
4 | import com.nstudiosappdev.core.model.DataHolder
5 | import kotlinx.coroutines.Deferred
6 |
7 | interface CallAdapter {
8 | suspend fun adapt(apiCall: Deferred>): DataHolder
9 | }
10 |
--------------------------------------------------------------------------------
/base/core_data/src/main/java/com/nstudiosappdev/core/data/api/ApiConstants.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.data.api
2 |
3 | class ApiConstants private constructor() {
4 |
5 | companion object {
6 | const val TIMEOUT_INMILIS = 15000L
7 |
8 | // Date
9 | const val DEFAULT_DATE_FORMAT = "yyyy MM dd"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/base/core_data/src/main/java/com/nstudiosappdev/core/data/api/interceptor/DefaultRequestInterceptor.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.data.api.interceptor
2 |
3 | import com.nstudiosappdev.core.data.BuildConfig
4 | import javax.inject.Inject
5 | import okhttp3.Interceptor
6 | import okhttp3.Response
7 |
8 | class DefaultRequestInterceptor @Inject constructor() : Interceptor {
9 |
10 | override fun intercept(chain: Interceptor.Chain): Response {
11 | return chain.proceed(with(chain.request().newBuilder()) {
12 | addHeader("Content-Type", "application/json")
13 | addHeader("VersionCode", BuildConfig.VERSION_CODE.toString())
14 | addHeader("VersionName", BuildConfig.VERSION_NAME)
15 | addHeader("ApplicationId", BuildConfig.APPLICATION_ID)
16 | build()
17 | })
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/base/core_data/src/main/java/com/nstudiosappdev/core/data/api/response/ApiResponse.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.data.api.response
2 |
3 | import com.google.gson.annotations.SerializedName
4 |
5 | data class ApiResponse(
6 | @SerializedName("GetPriceBankListResult") val data: T?
7 | )
8 |
--------------------------------------------------------------------------------
/base/core_data/src/main/java/com/nstudiosappdev/core/data/datasource/BaseDataSource.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.data.datasource
2 |
3 | import com.nstudiosappdev.core.coroutines.AsyncManager
4 |
5 | abstract class BaseDataSource(asyncManager: AsyncManager) : AsyncManager by asyncManager
6 |
--------------------------------------------------------------------------------
/base/core_data/src/main/java/com/nstudiosappdev/core/data/datasource/DataSource.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.data.datasource
2 |
3 | import com.nstudiosappdev.core.model.DataHolder
4 |
5 | interface DataSource {
6 | interface RemoteDataSource : DataSource {
7 | interface RequestDataSource : DataSource {
8 | suspend fun getResult(request: Req): DataHolder
9 | }
10 |
11 | interface FetchDataSource : DataSource {
12 | suspend fun fetch(): DataHolder
13 | }
14 | }
15 |
16 | interface LocalDataSource : DataSource {
17 | fun get(key: K): V?
18 |
19 | fun get(page: Int): List
20 |
21 | fun get(key: String): List
22 |
23 | fun get(key1: String, key2: String): V
24 |
25 | fun getAll(): List
26 |
27 | fun put(key: K?, data: V): Boolean
28 |
29 | fun remove(value: V): Boolean
30 |
31 | fun removeByKey(key: K): Boolean
32 |
33 | fun remove(key1: String, key2: String): Boolean
34 |
35 | fun clear()
36 | }
37 |
38 | interface CacheDataSource : DataSource {
39 | fun get(key: K): V?
40 | fun put(key: K, value: V): Boolean
41 | fun drop()
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/base/core_data/src/main/java/com/nstudiosappdev/core/data/db/Db.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.data.db
2 |
3 | class Db private constructor() {
4 |
5 | object Config {
6 | const val DB_NAME = "stocker"
7 | const val DB_VERSION = 3
8 | const val BANK_NAME = "bankName"
9 | const val BUY_PRICE = "buyPrice"
10 | const val BUY_STATUS = "buyStatus"
11 | const val SELL_PRICE = "sellPrice"
12 | const val SELL_STATUS = "sellStatus"
13 | const val CURRENCY_TYPE = "currencyType"
14 | const val CREATE_DATE = "create_date"
15 | const val UPDATE_DATE = "update_date"
16 | }
17 |
18 | object TABLES {
19 |
20 | object CURRENCIES {
21 | const val NAME = "currencies"
22 |
23 | object COLUMNS {
24 | const val BANK_NAME = Config.BANK_NAME
25 | const val BUY_PRICE = Config.BUY_PRICE
26 | const val BUY_STATUS = Config.BUY_STATUS
27 | const val SELL_PRICE = Config.SELL_PRICE
28 | const val SELL_STATUS = Config.SELL_STATUS
29 | const val CURRENCY_TYPE = Config.CURRENCY_TYPE
30 | const val CREATE_DATE = Config.CREATE_DATE
31 | const val UPDATE_DATE = Config.UPDATE_DATE
32 | }
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/base/core_data/src/main/java/com/nstudiosappdev/core/data/db/Migrations.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.data.db
2 |
3 | import androidx.room.migration.Migration
4 | import androidx.sqlite.db.SupportSQLiteDatabase
5 |
6 | val MIGRATION_1_2 = object : Migration(1, 2) {
7 | override fun migrate(database: SupportSQLiteDatabase) {
8 | database.execSQL(
9 | "CREATE TABLE IF NOT EXISTS currencies (" +
10 | "'bankName' TEXT PRIMARY KEY NOT NULL," +
11 | "'buyPrice' TEXT," +
12 | "'buyStatus' TEXT," +
13 | "'sellPrice' TEXT," +
14 | "'sellStatus' TEXT," +
15 | "'currencyType ' TEXT PRIMARY KEY NOT NULL," +
16 | "'createdDate' LONG," +
17 | "'updatedDate' LONG ) "
18 | )
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/base/core_data/src/main/java/com/nstudiosappdev/core/data/db/StockerDb.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.data.db
2 |
3 | import androidx.room.Database
4 | import androidx.room.RoomDatabase
5 | import com.nstudiosappdev.core.data.db.dao.CurrenciesDao
6 | import com.nstudiosappdev.core.data.db.entity.CurrenciesEntity
7 | import javax.inject.Singleton
8 |
9 | @Singleton
10 | @Database(
11 | entities = [CurrenciesEntity::class],
12 | version = Db.Config.DB_VERSION,
13 | exportSchema = true
14 | )
15 | abstract class StockerDb : RoomDatabase() {
16 | abstract fun currenciesDao(): CurrenciesDao
17 | }
18 |
--------------------------------------------------------------------------------
/base/core_data/src/main/java/com/nstudiosappdev/core/data/db/dao/CurrenciesDao.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.data.db.dao
2 |
3 | import androidx.room.Dao
4 | import androidx.room.Insert
5 | import androidx.room.OnConflictStrategy
6 | import androidx.room.Query
7 | import com.nstudiosappdev.core.data.db.entity.CurrenciesEntity
8 |
9 | @Dao
10 | interface CurrenciesDao {
11 | @Query("SELECT * FROM currencies")
12 | fun getAllCurrencies(): List
13 |
14 | @Query("SELECT * FROM currencies WHERE currencyType = :currencyType")
15 | fun getSpecificCurrencyTypes(currencyType: String): List
16 |
17 | @Insert(onConflict = OnConflictStrategy.ABORT)
18 | fun addCurrency(currenciesEntity: CurrenciesEntity): Long
19 |
20 | @Query("DELETE FROM currencies WHERE bankName = :bankName and currencyType = :currencyType")
21 | fun deleteCurrency(bankName: String, currencyType: String)
22 | }
23 |
--------------------------------------------------------------------------------
/base/core_data/src/main/java/com/nstudiosappdev/core/data/db/entity/CurrenciesEntity.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.data.db.entity
2 |
3 | import androidx.annotation.NonNull
4 | import androidx.room.ColumnInfo
5 | import androidx.room.Entity
6 | import com.nstudiosappdev.core.data.db.Db
7 |
8 | @Entity(
9 | tableName = Db.TABLES.CURRENCIES.NAME,
10 | primaryKeys = ["bankName", "currencyType"]
11 | )
12 | class CurrenciesEntity constructor(
13 | @ColumnInfo(name = Db.TABLES.CURRENCIES.COLUMNS.BANK_NAME) @NonNull val bankName: String,
14 | @ColumnInfo(name = Db.TABLES.CURRENCIES.COLUMNS.BUY_PRICE) val buyPrice: String?,
15 | @ColumnInfo(name = Db.TABLES.CURRENCIES.COLUMNS.BUY_STATUS) val buyStatus: String?,
16 | @ColumnInfo(name = Db.TABLES.CURRENCIES.COLUMNS.SELL_PRICE) val sellPrice: String?,
17 | @ColumnInfo(name = Db.TABLES.CURRENCIES.COLUMNS.CURRENCY_TYPE) @NonNull val currencyType: String,
18 | @ColumnInfo(name = Db.TABLES.CURRENCIES.COLUMNS.SELL_STATUS) val sellStatus: String?,
19 | @ColumnInfo(name = Db.TABLES.CURRENCIES.COLUMNS.CREATE_DATE) val createDate: Long?,
20 | @ColumnInfo(name = Db.TABLES.CURRENCIES.COLUMNS.UPDATE_DATE) val updateDate: Long?
21 | ) : DbEntity
22 |
--------------------------------------------------------------------------------
/base/core_data/src/main/java/com/nstudiosappdev/core/data/db/entity/DbEntity.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.data.db.entity
2 |
3 | // marker interface
4 | interface DbEntity
5 |
--------------------------------------------------------------------------------
/base/core_data/src/main/java/com/nstudiosappdev/core/data/db/entity/DbEntityMapper.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.data.db.entity
2 |
3 | interface DbEntityMapper {
4 | fun map(entity: R): T
5 | fun map(domainObject: T): R
6 | }
7 |
--------------------------------------------------------------------------------
/base/core_data/src/main/java/com/nstudiosappdev/core/data/modules/ApiModule.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.data.modules
2 |
3 | import com.jakewharton.retrofit2.adapter.kotlin.coroutines.CoroutineCallAdapterFactory
4 | import com.nstudiosappdev.core.data.BuildConfig
5 | import com.nstudiosappdev.core.data.api.ApiConstants
6 | import com.nstudiosappdev.core.data.api.interceptor.DefaultRequestInterceptor
7 | import dagger.Module
8 | import dagger.Provides
9 | import java.util.concurrent.TimeUnit
10 | import javax.inject.Named
11 | import javax.inject.Singleton
12 | import okhttp3.Interceptor
13 | import okhttp3.OkHttpClient
14 | import okhttp3.logging.HttpLoggingInterceptor
15 | import retrofit2.Retrofit
16 | import retrofit2.converter.gson.GsonConverterFactory
17 |
18 | @Module
19 | class ApiModule {
20 |
21 | @Provides
22 | @Singleton
23 | @Named(NAME_URL)
24 | fun provideBaseUrl(): String = "http://138.68.103.38:3000/currency_type/"
25 |
26 | @Provides
27 | @Singleton
28 | fun provideReqestInterceptor(): Interceptor = DefaultRequestInterceptor()
29 |
30 | @Provides
31 | @Singleton
32 | fun provideLoggingInterceptor(): HttpLoggingInterceptor =
33 | HttpLoggingInterceptor().apply { level = HttpLoggingInterceptor.Level.BODY }
34 |
35 | @Provides
36 | @Singleton
37 | fun provideOkHttpClient(
38 | requestInterceptor: DefaultRequestInterceptor,
39 | loggingInterceptor: HttpLoggingInterceptor
40 | ): OkHttpClient =
41 | with(OkHttpClient.Builder()) {
42 | addInterceptor(requestInterceptor)
43 | if (BuildConfig.DEBUG) addInterceptor(loggingInterceptor)
44 | connectTimeout(ApiConstants.TIMEOUT_INMILIS, TimeUnit.MILLISECONDS)
45 | build()
46 | }
47 |
48 | @Provides
49 | @Singleton
50 | fun provideRetrofit(@Named(NAME_URL) baseUrl: String, client: OkHttpClient): Retrofit =
51 | with(Retrofit.Builder()) {
52 | baseUrl(baseUrl)
53 | client(client)
54 | addConverterFactory(GsonConverterFactory.create())
55 | addCallAdapterFactory(CoroutineCallAdapterFactory())
56 | build()
57 | }
58 |
59 | companion object {
60 | private const val NAME_URL = "url"
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/base/core_data/src/main/java/com/nstudiosappdev/core/data/modules/CoreDataModule.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.data.modules
2 |
3 | import com.nstudiosappdev.core.data.adapter.ApiCallAdapter
4 | import com.nstudiosappdev.core.data.adapter.CallAdapter
5 | import com.nstudiosappdev.core.data.api.response.ApiResponse
6 | import com.nstudiosappdev.core.error.ErrorFactory
7 | import dagger.Module
8 | import dagger.Provides
9 | import javax.inject.Singleton
10 | import kotlinx.coroutines.Deferred
11 |
12 | @Module(includes = [ApiModule::class, DbModule::class])
13 | class CoreDataModule {
14 | @Singleton
15 | @Provides
16 | fun provideApiCallAdapter(errorFactory: ErrorFactory): CallAdapter>> =
17 | ApiCallAdapter(errorFactory)
18 | }
19 |
--------------------------------------------------------------------------------
/base/core_data/src/main/java/com/nstudiosappdev/core/data/modules/DbModule.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.data.modules
2 |
3 | import android.content.Context
4 | import androidx.room.Room
5 | import com.nstudiosappdev.core.data.db.Db
6 | import com.nstudiosappdev.core.data.db.MIGRATION_1_2
7 | import com.nstudiosappdev.core.data.db.StockerDb
8 | import dagger.Module
9 | import dagger.Provides
10 | import javax.inject.Singleton
11 |
12 | @Module
13 | class DbModule {
14 | @Singleton
15 | @Provides
16 | fun provideDb(context: Context): StockerDb = Room.databaseBuilder(
17 | context,
18 | StockerDb::class.java, Db.Config.DB_NAME
19 | ).addMigrations(MIGRATION_1_2).build()
20 | }
21 |
--------------------------------------------------------------------------------
/base/core_data/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | core_data
3 |
4 |
--------------------------------------------------------------------------------
/base/core_data/src/test/java/com/nstudiosappdev/core/data/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.data;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/base/core_domain/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | /lib
3 |
--------------------------------------------------------------------------------
/base/core_domain/build.gradle:
--------------------------------------------------------------------------------
1 | apply from: "$rootDir/common-android-library.gradle"
2 | dependencies {
3 | api project (Modules.core)
4 | }
--------------------------------------------------------------------------------
/base/core_domain/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/base/core_domain/src/androidTest/java/com/nstudiosappdev/core/domain/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.domain;
2 |
3 | import android.content.Context;
4 | import androidx.test.ext.junit.runners.AndroidJUnit4;
5 | import androidx.test.platform.app.InstrumentationRegistry;
6 | import org.junit.Test;
7 | import org.junit.runner.RunWith;
8 |
9 | import static org.junit.Assert.*;
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * @see Testing documentation
15 | */
16 | @RunWith(AndroidJUnit4.class)
17 | public class ExampleInstrumentedTest {
18 | @Test
19 | public void useAppContext() {
20 | // Context of the app under test.
21 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
22 |
23 | assertEquals("com.nstudiosappdev.core.domain.test", appContext.getPackageName());
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/base/core_domain/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/base/core_domain/src/main/java/com/nstudiosappdev/core/domain/BaseInteractor.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.domain
2 |
3 | import com.nstudiosappdev.core.coroutines.AsyncManager
4 |
5 | abstract class BaseInteractor constructor(asyncManager: AsyncManager) : AsyncManager by asyncManager
6 |
--------------------------------------------------------------------------------
/base/core_domain/src/main/java/com/nstudiosappdev/core/domain/DeferredInteractor.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.domain
2 |
3 | import com.nstudiosappdev.core.model.DataHolder
4 | import kotlinx.coroutines.Deferred
5 |
6 | interface Interactor {
7 |
8 | interface DeferredInteractor : Interactor {
9 | suspend fun executeAsync(postParams: params): Deferred>
10 | }
11 |
12 | interface DeferredRetrieveInteractor : Interactor {
13 | suspend fun executeAsync(): Deferred>
14 | }
15 |
16 | interface SingleInteractor : Interactor {
17 | fun execute(params: params): T?
18 | }
19 |
20 | interface SingleRetrieveInteractor {
21 | fun execute(): T?
22 | }
23 |
24 | abstract class Params {
25 | // marker class
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/base/core_domain/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | core_domain
3 |
4 |
--------------------------------------------------------------------------------
/base/core_domain/src/test/java/com/nstudiosappdev/core/domain/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.domain;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/base/core_presentation/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | /libs
3 | .iml
--------------------------------------------------------------------------------
/base/core_presentation/build.gradle:
--------------------------------------------------------------------------------
1 | apply from: "$rootDir/common-android-library.gradle"
2 | dependencies {
3 |
4 | api project(Modules.core)
5 | api project(Modules.navigation)
6 |
7 | // View
8 | api SupportLibraries.appCompat
9 | api SupportLibraries.design
10 | api SupportLibraries.recyclerView
11 | api SupportLibraries.constraintLayout
12 | api Libraries.lifecycleExtensions
13 | api Libraries.picasso
14 | api Libraries.lottie
15 |
16 | }
--------------------------------------------------------------------------------
/base/core_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.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/base/core_presentation/src/androidTest/java/com/nstudiosappdev/core/presentation/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.presentation;
2 |
3 | import android.content.Context;
4 | import androidx.test.ext.junit.runners.AndroidJUnit4;
5 | import androidx.test.platform.app.InstrumentationRegistry;
6 | import org.junit.Test;
7 | import org.junit.runner.RunWith;
8 |
9 | import static org.junit.Assert.assertEquals;
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * @see Testing documentation
15 | */
16 | @RunWith(AndroidJUnit4.class)
17 | public class ExampleInstrumentedTest {
18 | @Test
19 | public void useAppContext() {
20 | // Context of the app under test.
21 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
22 |
23 | assertEquals("com.nstudiosappdev.core.presentation.test", appContext.getPackageName());
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/java/com.nstudiosappdev.core.presentation/Constants.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.presentation
2 |
3 | class Constants {
4 | companion object {
5 | const val NO_RES = 0
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/java/com.nstudiosappdev.core.presentation/TabProvider.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.presentation
2 |
3 | import com.google.android.material.tabs.TabLayout
4 |
5 | interface TabProvider {
6 | fun provideTabLayout(): TabLayout
7 | }
8 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/java/com.nstudiosappdev.core.presentation/base/BaseInjectionActivity.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.presentation.base
2 |
3 | import android.os.Bundle
4 | import androidx.fragment.app.Fragment
5 | import dagger.android.AndroidInjection
6 | import dagger.android.AndroidInjector
7 | import dagger.android.DispatchingAndroidInjector
8 | import dagger.android.support.HasSupportFragmentInjector
9 | import javax.inject.Inject
10 |
11 | abstract class BaseInjectionActivity : BaseActivity(), HasSupportFragmentInjector {
12 |
13 | @Inject
14 | lateinit var dispatchAndroidInjector: DispatchingAndroidInjector
15 |
16 | override fun supportFragmentInjector(): AndroidInjector = dispatchAndroidInjector
17 |
18 | override fun onCreate(savedInstanceState: Bundle?) {
19 | AndroidInjection.inject(this)
20 | super.onCreate(savedInstanceState)
21 | }
22 |
23 | open fun onInject() {
24 | // can be overriden
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/java/com.nstudiosappdev.core.presentation/base/BaseInjectionFragment.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.presentation.base
2 |
3 | import android.content.Context
4 | import androidx.annotation.CallSuper
5 | import dagger.android.support.AndroidSupportInjection
6 | import dagger.android.support.HasSupportFragmentInjector
7 |
8 | abstract class BaseInjectionFragment : BaseFragment() {
9 |
10 | @CallSuper
11 | override fun onAttach(context: Context) {
12 | if (activity is HasSupportFragmentInjector) {
13 | AndroidSupportInjection.inject(this)
14 | onInject()
15 | }
16 | super.onAttach(context)
17 | }
18 |
19 | open fun onInject() {
20 | // empty for override
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/java/com.nstudiosappdev.core.presentation/base/BaseView.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.presentation.base
2 |
3 | import com.nstudiosappdev.core.error.Error
4 |
5 | interface BaseView {
6 | fun onError(e: Error)
7 | }
8 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/java/com.nstudiosappdev.core.presentation/base/BaseViewModelFragment.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.presentation.base
2 |
3 | import android.os.Bundle
4 | import androidx.annotation.CallSuper
5 | import androidx.lifecycle.Observer
6 | import androidx.lifecycle.ViewModel
7 | import androidx.lifecycle.ViewModelProvider
8 | import androidx.lifecycle.ViewModelProviders
9 | import com.nstudiosappdev.core.presentation.viewmodel.BaseViewModel
10 | import com.nstudiosappdev.navigation.navigation.DefaultNavigationController
11 | import com.nstudiosappdev.navigation.navigation.NavigationController
12 | import java.lang.ref.WeakReference
13 | import javax.inject.Inject
14 |
15 | abstract class BaseViewModelFragment : BaseInjectionFragment() {
16 |
17 | @Inject
18 | protected lateinit var vmFactory: ViewModelProvider.Factory
19 |
20 | protected lateinit var viewModel: VM
21 |
22 | private lateinit var navigationController: NavigationController
23 |
24 | abstract fun getModelClass(): Class
25 |
26 | @CallSuper
27 | override fun onCreate(savedInstanceState: Bundle?) {
28 | super.onCreate(savedInstanceState)
29 | this.navigationController = DefaultNavigationController(WeakReference(activity!!))
30 | viewModel = ViewModelProviders.of(this, vmFactory).get(getModelClass())
31 | }
32 |
33 | @CallSuper
34 | override fun onActivityCreated(savedInstanceState: Bundle?) {
35 | super.onActivityCreated(savedInstanceState)
36 | if (viewModel is BaseViewModel) {
37 | (viewModel as BaseViewModel).errorLiveData.observe(this, Observer {
38 | onError(it.e)
39 | })
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/java/com.nstudiosappdev.core.presentation/base/ContentView.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.presentation.base
2 |
3 | interface ContentView {
4 | fun fetchContent()
5 | }
6 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/java/com.nstudiosappdev.core.presentation/entity/ViewEntity.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.presentation.entity
2 |
3 | interface ViewEntity
4 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/java/com.nstudiosappdev.core.presentation/entity/ViewEntityMapper.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.presentation.entity
2 |
3 | interface ViewEntityMapper {
4 | fun map(value: R): T
5 | }
6 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/java/com.nstudiosappdev.core.presentation/enums/DialogType.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.presentation.enums
2 |
3 | enum class DialogType {
4 | WARNING, ERROR, INPUT, INFO
5 | }
6 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/java/com.nstudiosappdev.core.presentation/extensions/AlertDialogExt.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.presentation.extensions
2 |
3 | import android.content.Context
4 | import androidx.appcompat.app.AlertDialog
5 | import com.nstudiosappdev.core.presentation.enums.DialogType
6 | import com.nstudiosappdev.core.presentation.widget.CustomAlertDialog
7 |
8 | /*
9 | * Creates custom alert dialog
10 | */
11 | fun Context.createCustomAlertDialog(
12 | title: CharSequence? = null,
13 | message: CharSequence? = null,
14 | positiveButtonText: CharSequence? = null,
15 | negativeButtonText: CharSequence? = null,
16 | positiveButtonAction: (() -> Unit)? = null,
17 | negativeButtonAction: (() -> Unit)? = null,
18 | alertType: DialogType? = DialogType.WARNING,
19 | isAllCaps: Boolean = false
20 | ): AlertDialog = createCustomAlertDialogBuilder(
21 | title,
22 | message,
23 | positiveButtonText,
24 | negativeButtonText,
25 | positiveButtonAction,
26 | negativeButtonAction,
27 | alertType,
28 | isAllCaps
29 | ).create()
30 |
31 | /*
32 | * Creates custom alert dialog builder
33 | */
34 | fun Context.createCustomAlertDialogBuilder(
35 | title: CharSequence? = null,
36 | message: CharSequence? = null,
37 | positiveButtonText: CharSequence? = null,
38 | negativeButtonText: CharSequence? = null,
39 | positiveButtonAction: (() -> Unit)? = null,
40 | negativeButtonAction: (() -> Unit)? = null,
41 | alertType: DialogType? = DialogType.WARNING,
42 | isAllCaps: Boolean = false
43 | ): CustomAlertDialog {
44 | return CustomAlertDialog(this).apply {
45 |
46 | setIsAllCaps(isAllCaps)
47 |
48 | title?.let {
49 | setTitle(title)
50 | }
51 | message?.let {
52 | setMessage(message)
53 | }
54 |
55 | positiveButtonText?.let {
56 | setPositiveCustomButton(positiveButtonText) {
57 | positiveButtonAction?.invoke()
58 | }
59 | }
60 |
61 | negativeButtonText?.let {
62 | setNegativeCustomButton(negativeButtonText) {
63 | negativeButtonAction?.invoke()
64 | }
65 | }
66 | alertType?.let {
67 | setAlertType(alertType)
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/java/com.nstudiosappdev.core.presentation/extensions/ContextExt.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.presentation.extensions
2 |
3 | import android.content.Context
4 | import android.net.ConnectivityManager
5 | import android.widget.Toast
6 |
7 | fun Context.alert(message: String, length: Int = Toast.LENGTH_SHORT) =
8 | Toast.makeText(this, message, length).show()
9 |
10 | fun Context.isWifiConnected(): Boolean {
11 | val connManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
12 | val mWifi = connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI)
13 | return mWifi.isConnected
14 | }
15 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/java/com.nstudiosappdev.core.presentation/extensions/FragmentManagerExt.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.presentation.extensions
2 |
3 | import androidx.fragment.app.FragmentManager
4 | import androidx.fragment.app.FragmentTransaction
5 |
6 | inline fun FragmentManager.transact(func: FragmentTransaction.() -> FragmentTransaction) {
7 | beginTransaction().func().commit()
8 | }
9 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/java/com.nstudiosappdev.core.presentation/extensions/RecyclerViewExt.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.presentation.extensions
2 |
3 | import android.annotation.SuppressLint
4 | import android.content.Context
5 | import androidx.recyclerview.widget.LinearLayoutManager
6 | import androidx.recyclerview.widget.RecyclerView
7 | import com.nstudiosappdev.core.presentation.recyclerview.RecyclerViewAdapter
8 |
9 | /*
10 | * Setups RecyclerView with Default parameters
11 | */
12 | @SuppressLint("WrongConstant")
13 | fun RecyclerView.setup(
14 | context: Context,
15 | orientation: Int = LinearLayoutManager.VERTICAL,
16 | adapter: RecyclerViewAdapter?
17 | ) {
18 | val layoutManager = LinearLayoutManager(context)
19 | layoutManager.orientation = orientation
20 | this.layoutManager = layoutManager
21 | this.setHasFixedSize(false)
22 | adapter?.let {
23 | this.adapter = adapter
24 | }
25 | }
26 |
27 | /*
28 | * Scrolls to bottom if can
29 | */
30 | fun RecyclerView.scrollToBottom() {
31 | if (adapter != null && adapter!!.itemCount > 0) {
32 | scrollToPosition(adapter!!.itemCount - 1)
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/java/com.nstudiosappdev.core.presentation/extensions/StringExt.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.presentation.extensions
2 |
3 | import java.util.*
4 |
5 | fun String.adjustSensitivityGiveString(sensitivity: Int): String {
6 | return String.format(Locale.US, "%.${sensitivity}f", this.replace(",", ".").toFloat())
7 | }
8 |
9 | fun String.adjustSensitivityGiveFloat(sensitivity: Int): Float {
10 | return String.format(Locale.US, "%.${sensitivity}f", this.replace(",", ".").toFloat()).toFloat()
11 | }
12 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/java/com.nstudiosappdev.core.presentation/factory/DefaultIntentFactory.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.presentation.factory
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 | import java.lang.ref.WeakReference
6 |
7 | class DefaultIntentFactory(override val context: WeakReference) :
8 | IntentFactory {
9 |
10 | override fun createShareIntent(packageName: String): Intent? =
11 | Intent(Intent.ACTION_SEND).apply {
12 | type = "text/plain"
13 | putExtra(
14 | Intent.EXTRA_TEXT,
15 | "https://play.google.com/store/apps/details?id=$packageName"
16 | )
17 | }
18 |
19 | override fun createShareTextIntent(shareBody: String, title: String): Intent {
20 | return Intent(Intent.ACTION_SEND)
21 | .apply {
22 | type = "text/plain"
23 | putExtra(Intent.EXTRA_TEXT, shareBody)
24 | }.also {
25 | Intent.createChooser(it, title)
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/java/com.nstudiosappdev.core.presentation/factory/IntentFactory.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.presentation.factory
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 | import java.lang.ref.WeakReference
6 |
7 | interface IntentFactory {
8 |
9 | val context: WeakReference
10 |
11 | fun createShareIntent(packageName: String): Intent?
12 |
13 | fun createShareTextIntent(shareBody: String, title: String): Intent
14 | }
15 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/java/com.nstudiosappdev.core.presentation/livedata/LiveDataExt.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.presentation.livedata
2 |
3 | import androidx.lifecycle.LifecycleOwner
4 | import androidx.lifecycle.LiveData
5 | import androidx.lifecycle.Observer
6 | import com.nstudiosappdev.core.model.DataHolder
7 | import com.nstudiosappdev.core.presentation.base.BaseView
8 |
9 | inline fun LiveData>.observeApi(
10 | lifecycleOwner: LifecycleOwner,
11 | crossinline body: (DataHolder?) -> Unit
12 | ) {
13 | observe(lifecycleOwner, Observer { bean: DataHolder? ->
14 | if (bean is DataHolder.Fail) {
15 | if (lifecycleOwner is BaseView) {
16 | lifecycleOwner.onError(bean.e)
17 | }
18 | }
19 | body(bean)
20 | })
21 | }
22 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/java/com.nstudiosappdev.core.presentation/livedata/SingleLiveData.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.presentation.livedata
2 |
3 | import androidx.annotation.MainThread
4 | import androidx.lifecycle.LifecycleOwner
5 | import androidx.lifecycle.MutableLiveData
6 | import androidx.lifecycle.Observer
7 | import java.util.concurrent.atomic.AtomicBoolean
8 |
9 | class SingleLiveData : MutableLiveData() {
10 |
11 | private val pending = AtomicBoolean(false)
12 |
13 | @MainThread
14 | override fun observe(owner: LifecycleOwner, observer: Observer) {
15 | super.observe(owner, Observer { t ->
16 | if (pending.compareAndSet(true, false)) {
17 | observer.onChanged(t)
18 | }
19 | })
20 | }
21 |
22 | @MainThread
23 | override fun setValue(value: T) {
24 | pending.set(true)
25 | super.setValue(value)
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/java/com.nstudiosappdev.core.presentation/navigation/UiNavigation.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.presentation.navigation
2 |
3 | enum class UiNavigation {
4 | BACK,
5 | ROOT,
6 | NONE
7 | }
8 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/java/com.nstudiosappdev.core.presentation/recyclerview/DefaultDisplayItemComparator.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.presentation.recyclerview
2 |
3 | class DefaultDisplayItemComparator : DisplayItemComparator {
4 |
5 | override fun areItemsSame(oldItem: DisplayItem, newItem: DisplayItem): Boolean {
6 | return oldItem == newItem
7 | }
8 |
9 | override fun areContentsSame(oldItem: DisplayItem, newItem: DisplayItem): Boolean {
10 | return oldItem == newItem
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/java/com.nstudiosappdev.core.presentation/recyclerview/DiffAdapter.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Contains adapter operations which implements DiffUtil
3 | */
4 | package com.nstudiosappdev.core.presentation.recyclerview
5 |
6 | import androidx.recyclerview.widget.DiffUtil
7 |
8 | interface DiffAdapter {
9 | fun update(newItems: List)
10 |
11 | fun updateAllItems(newItems: List)
12 |
13 | fun updateDiffItemsOnly(newItems: List)
14 |
15 | fun updateItems(newItems: List)
16 |
17 | fun calculateDiff(newItems: List): DiffUtil.DiffResult
18 |
19 | fun updateWithOnlyDiffResult(result: DiffUtil.DiffResult)
20 | }
21 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/java/com.nstudiosappdev.core.presentation/recyclerview/DiffUtilImpl.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Default DiffUtilCallback implementation
3 | */
4 |
5 | package com.nstudiosappdev.core.presentation.recyclerview
6 |
7 | import androidx.recyclerview.widget.DiffUtil
8 |
9 | class DiffUtilImpl(
10 | private val oldItems: List,
11 | private val newItems: List,
12 | private val comparator: DisplayItemComparator
13 | ) : DiffUtil.Callback() {
14 |
15 | override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int) =
16 | comparator.areItemsSame(oldItems[oldItemPosition], newItems[newItemPosition])
17 |
18 | override fun getOldListSize() = oldItems.size
19 |
20 | override fun getNewListSize() = newItems.size
21 |
22 | override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int) =
23 | comparator.areContentsSame(oldItems[oldItemPosition], newItems[newItemPosition])
24 | }
25 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/java/com.nstudiosappdev.core.presentation/recyclerview/DisplayItem.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Ui Objects which'll be shown with Common RecyclerView Adapter must implement this interface.
3 | * Type represents item typeç
4 | * Model is base model of object.
5 | */
6 | package com.nstudiosappdev.core.presentation.recyclerview
7 |
8 | interface DisplayItem {
9 | fun type(): Int
10 | }
11 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/java/com.nstudiosappdev.core.presentation/recyclerview/DisplayItemComparator.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Compares display items
3 | */
4 |
5 | package com.nstudiosappdev.core.presentation.recyclerview
6 |
7 | interface DisplayItemComparator {
8 | fun areItemsSame(oldItem: DisplayItem, newItem: DisplayItem): Boolean
9 |
10 | fun areContentsSame(oldItem: DisplayItem, newItem: DisplayItem): Boolean
11 | }
12 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/java/com.nstudiosappdev.core.presentation/recyclerview/DisplayItemListMapper.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.presentation.recyclerview
2 |
3 | interface DisplayItemListMapper {
4 | fun map(items: List): List
5 | }
6 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/java/com.nstudiosappdev.core.presentation/recyclerview/SelectableItem.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.presentation.recyclerview
2 |
3 | interface SelectableItem {
4 | var isSelected: Boolean
5 | }
6 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/java/com.nstudiosappdev.core.presentation/recyclerview/SelectionAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.presentation.recyclerview
2 |
3 | interface SelectionAdapter {
4 | fun select(pos: Int)
5 | fun clear()
6 | fun getSelectedItemCount(): Int
7 | fun getSelectedItems(): List
8 | }
9 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/java/com.nstudiosappdev.core.presentation/recyclerview/ViewHolder.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.presentation.recyclerview
2 |
3 | import android.view.View
4 | import androidx.recyclerview.widget.RecyclerView
5 |
6 | abstract class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
7 | var itemClickListener: ((view: View, item: DisplayItem) -> Unit)? = null
8 | var itemLongClickListener: ((view: View, item: DisplayItem) -> Unit)? = null
9 | }
10 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/java/com.nstudiosappdev.core.presentation/recyclerview/ViewHolderBinder.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Binds ViewHolder and DisplayItem
3 | */
4 |
5 | package com.nstudiosappdev.core.presentation.recyclerview
6 |
7 | import androidx.recyclerview.widget.RecyclerView
8 |
9 | interface ViewHolderBinder {
10 | fun bind(holder: RecyclerView.ViewHolder, item: DisplayItem)
11 | }
12 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/java/com.nstudiosappdev.core.presentation/recyclerview/ViewHolderFactory.kt:
--------------------------------------------------------------------------------
1 | /**
2 | * Creates ViewHolder
3 | */
4 |
5 | package com.nstudiosappdev.core.presentation.recyclerview
6 |
7 | import android.view.ViewGroup
8 | import androidx.recyclerview.widget.RecyclerView
9 |
10 | interface ViewHolderFactory {
11 | fun createViewHolder(parent: ViewGroup): RecyclerView.ViewHolder
12 | }
13 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/java/com.nstudiosappdev.core.presentation/util/PermissionUtil.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.presentation.util
2 |
3 | import android.Manifest.permission.*
4 | import android.content.Context
5 | import android.content.pm.PackageManager
6 | import androidx.core.app.ActivityCompat
7 |
8 | class PermissionUtil {
9 | companion object {
10 | /**
11 | * Permissions
12 | */
13 | val cameraPermissions = arrayOf(CAMERA, WRITE_EXTERNAL_STORAGE)
14 |
15 | val galleryPermissions = arrayOf(READ_EXTERNAL_STORAGE)
16 |
17 | val locationPermissions = arrayOf(ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION)
18 |
19 | val connectionPermissions = arrayOf(ACCESS_WIFI_STATE, ACCESS_NETWORK_STATE)
20 |
21 | val storagePermissions = arrayOf(READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE)
22 |
23 | /**
24 | * Permission check methods
25 | */
26 |
27 | fun isCameraPermissionsGranted(context: Context) =
28 | cameraPermissions.isPermissionsGranted(context)
29 |
30 | fun isGalleryPermissionsGranted(context: Context) =
31 | galleryPermissions.isPermissionsGranted(context)
32 |
33 | fun isLocationPermissionsGranted(context: Context) =
34 | locationPermissions.isPermissionsGranted(context)
35 |
36 | fun isConnectionPermissionsGranted(context: Context) =
37 | connectionPermissions.isPermissionsGranted(context)
38 |
39 | fun isStoragePermissionGranted(context: Context) =
40 | storagePermissions.isPermissionsGranted(context)
41 |
42 | fun isPermissionResultsGranted(grantResult: IntArray) =
43 | grantResult.none { it != PackageManager.PERMISSION_GRANTED }
44 | }
45 | }
46 |
47 | /**
48 | * Permission check extension
49 | */
50 | private fun Array.isPermissionsGranted(context: Context): Boolean {
51 | for (i in this.indices) {
52 | if (ActivityCompat.checkSelfPermission(
53 | context,
54 | this[i]
55 | ) != PackageManager.PERMISSION_GRANTED
56 | ) {
57 | return false
58 | }
59 | }
60 | return true
61 | }
62 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/java/com.nstudiosappdev.core.presentation/viewmodel/BaseViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.presentation.viewmodel
2 |
3 | import androidx.lifecycle.MutableLiveData
4 | import androidx.lifecycle.ViewModel
5 | import com.nstudiosappdev.core.coroutines.CoroutineManager
6 | import com.nstudiosappdev.core.model.DataHolder
7 | import com.nstudiosappdev.core.presentation.livedata.SingleLiveData
8 |
9 | abstract class BaseViewModel constructor(coroutineManager: CoroutineManager) : ViewModel(),
10 | CoroutineManager by coroutineManager {
11 |
12 | private val _errorLiveData = SingleLiveData()
13 |
14 | val errorLiveData: MutableLiveData
15 | get() = _errorLiveData
16 |
17 | override fun onCleared() {
18 | destroy()
19 | super.onCleared()
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/java/com.nstudiosappdev.core.presentation/viewmodel/ViewModelKey.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.presentation.viewmodel
2 |
3 | import androidx.lifecycle.ViewModel
4 | import dagger.MapKey
5 | import kotlin.reflect.KClass
6 |
7 | @Retention(AnnotationRetention.RUNTIME)
8 | @Target(
9 | AnnotationTarget.FUNCTION,
10 | AnnotationTarget.PROPERTY_GETTER,
11 | AnnotationTarget.PROPERTY_SETTER
12 | )
13 | @MapKey
14 | annotation class ViewModelKey(val value: KClass)
15 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/java/com.nstudiosappdev.core.presentation/viewmodel/VmFactory.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.presentation.viewmodel
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.ViewModelProvider
5 | import java.lang.Exception
6 | import javax.inject.Inject
7 | import javax.inject.Provider
8 | import javax.inject.Singleton
9 |
10 | @Suppress("UNCHECKED_CAST")
11 | @Singleton
12 | class VmFactory @Inject constructor(private val creators: Map, @JvmSuppressWildcards Provider>) :
13 | ViewModelProvider.Factory {
14 |
15 | @SuppressWarnings("Unchecked")
16 | override fun create(modelClass: Class): T {
17 | var creator = creators[modelClass]
18 |
19 | if (creator == null) {
20 | for (entry in creators) {
21 | if (modelClass.isAssignableFrom(entry.key)) {
22 | creator = entry.value
23 | break
24 | }
25 | }
26 | }
27 |
28 | requireNotNull(creator) { "Unknown model class$modelClass" }
29 |
30 | try {
31 | return creator.get() as T
32 | } catch (e: Exception) {
33 | throw RuntimeException(e)
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/res/drawable/disable_primary_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/res/drawable/disable_secondary_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/res/drawable/edit_text_underline.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
9 |
10 |
-
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/res/drawable/primary_button_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/res/drawable/ripple_primary_button_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/res/drawable/ripple_primary_button_background_pressed.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/res/drawable/ripple_second_button_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/res/drawable/ripple_second_button_background_pressed.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/res/drawable/secondary_button_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/res/font/roboto_black.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harrunisk/Stocker/dca907383ca09c86c6a81b06820ef7ace3e45a5c/base/core_presentation/src/main/res/font/roboto_black.ttf
--------------------------------------------------------------------------------
/base/core_presentation/src/main/res/font/roboto_bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harrunisk/Stocker/dca907383ca09c86c6a81b06820ef7ace3e45a5c/base/core_presentation/src/main/res/font/roboto_bold.ttf
--------------------------------------------------------------------------------
/base/core_presentation/src/main/res/font/roboto_light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harrunisk/Stocker/dca907383ca09c86c6a81b06820ef7ace3e45a5c/base/core_presentation/src/main/res/font/roboto_light.ttf
--------------------------------------------------------------------------------
/base/core_presentation/src/main/res/font/roboto_medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harrunisk/Stocker/dca907383ca09c86c6a81b06820ef7ace3e45a5c/base/core_presentation/src/main/res/font/roboto_medium.ttf
--------------------------------------------------------------------------------
/base/core_presentation/src/main/res/font/roboto_regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harrunisk/Stocker/dca907383ca09c86c6a81b06820ef7ace3e45a5c/base/core_presentation/src/main/res/font/roboto_regular.ttf
--------------------------------------------------------------------------------
/base/core_presentation/src/main/res/layout/toolbar_default.xml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
19 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/res/values-tr-rTR/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Banka Döviz Kurları
4 | Cache boş.
5 | İşletme Hatası.
6 | Yetki hatası.
7 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/res/values-tr/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Banka Döviz Kurları
4 | Cache boş.
5 | İşletme Hatası.
6 | Yetki hatası.
7 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 8sp
4 | 9sp
5 | 10sp
6 | 12sp
7 | 14sp
8 | 16sp
9 | 22sp
10 | 30sp
11 | 34sp
12 | 5sp
13 |
14 | 4dp
15 | 8dp
16 | 16dp
17 | 24dp
18 | 32dp
19 | 40dp
20 | 48dp
21 | 64dp
22 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Stocker
3 | Empty Cache
4 | Business Error
5 | Your Authentication is fail.
6 |
7 |
--------------------------------------------------------------------------------
/base/core_presentation/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
19 |
20 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/base/core_presentation/src/test/java/com/nstudiosappdev/core/presentation/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.core.presentation;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/base/navigation/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/base/navigation/build.gradle:
--------------------------------------------------------------------------------
1 | apply from: "$rootDir/common-android-library.gradle"
2 |
3 | android {
4 | flavorDimensions Dimensions.default
5 | productFlavors {
6 | prod {
7 | buildConfigField("String", Fields.pName, "\"$Prod.packageName\"")
8 | }
9 |
10 | dev {
11 | buildConfigField("String", Fields.pName, "\"$Dev.packageName\"")
12 | }
13 | }
14 | }
15 |
16 |
17 | dependencies {
18 | implementation SupportLibraries.appCompat
19 | implementation project(Modules.core)
20 | }
21 |
--------------------------------------------------------------------------------
/base/navigation/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/base/navigation/src/androidTest/java/com/nstudiosappdev/stocker/navigation/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.stocker.navigation;
2 |
3 | import android.content.Context;
4 | import androidx.test.InstrumentationRegistry;
5 | import androidx.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.nstudiosappdev.stocker.navigation.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/base/navigation/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/base/navigation/src/main/java/com.nstudiosappdev.navigation/FragmentLoader.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.navigation
2 |
3 | import androidx.fragment.app.Fragment
4 |
5 | internal fun String.loadFragmentOrReturnNull(): Fragment? =
6 | try {
7 | this.loadClassOrReturnNull()?.newInstance()
8 | } catch (e: ClassNotFoundException) {
9 | null
10 | }
11 |
--------------------------------------------------------------------------------
/base/navigation/src/main/java/com.nstudiosappdev.navigation/IntentLoader.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.navigation
2 |
3 | import android.content.Intent
4 | import com.nstudiosappdev.stocker.navigation.BuildConfig
5 |
6 | private fun intentTo(className: String): Intent =
7 | Intent(Intent.ACTION_VIEW).setClassName(BuildConfig.PACKAGE_NAME, className)
8 |
9 | internal fun String.loadIntentOrReturnNull(): Intent? =
10 | try {
11 | Class.forName(this).run { intentTo((this@loadIntentOrReturnNull)) }
12 | } catch (e: ClassNotFoundException) {
13 | null
14 | }
15 |
--------------------------------------------------------------------------------
/base/navigation/src/main/java/com.nstudiosappdev.navigation/Loader.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.navigation
2 |
3 | const val PACKAGE_NAME = "com.nstudiosappdev.stocker"
4 |
5 | private val classMap = mutableMapOf>()
6 |
7 | private inline fun Any.castOrReturnNull() = this as? T
8 |
9 | internal fun String.loadClassOrReturnNull(): Class? =
10 | classMap.getOrPut(this) {
11 | try {
12 | Class.forName(this)
13 | } catch (e: ClassNotFoundException) {
14 | return null
15 | }
16 | }.castOrReturnNull()
17 |
--------------------------------------------------------------------------------
/base/navigation/src/main/java/com.nstudiosappdev.navigation/features/BottomNavigation.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.navigation.features
2 |
3 | import androidx.fragment.app.Fragment
4 | import com.nstudiosappdev.navigation.PACKAGE_NAME
5 | import com.nstudiosappdev.navigation.loadFragmentOrReturnNull
6 |
7 | object BottomNavigation : Feature {
8 | private const val BOTTOM_NAVIGATION =
9 | "$PACKAGE_NAME.dashboard.presentation.bottom.BottomNavigationFragment"
10 |
11 | override val dynamicStart: Fragment?
12 | get() = BOTTOM_NAVIGATION.loadFragmentOrReturnNull()
13 | }
14 |
--------------------------------------------------------------------------------
/base/navigation/src/main/java/com.nstudiosappdev.navigation/features/Currencies.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.navigation.features
2 |
3 | import androidx.fragment.app.Fragment
4 | import com.nstudiosappdev.navigation.PACKAGE_NAME
5 | import com.nstudiosappdev.navigation.loadFragmentOrReturnNull
6 |
7 | object Currencies : Feature {
8 | private const val CURRENCIES =
9 | "$PACKAGE_NAME.dashboard.presentation.liveCurrencies.LiveCurrenciesMainFragment"
10 |
11 | override val dynamicStart: Fragment?
12 | get() = CURRENCIES.loadFragmentOrReturnNull()
13 | }
14 |
--------------------------------------------------------------------------------
/base/navigation/src/main/java/com.nstudiosappdev.navigation/features/Feature.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.navigation.features
2 |
3 | interface Feature {
4 | val dynamicStart: T?
5 | }
6 |
--------------------------------------------------------------------------------
/base/navigation/src/main/java/com.nstudiosappdev.navigation/features/Main.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.navigation.features
2 |
3 | import android.content.Intent
4 | import com.nstudiosappdev.navigation.PACKAGE_NAME
5 | import com.nstudiosappdev.navigation.loadIntentOrReturnNull
6 |
7 | object Main : Feature {
8 | private const val MAIN = "$PACKAGE_NAME.dashboard.presentation.DashboardActivity"
9 |
10 | override val dynamicStart: Intent?
11 | get() = MAIN.loadIntentOrReturnNull()
12 | }
13 |
--------------------------------------------------------------------------------
/base/navigation/src/main/java/com.nstudiosappdev.navigation/features/Portfolio.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.navigation.features
2 |
3 | import androidx.fragment.app.Fragment
4 | import com.nstudiosappdev.navigation.PACKAGE_NAME
5 | import com.nstudiosappdev.navigation.loadFragmentOrReturnNull
6 |
7 | object Portfolio : Feature {
8 | private const val PORTFOLIO =
9 | "$PACKAGE_NAME.dashboard.presentation.portfolio.PortfolioMainFragment"
10 |
11 | override val dynamicStart: Fragment?
12 | get() = PORTFOLIO.loadFragmentOrReturnNull()
13 | }
14 |
--------------------------------------------------------------------------------
/base/navigation/src/main/java/com.nstudiosappdev.navigation/navigation/DefaultNavigationController.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.navigation.navigation
2 |
3 | import androidx.fragment.app.FragmentActivity
4 | import com.nstudiosappdev.navigation.features.BottomNavigation
5 | import com.nstudiosappdev.navigation.features.Currencies
6 | import com.nstudiosappdev.navigation.features.Main
7 | import com.nstudiosappdev.navigation.features.Portfolio
8 | import java.lang.ref.WeakReference
9 |
10 | class DefaultNavigationController constructor(
11 | override val activity: WeakReference
12 | ) : NavigationController {
13 |
14 | override fun navigateToMain() = start(Main.dynamicStart)
15 |
16 | override fun navigateToCurrencies(containerId: Int) =
17 | start(Currencies.dynamicStart,
18 | containerId, transaction = {
19 | replace(containerId, Currencies.dynamicStart!!).addToBackStack(null)
20 | })
21 |
22 | override fun navigateToBottomNavigation(containerId: Int) =
23 | start(BottomNavigation.dynamicStart,
24 | containerId, transaction = {
25 | replace(containerId, BottomNavigation.dynamicStart!!).addToBackStack(null)
26 | })
27 |
28 | override fun navigateToPortfolio(containerId: Int) =
29 | start(Portfolio.dynamicStart,
30 | containerId, transaction = {
31 | replace(containerId, Portfolio.dynamicStart!!).addToBackStack(null)
32 | })
33 | }
34 |
--------------------------------------------------------------------------------
/base/navigation/src/main/java/com.nstudiosappdev.navigation/navigation/NavigationController.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.navigation.navigation
2 |
3 | import android.content.Intent
4 | import androidx.annotation.IdRes
5 | import androidx.fragment.app.Fragment
6 | import androidx.fragment.app.FragmentActivity
7 | import androidx.fragment.app.FragmentTransaction
8 | import java.lang.ref.WeakReference
9 |
10 | interface NavigationController {
11 |
12 | val activity: WeakReference
13 |
14 | fun start(intent: Intent?) {
15 | intent?.let {
16 | activity.get()?.startActivity(it)
17 | }
18 | }
19 |
20 | fun start(
21 | fragment: Fragment?,
22 | @IdRes containerId: Int,
23 | transaction: FragmentTransaction.() -> FragmentTransaction = {
24 | replace(containerId, fragment!!)
25 | }
26 | ) {
27 | fragment?.let {
28 | activity.get()?.supportFragmentManager?.beginTransaction()?.transaction()?.commit()
29 | }
30 | }
31 |
32 | fun navigateToMain()
33 |
34 | fun navigateToCurrencies(@IdRes containerId: Int)
35 |
36 | fun navigateToBottomNavigation(@IdRes containerId: Int)
37 |
38 | fun navigateToPortfolio(@IdRes containerId: Int)
39 | }
40 |
--------------------------------------------------------------------------------
/base/navigation/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | navigation
3 |
4 |
--------------------------------------------------------------------------------
/base/navigation/src/test/java/com/nstudiosappdev/stocker/navigation/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.stocker.navigation;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | buildscript {
3 | ext.kotlin_version = '1.3.50'
4 |
5 | repositories {
6 | google()
7 | jcenter()
8 | maven { url 'https://jitpack.io' }
9 | maven { url 'https://maven.fabric.io/public' }
10 | }
11 | dependencies {
12 | classpath Paths.gradleClasspath
13 | classpath Paths.kotlinGradlePluginClasspath
14 | classpath 'io.fabric.tools:gradle:1.+'
15 |
16 | // NOTE: Do not place your application dependencies here; they belong
17 | // in the individual module build.gradle.kts files
18 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
19 | }
20 | }
21 |
22 | plugins {
23 | id 'io.gitlab.arturbosch.detekt' version '1.0.1'
24 | }
25 |
26 | allprojects {
27 | repositories {
28 | google()
29 | jcenter()
30 | maven { url 'https://jitpack.io' }
31 | maven { url 'https://maven.fabric.io/public' }
32 | }
33 | }
34 |
35 | task clean(type: Delete) {
36 | delete rootProject.buildDir
37 | }
--------------------------------------------------------------------------------
/buildSrc/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | `kotlin-dsl`
3 | }
4 |
5 | repositories {
6 | jcenter()
7 | }
8 |
9 | kotlinDslPluginOptions {
10 | experimentalWarning.set(false)
11 | }
--------------------------------------------------------------------------------
/buildSrc/src/main/java/Config.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * App configuration
3 | */
4 | object Config {
5 | const val applicationId = "com.nstudiosappdev.stocker"
6 | const val minSdkVersion = Versions.minSdkVersion
7 | const val targetSdkVersion = Versions.targetSdkVersion
8 | const val compileSdkVersion = Versions.compileSdkVersion
9 | const val testInstrumentationRunner = "android.support.test.runner.AndroidJUnitRunner"
10 | const val versionCode = 2
11 | const val versionName = "1.0.1"
12 | }
13 |
14 | /*
15 | * Auto generated buildConfig fileds
16 | */
17 | object Fields {
18 | const val rootUrl = "ROOT_URL"
19 | const val pName = "PACKAGE_NAME"
20 | }
21 |
22 | /*
23 | * Flavor Dimensions
24 | */
25 | object Dimensions {
26 | const val default = "default"
27 | }
28 |
29 | /*
30 | * Product Flavors
31 | */
32 | object Prod {
33 | const val versionCode = Config.versionCode
34 | const val versionName = Config.versionName
35 | const val packageName = Config.applicationId
36 |
37 | }
38 |
39 | object Dev {
40 | const val suffix = ".dev"
41 | const val versionCode = Config.versionCode * 10000
42 | const val versionName = Config.versionName
43 | const val versionNameSuffix = suffix
44 | const val applicationIdSuffix = suffix
45 | const val packageName = Config.applicationId + applicationIdSuffix
46 | }
47 |
48 |
--------------------------------------------------------------------------------
/buildSrc/src/main/java/Modules.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * App Modules
3 | */
4 | object Modules {
5 |
6 | private const val BASE_DIRECTORY = ":base"
7 | private const val DASBOARD_DIRECTORY = ":dashboard"
8 |
9 | /*
10 | * App
11 | */
12 | const val app = ":app"
13 |
14 | /*
15 | * Core Modules
16 | */
17 | const val corePresentation = "$BASE_DIRECTORY:core_presentation"
18 | const val coreDomain = "$BASE_DIRECTORY:core_domain"
19 | const val coreData = "$BASE_DIRECTORY:core_data"
20 | const val core = "$BASE_DIRECTORY:core"
21 | const val navigation = "$BASE_DIRECTORY:navigation"
22 |
23 | /*
24 | * Core Modules
25 | */
26 | const val dashboardPresentation = "$DASBOARD_DIRECTORY:dashboard_presentation"
27 | const val dashboardDomain = "$DASBOARD_DIRECTORY:dashboard_domain"
28 | const val dashboardData = "$DASBOARD_DIRECTORY:dashboard_data"
29 | }
--------------------------------------------------------------------------------
/buildSrc/src/main/java/Paths.kt:
--------------------------------------------------------------------------------
1 | /**
2 | * Common Paths
3 | */
4 | object Paths {
5 | val gradleClasspath = "com.android.tools.build:gradle:${Versions.gradleVersion}"
6 | var kotlinGradlePluginClasspath = "org.jetbrains.kotlin:kotlin-gradle-plugin:${Versions.kotlinVersion}"
7 | }
8 |
--------------------------------------------------------------------------------
/buildSrc/src/main/java/Plugins.kt:
--------------------------------------------------------------------------------
1 | /**
2 | * Plugins
3 | */
4 | object Plugins {
5 | const val androidApplication = "com.android.application"
6 | const val androidLibrary = "com.android.library"
7 | const val kotlinAndroid = "kotlin-android"
8 | const val kotlinAndroidExtensions = "kotlin-android-extensions"
9 | const val kotlinKapt = "kotlin-kapt"
10 | const val fabric = "io.fabric"
11 | }
--------------------------------------------------------------------------------
/buildSrc/src/main/java/Versions.kt:
--------------------------------------------------------------------------------
1 | /**
2 | * Sdk and dependency versions
3 | */
4 | object Versions {
5 | /**
6 | * Sdk Versions
7 | */
8 | const val minSdkVersion = 19
9 | const val targetSdkVersion = 28
10 | const val compileSdkVersion = 28
11 |
12 | /**
13 | * Dependency Versions
14 | */
15 | const val xVersion = "1.0.0"
16 | const val gradleVersion = "3.2.1"
17 | const val kotlinVersion = "1.3.31"
18 | const val jUnitVersion = "4.12"
19 | const val testRunnerVersion = "1.1.1"
20 | const val testImplementationVersion = "1.1.1"
21 | const val espressoCoreVersion = "3.1.0"
22 | const val dagger2Version = "2.11"
23 | const val javaxAnnotationVersion = "10.0-b28"
24 | const val coroutinesVersion = "1.0.1"
25 | const val retrofitVersion = "2.5.0"
26 | const val okHttpLoggingInterceptorVersion = "3.8.0"
27 | const val gsonVersion = "2.0.2"
28 | const val okHttpVersion = "4.0.1"
29 | const val retrofitCoroutineAdapterVersion = "0.9.2"
30 | const val viewModelVersion = "2.0.0"
31 | const val roomVersion = "2.1.0-alpha06"
32 | const val supportDesignVersion = "1.1.0-alpha06"
33 | const val picassoVersion = "2.71828"
34 | const val constraintLayoutVersion = "1.1.2"
35 | const val lottieVersion = "3.0.1"
36 | const val fabricVersion = "2.10.1"
37 |
38 | /**
39 | * Static code analysis
40 | **/
41 | const val detekt = "1.0.1"
42 | const val ben_manes = "0.25.0"
43 | const val ktlint = "8.2.0"
44 | }
45 |
46 |
--------------------------------------------------------------------------------
/common-android-library.gradle:
--------------------------------------------------------------------------------
1 | apply from: "$rootDir/ktlint.gradle"
2 | apply from: "$rootDir/detekt.gradle"
3 | apply plugin: Plugins.androidLibrary
4 | apply from: "$rootDir/common.gradle"
--------------------------------------------------------------------------------
/common.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: Plugins.kotlinAndroid
2 | apply plugin: Plugins.kotlinAndroidExtensions
3 | apply plugin: Plugins.kotlinKapt
4 | apply plugin: Plugins.fabric
5 |
6 | android {
7 | compileSdkVersion Config.compileSdkVersion
8 |
9 | defaultConfig {
10 | minSdkVersion Config.minSdkVersion
11 | targetSdkVersion Config.targetSdkVersion
12 | versionCode Config.versionCode
13 | versionName Config.versionName
14 | vectorDrawables.useSupportLibrary = true
15 | multiDexEnabled true
16 | javaCompileOptions {
17 | annotationProcessorOptions {
18 | arguments = ["room.schemaLocation": "$projectDir/schemas".toString()]
19 | }
20 | }
21 | }
22 |
23 | flavorDimensions Dimensions.default
24 | productFlavors {
25 | prod {
26 | versionCode Prod.versionCode
27 | versionName Prod.versionName
28 | }
29 |
30 | dev {
31 | versionCode Dev.versionCode
32 | versionName Dev.versionName
33 | }
34 | }
35 |
36 | buildTypes {
37 | release {
38 | minifyEnabled false
39 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
40 | }
41 |
42 | debug {
43 | debuggable true
44 | }
45 | }
46 |
47 | lintOptions {
48 | abortOnError false
49 | }
50 | }
51 |
52 | dependencies {
53 | implementation CoreLibraries.kotlin
54 | kapt Libraries.dagger2Compiler
55 | kapt Libraries.dagger2AndroidProcessor
56 | kapt Libraries.roomCompiler
57 | testAnnotationProcessor Libraries.dagger2Compiler
58 | compileOnly Libraries.javaxAnnotation
59 |
60 | implementation 'androidx.multidex:multidex:2.0.0'
61 |
62 | implementation(Libraries.fabric) {
63 | transitive = true
64 | }
65 | }
66 |
67 | configurations.all {
68 | resolutionStrategy.eachDependency { DependencyResolveDetails details ->
69 | def requested = details.requested
70 | if (requested.group == 'org.jetbrain.kotlin') {
71 | details.userVersion Version.kotlinVersion
72 | } else if (requested.group == 'com.android.support') {
73 | details.userVersion Versions.appCompatVersion
74 | }
75 | }
76 | }
--------------------------------------------------------------------------------
/dashboard/dashboard_data/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/dashboard/dashboard_data/build.gradle:
--------------------------------------------------------------------------------
1 | apply from: "$rootDir/common-android-library.gradle"
2 | dependencies {
3 | implementation project(Modules.core)
4 | implementation project(Modules.coreData)
5 | implementation project(Modules.dashboardDomain)
6 | }
--------------------------------------------------------------------------------
/dashboard/dashboard_data/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harrunisk/Stocker/dca907383ca09c86c6a81b06820ef7ace3e45a5c/dashboard/dashboard_data/consumer-rules.pro
--------------------------------------------------------------------------------
/dashboard/dashboard_data/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/dashboard/dashboard_data/src/androidTest/java/com/nstudiosappdev/stocker/dashboard/data/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.stocker.dashboard.data
2 |
3 | import androidx.test.ext.junit.runners.AndroidJUnit4
4 | import androidx.test.platform.app.InstrumentationRegistry
5 | import org.junit.Assert.*
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | /**
10 | * Instrumented test, which will execute on an Android device.
11 | *
12 | * See [testing documentation](http://d.android.com/tools/testing).
13 | */
14 | @RunWith(AndroidJUnit4::class)
15 | class ExampleInstrumentedTest {
16 | @Test
17 | fun useAppContext() {
18 | // Context of the app under test.
19 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
20 | assertEquals("com.nstudiosappdev.stocker.dashboard.data.test", appContext.packageName)
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/dashboard/dashboard_data/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/dashboard/dashboard_data/src/main/java/com/nstudiosappdev/stocker/dashboard/data/CurrenciesDbEntityMapper.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.stocker.dashboard.data
2 |
3 | import com.nstudiosappdev.core.data.db.entity.CurrenciesEntity
4 | import com.nstudiosappdev.core.data.db.entity.DbEntityMapper
5 | import com.nstudiosappdev.stocker.dashboard.domain.Currency
6 |
7 | class CurrenciesDbEntityMapper : DbEntityMapper {
8 |
9 | override fun map(domainObject: Currency): CurrenciesEntity {
10 | return CurrenciesEntity(
11 | bankName = domainObject.bankName!!,
12 | buyPrice = domainObject.buyPrice,
13 | buyStatus = domainObject.buyStatus,
14 | sellPrice = domainObject.sellPrice,
15 | sellStatus = domainObject.sellStatus,
16 | currencyType = domainObject.currencyType!!,
17 | createDate = null,
18 | updateDate = null
19 | )
20 | }
21 |
22 | override fun map(entity: CurrenciesEntity): Currency {
23 | return Currency(
24 | bankName = entity.bankName,
25 | buyPrice = entity.buyPrice,
26 | buyStatus = entity.buyStatus,
27 | sellPrice = entity.sellPrice,
28 | sellStatus = entity.sellStatus,
29 | currencyType = entity.currencyType
30 | )
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/dashboard/dashboard_data/src/main/java/com/nstudiosappdev/stocker/dashboard/data/CurrenciesRemoteDataSource.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.stocker.dashboard.data
2 |
3 | import com.nstudiosappdev.core.data.adapter.ApiCallAdapter
4 | import com.nstudiosappdev.core.data.datasource.DataSource
5 | import com.nstudiosappdev.core.error.ErrorFactory
6 | import com.nstudiosappdev.core.model.DataHolder
7 | import com.nstudiosappdev.stocker.dashboard.domain.CurrenciesRequest
8 | import com.nstudiosappdev.stocker.dashboard.domain.Currency
9 | import java.lang.IllegalArgumentException
10 | import javax.inject.Inject
11 |
12 | class CurrenciesRemoteDataSource @Inject constructor(
13 | private val currenciesServices: CurrenciesServices,
14 | private val errorFactory: ErrorFactory
15 | ) : DataSource.RemoteDataSource.RequestDataSource> {
16 | override suspend fun getResult(request: CurrenciesRequest): DataHolder> {
17 | val callAdapter = ApiCallAdapter>(errorFactory)
18 | return when (request.currencyType) {
19 | USD -> callAdapter.adapt(currenciesServices.getUsdCurrencies())
20 | EURO -> callAdapter.adapt(currenciesServices.getEuroCurrencies())
21 | GOLD -> callAdapter.adapt(currenciesServices.getGoldCurrencies())
22 | else -> throw IllegalArgumentException("Unknown position!")
23 | }
24 | }
25 |
26 | companion object {
27 | private const val USD = "usd"
28 | private const val EURO = "euro"
29 | private const val GOLD = "gold"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/dashboard/dashboard_data/src/main/java/com/nstudiosappdev/stocker/dashboard/data/CurrenciesRepositoryImpl.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.stocker.dashboard.data
2 |
3 | import com.nstudiosappdev.core.coroutines.AsyncManager
4 | import com.nstudiosappdev.core.data.datasource.BaseDataSource
5 | import com.nstudiosappdev.core.data.datasource.DataSource
6 | import com.nstudiosappdev.core.model.DataHolder
7 | import com.nstudiosappdev.stocker.dashboard.domain.CurrenciesRepository
8 | import com.nstudiosappdev.stocker.dashboard.domain.CurrenciesRequest
9 | import com.nstudiosappdev.stocker.dashboard.domain.Currency
10 | import javax.inject.Inject
11 | import kotlinx.coroutines.Deferred
12 |
13 | class CurrenciesRepositoryImpl @Inject constructor(
14 | private val currenciesRemoteDataSource: DataSource.RemoteDataSource.RequestDataSource>,
15 | private val currenciesLocalDataSource: DataSource.LocalDataSource,
16 | asyncManager: AsyncManager
17 | ) : BaseDataSource(asyncManager), CurrenciesRepository {
18 |
19 | override suspend fun getCurrencies(currenciesRequest: CurrenciesRequest): Deferred>> =
20 | handleAsync {
21 | val result = currenciesRemoteDataSource.getResult(currenciesRequest)
22 | result
23 | }
24 |
25 | override suspend fun getSavedCurrency(
26 | bankName: String,
27 | currencyType: String
28 | ): Deferred> = handleAsync {
29 | val result = currenciesLocalDataSource.get(bankName, currencyType)
30 | return@handleAsync DataHolder.Success(result)
31 | }
32 |
33 | override suspend fun getSavedCurrencies(currencyType: String): Deferred>> =
34 | handleAsync {
35 | val result = currenciesLocalDataSource.get(currencyType)
36 | return@handleAsync DataHolder.Success(result)
37 | }
38 |
39 | override suspend fun saveCurrency(
40 | currency: Currency
41 | ): Deferred> = handleAsync {
42 | val result = currenciesLocalDataSource.put(null, currency)
43 | return@handleAsync DataHolder.Success(result)
44 | }
45 |
46 | override suspend fun deleteCurrency(
47 | bankName: String,
48 | currencyType: String
49 | ): Deferred> = handleAsync {
50 | val result = currenciesLocalDataSource.remove(bankName, currencyType)
51 | return@handleAsync DataHolder.Success(result)
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/dashboard/dashboard_data/src/main/java/com/nstudiosappdev/stocker/dashboard/data/CurrenciesServices.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.stocker.dashboard.data
2 |
3 | import com.nstudiosappdev.core.data.api.response.ApiResponse
4 | import com.nstudiosappdev.stocker.dashboard.domain.Currency
5 | import kotlinx.coroutines.Deferred
6 | import retrofit2.http.GET
7 |
8 | interface CurrenciesServices {
9 |
10 | @GET("${END_POINT}$USD")
11 | fun getUsdCurrencies(): Deferred?>>
12 |
13 | @GET("${END_POINT}$EURO")
14 | fun getEuroCurrencies(): Deferred?>>
15 |
16 | @GET("${END_POINT}$GOLD")
17 | fun getGoldCurrencies(): Deferred?>>
18 |
19 | companion object {
20 | const val END_POINT = "http://138.68.103.38:3000/currency_type="
21 | const val USD = "usd"
22 | const val EURO = "euro"
23 | const val GOLD = "gold"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/dashboard/dashboard_data/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | dashboard_data
3 |
4 |
--------------------------------------------------------------------------------
/dashboard/dashboard_data/src/test/java/com/nstudiosappdev/stocker/dashboard/data/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.stocker.dashboard.data
2 |
3 | import org.junit.Assert.*
4 | import org.junit.Test
5 |
6 | /**
7 | * Example local unit test, which will execute on the development machine (host).
8 | *
9 | * See [testing documentation](http://d.android.com/tools/testing).
10 | */
11 | class ExampleUnitTest {
12 | @Test
13 | fun addition_isCorrect() {
14 | assertEquals(4, 2 + 2)
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/dashboard/dashboard_domain/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/dashboard/dashboard_domain/build.gradle:
--------------------------------------------------------------------------------
1 | apply from: "$rootDir/common-android-library.gradle"
2 | dependencies {
3 | api project(Modules.coreDomain)
4 | }
--------------------------------------------------------------------------------
/dashboard/dashboard_domain/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harrunisk/Stocker/dca907383ca09c86c6a81b06820ef7ace3e45a5c/dashboard/dashboard_domain/consumer-rules.pro
--------------------------------------------------------------------------------
/dashboard/dashboard_domain/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/dashboard/dashboard_domain/src/androidTest/java/com/nstudiosappdev/stocker/dashboard/domain/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.stocker.dashboard.domain
2 |
3 | import androidx.test.ext.junit.runners.AndroidJUnit4
4 | import androidx.test.platform.app.InstrumentationRegistry
5 | import org.junit.Assert.*
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | /**
10 | * Instrumented test, which will execute on an Android device.
11 | *
12 | * See [testing documentation](http://d.android.com/tools/testing).
13 | */
14 | @RunWith(AndroidJUnit4::class)
15 | class ExampleInstrumentedTest {
16 | @Test
17 | fun useAppContext() {
18 | // Context of the app under test.
19 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
20 | assertEquals("com.nstudiosappdev.stocker.dashboard.domain.test", appContext.packageName)
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/dashboard/dashboard_domain/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/dashboard/dashboard_domain/src/main/java/com/nstudiosappdev/stocker/dashboard/domain/CurrenciesRepository.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.stocker.dashboard.domain
2 |
3 | import com.nstudiosappdev.core.model.DataHolder
4 | import kotlinx.coroutines.Deferred
5 |
6 | interface CurrenciesRepository {
7 | suspend fun getCurrencies(currenciesRequest: CurrenciesRequest): Deferred>>
8 |
9 | suspend fun getSavedCurrency(
10 | bankName: String,
11 | currencyType: String
12 | ): Deferred>
13 |
14 | suspend fun getSavedCurrencies(currencyType: String): Deferred>>
15 |
16 | suspend fun saveCurrency(currency: Currency): Deferred>
17 |
18 | suspend fun deleteCurrency(
19 | bankName: String,
20 | currencyType: String
21 | ): Deferred>
22 | }
23 |
--------------------------------------------------------------------------------
/dashboard/dashboard_domain/src/main/java/com/nstudiosappdev/stocker/dashboard/domain/CurrenciesRequest.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.stocker.dashboard.domain
2 |
3 | import com.google.gson.annotations.SerializedName
4 |
5 | data class CurrenciesRequest(
6 | @SerializedName("currencyType") val currencyType: String
7 | )
8 |
--------------------------------------------------------------------------------
/dashboard/dashboard_domain/src/main/java/com/nstudiosappdev/stocker/dashboard/domain/Currency.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.stocker.dashboard.domain
2 |
3 | import com.google.gson.annotations.SerializedName
4 |
5 | data class Currency(
6 | @SerializedName("bankName") val bankName: String?,
7 | @SerializedName("buyPrice") val buyPrice: String?,
8 | @SerializedName("buyStatus") val buyStatus: String?,
9 | @SerializedName("sellPrice") val sellPrice: String?,
10 | @SerializedName("sellStatus") val sellStatus: String?,
11 | @SerializedName("currencyType") val currencyType: String?
12 | )
13 |
--------------------------------------------------------------------------------
/dashboard/dashboard_domain/src/main/java/com/nstudiosappdev/stocker/dashboard/domain/CurrencyStatus.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.stocker.dashboard.domain
2 |
3 | enum class CurrencyStatus(val value: String) {
4 | INCREASING("↑"),
5 | DECREASING("↓"),
6 | STABLE("=")
7 | }
8 |
--------------------------------------------------------------------------------
/dashboard/dashboard_domain/src/main/java/com/nstudiosappdev/stocker/dashboard/domain/DeleteCurrencyInteractor.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.stocker.dashboard.domain
2 |
3 | import com.nstudiosappdev.core.coroutines.AsyncManager
4 | import com.nstudiosappdev.core.domain.BaseInteractor
5 | import com.nstudiosappdev.core.domain.Interactor
6 | import com.nstudiosappdev.core.error.ErrorFactory
7 | import com.nstudiosappdev.core.injection.modules.CoroutineManagerModule
8 | import com.nstudiosappdev.core.model.DataHolder
9 | import javax.inject.Inject
10 | import javax.inject.Named
11 | import kotlinx.coroutines.Deferred
12 |
13 | class DeleteCurrencyInteractor @Inject constructor(
14 | private val currenciesRepository: CurrenciesRepository,
15 | private val errorFactory: ErrorFactory,
16 | @Named(CoroutineManagerModule.AM_NAME_INTERACTOR) asyncManager: AsyncManager
17 | ) : BaseInteractor(asyncManager),
18 | Interactor.DeferredInteractor {
19 |
20 | override suspend fun executeAsync(postParams: Params): Deferred> =
21 | handleAsync {
22 |
23 | return@handleAsync when (val response = currenciesRepository.deleteCurrency(
24 | postParams.bankName,
25 | postParams.currencyType
26 | ).await()) {
27 | is DataHolder.Success -> DataHolder.Success(response.data)
28 | else -> DataHolder.Fail(errorFactory.createUnknownError())
29 | }
30 | }
31 |
32 | class Params(
33 | val bankName: String,
34 | val currencyType: String
35 | ) : Interactor.Params()
36 | }
37 |
--------------------------------------------------------------------------------
/dashboard/dashboard_domain/src/main/java/com/nstudiosappdev/stocker/dashboard/domain/GetCurrenciesInteractor.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.stocker.dashboard.domain
2 |
3 | import com.nstudiosappdev.core.coroutines.AsyncManager
4 | import com.nstudiosappdev.core.domain.BaseInteractor
5 | import com.nstudiosappdev.core.domain.Interactor
6 | import com.nstudiosappdev.core.error.ErrorFactory
7 | import com.nstudiosappdev.core.injection.modules.CoroutineManagerModule
8 | import com.nstudiosappdev.core.model.DataHolder
9 | import javax.inject.Inject
10 | import javax.inject.Named
11 | import kotlinx.coroutines.Deferred
12 |
13 | class GetCurrenciesInteractor @Inject constructor(
14 | private val currenciesRepository: CurrenciesRepository,
15 | private val errorFactory: ErrorFactory,
16 | @Named(CoroutineManagerModule.AM_NAME_INTERACTOR) asyncManager: AsyncManager
17 | ) : BaseInteractor(asyncManager),
18 | Interactor.DeferredInteractor> {
19 |
20 | override suspend fun executeAsync(postParams: Params): Deferred>> =
21 | handleAsync {
22 | return@handleAsync when (val response = currenciesRepository.getCurrencies(
23 | CurrenciesRequest(
24 | currencyType = postParams.currencyType
25 | )
26 | ).await()) {
27 | is DataHolder.Success -> DataHolder.Success(response.data)
28 | else -> DataHolder.Fail(errorFactory.createUnknownError())
29 | }
30 | }
31 |
32 | class Params(
33 | val currencyType: String
34 | ) : Interactor.Params()
35 | }
36 |
--------------------------------------------------------------------------------
/dashboard/dashboard_domain/src/main/java/com/nstudiosappdev/stocker/dashboard/domain/GetSavedCurrenciesInteractor.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.stocker.dashboard.domain
2 |
3 | import com.nstudiosappdev.core.coroutines.AsyncManager
4 | import com.nstudiosappdev.core.domain.BaseInteractor
5 | import com.nstudiosappdev.core.domain.Interactor
6 | import com.nstudiosappdev.core.error.ErrorFactory
7 | import com.nstudiosappdev.core.injection.modules.CoroutineManagerModule
8 | import com.nstudiosappdev.core.model.DataHolder
9 | import javax.inject.Inject
10 | import javax.inject.Named
11 | import kotlinx.coroutines.Deferred
12 |
13 | class GetSavedCurrenciesInteractor @Inject constructor(
14 | private val currenciesRepository: CurrenciesRepository,
15 | private val errorFactory: ErrorFactory,
16 | @Named(CoroutineManagerModule.AM_NAME_INTERACTOR) asyncManager: AsyncManager
17 | ) : BaseInteractor(asyncManager),
18 | Interactor.DeferredInteractor> {
19 |
20 | override suspend fun executeAsync(postParams: Params): Deferred>> =
21 | handleAsync {
22 | return@handleAsync when (val response = currenciesRepository.getSavedCurrencies(
23 | postParams.currencyType
24 | ).await()) {
25 | is DataHolder.Success -> DataHolder.Success(response.data)
26 | else -> DataHolder.Fail(errorFactory.createUnknownError())
27 | }
28 | }
29 |
30 | class Params(
31 | val currencyType: String
32 | ) : Interactor.Params()
33 | }
34 |
--------------------------------------------------------------------------------
/dashboard/dashboard_domain/src/main/java/com/nstudiosappdev/stocker/dashboard/domain/GetSavedCurrencyInteractor.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.stocker.dashboard.domain
2 |
3 | import com.nstudiosappdev.core.coroutines.AsyncManager
4 | import com.nstudiosappdev.core.domain.BaseInteractor
5 | import com.nstudiosappdev.core.domain.Interactor
6 | import com.nstudiosappdev.core.error.ErrorFactory
7 | import com.nstudiosappdev.core.injection.modules.CoroutineManagerModule
8 | import com.nstudiosappdev.core.model.DataHolder
9 | import javax.inject.Inject
10 | import javax.inject.Named
11 | import kotlinx.coroutines.Deferred
12 |
13 | class GetSavedCurrencyInteractor @Inject constructor(
14 | private val currenciesRepository: CurrenciesRepository,
15 | private val errorFactory: ErrorFactory,
16 | @Named(CoroutineManagerModule.AM_NAME_INTERACTOR) asyncManager: AsyncManager
17 | ) : BaseInteractor(asyncManager),
18 | Interactor.DeferredInteractor {
19 |
20 | override suspend fun executeAsync(postParams: Params): Deferred> =
21 | handleAsync {
22 | return@handleAsync when (val response = currenciesRepository.getSavedCurrency(
23 | postParams.bankName,
24 | postParams.currencyType
25 | ).await()) {
26 | is DataHolder.Success -> DataHolder.Success(response.data)
27 | else -> DataHolder.Fail(errorFactory.createUnknownError())
28 | }
29 | }
30 |
31 | class Params(
32 | val bankName: String,
33 | val currencyType: String
34 | ) : Interactor.Params()
35 | }
36 |
--------------------------------------------------------------------------------
/dashboard/dashboard_domain/src/main/java/com/nstudiosappdev/stocker/dashboard/domain/SaveCurrencyInteractor.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.stocker.dashboard.domain
2 |
3 | import com.nstudiosappdev.core.coroutines.AsyncManager
4 | import com.nstudiosappdev.core.domain.BaseInteractor
5 | import com.nstudiosappdev.core.domain.Interactor
6 | import com.nstudiosappdev.core.error.ErrorFactory
7 | import com.nstudiosappdev.core.injection.modules.CoroutineManagerModule
8 | import com.nstudiosappdev.core.model.DataHolder
9 | import javax.inject.Inject
10 | import javax.inject.Named
11 | import kotlinx.coroutines.Deferred
12 |
13 | class SaveCurrencyInteractor @Inject constructor(
14 | private val currenciesRepository: CurrenciesRepository,
15 | private val errorFactory: ErrorFactory,
16 | @Named(CoroutineManagerModule.AM_NAME_INTERACTOR) asyncManager: AsyncManager
17 | ) : BaseInteractor(asyncManager),
18 | Interactor.DeferredInteractor {
19 | override suspend fun executeAsync(postParams: Params): Deferred> =
20 | handleAsync {
21 | val currency = Currency(
22 | bankName = postParams.currency.bankName,
23 | buyPrice = postParams.currency.buyPrice,
24 | buyStatus = postParams.currency.buyStatus,
25 | sellPrice = postParams.currency.sellPrice,
26 | sellStatus = postParams.currency.sellStatus,
27 | currencyType = postParams.currency.currencyType
28 | )
29 | return@handleAsync when (val response = currenciesRepository.saveCurrency(
30 | currency
31 | ).await()) {
32 | is DataHolder.Success -> DataHolder.Success(response.data)
33 | else -> DataHolder.Fail(errorFactory.createUnknownError())
34 | }
35 | }
36 |
37 | class Params(
38 | val currency: Currency
39 | ) : Interactor.Params()
40 | }
41 |
--------------------------------------------------------------------------------
/dashboard/dashboard_domain/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | dashboard_domain
3 |
4 |
--------------------------------------------------------------------------------
/dashboard/dashboard_domain/src/test/java/com/nstudiosappdev/stocker/dashboard/domain/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.stocker.dashboard.domain
2 |
3 | import org.junit.Assert.*
4 | import org.junit.Test
5 |
6 | /**
7 | * Example local unit test, which will execute on the development machine (host).
8 | *
9 | * See [testing documentation](http://d.android.com/tools/testing).
10 | */
11 | class ExampleUnitTest {
12 | @Test
13 | fun addition_isCorrect() {
14 | assertEquals(4, 2 + 2)
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/dashboard/dashboard_presentation/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/dashboard/dashboard_presentation/build.gradle:
--------------------------------------------------------------------------------
1 | apply from: "$rootDir/common-android-library.gradle"
2 | dependencies {
3 | implementation project(Modules.corePresentation)
4 | implementation project(Modules.dashboardDomain)
5 | }
--------------------------------------------------------------------------------
/dashboard/dashboard_presentation/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harrunisk/Stocker/dca907383ca09c86c6a81b06820ef7ace3e45a5c/dashboard/dashboard_presentation/consumer-rules.pro
--------------------------------------------------------------------------------
/dashboard/dashboard_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.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/dashboard/dashboard_presentation/src/androidTest/java/com/nstudiosappdev/stocker/presentation/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.stocker.presentation
2 |
3 | import androidx.test.ext.junit.runners.AndroidJUnit4
4 | import androidx.test.platform.app.InstrumentationRegistry
5 | import org.junit.Assert.*
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | /**
10 | * Instrumented test, which will execute on an Android device.
11 | *
12 | * See [testing documentation](http://d.android.com/tools/testing).
13 | */
14 | @RunWith(AndroidJUnit4::class)
15 | class ExampleInstrumentedTest {
16 | @Test
17 | fun useAppContext() {
18 | // Context of the app under test.
19 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
20 | assertEquals(
21 | "com.nstudiosappdev.stocker.dashboard_presentation.test",
22 | appContext.packageName
23 | )
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/dashboard/dashboard_presentation/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/dashboard/dashboard_presentation/src/main/java/com/nstudiosappdev/stocker/dashboard/presentation/CurrenciesListMapper.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.stocker.dashboard.presentation
2 |
3 | import com.nstudiosappdev.core.presentation.entity.ViewEntityMapper
4 | import com.nstudiosappdev.core.presentation.recyclerview.DisplayItem
5 | import com.nstudiosappdev.core.presentation.recyclerview.DisplayItemListMapper
6 | import com.nstudiosappdev.stocker.dashboard.domain.Currency
7 |
8 | class CurrenciesListMapper(
9 | private val currenciesViewEntityMapper: ViewEntityMapper
10 | ) : DisplayItemListMapper {
11 |
12 | override fun map(items: List): List {
13 | val mappedItems = arrayListOf()
14 | for (item in items) {
15 | mappedItems.add(currenciesViewEntityMapper.map(item))
16 | }
17 |
18 | return mappedItems
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/dashboard/dashboard_presentation/src/main/java/com/nstudiosappdev/stocker/dashboard/presentation/CurrenciesOrderingStyle.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.stocker.dashboard.presentation
2 |
3 | enum class OrderingStyle(val code: Int) {
4 | BY_NAME(0),
5 | BY_NAME_DESC(1),
6 | BY_BUYING_PRICE(2),
7 | BY_BUYING_PRICE_DESC(3),
8 | BY_SELLING_PRICE(4),
9 | BY_SELLING_PRICE_DESC(5),
10 | BY_DIFF(6),
11 | BY_DIFF_DESC(7)
12 | }
13 |
--------------------------------------------------------------------------------
/dashboard/dashboard_presentation/src/main/java/com/nstudiosappdev/stocker/dashboard/presentation/CurrenciesPresentationModule.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.stocker.dashboard.presentation
2 |
3 | import com.nstudiosappdev.core.preconditions.AndroidPreConditions
4 | import com.nstudiosappdev.core.presentation.recyclerview.*
5 | import com.nstudiosappdev.stocker.dashboard.presentation.DashboardPresentationConstants.DisplayTypes.CURRENCIES
6 | import dagger.Binds
7 | import dagger.Module
8 | import dagger.Provides
9 | import dagger.multibindings.IntKey
10 | import dagger.multibindings.IntoMap
11 |
12 | @Module
13 | abstract class CurrenciesPresentationModule {
14 |
15 | @Binds
16 | @IntoMap
17 | @IntKey(CURRENCIES)
18 | internal abstract fun provideCurrenciesViewModelFactory(factory: CurrenciesViewHolder.CurrenciesViewHolderFactory): ViewHolderFactory
19 |
20 | @Binds
21 | @IntoMap
22 | @IntKey(CURRENCIES)
23 | internal abstract fun provideCurrenciesViewHolderFactory(binder: CurrenciesViewHolder.CurrenciesViewHolderBinder): ViewHolderBinder
24 |
25 | @Module
26 | companion object {
27 |
28 | @JvmStatic
29 | @Provides
30 | fun provideDisplayItemComparator(): DisplayItemComparator = DefaultDisplayItemComparator()
31 |
32 | @JvmStatic
33 | @Provides
34 | fun provideRecyclerAdapter(
35 | itemComparator: DisplayItemComparator,
36 | factoryMap: Map,
37 | binderMap: Map,
38 | androidPreConditions: AndroidPreConditions
39 | ): RecyclerViewAdapter {
40 | return RecyclerViewAdapter(
41 | itemComparator = itemComparator,
42 | viewHolderFactoryMap = factoryMap,
43 | viewBinderFactoryMap = binderMap,
44 | androidPreconditions = androidPreConditions
45 | )
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/dashboard/dashboard_presentation/src/main/java/com/nstudiosappdev/stocker/dashboard/presentation/CurrenciesViewEntity.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.stocker.dashboard.presentation
2 |
3 | import com.nstudiosappdev.core.presentation.entity.ViewEntity
4 | import com.nstudiosappdev.core.presentation.recyclerview.DisplayItem
5 |
6 | class CurrenciesViewEntity(
7 | val bankName: String?,
8 | val buyPrice: String?,
9 | val buyStatus: String?,
10 | val sellPrice: String?,
11 | val sellStatus: String?,
12 | val currencyType: String?
13 | ) : ViewEntity, DisplayItem {
14 |
15 | override fun type(): Int =
16 | DashboardPresentationConstants.TYPES.USD
17 | }
18 |
--------------------------------------------------------------------------------
/dashboard/dashboard_presentation/src/main/java/com/nstudiosappdev/stocker/dashboard/presentation/CurrenciesViewEntityMapper.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.stocker.dashboard.presentation
2 |
3 | import com.nstudiosappdev.core.presentation.entity.ViewEntityMapper
4 | import com.nstudiosappdev.stocker.dashboard.domain.Currency
5 |
6 | class CurrenciesViewEntityMapper : ViewEntityMapper {
7 |
8 | override fun map(value: Currency): CurrenciesViewEntity {
9 | return CurrenciesViewEntity(
10 | value.bankName,
11 | value.buyPrice,
12 | value.buyStatus,
13 | value.sellPrice,
14 | value.sellStatus,
15 | value.currencyType
16 | )
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/dashboard/dashboard_presentation/src/main/java/com/nstudiosappdev/stocker/dashboard/presentation/CurrenciesViewModelModule.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.stocker.dashboard.presentation
2 |
3 | import androidx.lifecycle.ViewModel
4 | import com.nstudiosappdev.core.presentation.entity.ViewEntityMapper
5 | import com.nstudiosappdev.core.presentation.recyclerview.DisplayItemListMapper
6 | import com.nstudiosappdev.core.presentation.viewmodel.ViewModelKey
7 | import com.nstudiosappdev.stocker.dashboard.domain.Currency
8 | import com.nstudiosappdev.stocker.dashboard.presentation.liveCurrencies.LiveCurrenciesViewModel
9 | import com.nstudiosappdev.stocker.dashboard.presentation.portfolio.PortfolioViewModel
10 | import dagger.Binds
11 | import dagger.Module
12 | import dagger.Provides
13 | import dagger.multibindings.IntoMap
14 |
15 | @Module
16 | abstract class CurrenciesViewModelModule {
17 | @Binds
18 | @IntoMap
19 | @ViewModelKey(LiveCurrenciesViewModel::class)
20 | abstract fun bindCurrenciesViewModel(liveCurrenciesViewModel: LiveCurrenciesViewModel): ViewModel
21 |
22 | @Binds
23 | @IntoMap
24 | @ViewModelKey(PortfolioViewModel::class)
25 | abstract fun bindPortfolioViewModel(portfolioViewModel: PortfolioViewModel): ViewModel
26 |
27 | @Module
28 | companion object {
29 | @JvmStatic
30 | @Provides
31 | fun provideCurrenciesViewEntityMapper(): ViewEntityMapper =
32 | CurrenciesViewEntityMapper()
33 |
34 | @JvmStatic
35 | @Provides
36 | fun provideCurrenciesDisplayListMapper(viewEntityMapper: ViewEntityMapper): DisplayItemListMapper =
37 | CurrenciesListMapper(
38 | viewEntityMapper
39 | )
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/dashboard/dashboard_presentation/src/main/java/com/nstudiosappdev/stocker/dashboard/presentation/DashboardActivity.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.stocker.dashboard.presentation
2 |
3 | import android.os.Bundle
4 | import com.google.android.material.tabs.TabLayout
5 | import com.nstudiosappdev.core.presentation.TabProvider
6 | import com.nstudiosappdev.core.presentation.base.BaseInjectionActivity
7 | import com.nstudiosappdev.navigation.navigation.DefaultNavigationController
8 | import com.nstudiosappdev.navigation.navigation.NavigationController
9 | import com.nstudiosappdev.stocker.presentation.R
10 | import java.lang.ref.WeakReference
11 |
12 | class DashboardActivity : BaseInjectionActivity(), TabProvider {
13 |
14 | private lateinit var tabs: TabLayout
15 |
16 | private lateinit var navigationController: NavigationController
17 |
18 | override fun getLayoutRes() = R.layout.activity_main
19 |
20 | override fun onCreate(savedInstanceState: Bundle?) {
21 | super.onCreate(savedInstanceState)
22 | this.navigationController = DefaultNavigationController(WeakReference(this))
23 |
24 | tabs = findViewById(R.id.tabs)
25 | navigationController.navigateToCurrencies(R.id.fl_main)
26 | navigationController.navigateToBottomNavigation(R.id.fl_bottom_navigation)
27 | }
28 |
29 | override fun provideTabLayout(): TabLayout = tabs
30 |
31 | override fun onBackPressed() {
32 | // no-op
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/dashboard/dashboard_presentation/src/main/java/com/nstudiosappdev/stocker/dashboard/presentation/DashboardActivityModule.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.stocker.dashboard.presentation
2 |
3 | import com.nstudiosappdev.core.injection.scope.ActivityScope
4 | import com.nstudiosappdev.stocker.dashboard.presentation.liveCurrencies.LiveCurrenciesFragmentModule
5 | import com.nstudiosappdev.stocker.dashboard.presentation.portfolio.PortfolioFragmentModule
6 | import dagger.Module
7 | import dagger.android.ContributesAndroidInjector
8 |
9 | @Module
10 | abstract class DashboardActivityModule {
11 | @ActivityScope
12 | @ContributesAndroidInjector(
13 | modules = [PortfolioFragmentModule::class,
14 | LiveCurrenciesFragmentModule::class
15 | ]
16 | )
17 | abstract fun provideDashboardActivity(): DashboardActivity
18 | }
19 |
--------------------------------------------------------------------------------
/dashboard/dashboard_presentation/src/main/java/com/nstudiosappdev/stocker/dashboard/presentation/DashboardPresentationConstants.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.stocker.dashboard.presentation
2 |
3 | class DashboardPresentationConstants {
4 |
5 | object DisplayTypes {
6 | const val CURRENCIES = 0
7 | const val PORTFOLIO = 1
8 | }
9 |
10 | internal object TYPES {
11 | const val USD = 0
12 | const val EURO = 1
13 | const val GOLD = 2
14 | }
15 |
16 | internal object TYPES_STRING {
17 | const val USD = "usd"
18 | const val EURO = "euro"
19 | const val GOLD = "gold"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/dashboard/dashboard_presentation/src/main/java/com/nstudiosappdev/stocker/dashboard/presentation/bottom/BottomNavigationFragment.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.stocker.dashboard.presentation.bottom
2 |
3 | import android.os.Bundle
4 | import android.view.View
5 | import com.nstudiosappdev.core.presentation.base.BaseFragment
6 | import com.nstudiosappdev.navigation.navigation.DefaultNavigationController
7 | import com.nstudiosappdev.stocker.presentation.R
8 | import java.lang.ref.WeakReference
9 | import kotlinx.android.synthetic.main.fragment_bottom_navigation.*
10 |
11 | class BottomNavigationFragment : BaseFragment() {
12 |
13 | lateinit var navigationController: DefaultNavigationController
14 |
15 | override fun getLayoutRes() = R.layout.fragment_bottom_navigation
16 |
17 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
18 | super.onViewCreated(view, savedInstanceState)
19 |
20 | bottomNavigation.setOnNavigationItemSelectedListener {
21 | when (it.itemId) {
22 | R.id.navigationCurrencies -> {
23 | navigationController.navigateToCurrencies(R.id.fl_main)
24 | true
25 | }
26 | R.id.navigationPortfolio -> {
27 | navigationController.navigateToPortfolio(R.id.fl_main)
28 | true
29 | }
30 | else -> {
31 | true
32 | }
33 | }
34 | }
35 | }
36 |
37 | override fun onCreate(savedInstanceState: Bundle?) {
38 | super.onCreate(savedInstanceState)
39 | this.navigationController = DefaultNavigationController(WeakReference(activity!!))
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/dashboard/dashboard_presentation/src/main/java/com/nstudiosappdev/stocker/dashboard/presentation/liveCurrencies/LiveCurrenciesFragmentModule.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.stocker.dashboard.presentation.liveCurrencies
2 |
3 | import com.nstudiosappdev.core.injection.scope.FragmentScope
4 | import com.nstudiosappdev.stocker.dashboard.presentation.CurrenciesPresentationModule
5 | import dagger.Module
6 | import dagger.android.ContributesAndroidInjector
7 |
8 | @Module
9 | abstract class LiveCurrenciesFragmentModule {
10 | @FragmentScope
11 | @ContributesAndroidInjector(modules = [CurrenciesPresentationModule::class])
12 | abstract fun contributeCurrenciesFragment(): LiveCurrenciesFragment
13 | }
14 |
--------------------------------------------------------------------------------
/dashboard/dashboard_presentation/src/main/java/com/nstudiosappdev/stocker/dashboard/presentation/liveCurrencies/LiveCurrenciesMainFragment.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.stocker.dashboard.presentation.liveCurrencies
2 |
3 | import android.os.Bundle
4 | import android.view.View
5 | import androidx.viewpager.widget.ViewPager
6 | import com.nstudiosappdev.core.presentation.TabProvider
7 | import com.nstudiosappdev.core.presentation.base.BaseFragment
8 | import com.nstudiosappdev.stocker.presentation.R
9 | import kotlinx.android.synthetic.main.fragment_dashboard.*
10 |
11 | class LiveCurrenciesMainFragment : BaseFragment() {
12 |
13 | private var lastItem: Int = 0
14 |
15 | private lateinit var pagerAdapterLive: LiveCurrenciesPagerAdapter
16 |
17 | override fun getLayoutRes(): Int = R.layout.fragment_dashboard
18 |
19 | override val toolbarId = R.id.default_toolbar
20 |
21 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
22 | super.onViewCreated(view, savedInstanceState)
23 |
24 | pagerAdapterLive =
25 | LiveCurrenciesPagerAdapter(
26 | resources.getStringArray(R.array.main_items).toMutableList(),
27 | childFragmentManager
28 | )
29 |
30 | viewPagerDashboard.apply {
31 | adapter = pagerAdapterLive
32 | addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
33 |
34 | override fun onPageScrollStateChanged(state: Int) {
35 | // no-op
36 | }
37 |
38 | override fun onPageScrolled(
39 | position: Int,
40 | positionOffset: Float,
41 | positionOffsetPixels: Int
42 | ) {
43 | // no-op
44 | }
45 |
46 | override fun onPageSelected(position: Int) {
47 | lastItem = position
48 | }
49 | })
50 | offscreenPageLimit = 3
51 |
52 | (activity as TabProvider).provideTabLayout().setupWithViewPager(viewPagerDashboard)
53 | lastItem = viewPagerDashboard.currentItem
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/dashboard/dashboard_presentation/src/main/java/com/nstudiosappdev/stocker/dashboard/presentation/liveCurrencies/LiveCurrenciesPagerAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.stocker.dashboard.presentation.liveCurrencies
2 |
3 | import android.util.SparseArray
4 | import android.view.ViewGroup
5 | import androidx.fragment.app.Fragment
6 | import androidx.fragment.app.FragmentManager
7 | import androidx.fragment.app.FragmentPagerAdapter
8 | import com.nstudiosappdev.stocker.dashboard.presentation.DashboardPresentationConstants
9 | import java.lang.IllegalArgumentException
10 |
11 | class LiveCurrenciesPagerAdapter(private val titles: MutableList, fm: FragmentManager) :
12 | FragmentPagerAdapter(fm) {
13 |
14 | private val _fragments = SparseArray()
15 |
16 | private val fragments: SparseArray
17 | get() = _fragments
18 |
19 | override fun getItem(position: Int): Fragment {
20 | return when (position) {
21 | DashboardPresentationConstants.TYPES.USD -> LiveCurrenciesFragment.newInstance(
22 | DashboardPresentationConstants.TYPES_STRING.USD
23 | )
24 | DashboardPresentationConstants.TYPES.EURO -> LiveCurrenciesFragment.newInstance(
25 | DashboardPresentationConstants.TYPES_STRING.EURO
26 | )
27 | DashboardPresentationConstants.TYPES.GOLD -> LiveCurrenciesFragment.newInstance(
28 | DashboardPresentationConstants.TYPES_STRING.GOLD
29 | )
30 | else -> throw IllegalArgumentException("Unknown position!")
31 | }
32 | }
33 |
34 | override fun instantiateItem(container: ViewGroup, position: Int): Any {
35 | val fragment = super.instantiateItem(container, position) as Fragment
36 | fragments.put(position, fragment)
37 | return fragment
38 | }
39 |
40 | override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) {
41 | fragments.remove(position)
42 | super.destroyItem(container, position, `object`)
43 | }
44 |
45 | override fun getCount(): Int = titles.size
46 |
47 | override fun getPageTitle(position: Int): CharSequence? = titles[position]
48 | }
49 |
--------------------------------------------------------------------------------
/dashboard/dashboard_presentation/src/main/java/com/nstudiosappdev/stocker/dashboard/presentation/portfolio/PortfolioFragmentModule.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.stocker.dashboard.presentation.portfolio
2 |
3 | import com.nstudiosappdev.core.injection.scope.FragmentScope
4 | import com.nstudiosappdev.stocker.dashboard.presentation.CurrenciesPresentationModule
5 | import dagger.Module
6 | import dagger.android.ContributesAndroidInjector
7 |
8 | @Module
9 | abstract class PortfolioFragmentModule {
10 | @FragmentScope
11 | @ContributesAndroidInjector(modules = [CurrenciesPresentationModule::class])
12 | abstract fun contributePortfolioFragmentModule(): PortfolioFragment
13 | }
14 |
--------------------------------------------------------------------------------
/dashboard/dashboard_presentation/src/main/java/com/nstudiosappdev/stocker/dashboard/presentation/portfolio/PortfolioMainFragment.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.stocker.dashboard.presentation.portfolio
2 |
3 | import android.os.Bundle
4 | import android.view.View
5 | import androidx.viewpager.widget.ViewPager
6 | import com.nstudiosappdev.core.presentation.TabProvider
7 | import com.nstudiosappdev.core.presentation.base.BaseFragment
8 | import com.nstudiosappdev.stocker.presentation.R
9 | import kotlinx.android.synthetic.main.fragment_dashboard.*
10 |
11 | class PortfolioMainFragment : BaseFragment() {
12 |
13 | private var lastItem: Int = 0
14 |
15 | private lateinit var pagerAdapter: PortfolioPagerAdapter
16 |
17 | override fun getLayoutRes(): Int = R.layout.fragment_dashboard
18 |
19 | override val toolbarId = R.id.default_toolbar
20 |
21 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
22 | super.onViewCreated(view, savedInstanceState)
23 |
24 | pagerAdapter =
25 | PortfolioPagerAdapter(
26 | resources.getStringArray(R.array.main_items).toMutableList(),
27 | childFragmentManager
28 | )
29 |
30 | viewPagerDashboard.apply {
31 | adapter = pagerAdapter
32 | addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
33 |
34 | override fun onPageScrollStateChanged(state: Int) {
35 | // no-op
36 | }
37 |
38 | override fun onPageScrolled(
39 | position: Int,
40 | positionOffset: Float,
41 | positionOffsetPixels: Int
42 | ) {
43 | // no-op
44 | }
45 |
46 | override fun onPageSelected(position: Int) {
47 | lastItem = position
48 | }
49 | })
50 | offscreenPageLimit = 3
51 |
52 | (activity as TabProvider).provideTabLayout().setupWithViewPager(viewPagerDashboard)
53 | lastItem = viewPagerDashboard.currentItem
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/dashboard/dashboard_presentation/src/main/java/com/nstudiosappdev/stocker/dashboard/presentation/portfolio/PortfolioPagerAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.stocker.dashboard.presentation.portfolio
2 |
3 | import android.util.SparseArray
4 | import android.view.ViewGroup
5 | import androidx.fragment.app.Fragment
6 | import androidx.fragment.app.FragmentManager
7 | import androidx.fragment.app.FragmentPagerAdapter
8 | import com.nstudiosappdev.stocker.dashboard.presentation.DashboardPresentationConstants
9 |
10 | class PortfolioPagerAdapter(private val titles: MutableList, fm: FragmentManager) :
11 | FragmentPagerAdapter(fm) {
12 |
13 | private val _fragments = SparseArray()
14 |
15 | private val fragments: SparseArray
16 | get() = _fragments
17 |
18 | override fun getItem(position: Int): Fragment {
19 | return when (position) {
20 | DashboardPresentationConstants.TYPES.USD -> PortfolioFragment.newInstance(
21 | DashboardPresentationConstants.TYPES_STRING.USD
22 | )
23 | DashboardPresentationConstants.TYPES.EURO -> PortfolioFragment.newInstance(
24 | DashboardPresentationConstants.TYPES_STRING.EURO
25 | )
26 | DashboardPresentationConstants.TYPES.GOLD -> PortfolioFragment.newInstance(
27 | DashboardPresentationConstants.TYPES_STRING.GOLD
28 | )
29 | else -> throw IllegalArgumentException("Unknown position!")
30 | }
31 | }
32 |
33 | override fun instantiateItem(container: ViewGroup, position: Int): Any {
34 | val fragment = super.instantiateItem(container, position) as Fragment
35 | fragments.put(position, fragment)
36 | return fragment
37 | }
38 |
39 | override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) {
40 | fragments.remove(position)
41 | super.destroyItem(container, position, `object`)
42 | }
43 |
44 | override fun getCount(): Int = titles.size
45 |
46 | override fun getPageTitle(position: Int): CharSequence? = titles[position]
47 | }
48 |
--------------------------------------------------------------------------------
/dashboard/dashboard_presentation/src/main/res/drawable/ic_dollar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harrunisk/Stocker/dca907383ca09c86c6a81b06820ef7ace3e45a5c/dashboard/dashboard_presentation/src/main/res/drawable/ic_dollar.png
--------------------------------------------------------------------------------
/dashboard/dashboard_presentation/src/main/res/drawable/ic_portfolio.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harrunisk/Stocker/dca907383ca09c86c6a81b06820ef7ace3e45a5c/dashboard/dashboard_presentation/src/main/res/drawable/ic_portfolio.png
--------------------------------------------------------------------------------
/dashboard/dashboard_presentation/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
12 |
13 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/dashboard/dashboard_presentation/src/main/res/layout/content_home.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
19 |
20 |
25 |
26 |
27 |
28 |
32 |
33 |
--------------------------------------------------------------------------------
/dashboard/dashboard_presentation/src/main/res/layout/fragment_bottom_navigation.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
14 |
15 |
--------------------------------------------------------------------------------
/dashboard/dashboard_presentation/src/main/res/layout/fragment_dashboard.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
--------------------------------------------------------------------------------
/dashboard/dashboard_presentation/src/main/res/menu/menu_bottom_navigation.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/dashboard/dashboard_presentation/src/main/res/values-tr-rTR/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | - DOLAR
6 | - EURO
7 | - ALTIN
8 |
9 |
10 | dashboard_presentation
11 | Döviz Kurları
12 | Portföyüm
13 | ↓
14 | ↑
15 | Banka
16 | Alış
17 | Fark
18 | Satış
19 | EKLE
20 | Döviz kurunu favorilerinize eklemek ister misiniz?
21 | İşleminiz başarıyla gerçekleştirilmiştir.
22 | Döviz kuru daha önce portföye eklenmiş.
23 | İptal Et
24 | Bağlantı hatası yaşanıyor olabilir.
25 | Favori döviz kurunuz bulunmamaktadır.
26 | Bilgi
27 | Tamam
28 | KALDIR
29 | Döviz kurunu favorilerinizden kaldırmak ister misiniz?
30 |
--------------------------------------------------------------------------------
/dashboard/dashboard_presentation/src/main/res/values-tr/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | - DOLAR
6 | - EURO
7 | - ALTIN
8 |
9 |
10 | dashboard_presentation
11 | Döviz Kurları
12 | Portföyüm
13 | ↓
14 | ↑
15 | Banka
16 | Alış
17 | Fark
18 | Satış
19 | EKLE
20 | Döviz kurunu favorilerinize eklemek ister misiniz?
21 | İşleminiz başarıyla gerçekleştirilmiştir.
22 | Döviz kuru daha önce portföye eklenmiş.
23 | İptal Et
24 | Bağlantı hatası yaşanıyor olabilir.
25 | Favori döviz kurunuz bulunmamaktadır.
26 | Bilgi
27 | Tamam
28 | KALDIR
29 | Döviz kurunu favorilerinizden kaldırmak ister misiniz?
30 |
--------------------------------------------------------------------------------
/dashboard/dashboard_presentation/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #252525
4 | #FFFFFF
5 |
--------------------------------------------------------------------------------
/dashboard/dashboard_presentation/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | dashboard_presentation
3 |
4 |
5 |
6 | - USD
7 | - EURO
8 | - GOLD
9 |
10 |
11 | Exchange Rates
12 | Portfolio
13 |
14 | Bank
15 | Buying
16 | Sale
17 | Diff
18 | ↓
19 | ↑
20 |
21 |
22 | ADD
23 | REMOVE
24 | Cancel
25 | Would you like to add the exchange rate to your favorites?
26 | " Would you like to remove the exchange rate from your favorites?"
27 | Okay
28 | Info
29 | You do not have any favorite exchange rate.
30 | Please check your network connection status.
31 | Transaction was successfully completed.
32 | The exchange rate has already been added to the portfolio.
33 |
34 |
--------------------------------------------------------------------------------
/dashboard/dashboard_presentation/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
15 |
--------------------------------------------------------------------------------
/dashboard/dashboard_presentation/src/test/java/com/nstudiosappdev/stocker/presentation/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.nstudiosappdev.stocker.presentation
2 |
3 | import org.junit.Assert.*
4 | import org.junit.Test
5 |
6 | /**
7 | * Example local unit test, which will execute on the development machine (host).
8 | *
9 | * See [testing documentation](http://d.android.com/tools/testing).
10 | */
11 | class ExampleUnitTest {
12 | @Test
13 | fun addition_isCorrect() {
14 | assertEquals(4, 2 + 2)
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/detekt.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'io.gitlab.arturbosch.detekt'
2 |
3 | detekt {
4 | config = files("$rootDir/default-detekt-config.yml")
5 | filters = ".*build.*,.*/resources/.*,.*/tmp/.*"
6 | //Optional baseline, uncomment & run gradle command detektBaseline to exclude existing issues
7 | //baseline = file("detekt-baseline.xml")
8 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx1536m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app's APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=true
20 | # Kotlin code style for this project: "official" or "obsolete":
21 | kotlin.code.style=official
22 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harrunisk/Stocker/dca907383ca09c86c6a81b06820ef7ace3e45a5c/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon May 13 22:52:48 EET 2019
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/ktlint.gradle:
--------------------------------------------------------------------------------
1 | repositories {
2 | jcenter()
3 | }
4 |
5 | configurations {
6 | ktlint
7 | }
8 |
9 | dependencies {
10 | ktlint "com.pinterest:ktlint:0.34.2"
11 | }
12 |
13 | task ktlint(type: JavaExec, group: "verification") {
14 | description = "Check Kotlin code style."
15 | classpath = configurations.ktlint
16 | main = "com.pinterest.ktlint.Main"
17 | args "src/**/*.kt"
18 | }
19 |
20 | task ktlintFormat(type: JavaExec, group: "formatting") {
21 | description = "Fix Kotlin code style deviations."
22 | classpath = configurations.ktlint
23 | main = "com.pinterest.ktlint.Main"
24 | args "-F", "src/**/*.kt"
25 | }
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include Modules.app
2 | include Modules.core, Modules.corePresentation, Modules.coreDomain, Modules.coreData
3 | include Modules.navigation
4 | include Modules.dashboardPresentation, Modules.dashboardDomain, Modules.dashboardData
--------------------------------------------------------------------------------