diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 0000000..1f757e6
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1,16 @@
+# Lines starting with '#' are comments.
+# Each line is a file pattern followed by one or more owners.
+
+# More details are here: https://help.github.com/articles/about-codeowners/
+
+# The '*' pattern is global owners.
+# Not adding in this PR, but I'd like to try adding a global owner set with the entire team.
+# One interpretation of their docs is that global owners are added only if not removed
+# by a more local rule.
+
+# Order is important. The last matching pattern has the most precedence.
+# The folders are ordered as follows:
+
+# In each subsection folders are ordered first by depth, then alphabetically.
+# This should make it easy to add new rules without breaking existing ones.
+* @skydoves
\ No newline at end of file
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 0000000..6c24897
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1,2 @@
+github: skydoves
+custom: ["https://www.paypal.me/skydoves", "https://www.buymeacoffee.com/skydoves"]
diff --git a/.github/ISSUE_TEMPLATE/Bug_report.md b/.github/ISSUE_TEMPLATE/Bug_report.md
new file mode 100644
index 0000000..f568420
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/Bug_report.md
@@ -0,0 +1,17 @@
+---
+name: Bug report
+about: Something is crashing or not working as intended
+
+---
+
+**Please complete the following information:**
+- Library Version [e.g. v1.0.0]
+- Affected Device(s) [e.g. Samsung Galaxy s10 with Android 9.0]
+
+**Describe the Bug:**
+
+Add a clear description about the problem.
+
+**Expected Behavior:**
+
+A clear description of what you expected to happen.
diff --git a/.github/ISSUE_TEMPLATE/Feature_request.md b/.github/ISSUE_TEMPLATE/Feature_request.md
new file mode 100644
index 0000000..1e008d6
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/Feature_request.md
@@ -0,0 +1,17 @@
+---
+name: Feature request
+about: Suggest an idea for this project
+
+---
+
+**Is your feature request related to a problem?**
+
+A clear and concise description of what the problem is.
+
+**Describe the solution you'd like:**
+
+A clear and concise description of what you want to happen.
+
+**Describe alternatives you've considered:**
+
+A clear description of any alternative solutions you've considered.
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
new file mode 100644
index 0000000..1ec8706
--- /dev/null
+++ b/.github/pull_request_template.md
@@ -0,0 +1,18 @@
+## 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:
+
+```gradle
+$ ./gradlew spotlessApply
+```
+
+Please correct any failures before requesting a review.
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 56cc642..c442633 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,8 +1,6 @@
# Built application files
*.apk
-*.aar
*.ap_
-*.aab
# Files for the ART/Dalvik VM
*.dex
@@ -14,13 +12,16 @@
bin/
gen/
out/
-# Uncomment the following line in case you need and you don't have the release build type files in your app
-# release/
# Gradle files
+/.idea
.gradle/
build/
+# DS_Store
+*.DS_Store
+**/DS_Store
+
# Local configuration file (sdk path, etc)
local.properties
@@ -36,50 +37,24 @@ proguard/
# Android Studio captures folder
captures/
-# IntelliJ
+# Intellij
*.iml
.idea/workspace.xml
.idea/tasks.xml
.idea/gradle.xml
-.idea/assetWizardSettings.xml
.idea/dictionaries
.idea/libraries
-# Android Studio 3 in .gitignore file.
-.idea/caches
-.idea/modules.xml
-# Comment next line if keeping position of elements in Navigation Editor is relevant for you
-.idea/navEditor.xml
# Keystore files
-# Uncomment the following lines if you do not want to check your keystore files in.
-#*.jks
-#*.keystore
+*.jks
# External native build folder generated in Android Studio 2.2 and later
.externalNativeBuild
-.cxx/
# Google Services (e.g. APIs or Firebase)
-# google-services.json
+google-services.json
# Freeline
freeline.py
freeline/
-freeline_project_description.json
-
-# fastlane
-fastlane/report.xml
-fastlane/Preview.html
-fastlane/screenshots
-fastlane/test_output
-fastlane/readme.md
-
-# Version control
-vcs.xml
-
-# lint
-lint/intermediates/
-lint/generated/
-lint/outputs/
-lint/tmp/
-# lint/reports/
+freeline_project_description.json
\ No newline at end of file
diff --git a/app/.gitignore b/app/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/app/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/app/build.gradle b/app/build.gradle
new file mode 100644
index 0000000..a29ec91
--- /dev/null
+++ b/app/build.gradle
@@ -0,0 +1,77 @@
+apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
+apply plugin: 'kotlin-android-extensions'
+apply plugin: 'kotlin-kapt'
+apply from: '../dependencies.gradle'
+
+android {
+ compileSdkVersion versions.compileSdk
+ defaultConfig {
+ applicationId "com.skydoves.disneymotions"
+ minSdkVersion versions.minSdk
+ targetSdkVersion versions.compileSdk
+ versionCode versions.versionCode
+ versionName versions.versionName
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+ kotlinOptions {
+ jvmTarget = "1.8"
+ }
+ dataBinding {
+ enabled = true
+ }
+ androidExtensions {
+ experimental = true
+ }
+}
+
+dependencies {
+ // kotlin
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$versions.kotlin"
+
+ // android supports
+ implementation "com.google.android.material:material:$versions.materialVersion"
+ implementation "androidx.constraintlayout:constraintlayout:$versions.constraintVersion"
+
+ // architecture components
+ implementation "androidx.lifecycle:lifecycle-extensions:$versions.lifecycleVersion"
+ implementation "androidx.lifecycle:lifecycle-livedata-ktx:$versions.lifecycleVersion"
+ implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$versions.lifecycleVersion"
+ implementation "androidx.room:room-runtime:$versions.roomVersion"
+ kapt "androidx.room:room-compiler:$versions.roomVersion"
+ testImplementation "androidx.arch.core:core-testing:$versions.archCompomentVersion"
+
+ // koin
+ implementation "org.koin:koin-android:$versions.koinVersion"
+ implementation "org.koin:koin-android-scope:$versions.koinVersion"
+ implementation "org.koin:koin-android-viewmodel:$versions.koinVersion"
+
+ // network
+ implementation "com.squareup.retrofit2:retrofit:$versions.retrofitVersion"
+ implementation "com.squareup.okhttp3:logging-interceptor:$versions.okhttpVersion"
+ implementation "com.squareup.retrofit2:converter-gson:$versions.retrofitVersion"
+
+ // coroutines
+ implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$versions.coroutinesVersion"
+ testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$versions.coroutinesVersion"
+ testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$versions.coroutinesVersion"
+
+ // glide
+ implementation "com.github.bumptech.glide:glide:$versions.glideVersion"
+ implementation "com.github.florent37:glidepalette:$versions.glidePaletteVersion"
+ kapt "com.github.bumptech.glide:compiler:$versions.glideVersion"
+
+ // adapter
+ implementation "com.github.skydoves:baserecyclerviewadapter:$versions.baseAdapter"
+
+ // whatIf
+ implementation "com.github.skydoves:whatif:$versions.whatIfVersion"
+
+ // debugging
+ implementation "com.jakewharton.timber:timber:$versions.timberVersion"
+}
+
+apply from: '../spotless.gradle'
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..7b555b9
--- /dev/null
+++ b/app/src/main/AndroidManifest.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/skydoves/disneymotions/DisneyApplication.kt b/app/src/main/java/com/skydoves/disneymotions/DisneyApplication.kt
new file mode 100644
index 0000000..f48b4f8
--- /dev/null
+++ b/app/src/main/java/com/skydoves/disneymotions/DisneyApplication.kt
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+@file:Suppress("unused")
+
+package com.skydoves.disneymotions
+
+import android.app.Application
+import com.bumptech.glide.request.target.ViewTarget
+import com.skydoves.disneymotions.di.networkModule
+import com.skydoves.disneymotions.di.persistenceModule
+import com.skydoves.disneymotions.di.repositoryModule
+import com.skydoves.disneymotions.di.viewModelModule
+import org.koin.android.ext.koin.androidContext
+import org.koin.core.context.startKoin
+import timber.log.Timber
+
+class DisneyApplication : Application() {
+
+ override fun onCreate() {
+ super.onCreate()
+
+ ViewTarget.setTagId(R.string.app_name)
+
+ startKoin {
+ androidContext(this@DisneyApplication)
+ modules(networkModule)
+ modules(persistenceModule)
+ modules(repositoryModule)
+ modules(viewModelModule)
+ }
+
+ if (BuildConfig.DEBUG) {
+ Timber.plant(Timber.DebugTree())
+ }
+ }
+}
diff --git a/app/src/main/java/com/skydoves/disneymotions/base/DatabindingActivity.kt b/app/src/main/java/com/skydoves/disneymotions/base/DatabindingActivity.kt
new file mode 100644
index 0000000..7ceb272
--- /dev/null
+++ b/app/src/main/java/com/skydoves/disneymotions/base/DatabindingActivity.kt
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+package com.skydoves.disneymotions.base
+
+import androidx.annotation.LayoutRes
+import androidx.appcompat.app.AppCompatActivity
+import androidx.databinding.DataBindingUtil
+import androidx.databinding.ViewDataBinding
+
+/**
+ * DatabindingActivity is an abstract class for providing [DataBindingUtil].
+ * provides implementations of only [ViewDataBinding] from an abstract information.
+ * Do not modify this class. This is a first-level abstraction class.
+ * If you want to add more specifications, make another class which extends [DatabindingActivity].
+ */
+abstract class DatabindingActivity : AppCompatActivity() {
+
+ protected inline fun binding(
+ @LayoutRes resId: Int
+ ): Lazy = lazy { DataBindingUtil.setContentView(this, resId) }
+}
diff --git a/app/src/main/java/com/skydoves/disneymotions/base/DatabindingFragment.kt b/app/src/main/java/com/skydoves/disneymotions/base/DatabindingFragment.kt
new file mode 100644
index 0000000..f9650cd
--- /dev/null
+++ b/app/src/main/java/com/skydoves/disneymotions/base/DatabindingFragment.kt
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+package com.skydoves.disneymotions.base
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.annotation.LayoutRes
+import androidx.databinding.DataBindingUtil
+import androidx.databinding.ViewDataBinding
+import androidx.fragment.app.Fragment
+
+/**
+ * ViewModelFragment is an abstract class for providing [DataBindingUtil].
+ * provides implementations of only [ViewDataBinding] from an abstract information.
+ * Do not modify this class. This is a first-level abstraction class.
+ * If you want to add more specifications, make another class which extends [DatabindingFragment].
+ */
+abstract class DatabindingFragment : Fragment() {
+
+ protected inline fun binding(
+ inflater: LayoutInflater,
+ @LayoutRes resId: Int,
+ container: ViewGroup?
+ ): T = DataBindingUtil.inflate(inflater, resId, container, false)
+}
diff --git a/app/src/main/java/com/skydoves/disneymotions/base/LiveCoroutinesViewModel.kt b/app/src/main/java/com/skydoves/disneymotions/base/LiveCoroutinesViewModel.kt
new file mode 100644
index 0000000..04d799a
--- /dev/null
+++ b/app/src/main/java/com/skydoves/disneymotions/base/LiveCoroutinesViewModel.kt
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+package com.skydoves.disneymotions.base
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.liveData
+import androidx.lifecycle.viewModelScope
+import kotlinx.coroutines.Dispatchers
+
+abstract class LiveCoroutinesViewModel : ViewModel() {
+
+ inline fun launchOnViewModelScope(crossinline block: suspend () -> LiveData): LiveData {
+ return liveData(viewModelScope.coroutineContext + Dispatchers.IO) {
+ emitSource(block())
+ }
+ }
+}
diff --git a/app/src/main/java/com/skydoves/disneymotions/binding/ActivityBinding.kt b/app/src/main/java/com/skydoves/disneymotions/binding/ActivityBinding.kt
new file mode 100644
index 0000000..35bc5bf
--- /dev/null
+++ b/app/src/main/java/com/skydoves/disneymotions/binding/ActivityBinding.kt
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+package com.skydoves.disneymotions.binding
+
+import androidx.appcompat.app.AppCompatActivity
+import androidx.databinding.BindingAdapter
+import com.google.android.material.appbar.MaterialToolbar
+import com.skydoves.disneymotions.R
+
+fun AppCompatActivity.simpleToolbarWithHome(toolbar: MaterialToolbar, title_: String = "") {
+ setSupportActionBar(toolbar)
+ supportActionBar?.run {
+ setHomeAsUpIndicator(R.drawable.ic_arrow_back)
+ setDisplayHomeAsUpEnabled(true)
+ title = title_
+ }
+}
+
+@BindingAdapter("simpleToolbarWithHome", "simpleToolbarTitle")
+fun bindToolbarWithTitle(toolbar: MaterialToolbar, activity: AppCompatActivity, title: String) {
+ activity.simpleToolbarWithHome(toolbar, title)
+}
diff --git a/app/src/main/java/com/skydoves/disneymotions/binding/RecyclerViewBinding.kt b/app/src/main/java/com/skydoves/disneymotions/binding/RecyclerViewBinding.kt
new file mode 100644
index 0000000..3b26341
--- /dev/null
+++ b/app/src/main/java/com/skydoves/disneymotions/binding/RecyclerViewBinding.kt
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+package com.skydoves.disneymotions.binding
+
+import android.widget.Toast
+import androidx.databinding.BindingAdapter
+import androidx.lifecycle.LiveData
+import androidx.recyclerview.widget.RecyclerView
+import com.skydoves.baserecyclerviewadapter.BaseAdapter
+import com.skydoves.disneymotions.model.Poster
+import com.skydoves.disneymotions.view.adapter.PosterAdapter
+import com.skydoves.disneymotions.view.adapter.PosterLineAdapter
+import com.skydoves.whatif.whatIfNotNull
+import com.skydoves.whatif.whatIfNotNullOrEmpty
+
+@BindingAdapter("adapter")
+fun bindAdapter(view: RecyclerView, baseAdapter: BaseAdapter) {
+ view.adapter = baseAdapter
+}
+
+@BindingAdapter("toast")
+fun bindToast(view: RecyclerView, text: LiveData) {
+ text.value.whatIfNotNull {
+ Toast.makeText(view.context, it, Toast.LENGTH_SHORT).show()
+ }
+}
+
+@BindingAdapter("adapterPosterLIst")
+fun bindAdapterPosterLIst(view: RecyclerView, posters: List?) {
+ posters.whatIfNotNullOrEmpty {
+ (view.adapter as? PosterAdapter)?.addPosterList(it)
+ }
+}
+
+@BindingAdapter("adapterPosterLineLIst")
+fun bindAdapterPosterLineLIst(view: RecyclerView, posters: List?) {
+ posters.whatIfNotNullOrEmpty {
+ (view.adapter as? PosterLineAdapter)?.addPosterList(it)
+ }
+}
diff --git a/app/src/main/java/com/skydoves/disneymotions/binding/ViewBinding.kt b/app/src/main/java/com/skydoves/disneymotions/binding/ViewBinding.kt
new file mode 100644
index 0000000..3a062b4
--- /dev/null
+++ b/app/src/main/java/com/skydoves/disneymotions/binding/ViewBinding.kt
@@ -0,0 +1,118 @@
+/*
+ * 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.
+ */
+
+package com.skydoves.disneymotions.binding
+
+import android.graphics.Color
+import android.transition.TransitionManager
+import android.view.View
+import androidx.appcompat.widget.AppCompatImageView
+import androidx.coordinatorlayout.widget.CoordinatorLayout
+import androidx.databinding.BindingAdapter
+import androidx.viewpager.widget.PagerAdapter
+import androidx.viewpager.widget.ViewPager
+import com.bumptech.glide.Glide
+import com.google.android.material.appbar.AppBarLayout
+import com.google.android.material.appbar.AppBarLayout.OnOffsetChangedListener
+import com.google.android.material.bottomnavigation.BottomNavigationView
+import com.google.android.material.floatingactionbutton.FloatingActionButton
+import com.google.android.material.transition.MaterialArcMotion
+import com.google.android.material.transition.MaterialContainerTransform
+import com.skydoves.disneymotions.R
+import com.skydoves.disneymotions.extensions.gone
+import com.skydoves.disneymotions.extensions.visible
+import kotlin.math.abs
+
+@BindingAdapter("loadImage")
+fun bindLoadImage(view: AppCompatImageView, url: String) {
+ Glide.with(view.context)
+ .load(url)
+ .into(view)
+}
+
+@BindingAdapter("pagerAdapter")
+fun bindPagerAdapter(view: ViewPager, adapter: PagerAdapter) {
+ view.adapter = adapter
+ view.offscreenPageLimit = 3
+}
+
+@BindingAdapter("bindNavigation")
+fun bindNavigation(view: ViewPager, navigationView: BottomNavigationView) {
+ view.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
+ override fun onPageScrollStateChanged(state: Int) = Unit
+ override fun onPageScrolled(
+ position: Int,
+ positionOffset: Float,
+ positionOffsetPixels: Int
+ ) = Unit
+
+ override fun onPageSelected(position: Int) {
+ navigationView.menu.getItem(position).isChecked = true
+ }
+ })
+
+ navigationView.setOnNavigationItemSelectedListener {
+ when (it.itemId) {
+ R.id.action_one -> view.currentItem = 0
+ R.id.action_two -> view.currentItem = 1
+ R.id.action_three -> view.currentItem = 2
+ }
+ true
+ }
+}
+
+@BindingAdapter("bindFab")
+fun bindAppBarLayoutWithFab(appBarLayout: AppBarLayout, fab: FloatingActionButton) {
+ appBarLayout.addOnOffsetChangedListener(
+ OnOffsetChangedListener { appBarLayout1: AppBarLayout, verticalOffset: Int ->
+ val verticalOffsetPercentage = abs(
+ verticalOffset).toFloat() / appBarLayout1.totalScrollRange.toFloat()
+ if (verticalOffsetPercentage > 0.4f && fab.isOrWillBeShown) {
+ fab.hide()
+ } else if (verticalOffsetPercentage <= 0.4f && fab.isOrWillBeHidden && fab.tag != View.GONE) {
+ fab.show()
+ }
+ })
+}
+
+@BindingAdapter("transformFab", "transformContainer")
+fun bindTransformFab(view: View, fab: FloatingActionButton, container: CoordinatorLayout) {
+ fab.setOnClickListener {
+ // Begin the transition by changing properties on the start and end views or
+ // removing/adding them from the hierarchy.
+ fab.tag = View.GONE
+ TransitionManager.beginDelayedTransition(container, getTransform(fab, view))
+ fab.gone()
+ view.visible()
+ }
+
+ view.setOnClickListener {
+ fab.tag = View.VISIBLE
+ TransitionManager.beginDelayedTransition(container, getTransform(view, fab))
+ fab.visible()
+ view.gone()
+ }
+}
+
+internal fun getTransform(mStartView: View, mEndView: View): MaterialContainerTransform {
+ return MaterialContainerTransform(mStartView.context).apply {
+ startView = mStartView
+ endView = mEndView
+ pathMotion = MaterialArcMotion()
+ duration = 650
+ scrimColor = Color.TRANSPARENT
+ }
+}
diff --git a/app/src/main/java/com/skydoves/disneymotions/di/NetworkModule.kt b/app/src/main/java/com/skydoves/disneymotions/di/NetworkModule.kt
new file mode 100644
index 0000000..1807f86
--- /dev/null
+++ b/app/src/main/java/com/skydoves/disneymotions/di/NetworkModule.kt
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+package com.skydoves.disneymotions.di
+
+import com.skydoves.disneymotions.network.DisneyClient
+import com.skydoves.disneymotions.network.DisneyService
+import com.skydoves.disneymotions.network.RequestInterceptor
+import okhttp3.OkHttpClient
+import org.koin.dsl.module
+import retrofit2.Retrofit
+import retrofit2.converter.gson.GsonConverterFactory
+
+val networkModule = module {
+
+ single {
+ OkHttpClient.Builder()
+ .addInterceptor(RequestInterceptor())
+ .build()
+ }
+
+ single {
+ Retrofit.Builder()
+ .client(get())
+ .baseUrl("https://gist.githubusercontent.com/skydoves/aa3bbbf495b0fa91db8a9e89f34e4873/raw/a1a13d37027e8920412da5f00f6a89c5a3dbfb9a/")
+ .addConverterFactory(GsonConverterFactory.create())
+ .build()
+ }
+
+ single { get().create(DisneyService::class.java) }
+
+ single { DisneyClient(get()) }
+}
diff --git a/app/src/main/java/com/skydoves/disneymotions/di/PersistenceModule.kt b/app/src/main/java/com/skydoves/disneymotions/di/PersistenceModule.kt
new file mode 100644
index 0000000..194f943
--- /dev/null
+++ b/app/src/main/java/com/skydoves/disneymotions/di/PersistenceModule.kt
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+package com.skydoves.disneymotions.di
+
+import androidx.room.Room
+import com.skydoves.disneymotions.R
+import com.skydoves.disneymotions.persistence.AppDatabase
+import org.koin.android.ext.koin.androidApplication
+import org.koin.dsl.module
+
+val persistenceModule = module {
+
+ single {
+ Room
+ .databaseBuilder(androidApplication(), AppDatabase::class.java,
+ androidApplication().getString(R.string.database))
+ .allowMainThreadQueries()
+ .fallbackToDestructiveMigration()
+ .build()
+ }
+
+ single { get().posterDao() }
+}
diff --git a/app/src/main/java/com/skydoves/disneymotions/di/RepositoryModule.kt b/app/src/main/java/com/skydoves/disneymotions/di/RepositoryModule.kt
new file mode 100644
index 0000000..6d28039
--- /dev/null
+++ b/app/src/main/java/com/skydoves/disneymotions/di/RepositoryModule.kt
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+package com.skydoves.disneymotions.di
+
+import com.skydoves.disneymotions.repository.DetailRepository
+import com.skydoves.disneymotions.repository.MainRepository
+import org.koin.dsl.module
+
+val repositoryModule = module {
+
+ single { MainRepository(get(), get()) }
+
+ single { DetailRepository(get()) }
+}
diff --git a/app/src/main/java/com/skydoves/disneymotions/di/ViewModelModule.kt b/app/src/main/java/com/skydoves/disneymotions/di/ViewModelModule.kt
new file mode 100644
index 0000000..d92d1e4
--- /dev/null
+++ b/app/src/main/java/com/skydoves/disneymotions/di/ViewModelModule.kt
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+package com.skydoves.disneymotions.di
+
+import com.skydoves.disneymotions.view.ui.details.PosterDetailViewModel
+import com.skydoves.disneymotions.view.ui.main.MainViewModel
+import org.koin.android.viewmodel.dsl.viewModel
+import org.koin.dsl.module
+
+val viewModelModule = module {
+
+ viewModel { MainViewModel(get()) }
+
+ viewModel { PosterDetailViewModel(get()) }
+}
diff --git a/app/src/main/java/com/skydoves/disneymotions/extensions/ActivityExtensions.kt b/app/src/main/java/com/skydoves/disneymotions/extensions/ActivityExtensions.kt
new file mode 100644
index 0000000..776c9c7
--- /dev/null
+++ b/app/src/main/java/com/skydoves/disneymotions/extensions/ActivityExtensions.kt
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+package com.skydoves.disneymotions.extensions
+
+import android.view.View
+import android.view.Window
+import androidx.appcompat.app.AppCompatActivity
+import androidx.core.view.ViewCompat
+import com.google.android.material.transition.MaterialArcMotion
+import com.google.android.material.transition.MaterialContainerTransform
+import com.google.android.material.transition.MaterialContainerTransformSharedElementCallback
+
+/** get a material container arc transform. */
+fun AppCompatActivity.getContentTransform(): MaterialContainerTransform {
+ return MaterialContainerTransform(this).apply {
+ addTarget(android.R.id.content)
+ duration = 450
+ pathMotion = MaterialArcMotion()
+ }
+}
+
+/** apply material exit container transformation. */
+fun AppCompatActivity.applyExitMaterialTransform() {
+ window.requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS)
+ setExitSharedElementCallback(MaterialContainerTransformSharedElementCallback())
+ window.sharedElementsUseOverlay = false
+}
+
+/** apply material entered container transformation. */
+fun AppCompatActivity.applyMaterialTransform(transitionName: String) {
+ window.requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS)
+ ViewCompat.setTransitionName(findViewById(android.R.id.content), transitionName)
+
+ // set up shared element transition
+ setEnterSharedElementCallback(MaterialContainerTransformSharedElementCallback())
+ setEnterSharedElementCallback(MaterialContainerTransformSharedElementCallback())
+ window.sharedElementEnterTransition = getContentTransform()
+ window.sharedElementReturnTransition = getContentTransform()
+}
diff --git a/app/src/main/java/com/skydoves/disneymotions/extensions/ViewExtensions.kt b/app/src/main/java/com/skydoves/disneymotions/extensions/ViewExtensions.kt
new file mode 100644
index 0000000..cc7f148
--- /dev/null
+++ b/app/src/main/java/com/skydoves/disneymotions/extensions/ViewExtensions.kt
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+package com.skydoves.disneymotions.extensions
+
+import android.view.View
+
+/** makes visible a view. */
+fun View.visible() {
+ visibility = View.VISIBLE
+}
+
+/** makes gone a view. */
+fun View.gone() {
+ visibility = View.GONE
+}
diff --git a/app/src/main/java/com/skydoves/disneymotions/model/Poster.kt b/app/src/main/java/com/skydoves/disneymotions/model/Poster.kt
new file mode 100644
index 0000000..e7fb1cb
--- /dev/null
+++ b/app/src/main/java/com/skydoves/disneymotions/model/Poster.kt
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+package com.skydoves.disneymotions.model
+
+import android.os.Parcelable
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+import kotlinx.android.parcel.Parcelize
+
+@Parcelize
+@Entity
+data class Poster(
+ @PrimaryKey val id: Long,
+ val name: String,
+ val release: String,
+ val playtime: String,
+ val description: String,
+ val plot: String,
+ val poster: String
+) : Parcelable
diff --git a/app/src/main/java/com/skydoves/disneymotions/network/ApiResponse.kt b/app/src/main/java/com/skydoves/disneymotions/network/ApiResponse.kt
new file mode 100644
index 0000000..e743623
--- /dev/null
+++ b/app/src/main/java/com/skydoves/disneymotions/network/ApiResponse.kt
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ */
+
+package com.skydoves.disneymotions.network
+
+import okhttp3.ResponseBody
+import retrofit2.Response
+
+@Suppress("unused")
+sealed class ApiResponse {
+
+ /**
+ * API Success response class from retrofit.
+ *
+ * [data] is optional. (There are responses without data)
+ */
+ class Success(response: Response) : ApiResponse() {
+ val data: T? = response.body()
+ override fun toString() = "[ApiResponse.Success]: $data"
+ }
+
+ /**
+ * API Failure response class.
+ *
+ * ## Throw Exception case.
+ * Gets called when an unexpected exception occurs while creating the request or processing the response.
+ *
+ * ## API Network format error case.
+ * API communication conventions do not match or applications need to handle errors.
+ *
+ * ## API Network Excepttion error case.
+ * Gets called when an unexpected exception occurs while creating the request or processing the response.
+ */
+ sealed class Failure {
+ class Error(response: Response) : ApiResponse() {
+ val responseBody: ResponseBody? = response.errorBody()?.apply { close() }
+ val code: Int = response.code()
+ override fun toString(): String = "[ApiResponse.Failure $code]: ${responseBody?.string()}"
+ }
+
+ class Exception(exception: Throwable) : ApiResponse() {
+ val message: String? = exception.localizedMessage
+ override fun toString(): String = "[ApiResponse.Failure]: $message"
+ }
+ }
+
+ companion object {
+ /**
+ * ApiResponse Factory
+ *
+ * [Failure] factory function. Only receives [Throwable] arguments.
+ */
+ fun error(ex: Throwable) = Failure.Exception(ex)
+
+ /**
+ * ApiResponse Factory
+ *
+ * [f] Create ApiResponse from [retrofit2.Response] returning from the block.
+ * If [retrofit2.Response] has no errors, it will create [ApiResponse.Success]
+ * If [retrofit2.Response] has errors, it will create [ApiResponse.Failure.Error]
+ */
+ fun of(f: () -> Response): ApiResponse = try {
+ val response = f()
+ if (response.isSuccessful) {
+ Success(response)
+ } else {
+ Failure.Error(response)
+ }
+ } catch (ex: Exception) {
+ Failure.Exception(ex)
+ }
+ }
+}
diff --git a/app/src/main/java/com/skydoves/disneymotions/network/DisneyClient.kt b/app/src/main/java/com/skydoves/disneymotions/network/DisneyClient.kt
new file mode 100644
index 0000000..f8a55f3
--- /dev/null
+++ b/app/src/main/java/com/skydoves/disneymotions/network/DisneyClient.kt
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+package com.skydoves.disneymotions.network
+
+import com.skydoves.disneymotions.model.Poster
+
+class DisneyClient(private val disneyService: DisneyService) {
+
+ fun fetchDisneyPosters(
+ onResult: (response: ApiResponse>) -> Unit
+ ) {
+ this.disneyService.fetchDisneyPosterList().transform(onResult)
+ }
+}
diff --git a/app/src/main/java/com/skydoves/disneymotions/network/DisneyService.kt b/app/src/main/java/com/skydoves/disneymotions/network/DisneyService.kt
new file mode 100644
index 0000000..7ea60fd
--- /dev/null
+++ b/app/src/main/java/com/skydoves/disneymotions/network/DisneyService.kt
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+package com.skydoves.disneymotions.network
+
+import com.skydoves.disneymotions.model.Poster
+import retrofit2.Call
+import retrofit2.http.GET
+
+interface DisneyService {
+
+ @GET("DisneyPosters.json")
+ fun fetchDisneyPosterList(): Call>
+}
diff --git a/app/src/main/java/com/skydoves/disneymotions/network/RequestInterceptor.kt b/app/src/main/java/com/skydoves/disneymotions/network/RequestInterceptor.kt
new file mode 100644
index 0000000..802e5d5
--- /dev/null
+++ b/app/src/main/java/com/skydoves/disneymotions/network/RequestInterceptor.kt
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+package com.skydoves.disneymotions.network
+
+import okhttp3.Interceptor
+import okhttp3.Response
+import timber.log.Timber
+
+class RequestInterceptor : Interceptor {
+ override fun intercept(chain: Interceptor.Chain): Response {
+ val originalRequest = chain.request()
+ val request = originalRequest.newBuilder().url(originalRequest.url).build()
+ Timber.d(request.toString())
+ return chain.proceed(request)
+ }
+}
diff --git a/app/src/main/java/com/skydoves/disneymotions/network/ResponseTransformer.kt b/app/src/main/java/com/skydoves/disneymotions/network/ResponseTransformer.kt
new file mode 100644
index 0000000..085f99b
--- /dev/null
+++ b/app/src/main/java/com/skydoves/disneymotions/network/ResponseTransformer.kt
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+package com.skydoves.disneymotions.network
+
+import retrofit2.Call
+import retrofit2.Callback
+
+/** transforms [Call] to [ApiResponse] via enqueueing response callback. */
+fun Call.transform(onResult: (response: ApiResponse) -> Unit) {
+ enqueue(object : Callback {
+ override fun onResponse(call: Call, response: retrofit2.Response) {
+ onResult(ApiResponse.of { response })
+ }
+
+ override fun onFailure(call: Call, throwable: Throwable) {
+ onResult(ApiResponse.error(throwable))
+ }
+ })
+}
+
+/** gets the [ApiResponse.Failure.Error] message with a error code. */
+fun ApiResponse.Failure.Error.message() = "$code: ${responseBody?.string()}"
+
+/** gets the [ApiResponse.Failure.Exception] message. */
+fun ApiResponse.Failure.Exception.message() = "$message"
diff --git a/app/src/main/java/com/skydoves/disneymotions/persistence/AppDatabase.kt b/app/src/main/java/com/skydoves/disneymotions/persistence/AppDatabase.kt
new file mode 100644
index 0000000..d352efd
--- /dev/null
+++ b/app/src/main/java/com/skydoves/disneymotions/persistence/AppDatabase.kt
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+package com.skydoves.disneymotions.persistence
+
+import androidx.room.Database
+import androidx.room.RoomDatabase
+import com.skydoves.disneymotions.model.Poster
+
+@Database(entities = [Poster::class], version = 1, exportSchema = false)
+abstract class AppDatabase : RoomDatabase() {
+
+ abstract fun posterDao(): PosterDao
+}
diff --git a/app/src/main/java/com/skydoves/disneymotions/persistence/PosterDao.kt b/app/src/main/java/com/skydoves/disneymotions/persistence/PosterDao.kt
new file mode 100644
index 0000000..0ca96cc
--- /dev/null
+++ b/app/src/main/java/com/skydoves/disneymotions/persistence/PosterDao.kt
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+package com.skydoves.disneymotions.persistence
+
+import androidx.room.Dao
+import androidx.room.Insert
+import androidx.room.OnConflictStrategy
+import androidx.room.Query
+import com.skydoves.disneymotions.model.Poster
+
+@Dao
+interface PosterDao {
+
+ @Insert(onConflict = OnConflictStrategy.REPLACE)
+ fun insertPosterList(posters: List)
+
+ @Query("SELECT * FROM Poster WHERE id = :id_")
+ fun getPoster(id_: Long): Poster
+
+ @Query("SELECT * FROM Poster")
+ fun getPosterList(): List
+}
diff --git a/app/src/main/java/com/skydoves/disneymotions/repository/DetailRepository.kt b/app/src/main/java/com/skydoves/disneymotions/repository/DetailRepository.kt
new file mode 100644
index 0000000..a5a0c51
--- /dev/null
+++ b/app/src/main/java/com/skydoves/disneymotions/repository/DetailRepository.kt
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+package com.skydoves.disneymotions.repository
+
+import com.skydoves.disneymotions.persistence.PosterDao
+
+class DetailRepository constructor(
+ private val posterDao: PosterDao
+) : Repository {
+
+ override var isLoading = false
+
+ fun getPosterById(id: Long) = posterDao.getPoster(id)
+}
diff --git a/app/src/main/java/com/skydoves/disneymotions/repository/MainRepository.kt b/app/src/main/java/com/skydoves/disneymotions/repository/MainRepository.kt
new file mode 100644
index 0000000..8545a25
--- /dev/null
+++ b/app/src/main/java/com/skydoves/disneymotions/repository/MainRepository.kt
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+package com.skydoves.disneymotions.repository
+
+import androidx.lifecycle.MutableLiveData
+import com.skydoves.disneymotions.model.Poster
+import com.skydoves.disneymotions.network.ApiResponse
+import com.skydoves.disneymotions.network.DisneyClient
+import com.skydoves.disneymotions.network.message
+import com.skydoves.disneymotions.persistence.PosterDao
+import com.skydoves.whatif.whatIfNotNull
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+import timber.log.Timber
+
+class MainRepository constructor(
+ private val disneyClient: DisneyClient,
+ private val posterDao: PosterDao
+) : Repository {
+
+ override var isLoading = false
+
+ init {
+ Timber.d("Injection MainRepository")
+ }
+
+ suspend fun loadDisneyPosters(error: (String) -> Unit) = withContext(Dispatchers.IO) {
+ val liveData = MutableLiveData>()
+ var posters = posterDao.getPosterList()
+ if (posters.isEmpty()) {
+ isLoading = true
+ disneyClient.fetchDisneyPosters { response ->
+ isLoading = false
+ when (response) {
+ is ApiResponse.Success -> {
+ response.data.whatIfNotNull {
+ posters = it
+ liveData.postValue(it)
+ posterDao.insertPosterList(it)
+ }
+ }
+ is ApiResponse.Failure.Error -> error(response.message())
+ is ApiResponse.Failure.Exception -> error(response.message())
+ }
+ }
+ }
+ liveData.apply { postValue(posters) }
+ }
+}
diff --git a/app/src/main/java/com/skydoves/disneymotions/repository/Repository.kt b/app/src/main/java/com/skydoves/disneymotions/repository/Repository.kt
new file mode 100644
index 0000000..2b5694b
--- /dev/null
+++ b/app/src/main/java/com/skydoves/disneymotions/repository/Repository.kt
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+package com.skydoves.disneymotions.repository
+
+/** Repository is an interface for configuring base repository classes. */
+interface Repository {
+
+ // this override property is for saving network loading status.
+ var isLoading: Boolean
+}
diff --git a/app/src/main/java/com/skydoves/disneymotions/view/adapter/PosterAdapter.kt b/app/src/main/java/com/skydoves/disneymotions/view/adapter/PosterAdapter.kt
new file mode 100644
index 0000000..5097ef0
--- /dev/null
+++ b/app/src/main/java/com/skydoves/disneymotions/view/adapter/PosterAdapter.kt
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+package com.skydoves.disneymotions.view.adapter
+
+import android.view.View
+import com.skydoves.baserecyclerviewadapter.BaseAdapter
+import com.skydoves.baserecyclerviewadapter.SectionRow
+import com.skydoves.disneymotions.R
+import com.skydoves.disneymotions.model.Poster
+import com.skydoves.disneymotions.view.viewholder.PosterViewHolder
+
+class PosterAdapter : BaseAdapter() {
+
+ init {
+ addSection(arrayListOf())
+ }
+
+ fun addPosterList(posters: List) {
+ sections().first().run {
+ clear()
+ addAll(posters)
+ notifyDataSetChanged()
+ }
+ }
+
+ override fun layout(sectionRow: SectionRow) = R.layout.item_poster
+
+ override fun viewHolder(layout: Int, view: View) = PosterViewHolder(view)
+}
diff --git a/app/src/main/java/com/skydoves/disneymotions/view/adapter/PosterLineAdapter.kt b/app/src/main/java/com/skydoves/disneymotions/view/adapter/PosterLineAdapter.kt
new file mode 100644
index 0000000..7753196
--- /dev/null
+++ b/app/src/main/java/com/skydoves/disneymotions/view/adapter/PosterLineAdapter.kt
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+package com.skydoves.disneymotions.view.adapter
+
+import android.view.View
+import com.skydoves.baserecyclerviewadapter.BaseAdapter
+import com.skydoves.baserecyclerviewadapter.SectionRow
+import com.skydoves.disneymotions.R
+import com.skydoves.disneymotions.model.Poster
+import com.skydoves.disneymotions.view.viewholder.PosterLineViewHolder
+
+class PosterLineAdapter : BaseAdapter() {
+
+ init {
+ addSection(arrayListOf())
+ }
+
+ fun addPosterList(posters: List) {
+ sections().first().run {
+ clear()
+ addAll(posters)
+ notifyDataSetChanged()
+ }
+ }
+
+ override fun layout(sectionRow: SectionRow) = R.layout.item_poster_line
+
+ override fun viewHolder(layout: Int, view: View) = PosterLineViewHolder(view)
+}
diff --git a/app/src/main/java/com/skydoves/disneymotions/view/ui/details/PosterDetailActivity.kt b/app/src/main/java/com/skydoves/disneymotions/view/ui/details/PosterDetailActivity.kt
new file mode 100644
index 0000000..81af522
--- /dev/null
+++ b/app/src/main/java/com/skydoves/disneymotions/view/ui/details/PosterDetailActivity.kt
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+package com.skydoves.disneymotions.view.ui.details
+
+import android.app.Activity
+import android.app.ActivityOptions
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.view.View
+import com.skydoves.disneymotions.R
+import com.skydoves.disneymotions.base.DatabindingActivity
+import com.skydoves.disneymotions.databinding.ActivityPosterDetailBinding
+import com.skydoves.disneymotions.extensions.applyMaterialTransform
+import com.skydoves.disneymotions.model.Poster
+import org.koin.android.viewmodel.ext.android.getViewModel
+
+class PosterDetailActivity : DatabindingActivity() {
+
+ private val binding: ActivityPosterDetailBinding by binding(R.layout.activity_poster_detail)
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ val poster =
+ getViewModel().getPoster(intent.getLongExtra(posterKey, 0))
+ applyMaterialTransform(poster.name)
+ binding.apply {
+ this.poster = poster
+ activity = this@PosterDetailActivity
+ container = detailContainer
+ fab = fabMore
+ }
+ }
+
+ companion object {
+ private const val posterKey = "posterKey"
+ fun startActivityModel(context: Context?, startView: View, poster: Poster) {
+ if (context is Activity) {
+ val intent = Intent(context, PosterDetailActivity::class.java)
+ intent.putExtra(
+ posterKey, poster.id)
+ val options = ActivityOptions.makeSceneTransitionAnimation(context,
+ startView, poster.name
+ )
+ context.startActivity(intent, options.toBundle())
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/com/skydoves/disneymotions/view/ui/details/PosterDetailViewModel.kt b/app/src/main/java/com/skydoves/disneymotions/view/ui/details/PosterDetailViewModel.kt
new file mode 100644
index 0000000..4c58ca9
--- /dev/null
+++ b/app/src/main/java/com/skydoves/disneymotions/view/ui/details/PosterDetailViewModel.kt
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+package com.skydoves.disneymotions.view.ui.details
+
+import com.skydoves.disneymotions.base.LiveCoroutinesViewModel
+import com.skydoves.disneymotions.repository.DetailRepository
+
+class PosterDetailViewModel(
+ private val repository: DetailRepository
+) : LiveCoroutinesViewModel() {
+
+ fun getPoster(id: Long) = repository.getPosterById(id)
+}
diff --git a/app/src/main/java/com/skydoves/disneymotions/view/ui/main/HomeFragment.kt b/app/src/main/java/com/skydoves/disneymotions/view/ui/main/HomeFragment.kt
new file mode 100644
index 0000000..d2b6422
--- /dev/null
+++ b/app/src/main/java/com/skydoves/disneymotions/view/ui/main/HomeFragment.kt
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+package com.skydoves.disneymotions.view.ui.main
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import com.skydoves.disneymotions.R
+import com.skydoves.disneymotions.base.DatabindingFragment
+import com.skydoves.disneymotions.databinding.FragmentHomeBinding
+import com.skydoves.disneymotions.view.adapter.PosterAdapter
+import org.koin.android.viewmodel.ext.android.getViewModel
+
+class HomeFragment : DatabindingFragment() {
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ return binding(inflater, R.layout.fragment_home, container).apply {
+ viewModel = getViewModel().apply { fetchDisneyPosterList() }
+ lifecycleOwner = this@HomeFragment
+ adapter = PosterAdapter()
+ }.root
+ }
+}
diff --git a/app/src/main/java/com/skydoves/disneymotions/view/ui/main/LibraryFragment.kt b/app/src/main/java/com/skydoves/disneymotions/view/ui/main/LibraryFragment.kt
new file mode 100644
index 0000000..66efbbf
--- /dev/null
+++ b/app/src/main/java/com/skydoves/disneymotions/view/ui/main/LibraryFragment.kt
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+package com.skydoves.disneymotions.view.ui.main
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import com.skydoves.disneymotions.R
+import com.skydoves.disneymotions.base.DatabindingFragment
+import com.skydoves.disneymotions.databinding.FragmentLibraryBinding
+import com.skydoves.disneymotions.view.adapter.PosterLineAdapter
+import org.koin.android.viewmodel.ext.android.getViewModel
+
+class LibraryFragment : DatabindingFragment() {
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ return binding(inflater, R.layout.fragment_library, container).apply {
+ viewModel = getViewModel().apply { fetchDisneyPosterList() }
+ lifecycleOwner = this@LibraryFragment
+ adapter = PosterLineAdapter()
+ }.root
+ }
+}
diff --git a/app/src/main/java/com/skydoves/disneymotions/view/ui/main/MainActivity.kt b/app/src/main/java/com/skydoves/disneymotions/view/ui/main/MainActivity.kt
new file mode 100644
index 0000000..77bd124
--- /dev/null
+++ b/app/src/main/java/com/skydoves/disneymotions/view/ui/main/MainActivity.kt
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+package com.skydoves.disneymotions.view.ui.main
+
+import android.os.Bundle
+import com.skydoves.disneymotions.R
+import com.skydoves.disneymotions.base.DatabindingActivity
+import com.skydoves.disneymotions.databinding.ActivityMainBinding
+import com.skydoves.disneymotions.extensions.applyExitMaterialTransform
+
+class MainActivity : DatabindingActivity() {
+
+ private val binding: ActivityMainBinding by binding(R.layout.activity_main)
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ applyExitMaterialTransform()
+ super.onCreate(savedInstanceState)
+ binding.apply {
+ pagerAdapter = MainPagerAdapter(supportFragmentManager)
+ navigation = mainBottomNavigation
+ }
+ }
+}
diff --git a/app/src/main/java/com/skydoves/disneymotions/view/ui/main/MainPagerAdapter.kt b/app/src/main/java/com/skydoves/disneymotions/view/ui/main/MainPagerAdapter.kt
new file mode 100644
index 0000000..1aebf08
--- /dev/null
+++ b/app/src/main/java/com/skydoves/disneymotions/view/ui/main/MainPagerAdapter.kt
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+package com.skydoves.disneymotions.view.ui.main
+
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.FragmentManager
+import androidx.fragment.app.FragmentPagerAdapter
+
+class MainPagerAdapter(fm: FragmentManager) :
+ FragmentPagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
+
+ override fun getItem(position: Int): Fragment {
+ return when (position) {
+ 0 -> HomeFragment()
+ 1 -> LibraryFragment()
+ else -> RadioFragment()
+ }
+ }
+
+ override fun getCount() = 3
+}
diff --git a/app/src/main/java/com/skydoves/disneymotions/view/ui/main/MainViewModel.kt b/app/src/main/java/com/skydoves/disneymotions/view/ui/main/MainViewModel.kt
new file mode 100644
index 0000000..739e6b4
--- /dev/null
+++ b/app/src/main/java/com/skydoves/disneymotions/view/ui/main/MainViewModel.kt
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+package com.skydoves.disneymotions.view.ui.main
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.switchMap
+import com.skydoves.disneymotions.base.LiveCoroutinesViewModel
+import com.skydoves.disneymotions.model.Poster
+import com.skydoves.disneymotions.repository.MainRepository
+import timber.log.Timber
+
+class MainViewModel constructor(
+ private val mainRepository: MainRepository
+) : LiveCoroutinesViewModel() {
+
+ private var posterFetchingLiveData: MutableLiveData = MutableLiveData()
+ val posterListLiveData: LiveData>
+
+ val toastLiveData: MutableLiveData = MutableLiveData()
+
+ init {
+ Timber.d("injection MainViewModel")
+
+ this.posterListLiveData = this.posterFetchingLiveData.switchMap {
+ launchOnViewModelScope {
+ this.mainRepository.loadDisneyPosters { this.toastLiveData.postValue(it) }
+ }
+ }
+ }
+
+ fun fetchDisneyPosterList() = this.posterFetchingLiveData.postValue(true)
+}
diff --git a/app/src/main/java/com/skydoves/disneymotions/view/ui/main/RadioFragment.kt b/app/src/main/java/com/skydoves/disneymotions/view/ui/main/RadioFragment.kt
new file mode 100644
index 0000000..d7c6e00
--- /dev/null
+++ b/app/src/main/java/com/skydoves/disneymotions/view/ui/main/RadioFragment.kt
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+package com.skydoves.disneymotions.view.ui.main
+
+import com.skydoves.disneymotions.base.DatabindingFragment
+
+// TODO [WIP]
+class RadioFragment : DatabindingFragment()
diff --git a/app/src/main/java/com/skydoves/disneymotions/view/viewholder/BindingLazy.kt b/app/src/main/java/com/skydoves/disneymotions/view/viewholder/BindingLazy.kt
new file mode 100644
index 0000000..eac75a6
--- /dev/null
+++ b/app/src/main/java/com/skydoves/disneymotions/view/viewholder/BindingLazy.kt
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+package com.skydoves.disneymotions.view.viewholder
+
+import android.view.View
+import androidx.databinding.DataBindingUtil
+import androidx.databinding.ViewDataBinding
+
+inline fun bindings(view: View): Lazy =
+ lazy {
+ requireNotNull(DataBindingUtil.bind(view)) { "cannot find the matched view to layout." }
+ }
diff --git a/app/src/main/java/com/skydoves/disneymotions/view/viewholder/PosterLineViewHolder.kt b/app/src/main/java/com/skydoves/disneymotions/view/viewholder/PosterLineViewHolder.kt
new file mode 100644
index 0000000..d957e9d
--- /dev/null
+++ b/app/src/main/java/com/skydoves/disneymotions/view/viewholder/PosterLineViewHolder.kt
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+package com.skydoves.disneymotions.view.viewholder
+
+import android.view.View
+import androidx.core.view.ViewCompat
+import com.skydoves.baserecyclerviewadapter.BaseViewHolder
+import com.skydoves.disneymotions.databinding.ItemPosterLineBinding
+import com.skydoves.disneymotions.model.Poster
+import com.skydoves.disneymotions.view.ui.details.PosterDetailActivity
+
+class PosterLineViewHolder(view: View) : BaseViewHolder(view) {
+
+ private lateinit var data: Poster
+ private val binding: ItemPosterLineBinding by bindings(view)
+
+ override fun bindData(data: Any) {
+ if (data is Poster) {
+ this.data = data
+ drawItemUI()
+ }
+ }
+
+ private fun drawItemUI() {
+ binding.apply {
+ ViewCompat.setTransitionName(binding.itemContainer, data.name)
+ poster = data
+ executePendingBindings()
+ }
+ }
+
+ override fun onClick(p0: View?) =
+ PosterDetailActivity.startActivityModel(context(), binding.itemContainer, data)
+
+ override fun onLongClick(p0: View?) = false
+}
diff --git a/app/src/main/java/com/skydoves/disneymotions/view/viewholder/PosterViewHolder.kt b/app/src/main/java/com/skydoves/disneymotions/view/viewholder/PosterViewHolder.kt
new file mode 100644
index 0000000..909b3e1
--- /dev/null
+++ b/app/src/main/java/com/skydoves/disneymotions/view/viewholder/PosterViewHolder.kt
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+package com.skydoves.disneymotions.view.viewholder
+
+import android.view.View
+import androidx.core.view.ViewCompat
+import com.skydoves.baserecyclerviewadapter.BaseViewHolder
+import com.skydoves.disneymotions.databinding.ItemPosterBinding
+import com.skydoves.disneymotions.model.Poster
+import com.skydoves.disneymotions.view.ui.details.PosterDetailActivity
+
+class PosterViewHolder(view: View) : BaseViewHolder(view) {
+
+ private lateinit var data: Poster
+ private val binding: ItemPosterBinding by bindings(view)
+
+ override fun bindData(data: Any) {
+ if (data is Poster) {
+ this.data = data
+ drawItemUI()
+ }
+ }
+
+ private fun drawItemUI() {
+ binding.apply {
+ ViewCompat.setTransitionName(binding.itemContainer, data.name)
+ poster = data
+ executePendingBindings()
+ }
+ }
+
+ override fun onClick(p0: View?) =
+ PosterDetailActivity.startActivityModel(context(), binding.itemContainer, data)
+
+ override fun onLongClick(p0: View?) = false
+}
diff --git a/app/src/main/res/drawable-hdpi/ic_add.png b/app/src/main/res/drawable-hdpi/ic_add.png
new file mode 100644
index 0000000..9999b98
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_add.png differ
diff --git a/app/src/main/res/drawable-hdpi/ic_arrow_back.png b/app/src/main/res/drawable-hdpi/ic_arrow_back.png
new file mode 100644
index 0000000..de3bc34
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_arrow_back.png differ
diff --git a/app/src/main/res/drawable-hdpi/ic_home.png b/app/src/main/res/drawable-hdpi/ic_home.png
new file mode 100644
index 0000000..fea55b8
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_home.png differ
diff --git a/app/src/main/res/drawable-hdpi/ic_library.png b/app/src/main/res/drawable-hdpi/ic_library.png
new file mode 100644
index 0000000..d40efde
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_library.png differ
diff --git a/app/src/main/res/drawable-hdpi/ic_radio.png b/app/src/main/res/drawable-hdpi/ic_radio.png
new file mode 100644
index 0000000..061217e
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_radio.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_add.png b/app/src/main/res/drawable-mdpi/ic_add.png
new file mode 100644
index 0000000..9d8a94e
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_add.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_arrow_back.png b/app/src/main/res/drawable-mdpi/ic_arrow_back.png
new file mode 100644
index 0000000..974cba8
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_arrow_back.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_home.png b/app/src/main/res/drawable-mdpi/ic_home.png
new file mode 100644
index 0000000..80e9fcb
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_home.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_library.png b/app/src/main/res/drawable-mdpi/ic_library.png
new file mode 100644
index 0000000..a053747
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_library.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_radio.png b/app/src/main/res/drawable-mdpi/ic_radio.png
new file mode 100644
index 0000000..87568e4
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_radio.png differ
diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 0000000..1f6bb29
--- /dev/null
+++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable-xhdpi/ic_add.png b/app/src/main/res/drawable-xhdpi/ic_add.png
new file mode 100644
index 0000000..6d8e55d
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_add.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_arrow_back.png b/app/src/main/res/drawable-xhdpi/ic_arrow_back.png
new file mode 100644
index 0000000..8214d9d
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_arrow_back.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_home.png b/app/src/main/res/drawable-xhdpi/ic_home.png
new file mode 100644
index 0000000..b7fda30
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_home.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_library.png b/app/src/main/res/drawable-xhdpi/ic_library.png
new file mode 100644
index 0000000..75c3ada
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_library.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_radio.png b/app/src/main/res/drawable-xhdpi/ic_radio.png
new file mode 100644
index 0000000..6ce069f
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_radio.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_add.png b/app/src/main/res/drawable-xxhdpi/ic_add.png
new file mode 100644
index 0000000..3a15191
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_add.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_arrow_back.png b/app/src/main/res/drawable-xxhdpi/ic_arrow_back.png
new file mode 100644
index 0000000..0e43ff9
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_arrow_back.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_home.png b/app/src/main/res/drawable-xxhdpi/ic_home.png
new file mode 100644
index 0000000..ebbba2e
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_home.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_library.png b/app/src/main/res/drawable-xxhdpi/ic_library.png
new file mode 100644
index 0000000..35c4edc
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_library.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_radio.png b/app/src/main/res/drawable-xxhdpi/ic_radio.png
new file mode 100644
index 0000000..466b96d
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_radio.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_add.png b/app/src/main/res/drawable-xxxhdpi/ic_add.png
new file mode 100644
index 0000000..078af52
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_add.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_arrow_back.png b/app/src/main/res/drawable-xxxhdpi/ic_arrow_back.png
new file mode 100644
index 0000000..7cbef74
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_arrow_back.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_home.png b/app/src/main/res/drawable-xxxhdpi/ic_home.png
new file mode 100644
index 0000000..a2a59d7
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_home.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_library.png b/app/src/main/res/drawable-xxxhdpi/ic_library.png
new file mode 100644
index 0000000..715aaa1
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_library.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_radio.png b/app/src/main/res/drawable-xxxhdpi/ic_radio.png
new file mode 100644
index 0000000..f1e027b
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_radio.png differ
diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..0d025f9
--- /dev/null
+++ b/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..ea1f511
--- /dev/null
+++ b/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_poster_detail.xml b/app/src/main/res/layout/activity_poster_detail.xml
new file mode 100644
index 0000000..400e83b
--- /dev/null
+++ b/app/src/main/res/layout/activity_poster_detail.xml
@@ -0,0 +1,185 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml
new file mode 100644
index 0000000..e348ce9
--- /dev/null
+++ b/app/src/main/res/layout/fragment_home.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_library.xml b/app/src/main/res/layout/fragment_library.xml
new file mode 100644
index 0000000..620269c
--- /dev/null
+++ b/app/src/main/res/layout/fragment_library.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_poster_detail.xml b/app/src/main/res/layout/fragment_poster_detail.xml
new file mode 100644
index 0000000..5657de2
--- /dev/null
+++ b/app/src/main/res/layout/fragment_poster_detail.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_poster.xml b/app/src/main/res/layout/item_poster.xml
new file mode 100644
index 0000000..cadf993
--- /dev/null
+++ b/app/src/main/res/layout/item_poster.xml
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_poster_line.xml b/app/src/main/res/layout/item_poster_line.xml
new file mode 100644
index 0000000..9023580
--- /dev/null
+++ b/app/src/main/res/layout/item_poster_line.xml
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/toolbar_home.xml b/app/src/main/res/layout/toolbar_home.xml
new file mode 100644
index 0000000..4989697
--- /dev/null
+++ b/app/src/main/res/layout/toolbar_home.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/menus.xml b/app/src/main/res/menu/menus.xml
new file mode 100644
index 0000000..da5d081
--- /dev/null
+++ b/app/src/main/res/menu/menus.xml
@@ -0,0 +1,22 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..898f3ed
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000..dffca36
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..64ba76f
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000..dae5e08
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..e5ed465
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..14ed0af
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..b0907ca
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..d8ae031
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..2c18de9
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..beed3cd
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..7bb92c5
--- /dev/null
+++ b/app/src/main/res/values/colors.xml
@@ -0,0 +1,25 @@
+
+
+ #651FFF
+ #6200EA
+ #651FFF
+ #2B292B
+ #424242
+ #212121
+ #8effffff
+ #b2ffffff
+ #ddffffff
+ #edf8f8f8
+ #ffffffff
+ #57A8D8
+ #FBC02D
+ #FFD600
+ #FBC02D
+ #FFA000
+ #FFA726
+ #FF6D00
+ #81C784
+ #388E3C
+ #81D4fA
+ #0091EA
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..587396e
--- /dev/null
+++ b/app/src/main/res/values/strings.xml
@@ -0,0 +1,9 @@
+
+ DisneyMotions
+ DisneyMotions.db
+ Home
+ Library
+ Radio
+ poster_shared_element_container
+ Plot
+
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..cf4a26b
--- /dev/null
+++ b/app/src/main/res/values/styles.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..c29ea76
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,26 @@
+apply from: './versionsPlugin.gradle'
+buildscript {
+ apply from: './dependencies.gradle'
+ repositories {
+ google()
+ jcenter()
+ }
+ dependencies {
+ classpath "com.android.tools.build:gradle:$versions.gradleBuildTool"
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$versions.kotlin"
+ classpath "com.diffplug.spotless:spotless-plugin-gradle:$versions.spotlessGradle"
+ classpath "com.github.ben-manes:gradle-versions-plugin:$versions.versionPlugin"
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ jcenter()
+
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
diff --git a/dependencies.gradle b/dependencies.gradle
new file mode 100644
index 0000000..8fe5b3f
--- /dev/null
+++ b/dependencies.gradle
@@ -0,0 +1,49 @@
+ext.versions = [
+ minSdk : 21,
+ compileSdk : 29,
+ versionCode : 1,
+ versionName : '1.0.0',
+
+ // gradle plugins
+ gradleBuildTool : '3.5.3',
+ spotlessGradle : '3.26.1',
+ versionPlugin : '0.23.0',
+
+ // kotlin
+ kotlin : '1.3.61',
+
+ // support library
+ materialVersion : '1.2.0-alpha05',
+ constraintVersion : '1.1.3',
+
+ // architecture components
+ activityKtxVersion : '1.1.0',
+ fragmentKtxVersion : '1.2.1',
+ activityVersion : '1.1.0-rc03',
+ archCompomentVersion: '2.0.0',
+ lifecycleVersion : '2.2.0',
+ roomVersion : '2.2.4',
+
+ // di
+ koinVersion : '2.0.1',
+
+ // network
+ retrofitVersion : '2.6.0',
+ okhttpVersion : '4.1.0',
+
+ // coroutines
+ coroutinesVersion : '1.3.0',
+
+ // glide
+ glideVersion : '4.9.0',
+ glidePaletteVersion : '2.1.2',
+
+ // adapter
+ baseAdapter : '0.1.3',
+
+ // whatIf
+ whatIfVersion : '1.0.4',
+
+ // debugging
+ timberVersion : '4.7.1',
+]
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 0000000..f6853fb
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,19 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx1536m
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
+# AndroidX package structure to make it clearer which packages are bundled with the
+# Android operating system, and which are packaged with your app's APK
+# https://developer.android.com/topic/libraries/support-library/androidx-rn
+android.useAndroidX=true
+# Automatically convert third-party libraries to use AndroidX
+android.enableJetifier=true
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..f6b961f
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..4ad7315
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Sat Feb 22 15:11:11 KST 2020
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
diff --git a/gradlew b/gradlew
new file mode 100644
index 0000000..cccdd3d
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..f955316
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 0000000..7396b17
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1,2 @@
+include ':app'
+rootProject.name='DisneyMotions'
diff --git a/spotless.gradle b/spotless.gradle
new file mode 100644
index 0000000..1858c60
--- /dev/null
+++ b/spotless.gradle
@@ -0,0 +1,10 @@
+apply plugin: "com.diffplug.gradle.spotless"
+spotless {
+ kotlin {
+ target "**/*.kt"
+ ktlint().userData(['indent_size': '2', 'continuation_indent_size': '2'])
+ licenseHeaderFile '../spotless.license.kt'
+ trimTrailingWhitespace()
+ endWithNewline()
+ }
+}
\ No newline at end of file
diff --git a/spotless.license.kt b/spotless.license.kt
new file mode 100644
index 0000000..c38b44d
--- /dev/null
+++ b/spotless.license.kt
@@ -0,0 +1,16 @@
+/*
+ * 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.
+ */
+
diff --git a/versionsPlugin.gradle b/versionsPlugin.gradle
new file mode 100644
index 0000000..1062c5f
--- /dev/null
+++ b/versionsPlugin.gradle
@@ -0,0 +1,14 @@
+apply plugin: "com.github.ben-manes.versions"
+
+dependencyUpdates.resolutionStrategy {
+ componentSelection { rules ->
+ rules.all { ComponentSelection selection ->
+ boolean rejected = ['alpha', 'beta', 'rc', 'cr', 'm'].any { qualifier ->
+ selection.candidate.version ==~ /(?i).*[.-]${qualifier}[.\d-]*/
+ }
+ if (rejected) {
+ selection.reject('Not stable')
+ }
+ }
+ }
+}