🦁 A Disney app using transformation motions based on MVVM (ViewModel, Coroutines, Flow, LiveData, Room, Repository, Koin) architecture.

Overview

DisneyMotions


A demo Disney app using transformation motions based on MVVM architecture.
The motion system is included in the 1.2.0-alpha05 released material version.


License API Build Status KotlinWeekly Medium Profile

Download

Go to the Releases to download the latest APK.

Screenshots

Tech stack & Open-source libraries

  • Minimum SDK level 21
  • 100% Kotlin based + Coroutines + Flow for asynchronous.
  • JetPack
    • LiveData - notify domain layer data to views.
    • Lifecycle - dispose observing data when lifecycle state changes.
    • ViewModel - UI related data holder, lifecycle aware.
    • Room Persistence - construct database.
  • Architecture
    • MVVM Architecture (View - DataBinding - ViewModel - Model)
    • Repository pattern
    • Koin - dependency injection
  • Material Design & Animations
  • Sandwich - construct lightweight network response interfaces and handling error responses.
  • Retrofit2 & Gson - constructing the REST API
  • OkHttp3 - implementing interceptor, logging and mocking web server
  • Glide - loading images
  • BaseRecyclerViewAdapter - implementing adapters and viewHolders
  • WhatIf - checking nullable object and empty collections more fluently
  • Bundler - Android Intent & Bundle extensions that insert and retrieve values elegantly.
  • Timber - logging
  • Ripple animation, Shared element container transform/transition

MAD Score

summary kotlin

Unit Testing Frameworks

Unit Tests verify the interactions of viewmodels between repositories and dao & REST api requests.

  • Robolectric - Robolectric is the industry-standard unit testing framework for Android.
  • Mockito-Kotlin - a small library that provides helper functions to work with Mockito in Kotlin.

screenshot483387955

Find this repository useful? ❤️

Support it by joining stargazers for this repository.
And follow me for my next creations! 🤩

License

Designed and developed by 2020 skydoves (Jaewoong Eum)

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Comments
  • Crash when select first item

    Crash when select first item

    Please complete the following information:

    • Library Version [e.g. v1.0.0]
    • Affected Device(s) [e.g. Nokia 6.1+ with Android 10.0]

    Describe the Bug:

    • Running the app
    • Select the first item, I have try at all tabs. All the result same.
    • The app will crash

    Crash when select first item

    This is the error log

    FATAL EXCEPTION: main
        Process: com.skydoves.disneymotions, PID: 18526
        java.lang.RuntimeException: Unable to start activity ComponentInfo{com.skydoves.disneymotions/com.skydoves.disneymotions.view.ui.details.PosterDetailActivity}: java.lang.IllegalArgumentException: Required value was null.
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3271)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3410)
            at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
            at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
            at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2017)
            at android.os.Handler.dispatchMessage(Handler.java:107)
            at android.os.Looper.loop(Looper.java:214)
            at android.app.ActivityThread.main(ActivityThread.java:7397)
            at java.lang.reflect.Method.invoke(Native Method)
            at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:935)
         Caused by: java.lang.IllegalArgumentException: Required value was null.
            at com.skydoves.disneymotions.extensions.ActivityExtensionsKt$extraLong$1.invoke(ActivityExtensions.kt:63)
            at com.skydoves.disneymotions.extensions.ActivityExtensionsKt$extraLong$1.invoke(Unknown Source:0)
            at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
            at com.skydoves.disneymotions.view.ui.details.PosterDetailActivity.getPosterId(Unknown Source:2)
            at com.skydoves.disneymotions.view.ui.details.PosterDetailActivity.onCreate(PosterDetailActivity.kt:41)
            at android.app.Activity.performCreate(Activity.java:7802)
            at android.app.Activity.performCreate(Activity.java:7791)
            at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1300)
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3246)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3410) 
            at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83) 
            at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
            at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2017) 
            at android.os.Handler.dispatchMessage(Handler.java:107) 
            at android.os.Looper.loop(Looper.java:214) 
            at android.app.ActivityThread.main(ActivityThread.java:7397) 
            at java.lang.reflect.Method.invoke(Native Method) 
            at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) 
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:935) 
    I: Sending signal. PID: 18526 SIG: 9
    
    

    Expected Behavior:

    Not crash when select first item

    opened by derohimat 2
  • How does this project compare to your other project MarvelHeroes in terms of Architecture esp MVVM side

    How does this project compare to your other project MarvelHeroes in terms of Architecture esp MVVM side

    I am little confused when comparing both your projects As both use MVVM with Repository pattern and Coroutines what is the major difference between the two setup comparing only the architecture excluding the UI.

    Thanks for sharing this great repo, It serves as a great reference point to building modern android app with good architecture implementation

    opened by rinav 2
  • Adjust the color of the status bar to match the prominent background color of image.

    Adjust the color of the status bar to match the prominent background color of image.

    Is your feature request related to a problem?

    The color of the status bar doesn't go together with the prominent background color of the selected movie.

    Describe the solution you'd like:

    The status bar color should be dynamically adjusted to the prominent background color of the selected movie.

    Describe alternatives you've considered:

    Use the Palette API to select the prominent background color of the selected movie. During runtime change the status bar color to the color selected from the palette.

    opened by cleverSheep 2
  • Type mismatch required LiveData<TypeVariable(T)> found Unit

    Type mismatch required LiveData found Unit

    I'm trying to understanding this architecture by coding example and I followed the project set up till I stuck with that compile time error

    Type mismatch required LiveData<TypeVariable(T)> found Unit

    in the viewModel I have code like that for register request

     fun postRegisterRequest(request: RegisterRequest) {
        this.registerLiveData =  launchOnViewModelScope {
                this.authRepository.postRegister ({ s -> this.toastLiveData.postValue(s) },
                    request
                )
            }
    }
    

    in the repository I have the following code

    suspend fun postRegister(error: (String) -> Unit, request: RegisterRequest) = withContext(Dispatchers.IO) {
        val liveData = MutableLiveData<ResponseWrapper<RegisterResponse>>()
        isLoading = true
        networkClient.postRegister( { response ->
            isLoading = false
            when (response) {
                is ApiResponse.Success -> {
                    response.data.whatIfNotNull {
                        liveData.postValue(it)
                    }
                }
                is ApiResponse.Failure.Error -> error(response.message())
                is ApiResponse.Failure.Exception -> error(response.message())
            }
        },request)
    }
    

    the network client request look like that

     fun postRegister(
        onResult: (response: ApiResponse<ResponseWrapper<RegisterResponse>>) -> Unit,
        request: RegisterRequest
    ) {
        this.authService.register(request).transform(onResult)
    }
    

    the authService code

      @POST(Urls.REGISTER)
    fun register(@Body request: RegisterRequest): Call<ResponseWrapper<RegisterResponse>>
    

    what I did wrong and how to make postRegister in the repository return LiveData<TypeVariable(T)> instead of Unit

    opened by abdulmalekDery 2
  • Please help me this error

    Please help me this error

    import androidx.appcompat.app.AppCompatActivity; import androidx.viewpager.widget.ViewPager;

    import android.annotation.SuppressLint; import android.os.Bundle;

    import com.example.appnhac2.Adapter.MainViewPagerAdapter; import com.example.appnhac2.Fragment.Fragment_Tim_Kiem; import com.example.appnhac2.Fragment.Fragment_Trang_Chu; import com.example.appnhac2.R; import com.google.android.material.tabs.TabLayout;

    public class MainActivity extends AppCompatActivity {

    TabLayout tabLayout;
    ViewPager viewPager;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        anhxa();
        init();
    }
    
    private void init() {
        MainViewPagerAdapter mainViewPagerAdapter = new MainViewPagerAdapter(getSupportFragmentManager());
        mainViewPagerAdapter.addFragment(new Fragment_Trang_Chu(), "Trang Chu");
        mainViewPagerAdapter.addFragment(new Fragment_Tim_Kiem(), "Tim Kiem");
        viewPager.setAdapter(mainViewPagerAdapter);
        tabLayout.setupWithViewPager(viewPager);
        tabLayout.getTabAt(0).setIcon(R.drawable.icontrangchu);
        tabLayout.getTabAt(1).setIcon(R.drawable.iconsearch);
    }
    @SuppressLint("WrongViewCast")
    private void anhxa() {
        tabLayout = findViewById(R.id.myTabLayout);
        viewPager = findViewById(R.id.myViewPager);
    }
    

    }

    E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.appnhac2, PID: 10439 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.appnhac2/com.example.appnhac2.Ativity.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void androidx.viewpager.widget.ViewPager.setAdapter(androidx.viewpager.widget.PagerAdapter)' on a null object reference at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3270) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409) at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83) at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016) at android.os.Handler.dispatchMessage(Handler.java:107) at android.os.Looper.loop(Looper.java:214) at android.app.ActivityThread.main(ActivityThread.java:7356) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930) Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void androidx.viewpager.widget.ViewPager.setAdapter(androidx.viewpager.widget.PagerAdapter)' on a null object reference at com.example.appnhac2.Ativity.MainActivity.init(MainActivity.java:32) at com.example.appnhac2.Ativity.MainActivity.onCreate(MainActivity.java:25) at android.app.Activity.performCreate(Activity.java:7802) at android.app.Activity.performCreate(Activity.java:7791) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1299) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3245) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409)  at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)  at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)  at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)  at android.os.Handler.dispatchMessage(Handler.java:107)  at android.os.Looper.loop(Looper.java:214)  at android.app.ActivityThread.main(ActivityThread.java:7356)  at java.lang.reflect.Method.invoke(Native Method)  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930) 

    opened by tranminhquan536 1
  • Change the id of the navigation items

    Change the id of the navigation items

    Allows for better understanding of each nav item.

    Guidelines

    Describe the big picture of your changes here to communicate to the maintainers why we should accept this pull request. If it fixes a bug or resolves a feature request, be sure to link to that issue.

    Types of changes

    What types of changes does your code introduce? A minor refactor was made.

    opened by cleverSheep 1
  • Animation does not start

    Animation does not start

    • Affected Device(s) [Pixel 3A API 28]

    Describe the Bug:

    The navigation works when clicking a movie, but the animation does doesn't. This only occurs on API 28. I've tested API 29, 27, 26; all of which work fine.

    Expected Behavior:

    Clicking on a movie should should start the material transform animation.

    opened by cleverSheep 1
  • Tests to be added

    Tests to be added

    Is your feature request related to a problem? No

    The arch. of the app is really good, but for a developer to get more understanding on how to test such an app, tehre should be tests included.

    Describe the solution you'd like: Unit tests, integration and some UI tests

    opened by jaydeepw 1
  • Update DatabindingFragment.kt

    Update DatabindingFragment.kt

    Bugfix - A small correction for the class name in the doc comment.

    Guidelines

    Describe the big picture of your changes here to communicate to the maintainers why we should accept this pull request. If it fixes a bug or resolves a feature request, be sure to link to that issue.

    Types of changes

    What types of changes does your code introduce?

    • [ ] Bugfix (non-breaking change which fixes an issue)
    • [ ] New feature (non-breaking change which adds functionality)
    • [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)

    Preparing a pull request for review

    Ensure your change is properly formatted by running:

    $ ./gradlew spotlessApply
    

    Please correct any failures before requesting a review.

    opened by sukie2 0
Releases(1.0.4)
Owner
Jaewoong Eum
Android software engineer. Digital Nomad. Open Source Contributor. ❤️ Love coffee, music, magic tricks and writing poems. Coffee Driven Development.
Jaewoong Eum
🚀 🥳 MVVM based sample currency converter application using Room, Koin, ViewModel, LiveData, Coroutine

Currency Converter A demo currency converter app using Modern Android App Development techniques Tech stack & Open-source libraries Minimum SDK level

Abinash Neupane 2 Jul 17, 2022
🛒 Mercado Libre App Clone using modern Android development with Hilt, Coroutines, Jetpack (Room, ViewModel), and Jetpack Compose based on MVVM architecture.

Meli Clone ?? Mercado Libre App Clone using modern Android development with Hilt, Coroutines, Jetpack (Room, ViewModel), and Jetpack Compose based on

Esteban Aragon 7 Sep 22, 2022
Shreyas Patil 2.2k Jan 4, 2023
MVVM ,Hilt DI ,LiveData ,Flow ,SharedFlow ,Room ,Retrofit ,Coroutine , Navigation Component ,DataStore ,DataBinding , ViewBinding, Coil

RickMorty This is a simple app which has been implemented using Clean Architecture alongside MVVM design to run (online/offline) using : [ MVVM ,Hilt

Ali Assalem 13 Jan 5, 2023
:cyclone: A Pokedex app using ViewModel, LiveData, Room and Navigation

Pokedex app built with Kotlin Download Go to the releases page to download the latest available apk. Screenshots Development Roadmap Kotlin LiveData N

Marcos Paulo Farias 1.4k Dec 28, 2022
ViewModel-Lifecycle - ViewModel Lifecycle allows you to track and observe Jetpack ViewModel's lifecycle changes

ViewModel Lifecycle ?? ViewModel Lifecycle allows you to track and observe Jetpa

Jaewoong Eum 97 Nov 25, 2022
Viewmodel-lifecycle - ViewModel Lifecycle allows you to track and observe Jetpack ViewModel's lifecycle changes

ViewModel Lifecycle ?? ViewModel Lifecycle allows you to track and observe Jetpa

Jaewoong Eum 36 Feb 6, 2022
🗡️ Deddit demonstrates modern Android development with Hilt, Coroutines, Flow, Jetpack, and Material Design based on MVVM architecture

Deddit demonstrates modern Android development with Hilt, Coroutines, Flow, Jetpack (ViewModel,Paging3), and Material Design based on MVVM

Krish Parekh 9 Sep 2, 2022
App built using Kotlin, Dagger Hilt, Room Database, Coroutines, Flow, AndroidX Glance, WorkManager, Coil etc.

An article sharing platform where you can personalize, subscribe to your favorite topics, get daily-read reminders, etc. App built using Kotlin, Dagger Hilt, Room Database, Coroutines, Flow, AndroidX Glance, WorkManager, Coil etc.

Kasem SM 484 Jan 3, 2023
Android MVVM Architecture using Kotlin, RxJava, Koin.

Android-MVVM-RxJava-Digikala_kotlin Digikala sample app developed MVVM architecture design pattern that follow the best practices of Object Oriented D

Hossein Soltani Nejad 2 Sep 10, 2022
Use Android Jetpack libraries, Android Architecture Components, ViewModel and LiveData to build this app.

Unscramble App Starter code for Android Basics codelab - Store the data in a ViewModel Unscramble is a single player game app that displays scrambled

Shaima Alghamdi 2 Aug 18, 2022
🔥采用 Kotlin 语言编写,专为新手入门准备的项目。单Activity多Fragment,MVVM,ViewModel + LiveData + Retrofit + 协程, ViewBinding等等。拒绝过度设计和封装,项目结构清晰,代码简洁优雅。

前言 学习Kotlin有一段时间了,想写一个项目总结收获,就有了这个可能是东半球最简洁的玩安卓客户端,在此感谢玩Android 的开放API。 简介 采用 Kotlin 语言编写,专为新手入门准备的项目。单Activity多Fragment,MVVM,ViewModel + LiveData + R

zst 827 Dec 31, 2022
Clean Android multi-module offline-first scalable app in 2022. Including Jetpack Compose, MVI, Kotlin coroutines/Flow, Kotlin serialization, Hilt and Room.

Android Kotlin starter project - 2022 edition Android starter project, described precisely in this article. Purpose To show good practices using Kotli

Krzysztof Dąbrowski 176 Jan 3, 2023
In this single activity app. i was trying to practice on ViewModel and Livedata

CalwithViewModel In this single activity app. i was trying to practice on ViewModel and Livedata Min Api Level : 19 Setup Requirements Android device

Tech_G 1 Feb 16, 2022
Exercício utilizando ViewModel e LiveData

Unscramble App Starter code for Android Basics codelab - Store the data in a ViewModel Unscramble is a single player game app that displays scrambled

Lucas Caetano 1 Nov 22, 2021
Enemigos5 - Recyclerview-ViewModel-LiveData on Android with Kotlin

Enemigos5 Recyclerview-VievModel-LiveData on Android with Kotlin. Es muy simple:

null 1 Feb 6, 2022
🍓CookHelper - food social network. The Api and Websocket are based on Ktor framework. Dependency injection with Koin library.

CookHelper [ ?? Work in Progress ?? ] CookHelper is a cross-platform application that will allow you to cook a delicious dish from an existing recipe

Arthur 11 Nov 9, 2022
Android Kotlin+ MVVM + Retrofit2 + Room +Dagger2 + Coroutines + Junit4 + Espresso + Mockito + MockWebServer

Movies-TMDB Android Kotlin+ MVVM + Retrofit2 + Room +Dagger2 + Coroutines + Junit4 + + Espresso + Mockito + MockWebServer Movies-TMDB Android Movies-T

kavin 2 Oct 24, 2022