├── .gitmodules
├── common
├── .gitignore
├── consumer-rules.pro
├── src
│ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── res
│ │ ├── values
│ │ │ └── styles.xml
│ │ └── layout
│ │ │ └── include_base_appbar.xml
│ │ └── kotlin
│ │ └── com
│ │ └── mobiledevpro
│ │ └── common
│ │ └── ui
│ │ ├── base
│ │ ├── ActivitySettings.kt
│ │ ├── FragmentSettings.kt
│ │ ├── BaseActivityInterface.kt
│ │ └── BaseViewModel.kt
│ │ ├── coroutines
│ │ ├── BaseUseCase.kt
│ │ ├── BaseCoroutinesUseCase.kt
│ │ ├── BaseCoroutinesFLowUseCase.kt
│ │ └── ResultExt.kt
│ │ ├── extension
│ │ └── LifecycleOwnerExtensions.kt
│ │ ├── livedata
│ │ ├── Event.kt
│ │ └── SingleLiveData.kt
│ │ └── lifecycle
│ │ └── RuntimePermissionObserver.kt
├── proguard-rules.pro
└── build.gradle
├── app
├── .gitignore
├── src
│ ├── main
│ │ ├── ic_launcher-playstore.png
│ │ ├── kotlin
│ │ │ └── com
│ │ │ │ └── mobiledevpro
│ │ │ │ └── app
│ │ │ │ ├── helper
│ │ │ │ ├── TypeConverter.kt
│ │ │ │ ├── ResourcesProvider.kt
│ │ │ │ └── ImplResourcesProvider.kt
│ │ │ │ ├── App.kt
│ │ │ │ ├── di
│ │ │ │ └── Module.kt
│ │ │ │ └── ui
│ │ │ │ └── mainscreen
│ │ │ │ └── view
│ │ │ │ └── MainActivity.kt
│ │ ├── res
│ │ │ ├── layouts
│ │ │ │ ├── activity
│ │ │ │ │ └── layout
│ │ │ │ │ │ └── activity_main.xml
│ │ │ │ └── include
│ │ │ │ │ └── layout
│ │ │ │ │ └── include_appbar_custom.xml
│ │ │ └── values
│ │ │ │ └── strings.xml
│ │ └── AndroidManifest.xml
│ └── test
│ │ └── java
│ │ └── com
│ │ └── mobiledevpro
│ │ └── app
│ │ └── CheckKoinModulesTest.kt
├── google-services.json
├── proguard-rules.pro
└── build.gradle
├── core
├── ui
│ ├── .gitignore
│ ├── consumer-rules.pro
│ ├── src
│ │ └── main
│ │ │ ├── AndroidManifest.xml
│ │ │ └── res
│ │ │ ├── mipmap-hdpi
│ │ │ ├── ic_launcher.png
│ │ │ ├── ic_launcher_round.png
│ │ │ └── ic_launcher_foreground.png
│ │ │ ├── mipmap-mdpi
│ │ │ ├── ic_launcher.png
│ │ │ ├── ic_launcher_round.png
│ │ │ └── ic_launcher_foreground.png
│ │ │ ├── mipmap-xhdpi
│ │ │ ├── ic_launcher.png
│ │ │ ├── ic_launcher_round.png
│ │ │ └── ic_launcher_foreground.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ ├── ic_launcher_round.png
│ │ │ └── ic_launcher_foreground.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ ├── ic_launcher_round.png
│ │ │ └── ic_launcher_foreground.png
│ │ │ ├── values
│ │ │ ├── theme_attrs.xml
│ │ │ ├── style_image_button.xml
│ │ │ ├── dimens.xml
│ │ │ ├── style_toolbar.xml
│ │ │ ├── style_textview.xml
│ │ │ ├── style_button.xml
│ │ │ ├── style_edittext.xml
│ │ │ ├── colors_base.xml
│ │ │ ├── colors_material3.xml
│ │ │ └── themes.xml
│ │ │ ├── drawable
│ │ │ ├── background_edittext_cursor.xml
│ │ │ ├── background_window_dark.xml
│ │ │ ├── background_window_light.xml
│ │ │ ├── ic_send_white_24dp.xml
│ │ │ ├── background_layout_top_rounding.xml
│ │ │ ├── background_layout_bottom_rounding.xml
│ │ │ ├── background_window_default.xml
│ │ │ ├── ic_back_arrow_light_24dp.xml
│ │ │ ├── ic_list_dark_24dp.xml
│ │ │ ├── ic_profile_avatar_dark_24dp.xml
│ │ │ ├── background_profile_avatar.xml
│ │ │ ├── ic_login_24dp.xml
│ │ │ ├── background_edittext_login.xml
│ │ │ ├── background_edittext_message.xml
│ │ │ ├── background_button_common.xml
│ │ │ ├── ic_settings_dark_24dp.xml
│ │ │ ├── ic_facebook_circle_white_56dp.xml
│ │ │ └── ic_google_circle_white_56dp.xml
│ │ │ ├── mipmap-anydpi-v26
│ │ │ ├── ic_launcher.xml
│ │ │ └── ic_launcher_round.xml
│ │ │ └── values-night
│ │ │ └── themes.xml
│ ├── build.gradle
│ └── proguard-rules.pro
├── utils
│ ├── .gitignore
│ ├── build.gradle
│ └── src
│ │ └── main
│ │ └── kotlin
│ │ └── com
│ │ └── mobiledevpro
│ │ └── utils
│ │ ├── Constant.kt
│ │ ├── Error.kt
│ │ └── TimeUtil.kt
├── database
│ ├── .gitignore
│ ├── consumer-rules.pro
│ ├── src
│ │ ├── main
│ │ │ ├── AndroidManifest.xml
│ │ │ └── kotlin
│ │ │ │ └── com
│ │ │ │ └── mobiledevpro
│ │ │ │ └── database
│ │ │ │ ├── di
│ │ │ │ └── Module.kt
│ │ │ │ ├── entity
│ │ │ │ └── UserEntity.kt
│ │ │ │ ├── dao
│ │ │ │ └── BaseDao.kt
│ │ │ │ └── AppDatabase.kt
│ │ └── androidTest
│ │ │ └── java
│ │ │ └── com
│ │ │ └── mobiledevpro
│ │ │ └── database
│ │ │ ├── ExampleInstrumentedTest.kt
│ │ │ └── RoomMigrationTest.java
│ ├── proguard-rules.pro
│ ├── build.gradle
│ └── schemas
│ │ └── com.mobiledevpro.database.AppDatabase
│ │ └── 1.json
└── navigation
│ ├── .gitignore
│ ├── consumer-rules.pro
│ ├── src
│ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── res
│ │ ├── transition
│ │ │ ├── fade.xml
│ │ │ ├── slide_left.xml
│ │ │ └── slide_right.xml
│ │ ├── values
│ │ │ └── nav_ids.xml
│ │ └── navigation
│ │ │ └── nav_main.xml
│ │ └── kotlin
│ │ └── com
│ │ └── mobiledevpro
│ │ └── navigation
│ │ ├── Navigation.kt
│ │ └── ext
│ │ └── NavigationExt.kt
│ ├── build.gradle
│ └── proguard-rules.pro
├── feature
├── chat_core
│ ├── .gitignore
│ ├── build.gradle
│ └── src
│ │ └── main
│ │ ├── kotlin
│ │ └── com
│ │ │ └── mobiledevpro
│ │ │ └── chat
│ │ │ └── core
│ │ │ ├── data
│ │ │ └── model
│ │ │ │ ├── ChatUserData.kt
│ │ │ │ └── ChatMessageData.kt
│ │ │ ├── view
│ │ │ ├── recycler
│ │ │ │ ├── RecyclerViewHandler.kt
│ │ │ │ ├── RecyclerItem.kt
│ │ │ │ └── RecyclerViewAdapter.kt
│ │ │ ├── mapper
│ │ │ │ └── RecyclerMapper.kt
│ │ │ └── extension
│ │ │ │ └── ImageViewExtension.kt
│ │ │ ├── domain
│ │ │ └── model
│ │ │ │ ├── ChatUser.kt
│ │ │ │ └── ChatMessage.kt
│ │ │ └── mapper
│ │ │ ├── ChatUserMapper.kt
│ │ │ └── ChatMessageMapper.kt
│ │ ├── AndroidManifest.xml
│ │ └── res
│ │ ├── drawable
│ │ ├── background_message_sent.xml
│ │ ├── background_message_received.xml
│ │ └── ic_message_avatar_white_24dp.xml
│ │ └── layout
│ │ ├── item_chat_message_send.xml
│ │ └── item_chat_message_received.xml
├── chat_main
│ ├── .gitignore
│ ├── build.gradle
│ └── src
│ │ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── res
│ │ ├── menu
│ │ │ └── menu_chat_public.xml
│ │ ├── navigation
│ │ │ └── nav_chat_main.xml
│ │ └── layout
│ │ │ └── fragment_chat_public.xml
│ │ └── kotlin
│ │ └── com
│ │ └── mobiledevpro
│ │ └── chat
│ │ └── main
│ │ ├── data
│ │ ├── repository
│ │ │ ├── ChatPublicRepository.kt
│ │ │ └── ImplChatPublicRepository.kt
│ │ └── local
│ │ │ ├── ChatPublicLocalSource.kt
│ │ │ └── ImplChatPublicLocalSource.kt
│ │ ├── domain
│ │ ├── interactor
│ │ │ ├── ChatPublicInteractor.kt
│ │ │ └── ImplChatPublicInteractor.kt
│ │ └── usecase
│ │ │ ├── GetCurrentUserUseCase.kt
│ │ │ └── GetPublicChatMessagesUseCase.kt
│ │ ├── view
│ │ ├── RecyclerViewExtension.kt
│ │ ├── ChatPublicViewModel.kt
│ │ └── ChatPublicFragment.kt
│ │ └── di
│ │ └── Module.kt
└── profile_settings
│ ├── .gitignore
│ ├── src
│ └── main
│ │ ├── kotlin
│ │ └── com
│ │ │ └── mobiledevpro
│ │ │ └── profile
│ │ │ └── settings
│ │ │ ├── data
│ │ │ └── local_and_remote_source
│ │ │ ├── domain
│ │ │ └── interactor_and_usecases
│ │ │ ├── di
│ │ │ └── Module.kt
│ │ │ └── view
│ │ │ ├── ProfileSettingsViewModel.kt
│ │ │ └── ProfileSettingsFragment.kt
│ │ ├── AndroidManifest.xml
│ │ └── res
│ │ └── navigation
│ │ └── nav_profile_settings.xml
│ └── build.gradle
├── github_social_preview.png
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── doc
└── MVVM-Kotlin-Modularization - Frame.jpg
├── .gitignore
├── common-kotlin-library.gradle
├── settings.gradle.kts
├── .github
└── FUNDING.yml
├── ci-deploy-dropbox.sh
├── common-android-library.gradle
├── common-dynamic-feature.gradle
├── gradle.properties
├── install-bundles-on-device.sh
├── gradlew.bat
├── .circleci
└── config.yml
├── README.md
└── gradlew
/.gitmodules:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/common/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/core/ui/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/core/ui/consumer-rules.pro:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/core/utils/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/core/database/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/core/database/consumer-rules.pro:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/core/navigation/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/core/navigation/consumer-rules.pro:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/feature/chat_core/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/feature/chat_main/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/feature/profile_settings/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/common/consumer-rules.pro:
--------------------------------------------------------------------------------
1 | # Rules for this library
--------------------------------------------------------------------------------
/core/utils/build.gradle:
--------------------------------------------------------------------------------
1 | apply from: "$rootDir/common-kotlin-library.gradle"
2 |
--------------------------------------------------------------------------------
/common/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
15 | * Created by Dmitri Chernysh 16 | *
17 | * http://mobile-dev.pro
18 | */
19 | @RunWith(AndroidJUnit4.class)
20 | public class RoomMigrationTest {
21 | // private static final String TEST_DB = BuildConfig.AppDatabaseName;
22 |
23 | @Rule
24 | public MigrationTestHelper helper;
25 |
26 | public RoomMigrationTest() {
27 | /* helper = new MigrationTestHelper(InstrumentationRegistry.getInstrumentation(),
28 | AppDatabase.class.getCanonicalName(),
29 | new FrameworkSQLiteOpenHelperFactory());
30 |
31 | */
32 | }
33 |
34 | @Test
35 | public void migrate5to6() throws IOException {
36 | /* int currentVersion = 5;
37 | int newVersion = 6;
38 | int examQuestionId = 11111111;
39 | // Create earliest version of the database.
40 | SupportSQLiteDatabase dbCurrent = helper.createDatabase(TEST_DB, currentVersion);
41 | dbCurrent.close();
42 |
43 | //make project before run this
44 | try {
45 | helper.runMigrationsAndValidate(TEST_DB, newVersion, true, AppDatabase.MIGRATION_5_6);
46 | } catch (IllegalStateException e) {
47 | throw new IOException("Make project before run test for migration from 5 to 6. " + e.getLocalizedMessage());
48 | }
49 |
50 | //test inserting
51 | AppDatabase newDb = getMigratedDatabase();
52 | long[] result = newDb.examDao()
53 | .insertQuestionAttachments(
54 | buildQuestionAttachmentToInsert(examQuestionId)
55 | );
56 |
57 | if (result.length == 0)
58 | throw new IOException("ExamQuestionAttachment is not inserting into a new database");
59 |
60 | */
61 | }
62 |
63 |
64 | // Array of all migrations
65 | /* private static final Migration[] ALL_MIGRATIONS =
66 | new Migration[]{
67 | AppDatabase.MIGRATION_5_6
68 | };
69 |
70 | private AppDatabase getMigratedDatabase() {
71 | // Open latest version of the database. Room will validate the schema
72 | // once all migrations execute.
73 | AppDatabase appDb = Room.databaseBuilder(
74 | InstrumentationRegistry.getInstrumentation().getTargetContext(),
75 | AppDatabase.class,
76 | TEST_DB)
77 | .addMigrations(ALL_MIGRATIONS).build();
78 | appDb.getOpenHelper().getWritableDatabase();
79 | appDb.close();
80 | return appDb;
81 | }
82 |
83 | private ArrayList
45 |
46 |
47 | **Dmitri Chernysh**
48 |
49 | [](https://www.youtube.com/@mobiledevpro?sub_confirmation=1)
50 | [](https://www.instagram.com/mobiledevpro/)
51 | [](https://twitter.com/mobiledev_pro)
52 | [](https://www.linkedin.com/in/dmitriychernysh/)
53 |
54 | ## License:
55 |
56 | Copyright 2020 Dmitri Chernysh
57 |
58 | Licensed under the Apache License, Version 2.0 (the "License");
59 | you may not use this file except in compliance with the License.
60 | You may obtain a copy of the License at
61 |
62 | http://www.apache.org/licenses/LICENSE-2.0
63 |
64 | Unless required by applicable law or agreed to in writing, software
65 | distributed under the License is distributed on an "AS IS" BASIS,
66 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
67 | See the License for the specific language governing permissions and
68 | limitations under the License.
69 |
70 | ## Thanks for support !
71 |
72 | **Stargazers**
73 |
74 | [](https://github.com/mobiledevpro/Android-Kotlin-MVVM-Template/stargazers)
75 |
76 | **Forkers**
77 |
78 | [](https://github.com/mobiledevpro/Android-Kotlin-MVVM-Template/network/members)
79 |
80 |
--------------------------------------------------------------------------------
/core/ui/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |