[Sample App] Modernized sample app (#1622)
Upgraded all dependencies, migrated RxJava to coroutines, and ViewBinding
diff --git a/LottieSample/build.gradle b/LottieSample/build.gradle
index 7447eb2..db18b90 100644
--- a/LottieSample/build.gradle
+++ b/LottieSample/build.gradle
@@ -2,8 +2,15 @@
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
+
androidExtensions {
- experimental = true
+ features = ["parcelize"]
+}
+
+tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
+ kotlinOptions {
+ freeCompilerArgs += ["-Xuse-experimental=kotlinx.coroutines.ExperimentalCoroutinesApi"]
+ }
}
android {
@@ -34,6 +41,9 @@
minifyEnabled false
}
}
+ viewBinding {
+ enabled = true
+ }
lintOptions {
ignore 'InvalidPackage'
textReport true
@@ -62,60 +72,52 @@
implementation project(':lottie')
implementation 'androidx.multidex:multidex:2.0.1'
- implementation "androidx.fragment:fragment:1.2.1"
- implementation "androidx.appcompat:appcompat:1.1.0"
+ implementation "androidx.fragment:fragment-ktx:1.2.5"
+ implementation "androidx.appcompat:appcompat:1.2.0"
implementation "androidx.recyclerview:recyclerview:1.1.0"
- implementation "androidx.paging:paging-runtime-ktx:2.1.1"
- implementation "androidx.paging:paging-rxjava2-ktx:2.1.1"
+ implementation "androidx.paging:paging-runtime:3.0.0-alpha5"
+ implementation "androidx.paging:paging-runtime-ktx:3.0.0-alpha06"
implementation "androidx.cardview:cardview:1.0.0"
- implementation 'androidx.core:core-ktx:1.2.0'
- implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta4'
+ implementation 'androidx.core:core-ktx:1.3.1'
+ implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
implementation "androidx.browser:browser:1.2.0"
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
kapt "androidx.lifecycle:lifecycle-common-java8:2.2.0"
- implementation "com.google.android.material:material:1.1.0"
+ implementation "com.google.android.material:material:1.2.1"
- implementation 'com.airbnb.android:epoxy:3.9.0'
- implementation 'com.airbnb.android:epoxy-paging:3.9.0'
- kapt 'com.airbnb.android:epoxy-processor:3.9.0'
- implementation 'com.airbnb.android:mvrx:1.3.0'
+ implementation 'com.airbnb.android:epoxy:4.0.0-beta6'
+ kapt 'com.airbnb.android:epoxy-processor:4.0.0-beta6'
+ implementation 'com.airbnb.android:mvrx:1.5.1'
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion"
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion"
- implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.3'
- implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.3'
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9'
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9'
implementation 'com.matthew-tamlin:sliding-intro-screen:3.2.0'
implementation 'com.dlazaro66.qrcodereaderview:qrcodereaderview:2.0.2'
implementation 'com.github.PhilJay:MPAndroidChart:v3.0.2'
- implementation 'com.amazonaws:aws-android-sdk-s3:2.7.+'
- implementation ('com.amazonaws:aws-android-sdk-mobile-client:2.7.+@aar') { transitive = true }
- implementation ('com.amazonaws:aws-android-sdk-auth-userpools:2.7.+@aar') { transitive = true }
- implementation 'com.google.code.gson:gson:2.8.2'
- implementation 'com.squareup.okhttp3:okhttp:3.11.0'
- implementation 'com.squareup.retrofit2:retrofit:2.4.0'
- implementation 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
- implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
- implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
- implementation 'io.reactivex.rxjava2:rxjava:2.2.1'
+ implementation 'com.amazonaws:aws-android-sdk-s3:2.8.3'
+ implementation ('com.amazonaws:aws-android-sdk-mobile-client:2.8.3@aar') { transitive = true }
+ implementation ('com.amazonaws:aws-android-sdk-auth-userpools:2.8.3@aar') { transitive = true }
+ implementation 'com.google.code.gson:gson:2.8.6'
+ implementation 'com.squareup.okhttp3:okhttp:4.8.1'
+ implementation 'com.squareup.retrofit2:retrofit:2.9.0'
+ implementation 'com.squareup.retrofit2:adapter-rxjava2:2.9.0'
+ implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.github.bumptech.glide:glide:4.8.0'
- debugImplementation("androidx.fragment:fragment-testing:1.2.0-rc04")
+ debugImplementation("androidx.fragment:fragment-testing:1.3.0-alpha08")
- testImplementation 'junit:junit:4.12'
+ testImplementation 'junit:junit:4.13'
- androidTestImplementation 'androidx.test:core:1.2.0'
- androidTestImplementation 'androidx.test.ext:junit:1.1.0'
- androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
- androidTestImplementation 'androidx.test.espresso:espresso-idling-resource:3.1.0-alpha4'
- androidTestImplementation "androidx.fragment:fragment-testing:1.2.0-rc04"
- androidTestImplementation 'androidx.test:rules:1.2.0'
- androidTestImplementation 'io.reactivex.rxjava2:rxjava:2.2.1'
- androidTestImplementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
- androidTestImplementation 'com.squareup.okhttp3:okhttp:3.11.0'
+ androidTestImplementation 'androidx.test:core:1.3.0-rc01'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.2'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
+ androidTestImplementation 'androidx.test.espresso:espresso-idling-resource:3.3.0'
+ androidTestImplementation 'androidx.test:rules:1.3.0'
+ androidTestImplementation 'com.squareup.okhttp3:okhttp:4.8.1'
androidTestImplementation 'io.jsonwebtoken:jjwt:0.9.0'
- androidTestImplementation 'com.amazonaws:aws-android-sdk-core:2.6.31'
- androidTestImplementation 'com.amazonaws:aws-android-sdk-s3:2.6.31'
androidTestImplementation "org.mockito:mockito-android:2.28.2"
- androidTestImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:2.1.0"
+ androidTestImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0"
}
diff --git a/LottieSample/src/androidTest/java/com/airbnb/lottie/samples/HappoSnapshotter.kt b/LottieSample/src/androidTest/java/com/airbnb/lottie/samples/HappoSnapshotter.kt
index fed3160..4d3d279 100644
--- a/LottieSample/src/androidTest/java/com/airbnb/lottie/samples/HappoSnapshotter.kt
+++ b/LottieSample/src/androidTest/java/com/airbnb/lottie/samples/HappoSnapshotter.kt
@@ -4,7 +4,6 @@
import android.graphics.Bitmap
import android.os.Build
import android.util.Log
-import com.airbnb.lottie.BuildConfig
import com.airbnb.lottie.L
import com.amazonaws.auth.BasicAWSCredentials
import com.amazonaws.mobileconnectors.s3.transferutility.TransferObserver
@@ -14,20 +13,10 @@
import com.google.gson.JsonArray
import com.google.gson.JsonElement
import com.google.gson.JsonObject
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.Job
-import kotlinx.coroutines.async
-import kotlinx.coroutines.delay
-import kotlinx.coroutines.withContext
-import okhttp3.Call
-import okhttp3.Callback
-import okhttp3.Credentials
-import okhttp3.MediaType
-import okhttp3.OkHttpClient
-import okhttp3.Request
-import okhttp3.RequestBody
-import okhttp3.Response
+import kotlinx.coroutines.*
+import okhttp3.*
+import okhttp3.MediaType.Companion.toMediaType
+import okhttp3.RequestBody.Companion.toRequestBody
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
@@ -61,7 +50,7 @@
private val happoSecretKey = BC.HappoSecretKey
private val gitBranch = URLEncoder.encode((if (BC.BITRISE_GIT_BRANCH == "null") BC.GIT_BRANCH else BC.BITRISE_GIT_BRANCH).replace("/", "_"), "UTF-8")
private val androidVersion = "android${Build.VERSION.SDK_INT}"
- private val reportNamePrefixes = listOf(BC.GIT_SHA, gitBranch, BuildConfig.VERSION_NAME).filter { it.isNotBlank() }
+ private val reportNamePrefixes = listOf(BC.GIT_SHA, gitBranch, BC.VERSION_NAME).filter { it.isNotBlank() }
private val reportNames = reportNamePrefixes.map { "$it-$androidVersion" }
private val okhttp = OkHttpClient()
@@ -104,7 +93,7 @@
}
private suspend fun upload(reportName: String, json: JsonElement) {
- val body = RequestBody.create(MediaType.get("application/json"), json.toString())
+ val body = json.toString().toRequestBody("application/json".toMediaType())
val request = Request.Builder()
.addHeader("Authorization", Credentials.basic(happoApiKey, happoSecretKey, Charset.forName("UTF-8")))
.url("https://happo.io/api/reports/$reportName")
@@ -115,7 +104,7 @@
if (response.isSuccessful) {
Log.d(TAG, "Uploaded $reportName to happo")
} else {
- throw IllegalStateException("Failed to upload $reportName to Happo. Failed with code ${response.code()}. " + response.body()?.string())
+ throw IllegalStateException("Failed to upload $reportName to Happo. Failed with code ${response.code}. " + response.body?.string())
}
}
diff --git a/LottieSample/src/androidTest/java/com/airbnb/lottie/samples/LottieTest.kt b/LottieSample/src/androidTest/java/com/airbnb/lottie/samples/LottieTest.kt
index 973b21e..30271c3 100644
--- a/LottieSample/src/androidTest/java/com/airbnb/lottie/samples/LottieTest.kt
+++ b/LottieSample/src/androidTest/java/com/airbnb/lottie/samples/LottieTest.kt
@@ -1,10 +1,10 @@
package com.airbnb.lottie.samples
import android.Manifest
+import android.content.Context
import android.content.res.Configuration
import android.content.res.Resources
import android.graphics.*
-import android.os.Build.VERSION
import android.util.DisplayMetrics
import android.util.Log
import android.view.View
@@ -12,6 +12,8 @@
import android.widget.FrameLayout
import android.widget.ImageView
import androidx.core.view.updateLayoutParams
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
import androidx.test.rule.ActivityTestRule
@@ -19,6 +21,7 @@
import com.airbnb.lottie.*
import com.airbnb.lottie.model.KeyPath
import com.airbnb.lottie.model.LottieCompositionCache
+import com.airbnb.lottie.samples.testing.NoCacheLottieAnimationView
import com.airbnb.lottie.samples.views.FilmStripView
import com.airbnb.lottie.value.*
import com.amazonaws.auth.BasicAWSCredentials
@@ -37,22 +40,18 @@
import java.util.concurrent.TimeUnit
import java.util.zip.ZipInputStream
-/**
- * Run these with: ./gradlew recordMode screenshotTests
- * If you run that command, it completes successfully, and nothing shows up in git, then you
- * haven't broken anything!
- */
@ExperimentalCoroutinesApi
@RunWith(AndroidJUnit4::class)
@LargeTest
class LottieTest {
+ @Suppress("DEPRECATION")
@get:Rule
- var snapshotActivityRule = ActivityTestRule(SnapshotTestActivity::class.java)
- private val activity get() = snapshotActivityRule.activity
+ val snapshotActivityRule = ActivityScenarioRule(SnapshotTestActivity::class.java)
+ private val application get() = ApplicationProvider.getApplicationContext<Context>()
@get:Rule
- var permissionRule = GrantPermissionRule.grant(
+ val permissionRule = GrantPermissionRule.grant(
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE
)
@@ -62,11 +61,11 @@
private lateinit var snapshotter: HappoSnapshotter
private val bitmapPool by lazy { BitmapPool() }
- private val dummyBitmap by lazy { BitmapFactory.decodeResource(activity.resources, R.drawable.airbnb); }
+ private val dummyBitmap by lazy { BitmapFactory.decodeResource(application.resources, R.drawable.airbnb) }
- private val filmStripViewPool = ObjectPool<FilmStripView> {
- FilmStripView(activity).apply {
- setImageAssetDelegate(ImageAssetDelegate { dummyBitmap })
+ private val filmStripViewPool = ObjectPool {
+ FilmStripView(application).apply {
+ setImageAssetDelegate { dummyBitmap }
setFontAssetDelegate(object : FontAssetDelegate() {
override fun getFontPath(fontFamily: String?): String {
return "fonts/Roboto.ttf"
@@ -77,8 +76,8 @@
}
@Suppress("DEPRECATION")
private val animationViewPool = ObjectPool<LottieAnimationView> {
- val animationViewContainer = FrameLayout(activity)
- NoCacheLottieAnimationView(activity).apply {
+ val animationViewContainer = FrameLayout(application)
+ NoCacheLottieAnimationView(application).apply {
animationViewContainer.addView(this)
}
}
@@ -86,9 +85,9 @@
@Before
fun setup() {
L.DBG = false
- snapshotter = HappoSnapshotter(activity)
+ snapshotter = HappoSnapshotter(application)
prodAnimationsTransferUtility = TransferUtility.builder()
- .context(activity)
+ .context(application)
.s3Client(AmazonS3Client(BasicAWSCredentials(BuildConfig.S3AccessKey, BuildConfig.S3SecretKey)))
.defaultBucket("lottie-prod-animations")
.build()
@@ -96,7 +95,6 @@
}
@Test
- @ObsoleteCoroutinesApi
fun testAll() = runBlocking {
withTimeout(TimeUnit.MINUTES.toMillis(45)) {
snapshotFailure()
@@ -128,7 +126,7 @@
capacity = 10
) {
for (animation in animations) {
- val file = File(activity.cacheDir, animation.key)
+ val file = File(application.cacheDir, animation.key)
file.deleteOnExit()
prodAnimationsTransferUtility.download(animation.key, file).await()
send(file)
@@ -178,7 +176,9 @@
filmStripViewPool.release(filmStripView)
LottieCompositionCache.getInstance().clear()
snapshotter.record(bitmap, name, variant)
- activity.recordSnapshot(name, variant)
+ snapshotActivityRule.scenario.onActivity { activity ->
+ activity.recordSnapshot(name, variant)
+ }
bitmapPool.release(bitmap)
}
@@ -190,7 +190,7 @@
}
private fun listAssets(assets: MutableList<String> = mutableListOf(), pathPrefix: String = ""): List<String> {
- activity.getAssets().list(pathPrefix)?.forEach { animation ->
+ application.assets.list(pathPrefix)?.forEach { animation ->
val pathWithPrefix = if (pathPrefix.isEmpty()) animation else "$pathPrefix/$animation"
if (!animation.contains('.')) {
listAssets(assets, pathWithPrefix)
@@ -209,7 +209,7 @@
) {
for (asset in assets) {
log("Parsing $asset")
- val composition = LottieCompositionFactory.fromAssetSync(activity, asset).value
+ val composition = LottieCompositionFactory.fromAssetSync(application, asset).value
?: throw java.lang.IllegalArgumentException("Unable to parse $asset.")
send(asset to composition)
}
@@ -225,8 +225,11 @@
animationView.layoutParams = FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
animationView.scale = 1f
animationView.scaleType = ImageView.ScaleType.FIT_CENTER
- val widthSpec = View.MeasureSpec.makeMeasureSpec(activity.resources.displayMetrics.widthPixels, View.MeasureSpec.EXACTLY)
- val heightSpec = View.MeasureSpec.makeMeasureSpec(activity.resources.displayMetrics.heightPixels, View.MeasureSpec.EXACTLY)
+ val widthSpec = View.MeasureSpec.makeMeasureSpec(application.resources.displayMetrics
+ .widthPixels,
+ View.MeasureSpec.EXACTLY)
+ val heightSpec = View.MeasureSpec.makeMeasureSpec(application.resources.displayMetrics
+ .heightPixels, View.MeasureSpec.EXACTLY)
val animationViewContainer = animationView.parent as ViewGroup
animationViewContainer.measure(widthSpec, heightSpec)
animationViewContainer.layout(0, 0, animationViewContainer.measuredWidth, animationViewContainer.measuredHeight)
@@ -237,7 +240,9 @@
val snapshotName = "Failure"
val snapshotVariant = "Default"
snapshotter.record(bitmap, snapshotName, snapshotVariant)
- activity.recordSnapshot(snapshotName, snapshotVariant)
+ snapshotActivityRule.scenario.onActivity { activity ->
+ activity.recordSnapshot(snapshotName, snapshotVariant)
+ }
bitmapPool.release(bitmap)
}
@@ -922,37 +927,41 @@
}
private suspend fun testNightMode() {
- var newConfig = Configuration(activity.getResources().getConfiguration())
- newConfig.uiMode = newConfig.uiMode and Configuration.UI_MODE_NIGHT_MASK.inv();
- newConfig.uiMode = newConfig.uiMode or Configuration.UI_MODE_NIGHT_NO;
- val dayContext = activity.createConfigurationContext(newConfig)
+ var newConfig = Configuration(application.resources.configuration)
+ newConfig.uiMode = newConfig.uiMode and Configuration.UI_MODE_NIGHT_MASK.inv()
+ newConfig.uiMode = newConfig.uiMode or Configuration.UI_MODE_NIGHT_NO
+ val dayContext = application.createConfigurationContext(newConfig)
var result = LottieCompositionFactory.fromRawResSync(dayContext, R.raw.day_night)
var composition = result.value!!
var drawable = LottieDrawable()
- drawable.setComposition(composition)
+ drawable.composition = composition
var bitmap = bitmapPool.acquire(drawable.intrinsicWidth, drawable.intrinsicHeight)
var canvas = Canvas(bitmap)
log("Drawing day_night day")
drawable.draw(canvas)
snapshotter.record(bitmap, "Day/Night", "Day")
- activity.recordSnapshot("Day/Night", "Day")
+ snapshotActivityRule.scenario.onActivity { activity ->
+ activity.recordSnapshot("Day/Night", "Day")
+ }
LottieCompositionCache.getInstance().clear()
bitmapPool.release(bitmap)
- newConfig = Configuration(activity.getResources().getConfiguration())
- newConfig.uiMode = newConfig.uiMode and Configuration.UI_MODE_NIGHT_MASK.inv();
- newConfig.uiMode = newConfig.uiMode or Configuration.UI_MODE_NIGHT_YES;
- val nightContext = activity.createConfigurationContext(newConfig)
+ newConfig = Configuration(application.resources.configuration)
+ newConfig.uiMode = newConfig.uiMode and Configuration.UI_MODE_NIGHT_MASK.inv()
+ newConfig.uiMode = newConfig.uiMode or Configuration.UI_MODE_NIGHT_YES
+ val nightContext = application.createConfigurationContext(newConfig)
result = LottieCompositionFactory.fromRawResSync(nightContext, R.raw.day_night)
composition = result.value!!
drawable = LottieDrawable()
- drawable.setComposition(composition)
+ drawable.composition = composition
bitmap = bitmapPool.acquire(drawable.intrinsicWidth, drawable.intrinsicHeight)
canvas = Canvas(bitmap)
log("Drawing day_night day")
drawable.draw(canvas)
snapshotter.record(bitmap, "Day/Night", "Night")
- activity.recordSnapshot("Day/Night", "Night")
+ snapshotActivityRule.scenario.onActivity { activity ->
+ activity.recordSnapshot("Day/Night", "Night")
+ }
LottieCompositionCache.getInstance().clear()
bitmapPool.release(bitmap)
}
@@ -975,18 +984,20 @@
}
private suspend fun withDrawable(assetName: String, snapshotName: String, snapshotVariant: String, callback: (LottieDrawable) -> Unit) {
- val result = LottieCompositionFactory.fromAssetSync(activity, assetName)
+ val result = LottieCompositionFactory.fromAssetSync(application, assetName)
val composition = result.value
?: throw IllegalArgumentException("Unable to parse $assetName.", result.exception)
val drawable = LottieDrawable()
- drawable.setComposition(composition)
+ drawable.composition = composition
callback(drawable)
val bitmap = bitmapPool.acquire(drawable.intrinsicWidth, drawable.intrinsicHeight)
val canvas = Canvas(bitmap)
log("Drawing $assetName")
drawable.draw(canvas)
snapshotter.record(bitmap, snapshotName, snapshotVariant)
- activity.recordSnapshot(snapshotName, snapshotVariant)
+ snapshotActivityRule.scenario.onActivity { activity ->
+ activity.recordSnapshot(snapshotName, snapshotVariant)
+ }
LottieCompositionCache.getInstance().clear()
bitmapPool.release(bitmap)
}
@@ -997,7 +1008,7 @@
snapshotVariant: String = "default",
callback: (LottieAnimationView) -> Unit
) {
- val result = LottieCompositionFactory.fromAssetSync(activity, assetName)
+ val result = LottieCompositionFactory.fromAssetSync(application, assetName)
val composition = result.value
?: throw IllegalArgumentException("Unable to parse $assetName.", result.exception)
val animationView = animationViewPool.acquire()
@@ -1006,8 +1017,11 @@
animationView.scale = 1f
animationView.scaleType = ImageView.ScaleType.FIT_CENTER
callback(animationView)
- val widthSpec = View.MeasureSpec.makeMeasureSpec(activity.resources.displayMetrics.widthPixels, View.MeasureSpec.EXACTLY)
- val heightSpec = View.MeasureSpec.makeMeasureSpec(activity.resources.displayMetrics.heightPixels, View.MeasureSpec.EXACTLY)
+ val widthSpec = View.MeasureSpec.makeMeasureSpec(application.resources.displayMetrics
+ .widthPixels,
+ View.MeasureSpec.EXACTLY)
+ val heightSpec = View.MeasureSpec.makeMeasureSpec(application.resources.displayMetrics
+ .heightPixels, View.MeasureSpec.EXACTLY)
val animationViewContainer = animationView.parent as ViewGroup
animationViewContainer.measure(widthSpec, heightSpec)
animationViewContainer.layout(0, 0, animationViewContainer.measuredWidth, animationViewContainer.measuredHeight)
@@ -1017,7 +1031,9 @@
animationView.draw(canvas)
animationViewPool.release(animationView)
snapshotter.record(bitmap, snapshotName, snapshotVariant)
- activity.recordSnapshot(snapshotName, snapshotVariant)
+ snapshotActivityRule.scenario.onActivity { activity ->
+ activity.recordSnapshot(snapshotName, snapshotVariant)
+ }
bitmapPool.release(bitmap)
}
@@ -1027,7 +1043,7 @@
snapshotVariant: String = "default",
callback: (FilmStripView) -> Unit
) {
- val result = LottieCompositionFactory.fromAssetSync(activity, assetName)
+ val result = LottieCompositionFactory.fromAssetSync(application, assetName)
val composition = result.value
?: throw IllegalArgumentException("Unable to parse $assetName.", result.exception)
snapshotComposition(snapshotName, snapshotVariant, composition, callback)
diff --git a/LottieSample/src/main/AndroidManifest.xml b/LottieSample/src/main/AndroidManifest.xml
index 74388c1..34964be 100644
--- a/LottieSample/src/main/AndroidManifest.xml
+++ b/LottieSample/src/main/AndroidManifest.xml
@@ -41,10 +41,6 @@
<activity
android:name=".QRScanActivity"
android:screenOrientation="portrait" />
- <activity android:name=".FullScreenActivity" />
- <activity
- android:name=".TestColorFilterActivity"
- android:screenOrientation="portrait" />
<activity android:name=".DynamicActivity" />
<activity
android:name=".PlayerActivity"
@@ -63,9 +59,9 @@
</intent-filter>
</activity>
<activity android:name=".DynamicTextActivity" />
- <activity android:name=".ListActivity" />
+ <activity android:name=".WishListActivity" />
<activity
- android:name=".FilmStripSnapshotActivity"
+ android:name=".testing.FilmStripSnapshotActivity"
android:exported="true" />
<activity
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/AppIntroActivity.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/AppIntroActivity.kt
index cfcdba7..511249d 100644
--- a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/AppIntroActivity.kt
+++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/AppIntroActivity.kt
@@ -1,36 +1,26 @@
package com.airbnb.lottie.samples
import android.os.Bundle
-import androidx.fragment.app.Fragment
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
import android.view.animation.Interpolator
import android.widget.Scroller
+import androidx.fragment.app.Fragment
import com.airbnb.lottie.LottieAnimationView
+import com.airbnb.lottie.samples.utils.inflate
+import com.airbnb.lottie.samples.utils.lerp
import com.matthewtamlin.sliding_intro_screen_library.buttons.IntroButton
import com.matthewtamlin.sliding_intro_screen_library.core.IntroActivity
import com.matthewtamlin.sliding_intro_screen_library.core.LockableViewPager
class AppIntroActivity : IntroActivity() {
- private val ANIMATION_TIMES = floatArrayOf(0f, 0.3333f, 0.6666f, 1f, 1f)
-
private val animationView: LottieAnimationView by lazy {
rootView.inflate(R.layout.app_intro_animation_view, false) as LottieAnimationView
}
private val viewPager: LockableViewPager by lazy {
- findViewById<LockableViewPager>(R.id.intro_activity_viewPager)
+ findViewById(R.id.intro_activity_viewPager)
}
- override fun generatePages(savedInstanceState: Bundle?): Collection<Fragment> {
- return listOf(
- EmptyFragment.newInstance(),
- EmptyFragment.newInstance(),
- EmptyFragment.newInstance(),
- EmptyFragment.newInstance()
- )
- }
+ override fun generatePages(savedInstanceState: Bundle?) = listOf(EmptyFragment(), EmptyFragment(), EmptyFragment(), EmptyFragment())
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -59,18 +49,7 @@
animationView.progress = startProgress.lerp(endProgress, positionOffset)
}
- class EmptyFragment : androidx.fragment.app.Fragment() {
-
- override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
- return container!!.inflate(R.layout.fragment_empty, false)
- }
-
- companion object {
- internal fun newInstance(): EmptyFragment {
- return EmptyFragment()
- }
- }
- }
+ class EmptyFragment : Fragment(R.layout.empty_fragment)
private fun setViewPagerScroller() {
try {
@@ -91,4 +70,8 @@
// Do nothing.
}
}
+
+ companion object {
+ private val ANIMATION_TIMES = floatArrayOf(0f, 0.3333f, 0.6666f, 1f, 1f)
+ }
}
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/BaseEpoxyFragment.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/BaseEpoxyFragment.kt
deleted file mode 100644
index 1c18749..0000000
--- a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/BaseEpoxyFragment.kt
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.airbnb.lottie.samples
-
-import android.os.Bundle
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import com.airbnb.epoxy.AsyncEpoxyController
-import com.airbnb.epoxy.EpoxyController
-import com.airbnb.lottie.samples.R.id.recyclerView
-import com.airbnb.mvrx.BaseMvRxFragment
-import kotlinx.android.synthetic.main.fragment_base.*
-import kotlinx.android.synthetic.main.fragment_base.view.*
-
-
-private class BaseEpoxyController(
- private val buildModelsCallback: EpoxyController.() -> Unit
-) : AsyncEpoxyController() {
- override fun buildModels() {
- buildModelsCallback()
- }
-}
-
-abstract class BaseEpoxyFragment : BaseMvRxFragment() {
-
- override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? =
- inflater.inflate(R.layout.fragment_base, container, false).apply {
- recyclerView.setController(BaseEpoxyController { buildModels() })
- }
-
- override fun invalidate() {
- recyclerView.requestModelBuild()
- }
-
- abstract fun EpoxyController.buildModels()
-}
\ No newline at end of file
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/BullseyeActivity.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/BullseyeActivity.kt
index 1ad64ed..b418c7c 100644
--- a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/BullseyeActivity.kt
+++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/BullseyeActivity.kt
@@ -2,34 +2,35 @@
import android.graphics.PointF
import android.os.Bundle
-import androidx.customview.widget.ViewDragHelper
-import androidx.appcompat.app.AppCompatActivity
import android.view.View
+import androidx.appcompat.app.AppCompatActivity
+import androidx.customview.widget.ViewDragHelper
import com.airbnb.lottie.LottieProperty
import com.airbnb.lottie.model.KeyPath
+import com.airbnb.lottie.samples.databinding.BullseyeActivityBinding
+import com.airbnb.lottie.samples.utils.viewBinding
import com.airbnb.lottie.value.LottieRelativePointValueCallback
-import kotlinx.android.synthetic.main.activity_bullseye.*
class BullseyeActivity : AppCompatActivity() {
+ private val binding: BullseyeActivityBinding by viewBinding()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_bullseye)
val largeValueCallback = LottieRelativePointValueCallback(PointF(0f, 0f))
- animationView.addValueCallback(KeyPath("First"), LottieProperty.TRANSFORM_POSITION, largeValueCallback)
+ binding.animationView.addValueCallback(KeyPath("First"), LottieProperty.TRANSFORM_POSITION, largeValueCallback)
val mediumValueCallback = LottieRelativePointValueCallback(PointF(0f, 0f))
- animationView.addValueCallback(KeyPath("Fourth"), LottieProperty.TRANSFORM_POSITION, mediumValueCallback)
+ binding.animationView.addValueCallback(KeyPath("Fourth"), LottieProperty.TRANSFORM_POSITION, mediumValueCallback)
val smallValueCallback = LottieRelativePointValueCallback(PointF(0f, 0f))
- animationView.addValueCallback(KeyPath("Seventh"), LottieProperty.TRANSFORM_POSITION, smallValueCallback)
+ binding.animationView.addValueCallback(KeyPath("Seventh"), LottieProperty.TRANSFORM_POSITION, smallValueCallback)
var totalDx = 0f
var totalDy = 0f
- val viewDragHelper = ViewDragHelper.create(containerView, object : ViewDragHelper.Callback() {
- override fun tryCaptureView(child: View, pointerId: Int) = child == targetView
+ val viewDragHelper = ViewDragHelper.create(binding.containerView, object : ViewDragHelper.Callback() {
+ override fun tryCaptureView(child: View, pointerId: Int) = child == binding.targetView
override fun clampViewPositionVertical(child: View, top: Int, dy: Int): Int {
return top
@@ -48,7 +49,7 @@
}
})
- containerView.viewDragHelper = viewDragHelper
+ binding.containerView.viewDragHelper = viewDragHelper
}
private fun getPoint(dx: Float, dy: Float, factor: Float) = PointF(dx * factor, dy * factor)
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/DynamicActivity.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/DynamicActivity.kt
index 8970d49..495803e 100644
--- a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/DynamicActivity.kt
+++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/DynamicActivity.kt
@@ -1,13 +1,15 @@
package com.airbnb.lottie.samples
+import android.annotation.SuppressLint
import android.graphics.PointF
import android.os.Bundle
-import androidx.appcompat.app.AppCompatActivity
import android.util.Log
+import androidx.appcompat.app.AppCompatActivity
import com.airbnb.lottie.LottieProperty
import com.airbnb.lottie.model.KeyPath
+import com.airbnb.lottie.samples.databinding.DynamicActivityBinding
+import com.airbnb.lottie.samples.utils.viewBinding
import com.airbnb.lottie.utils.MiscUtils
-import kotlinx.android.synthetic.main.activity_dynamic.*
private val COLORS = arrayOf(
0xff5a5f,
@@ -17,41 +19,38 @@
private val EXTRA_JUMP = arrayOf(0f, 20f, 50f)
class DynamicActivity : AppCompatActivity() {
+ private val binding: DynamicActivityBinding by viewBinding()
+
private var speed = 1
private var colorIndex = 0
private var extraJumpIndex = 0
- companion object {
- val TAG = DynamicActivity::class.simpleName
- }
-
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_dynamic)
- speedButton.setOnClickListener {
+ binding.speedButton.setOnClickListener {
speed = ++speed % 4
updateButtonText()
}
- colorButton.setOnClickListener {
+ binding.colorButton.setOnClickListener {
colorIndex = (colorIndex + 1) % COLORS.size
updateButtonText()
}
- jumpHeight.setOnClickListener {
+ binding.jumpHeight.setOnClickListener {
extraJumpIndex = (extraJumpIndex + 1) % EXTRA_JUMP.size
updateButtonText()
setupValueCallbacks()
}
- animationView.addLottieOnCompositionLoadedListener { _ ->
- animationView.resolveKeyPath(KeyPath("**")).forEach {
+ binding.animationView.addLottieOnCompositionLoadedListener { _ ->
+ binding.animationView.resolveKeyPath(KeyPath("**")).forEach {
Log.d(TAG, it.keysToString())
setupValueCallbacks()
}
}
- animationView.setFailureListener { e ->
+ binding.animationView.setFailureListener { e ->
Log.e(TAG, "Failed to load animation!", e)
}
@@ -59,7 +58,7 @@
}
private fun setupValueCallbacks() {
- animationView.addValueCallback(KeyPath("LeftArmWave"), LottieProperty.TIME_REMAP) { frameInfo ->
+ binding.animationView.addValueCallback(KeyPath("LeftArmWave"), LottieProperty.TIME_REMAP) { frameInfo ->
2 * speed.toFloat() * frameInfo.overallProgress
}
@@ -67,11 +66,11 @@
val leftArm = KeyPath("LeftArmWave", "LeftArm", "Group 6", "Fill 1")
val rightArm = KeyPath("RightArm", "Group 6", "Fill 1")
- animationView.addValueCallback(shirt, LottieProperty.COLOR) { COLORS[colorIndex] }
- animationView.addValueCallback(leftArm, LottieProperty.COLOR) { COLORS[colorIndex] }
- animationView.addValueCallback(rightArm, LottieProperty.COLOR) { COLORS[colorIndex] }
+ binding.animationView.addValueCallback(shirt, LottieProperty.COLOR) { COLORS[colorIndex] }
+ binding.animationView.addValueCallback(leftArm, LottieProperty.COLOR) { COLORS[colorIndex] }
+ binding.animationView.addValueCallback(rightArm, LottieProperty.COLOR) { COLORS[colorIndex] }
val point = PointF()
- animationView.addValueCallback(KeyPath("Body"),
+ binding.animationView.addValueCallback(KeyPath("Body"),
LottieProperty.TRANSFORM_POSITION) { frameInfo ->
val startX = frameInfo.startValue.x
var startY = frameInfo.startValue.y
@@ -87,8 +86,13 @@
}
}
+ @SuppressLint("SetTextI18n")
private fun updateButtonText() {
- speedButton.text = "Wave: ${speed}x Speed"
- jumpHeight.text = "Extra jump height ${EXTRA_JUMP[extraJumpIndex]}"
+ binding.speedButton.text = "Wave: ${speed}x Speed"
+ binding.jumpHeight.text = "Extra jump height ${EXTRA_JUMP[extraJumpIndex]}"
+ }
+
+ companion object {
+ val TAG = DynamicActivity::class.simpleName
}
}
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/DynamicTextActivity.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/DynamicTextActivity.kt
index 71dd6b2..ae0ad19 100644
--- a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/DynamicTextActivity.kt
+++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/DynamicTextActivity.kt
@@ -1,20 +1,21 @@
package com.airbnb.lottie.samples
import android.os.Bundle
-import androidx.appcompat.app.AppCompatActivity
import android.text.Editable
import android.text.TextWatcher
+import androidx.appcompat.app.AppCompatActivity
import com.airbnb.lottie.TextDelegate
-import kotlinx.android.synthetic.main.activity_dynamic_text.*
+import com.airbnb.lottie.samples.databinding.DynamicTextActivityBinding
+import com.airbnb.lottie.samples.utils.viewBinding
class DynamicTextActivity : AppCompatActivity() {
+ private val binding: DynamicTextActivityBinding by viewBinding()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_dynamic_text)
- val textDelegate = TextDelegate(dynamicTextView)
- nameEditText.addTextChangedListener(object: TextWatcher {
+ val textDelegate = TextDelegate(binding.dynamicTextView)
+ binding.nameEditText.addTextChangedListener(object: TextWatcher {
override fun afterTextChanged(s: Editable?) {
textDelegate.setText("NAME", s.toString())
}
@@ -23,6 +24,6 @@
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
})
- dynamicTextView.setTextDelegate(textDelegate)
+ binding.dynamicTextView.setTextDelegate(textDelegate)
}
}
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/EmptyActivity.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/EmptyActivity.kt
index ec76d6b..f23d617 100644
--- a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/EmptyActivity.kt
+++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/EmptyActivity.kt
@@ -1,14 +1,15 @@
package com.airbnb.lottie.samples
import android.os.Bundle
-import android.view.View
import androidx.appcompat.app.AppCompatActivity
+import com.airbnb.lottie.samples.databinding.EmptyActivityBinding
+import com.airbnb.lottie.samples.utils.viewBinding
class EmptyActivity : AppCompatActivity() {
+ private val binding: EmptyActivityBinding by viewBinding()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_empty)
- findViewById<View>(R.id.finish).setOnClickListener { finish() }
+ binding.finish.setOnClickListener { finish() }
}
}
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/FullScreenActivity.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/FullScreenActivity.kt
deleted file mode 100644
index 07014cb..0000000
--- a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/FullScreenActivity.kt
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.airbnb.lottie.samples
-
-import android.os.Bundle
-import androidx.appcompat.app.AppCompatActivity
-
-/**
- * To have a full screen animation, make an animation that is wider than the screen and set the
- * scaleType to centerCrop.
- */
-class FullScreenActivity : AppCompatActivity() {
-
- public override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(R.layout.fragment_full_screen)
- }
-}
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/ListActivity.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/ListActivity.kt
deleted file mode 100644
index b3fefe8..0000000
--- a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/ListActivity.kt
+++ /dev/null
@@ -1,43 +0,0 @@
-package com.airbnb.lottie.samples
-
-import android.os.Bundle
-import androidx.appcompat.app.AppCompatActivity
-import com.airbnb.epoxy.EpoxyController
-import com.airbnb.epoxy.EpoxyRecyclerView
-import com.airbnb.lottie.samples.views.WishListIconView
-import com.airbnb.lottie.samples.views.listingCard
-import com.airbnb.lottie.samples.views.marquee
-import kotlinx.android.synthetic.main.activity_list.*
-
-class ListActivity : AppCompatActivity() {
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_list)
-
- setSupportActionBar(toolbar)
- supportActionBar?.setDisplayShowTitleEnabled(false)
- toolbar.setNavigationOnClickListener { finish() }
-
- recyclerView.buildModelsWith(object : EpoxyRecyclerView.ModelBuilderCallback {
- override fun buildModels(controller: EpoxyController) {
- controller.buildModels()
- }
- })
- }
-
- private fun EpoxyController.buildModels() {
- marquee {
- id("marquee")
- title("List")
- subtitle("Loading the same animation many times in a list")
- }
-
- repeat(100) {
- listingCard {
- id(it)
- clickListener { view -> (view as WishListIconView).toggleWishlisted() }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/LottieApplication.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/LottieApplication.kt
index 451d150..d4affd8 100644
--- a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/LottieApplication.kt
+++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/LottieApplication.kt
@@ -2,6 +2,7 @@
import androidx.multidex.MultiDexApplication
import com.airbnb.lottie.L
+import com.airbnb.lottie.samples.api.LottiefilesApi
import com.google.gson.FieldNamingPolicy
import com.google.gson.GsonBuilder
import okhttp3.OkHttpClient
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/LottiefilesApi.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/LottiefilesApi.kt
deleted file mode 100644
index be114f6..0000000
--- a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/LottiefilesApi.kt
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.airbnb.lottie.samples
-
-import com.airbnb.lottie.samples.model.AnimationResponse
-import com.airbnb.lottie.samples.model.AnimationResponseV2
-import io.reactivex.Single
-import retrofit2.http.GET
-import retrofit2.http.Path
-import retrofit2.http.Query
-
-interface LottiefilesApi {
- @GET("v1/recent")
- fun getRecent(@Query("page") page: Int): Single<AnimationResponse>
-
- @GET("v1/popular")
- fun getPopular(@Query("page") page: Int): Single<AnimationResponse>
-
- @GET("v2/featured")
- fun getCollection(): Single<AnimationResponseV2>
-
- @GET("v1/search/{query}")
- fun search(@Path("query") query: String, @Query("page") page: Int): Single<AnimationResponse>
-}
\ No newline at end of file
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/LottiefilesFragment.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/LottiefilesFragment.kt
index 479e765..cfaa7b9 100644
--- a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/LottiefilesFragment.kt
+++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/LottiefilesFragment.kt
@@ -1,22 +1,29 @@
package com.airbnb.lottie.samples
+import android.content.Context
import android.os.Bundle
import android.view.View
-import androidx.lifecycle.Observer
-import androidx.paging.DataSource
-import androidx.paging.LivePagedListBuilder
-import androidx.paging.PageKeyedDataSource
-import com.airbnb.epoxy.EpoxyModel
-import com.airbnb.epoxy.paging.PagedListEpoxyController
+import android.view.ViewGroup
+import androidx.core.view.isVisible
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.viewModelScope
+import androidx.paging.*
+import androidx.recyclerview.widget.DiffUtil
+import androidx.recyclerview.widget.RecyclerView
+import com.airbnb.lottie.samples.api.LottiefilesApi
+import com.airbnb.lottie.samples.databinding.LottiefilesFragmentBinding
import com.airbnb.lottie.samples.model.AnimationData
+import com.airbnb.lottie.samples.model.AnimationResponse
import com.airbnb.lottie.samples.model.CompositionArgs
-import com.airbnb.lottie.samples.views.AnimationItemViewModel_
-import com.airbnb.lottie.samples.views.lottiefilesTabBar
-import com.airbnb.lottie.samples.views.marquee
-import com.airbnb.lottie.samples.views.searchInputItemView
+import com.airbnb.lottie.samples.utils.MvRxViewModel
+import com.airbnb.lottie.samples.utils.hideKeyboard
+import com.airbnb.lottie.samples.utils.viewBinding
+import com.airbnb.lottie.samples.views.AnimationItemView
import com.airbnb.mvrx.*
-import kotlinx.android.synthetic.main.fragment_epoxy_recycler_view.*
-import kotlin.properties.Delegates
+import kotlinx.coroutines.flow.collectLatest
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.launch
data class LottiefilesState(
val mode: LottiefilesMode = LottiefilesMode.Recent,
@@ -28,17 +35,16 @@
private var mode = initialState.mode
private var query = initialState.query
- val pagedList = LivePagedListBuilder<Int, AnimationData>(object : DataSource.Factory<Int, AnimationData>() {
- override fun create(): DataSource<Int, AnimationData> {
- return LottiefilesDataSource(api, mode, query)
- }
- }, 16).build()
+ private var dataSource: LottiefilesDataSource? = null
+ val pager = Pager(PagingConfig(pageSize = 16)) {
+ LottiefilesDataSource(api, mode, query).also { dataSource = it }
+ }.flow.cachedIn(viewModelScope)
init {
selectSubscribe(LottiefilesState::mode, LottiefilesState::query) { mode, query ->
this.mode = mode
this.query = query
- pagedList.value?.dataSource?.invalidate()
+ dataSource?.invalidate()
}
}
@@ -57,136 +63,90 @@
class LottiefilesDataSource(
private val api: LottiefilesApi,
val mode: LottiefilesMode,
- val query: String
-) : PageKeyedDataSource<Int, AnimationData>() {
- override fun loadInitial(params: LoadInitialParams<Int>, callback: LoadInitialCallback<Int, AnimationData>) {
- if (mode == LottiefilesMode.Search && query.isEmpty()) {
- callback.onResult(emptyList(), null, null)
- return
- }
+ private val query: String
+) : PagingSource<Int, AnimationData>() {
- try {
- val response = when (mode) {
- LottiefilesMode.Popular -> api.getPopular(1)
- LottiefilesMode.Recent -> api.getRecent(1)
- LottiefilesMode.Search -> api.search(query, 1)
- }.blockingGet()
-
- callback.onResult(
- response.data,
- 0,
- response.total,
- null,
- 2.takeIf {
- !response.nextPageUrl.isNullOrEmpty()
- }
- )
- } catch (e: Exception) {
- callback.onError(e)
- }
- }
-
- override fun loadAfter(params: LoadParams<Int>, callback: LoadCallback<Int, AnimationData>) {
- loadPage(params.key, callback)
- }
-
- override fun loadBefore(params: LoadParams<Int>, callback: LoadCallback<Int, AnimationData>) {
- // ignored, prepend will never happen.
- }
-
- private fun loadPage(page: Int, callback: LoadCallback<Int, AnimationData>) {
- try {
+ override suspend fun load(params: LoadParams<Int>): LoadResult<Int, AnimationData> {
+ val page = params.key ?: 1
+ return try {
val response = when (mode) {
LottiefilesMode.Popular -> api.getPopular(page)
LottiefilesMode.Recent -> api.getRecent(page)
- LottiefilesMode.Search -> api.search(query, page)
- }.blockingGet()
-
- callback.onResult(
- response.data,
- (page + 1).takeIf {
- !response.nextPageUrl.isNullOrEmpty()
+ LottiefilesMode.Search -> {
+ if (query.isBlank()) {
+ AnimationResponse(page, emptyList(), "", page, null, "", 0, "", 0, 0)
+ } else {
+ api.search(query, page)
}
- )
+ }
+ }
+ LoadResult.Page(
+ response.data,
+ if (page == 1) null else page + 1,
+ (page + 1).takeIf { page < response.lastPage }
+ )
} catch (e: Exception) {
- callback.onError(e)
+ LoadResult.Error(e)
}
}
}
-class LottiefilesFragment : BaseMvRxFragment(R.layout.fragment_epoxy_recycler_view) {
+class LottiefilesFragment : BaseMvRxFragment(R.layout.lottiefiles_fragment) {
+ private val binding: LottiefilesFragmentBinding by viewBinding()
private val viewModel: LottiefilesViewModel by fragmentViewModel()
- private val controller by lazy {
- object : PagedListEpoxyController<AnimationData>() {
+ private object AnimationItemDataDiffCallback : DiffUtil.ItemCallback<AnimationData>() {
+ override fun areItemsTheSame(oldItem: AnimationData, newItem: AnimationData) = oldItem.id == newItem.id
- var mode by Delegates.observable(LottiefilesMode.Recent) { _, _, _ -> requestModelBuild() }
+ override fun areContentsTheSame(oldItem: AnimationData, newItem: AnimationData) = oldItem == newItem
+ }
- override fun buildItemModel(currentPosition: Int, item: AnimationData?): EpoxyModel<*> {
- return if (item == null) {
- AnimationItemViewModel_().id(-currentPosition)
- } else {
- AnimationItemViewModel_()
- .id(item.id)
- .previewUrl(item.preview)
- .title(item.title)
- .previewBackgroundColor(item.bgColorInt)
- .onClickListener { _ ->
- val intent = PlayerActivity.intent(requireContext(), CompositionArgs(animationData = item))
- requireContext().startActivity(intent)
- }
-
- }
- }
-
- override fun addModels(models: List<EpoxyModel<*>>) {
- marquee {
- id("lottiefiles")
- title(R.string.lottiefiles)
- subtitle(R.string.lottiefiles_airbnb)
- }
-
- lottiefilesTabBar {
- id("mode")
- mode(mode)
- recentClickListener { _ ->
- viewModel.setMode(LottiefilesMode.Recent)
- requireContext().hideKeyboard()
- }
- popularClickListener { _ ->
- viewModel.setMode(LottiefilesMode.Popular)
- requireContext().hideKeyboard()
- }
- searchClickListener { _ ->
- viewModel.setMode(LottiefilesMode.Search)
- requireContext().hideKeyboard()
- }
- }
-
- if (mode == LottiefilesMode.Search) {
- searchInputItemView {
- id("search")
- searchClickListener(viewModel::setQuery)
- }
- }
- super.addModels(models)
+ private class AnimationItemViewHolder(context: Context) : RecyclerView.ViewHolder(AnimationItemView(context)) {
+ fun bind(data: AnimationData?) {
+ val view = itemView as AnimationItemView
+ view.setTitle(data?.title)
+ view.setPreviewUrl(data?.preview)
+ view.setPreviewBackgroundColor(data?.bgColorInt)
+ view.setOnClickListener {
+ val intent = PlayerActivity.intent(view.context, CompositionArgs(animationData = data))
+ view.context.startActivity(intent)
}
}
}
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- viewModel.pagedList.observe(this, Observer {
- controller.submitList(it)
- })
+
+ private val adapter = object : PagingDataAdapter<AnimationData, AnimationItemViewHolder>(AnimationItemDataDiffCallback) {
+ override fun onBindViewHolder(holder: AnimationItemViewHolder, position: Int) = holder.bind(getItem(position))
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = AnimationItemViewHolder(parent.context)
+
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- recyclerView.setController(controller)
+ binding.recyclerView.adapter = adapter
+ viewLifecycleOwner.lifecycleScope.launch {
+ viewModel.pager.collectLatest(adapter::submitData)
+ }
+ binding.tabBar.setRecentClickListener {
+ viewModel.setMode(LottiefilesMode.Recent)
+ requireContext().hideKeyboard()
+ }
+ binding.tabBar.setPopularClickListener {
+ viewModel.setMode(LottiefilesMode.Popular)
+ requireContext().hideKeyboard()
+ }
+ binding.tabBar.setSearchClickListener {
+ viewModel.setMode(LottiefilesMode.Search)
+ requireContext().hideKeyboard()
+ }
+ binding.searchView.query.onEach { query ->
+ viewModel.setQuery(query)
+ }.launchIn(viewLifecycleOwner.lifecycleScope)
}
override fun invalidate(): Unit = withState(viewModel) { state ->
- controller.mode = state.mode
+ binding.searchView.isVisible = state.mode == LottiefilesMode.Search
+ binding.tabBar.setMode(state.mode)
}
}
\ No newline at end of file
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/Mode.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/LottiefilesMode.kt
similarity index 100%
rename from LottieSample/src/main/kotlin/com/airbnb/lottie/samples/Mode.kt
rename to LottieSample/src/main/kotlin/com/airbnb/lottie/samples/LottiefilesMode.kt
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/MainActivity.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/MainActivity.kt
index 2ae2d19..c36a34e 100644
--- a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/MainActivity.kt
+++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/MainActivity.kt
@@ -7,15 +7,17 @@
import androidx.browser.customtabs.CustomTabsIntent
import androidx.core.net.toUri
import androidx.fragment.app.Fragment
+import com.airbnb.lottie.samples.databinding.MainActivityBinding
+import com.airbnb.lottie.samples.utils.viewBinding
import com.google.android.material.bottomnavigation.BottomNavigationView
-import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemSelectedListener {
+ private val binding: MainActivityBinding by viewBinding()
+
override fun onCreate(savedInstanceState: Bundle?) {
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_main)
- bottomNavigation.setOnNavigationItemSelectedListener(this)
+ binding.bottomNavigation.setOnNavigationItemSelectedListener(this)
savedInstanceState ?: showFragment(ShowcaseFragment())
}
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/MvRxViewModel.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/MvRxViewModel.kt
deleted file mode 100644
index 41ad0ea..0000000
--- a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/MvRxViewModel.kt
+++ /dev/null
@@ -1,6 +0,0 @@
-package com.airbnb.lottie.samples
-
-import com.airbnb.mvrx.BaseMvRxViewModel
-import com.airbnb.mvrx.MvRxState
-
-open class MvRxViewModel<S : MvRxState>(initialState: S) : BaseMvRxViewModel<S>(initialState, BuildConfig.DEBUG)
\ No newline at end of file
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/OkHttpCallback.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/OkHttpCallback.kt
deleted file mode 100644
index 6bd1017..0000000
--- a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/OkHttpCallback.kt
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.airbnb.lottie.samples
-
-import okhttp3.Call
-import okhttp3.Callback
-import okhttp3.Response
-import java.io.IOException
-
-internal open class OkHttpCallback(
- val onResponse: ((call: Call, response: Response) -> Unit)? = null,
- val onFailure: ((call: Call, exception: IOException) -> Unit)? = null
-): Callback {
- override fun onResponse(call: Call, response: Response) = onResponse?.invoke(call, response) ?: Unit
- override fun onFailure(call: Call, response: IOException) = onFailure?.invoke(call, response) ?: Unit
-
-}
\ No newline at end of file
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/OnSeekBarChangeListenerAdapter.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/OnSeekBarChangeListenerAdapter.kt
index ac4dc0c..523461a 100644
--- a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/OnSeekBarChangeListenerAdapter.kt
+++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/OnSeekBarChangeListenerAdapter.kt
@@ -2,13 +2,13 @@
import android.widget.SeekBar
-internal open class OnSeekBarChangeListenerAdapter(
- val onProgressChanged: ((seekBar: SeekBar, progress: Int, fromUser: Boolean) -> Unit)? = null,
- val onStartTrackingTouch: ((seekBar: SeekBar) -> Unit)? = null,
- val onStopTrackingTouch: ((seekBar: SeekBar) -> Unit)? = null
-): SeekBar.OnSeekBarChangeListener {
+internal class OnSeekBarChangeListenerAdapter(
+ private val onProgressChanged: ((seekBar: SeekBar, progress: Int, fromUser: Boolean) -> Unit)? = null,
+ private val onStartTrackingTouch: ((seekBar: SeekBar) -> Unit)? = null,
+ private val onStopTrackingTouch: ((seekBar: SeekBar) -> Unit)? = null
+) : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) =
- onProgressChanged?.invoke(seekBar, progress, fromUser) ?: Unit
+ onProgressChanged?.invoke(seekBar, progress, fromUser) ?: Unit
override fun onStartTrackingTouch(seekBar: SeekBar) =
onStartTrackingTouch?.invoke(seekBar) ?: Unit
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/PlayerActivity.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/PlayerActivity.kt
index 8b1cb7f..99be680 100644
--- a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/PlayerActivity.kt
+++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/PlayerActivity.kt
@@ -6,11 +6,10 @@
import androidx.appcompat.app.AppCompatActivity
import com.airbnb.lottie.samples.model.CompositionArgs
-class PlayerActivity : AppCompatActivity() {
+class PlayerActivity : AppCompatActivity(R.layout.player_activity) {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_player)
if (savedInstanceState == null) {
val args = intent.getParcelableExtra(PlayerFragment.EXTRA_ANIMATION_ARGS) ?:
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/PlayerFragment.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/PlayerFragment.kt
index 632bbac..0f92052 100644
--- a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/PlayerFragment.kt
+++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/PlayerFragment.kt
@@ -7,12 +7,14 @@
import android.graphics.Typeface
import android.os.Bundle
import android.util.Log
-import android.view.*
+import android.view.Menu
+import android.view.MenuInflater
+import android.view.MenuItem
+import android.view.View
import android.widget.EditText
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.view.children
-import androidx.core.view.get
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.lifecycle.Lifecycle
@@ -22,8 +24,9 @@
import com.airbnb.epoxy.EpoxyRecyclerView
import com.airbnb.lottie.*
import com.airbnb.lottie.model.KeyPath
+import com.airbnb.lottie.samples.databinding.PlayerFragmentBinding
import com.airbnb.lottie.samples.model.CompositionArgs
-import com.airbnb.lottie.samples.views.BackgroundColorView
+import com.airbnb.lottie.samples.utils.viewBinding
import com.airbnb.lottie.samples.views.BottomSheetItemView
import com.airbnb.lottie.samples.views.BottomSheetItemViewModel_
import com.airbnb.lottie.samples.views.ControlBarItemToggleView
@@ -37,34 +40,27 @@
import com.github.mikephil.charting.data.LineDataSet
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.snackbar.Snackbar
-import kotlinx.android.synthetic.main.bottom_sheet_key_paths.*
-import kotlinx.android.synthetic.main.bottom_sheet_render_times.*
-import kotlinx.android.synthetic.main.bottom_sheet_warnings.*
-import kotlinx.android.synthetic.main.control_bar.*
-import kotlinx.android.synthetic.main.control_bar_background_color.*
-import kotlinx.android.synthetic.main.control_bar_player_controls.*
-import kotlinx.android.synthetic.main.control_bar_scale.*
-import kotlinx.android.synthetic.main.control_bar_speed.*
-import kotlinx.android.synthetic.main.control_bar_trim.*
-import kotlinx.android.synthetic.main.fragment_player.*
+import kotlin.math.abs
import kotlin.math.min
import kotlin.math.roundToInt
-class PlayerFragment : BaseMvRxFragment() {
+class PlayerFragment : BaseMvRxFragment(R.layout.player_fragment) {
+ private val binding: PlayerFragmentBinding by viewBinding()
+ private val viewModel: PlayerViewModel by fragmentViewModel()
private val transition = AutoTransition().apply { duration = 175 }
private val renderTimesBehavior by lazy {
- BottomSheetBehavior.from(renderTimesBottomSheet).apply {
+ BottomSheetBehavior.from(binding.bottomSheetRenderTimes.root).apply {
peekHeight = resources.getDimensionPixelSize(R.dimen.bottom_bar_peek_height)
}
}
private val warningsBehavior by lazy {
- BottomSheetBehavior.from(warningsBottomSheet).apply {
+ BottomSheetBehavior.from(binding.bottomSheetWarnings.root).apply {
peekHeight = resources.getDimensionPixelSize(R.dimen.bottom_bar_peek_height)
}
}
private val keyPathsBehavior by lazy {
- BottomSheetBehavior.from(keyPathsBottomSheet).apply {
+ BottomSheetBehavior.from(binding.bottomSheetKeyPaths.root).apply {
peekHeight = resources.getDimensionPixelSize(R.dimen.bottom_bar_peek_height)
}
}
@@ -81,36 +77,31 @@
}
private val animatorListener = AnimatorListenerAdapter(
- onStart = { playButton.isActivated = true },
+ onStart = { binding.controlBarPlayerControls.playButton.isActivated = true },
onEnd = {
- playButton.isActivated = false
- animationView.performanceTracker?.logRenderTimes()
+ binding.controlBarPlayerControls.playButton.isActivated = false
+ binding.animationView.performanceTracker?.logRenderTimes()
updateRenderTimesPerLayer()
},
onCancel = {
- playButton.isActivated = false
+ binding.controlBarPlayerControls.playButton.isActivated = false
},
onRepeat = {
- animationView.performanceTracker?.logRenderTimes()
+ binding.animationView.performanceTracker?.logRenderTimes()
updateRenderTimesPerLayer()
}
)
- private val viewModel: PlayerViewModel by fragmentViewModel()
-
- override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
- inflater.inflate(R.layout.fragment_player, container, false)
-
@SuppressLint("SetTextI18n")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
- (requireActivity() as AppCompatActivity).setSupportActionBar(toolbar)
+ (requireActivity() as AppCompatActivity).setSupportActionBar(binding.toolbar)
(requireActivity() as AppCompatActivity).supportActionBar?.setDisplayShowTitleEnabled(false)
setHasOptionsMenu(true)
- lottieVersionView.text = getString(R.string.lottie_version, BuildConfig.VERSION_NAME)
+ binding.controlBarPlayerControls.lottieVersionView.text = getString(R.string.lottie_version, BuildConfig.VERSION_NAME)
- animationView.setFontAssetDelegate(object : FontAssetDelegate() {
+ binding.animationView.setFontAssetDelegate(object : FontAssetDelegate() {
override fun fetchFont(fontFamily: String?): Typeface {
return Typeface.DEFAULT
}
@@ -119,118 +110,118 @@
val args = arguments?.getParcelable<CompositionArgs>(EXTRA_ANIMATION_ARGS)
?: throw IllegalArgumentException("No composition args specified")
args.animationData?.bgColorInt?.let {
- backgroundButton1.setBackgroundColor(it)
- animationContainer.setBackgroundColor(it)
+ binding.controlBarBackgroundColor.backgroundButton1.setBackgroundColor(it)
+ binding.animationContainer.setBackgroundColor(it)
invertColor(it)
}
args.animationDataV2?.bgColorInt?.let {
- backgroundButton1.setBackgroundColor(it)
- animationContainer.setBackgroundColor(it)
+ binding.controlBarBackgroundColor.backgroundButton1.setBackgroundColor(it)
+ binding.animationContainer.setBackgroundColor(it)
invertColor(it)
}
- minFrameView.setOnClickListener { showMinFrameDialog() }
- maxFrameView.setOnClickListener { showMaxFrameDialog() }
+ binding.controlBarTrim.minFrameView.setOnClickListener { showMinFrameDialog() }
+ binding.controlBarTrim.maxFrameView.setOnClickListener { showMaxFrameDialog() }
viewModel.selectSubscribe(PlayerState::minFrame, PlayerState::maxFrame) { minFrame, maxFrame ->
- animationView.setMinAndMaxFrame(minFrame, maxFrame)
+ binding.animationView.setMinAndMaxFrame(minFrame, maxFrame)
// I think this is a lint bug. It complains about int being <ErrorType>
//noinspection StringFormatMatches
- minFrameView.setText(resources.getString(R.string.min_frame, animationView.minFrame.toInt()))
+ binding.controlBarTrim.minFrameView.setText(resources.getString(R.string.min_frame, binding.animationView.minFrame.toInt()))
//noinspection StringFormatMatches
- maxFrameView.setText(resources.getString(R.string.max_frame, animationView.maxFrame.toInt()))
+ binding.controlBarTrim.maxFrameView.setText(resources.getString(R.string.max_frame, binding.animationView.maxFrame.toInt()))
}
viewModel.fetchAnimation(args)
viewModel.asyncSubscribe(PlayerState::composition, onFail = {
- Snackbar.make(coordinatorLayout, R.string.composition_load_error, Snackbar.LENGTH_LONG).show()
+ Snackbar.make(binding.coordinatorLayout, R.string.composition_load_error, Snackbar.LENGTH_LONG).show()
Log.w(L.TAG, "Error loading composition.", it)
}) {
- loadingView.isVisible = false
+ binding.loadingView.isVisible = false
onCompositionLoaded(it)
}
- borderToggle.setOnClickListener { viewModel.toggleBorderVisible() }
+ binding.controlBar.borderToggle.setOnClickListener { viewModel.toggleBorderVisible() }
viewModel.selectSubscribe(PlayerState::borderVisible) {
- borderToggle.isActivated = it
- borderToggle.setImageResource(
+ binding.controlBar.borderToggle.isActivated = it
+ binding.controlBar.borderToggle.setImageResource(
if (it) R.drawable.ic_border_on
else R.drawable.ic_border_off
)
- animationView.setBackgroundResource(if (it) R.drawable.outline else 0)
+ binding.animationView.setBackgroundResource(if (it) R.drawable.outline else 0)
}
- hardwareAccelerationToggle.setOnClickListener {
- val renderMode = if (animationView.layerType == View.LAYER_TYPE_HARDWARE) {
+ binding.controlBar.hardwareAccelerationToggle.setOnClickListener {
+ val renderMode = if (binding.animationView.layerType == View.LAYER_TYPE_HARDWARE) {
RenderMode.SOFTWARE
} else {
RenderMode.HARDWARE
}
- animationView.setRenderMode(renderMode)
- hardwareAccelerationToggle.isActivated = animationView.layerType == View.LAYER_TYPE_HARDWARE
+ binding.animationView.setRenderMode(renderMode)
+ binding.controlBar.hardwareAccelerationToggle.isActivated = binding.animationView.layerType == View.LAYER_TYPE_HARDWARE
}
- enableApplyingOpacityToLayers.setOnClickListener {
- val isApplyingOpacityToLayersEnabled = !enableApplyingOpacityToLayers.isActivated
- animationView.setApplyingOpacityToLayersEnabled(isApplyingOpacityToLayersEnabled)
- enableApplyingOpacityToLayers.isActivated = isApplyingOpacityToLayersEnabled
+ binding.controlBar.enableApplyingOpacityToLayers.setOnClickListener {
+ val isApplyingOpacityToLayersEnabled = !binding.controlBar.enableApplyingOpacityToLayers.isActivated
+ binding.animationView.setApplyingOpacityToLayersEnabled(isApplyingOpacityToLayersEnabled)
+ binding.controlBar.enableApplyingOpacityToLayers.isActivated = isApplyingOpacityToLayersEnabled
}
- viewModel.selectSubscribe(PlayerState::controlsVisible) { controlsContainer.animateVisible(it) }
+ viewModel.selectSubscribe(PlayerState::controlsVisible) { binding.controlBarPlayerControls.controlsContainer.animateVisible(it) }
- viewModel.selectSubscribe(PlayerState::controlBarVisible) { controlBar.animateVisible(it) }
+ viewModel.selectSubscribe(PlayerState::controlBarVisible) { binding.controlBar.root.animateVisible(it) }
- renderGraphToggle.setOnClickListener { viewModel.toggleRenderGraphVisible() }
+ binding.controlBar.renderGraphToggle.setOnClickListener { viewModel.toggleRenderGraphVisible() }
viewModel.selectSubscribe(PlayerState::renderGraphVisible) {
- renderGraphToggle.isActivated = it
- renderTimesGraphContainer.animateVisible(it)
- renderTimesPerLayerButton.animateVisible(it)
- lottieVersionView.animateVisible(!it)
+ binding.controlBar.renderGraphToggle.isActivated = it
+ binding.controlBarPlayerControls.renderTimesGraphContainer.animateVisible(it)
+ binding.controlBarPlayerControls.renderTimesPerLayerButton.animateVisible(it)
+ binding.controlBarPlayerControls.lottieVersionView.animateVisible(!it)
}
- backgroundColorToggle.setOnClickListener { viewModel.toggleBackgroundColorVisible() }
- closeBackgroundColorButton.setOnClickListener { viewModel.setBackgroundColorVisible(false) }
+ binding.controlBar.backgroundColorToggle.setOnClickListener { viewModel.toggleBackgroundColorVisible() }
+ binding.controlBarBackgroundColor.closeBackgroundColorButton.setOnClickListener { viewModel.setBackgroundColorVisible(false) }
viewModel.selectSubscribe(PlayerState::backgroundColorVisible) {
- backgroundColorToggle.isActivated = it
- backgroundColorContainer.animateVisible(it)
+ binding.controlBar.backgroundColorToggle.isActivated = it
+ binding.controlBarBackgroundColor.backgroundColorContainer.animateVisible(it)
}
- scaleToggle.setOnClickListener { viewModel.toggleScaleVisible() }
- closeScaleButton.setOnClickListener { viewModel.setScaleVisible(false) }
+ binding.controlBar.scaleToggle.setOnClickListener { viewModel.toggleScaleVisible() }
+ binding.controlBarScale.closeScaleButton.setOnClickListener { viewModel.setScaleVisible(false) }
viewModel.selectSubscribe(PlayerState::scaleVisible) {
- scaleToggle.isActivated = it
- scaleContainer.animateVisible(it)
+ binding.controlBar.scaleToggle.isActivated = it
+ binding.controlBarScale.scaleContainer.animateVisible(it)
}
- trimToggle.setOnClickListener { viewModel.toggleTrimVisible() }
- closeTrimButton.setOnClickListener { viewModel.setTrimVisible(false) }
+ binding.controlBar.trimToggle.setOnClickListener { viewModel.toggleTrimVisible() }
+ binding.controlBarTrim.closeTrimButton.setOnClickListener { viewModel.setTrimVisible(false) }
viewModel.selectSubscribe(PlayerState::trimVisible) {
- trimToggle.isActivated = it
- trimContainer.animateVisible(it)
+ binding.controlBar.trimToggle.isActivated = it
+ binding.controlBarTrim.trimContainer.animateVisible(it)
}
- mergePathsToggle.setOnClickListener { viewModel.toggleMergePaths() }
+ binding.controlBar.mergePathsToggle.setOnClickListener { viewModel.toggleMergePaths() }
viewModel.selectSubscribe(PlayerState::useMergePaths) {
- animationView.enableMergePathsForKitKatAndAbove(it)
- mergePathsToggle.isActivated = it
+ binding.animationView.enableMergePathsForKitKatAndAbove(it)
+ binding.controlBar.mergePathsToggle.isActivated = it
}
- speedToggle.setOnClickListener { viewModel.toggleSpeedVisible() }
- closeSpeedButton.setOnClickListener { viewModel.setSpeedVisible(false) }
+ binding.controlBar.speedToggle.setOnClickListener { viewModel.toggleSpeedVisible() }
+ binding.controlBarSpeed.closeSpeedButton.setOnClickListener { viewModel.setSpeedVisible(false) }
viewModel.selectSubscribe(PlayerState::speedVisible) {
- speedToggle.isActivated = it
- speedContainer.isVisible = it
+ binding.controlBar.speedToggle.isActivated = it
+ binding.controlBarSpeed.speedContainer.isVisible = it
}
viewModel.selectSubscribe(PlayerState::speed) {
- animationView.speed = it
- speedButtonsContainer
+ binding.animationView.speed = it
+ binding.controlBarSpeed.speedButtonsContainer
.children
.filterIsInstance<ControlBarItemToggleView>()
.forEach { toggleView ->
- toggleView.isActivated = toggleView.getText().replace("x", "").toFloat() == animationView.speed
+ toggleView.isActivated = toggleView.getText().replace("x", "").toFloat() == binding.animationView.speed
}
}
- speedButtonsContainer
+ binding.controlBarSpeed.speedButtonsContainer
.children
.filterIsInstance(ControlBarItemToggleView::class.java)
.forEach { child ->
@@ -244,68 +235,68 @@
}
- loopButton.setOnClickListener { viewModel.toggleLoop() }
+ binding.controlBarPlayerControls.loopButton.setOnClickListener { viewModel.toggleLoop() }
viewModel.selectSubscribe(PlayerState::repeatCount) {
- animationView.repeatCount = it
- loopButton.isActivated = animationView.repeatCount == ValueAnimator.INFINITE
+ binding.animationView.repeatCount = it
+ binding.controlBarPlayerControls.loopButton.isActivated = binding.animationView.repeatCount == ValueAnimator.INFINITE
}
- playButton.isActivated = animationView.isAnimating
+ binding.controlBarPlayerControls.playButton.isActivated = binding.animationView.isAnimating
- seekBar.setOnSeekBarChangeListener(OnSeekBarChangeListenerAdapter(
+ binding.controlBarPlayerControls.seekBar.setOnSeekBarChangeListener(OnSeekBarChangeListenerAdapter(
onProgressChanged = { _, progress, _ ->
- if (seekBar.isPressed && progress in 1..4) {
- seekBar.progress = 0
+ if (binding.controlBarPlayerControls.seekBar.isPressed && progress in 1..4) {
+ binding.controlBarPlayerControls.seekBar.progress = 0
return@OnSeekBarChangeListenerAdapter
}
- if (animationView.isAnimating) return@OnSeekBarChangeListenerAdapter
- animationView.progress = progress / seekBar.max.toFloat()
+ if (binding.animationView.isAnimating) return@OnSeekBarChangeListenerAdapter
+ binding.animationView.progress = progress / binding.controlBarPlayerControls.seekBar.max.toFloat()
}
))
- animationView.addAnimatorUpdateListener {
- currentFrameView.text = updateFramesAndDurationLabel(animationView)
+ binding.animationView.addAnimatorUpdateListener {
+ binding.controlBarPlayerControls.currentFrameView.text = updateFramesAndDurationLabel(binding.animationView)
- if (seekBar.isPressed) return@addAnimatorUpdateListener
- seekBar.progress = ((it.animatedValue as Float) * seekBar.max).roundToInt()
+ if (binding.controlBarPlayerControls.seekBar.isPressed) return@addAnimatorUpdateListener
+ binding.controlBarPlayerControls.seekBar.progress = ((it.animatedValue as Float) * binding.controlBarPlayerControls.seekBar.max).roundToInt()
}
- animationView.addAnimatorListener(animatorListener)
- playButton.setOnClickListener {
- if (animationView.isAnimating) animationView.pauseAnimation() else animationView.resumeAnimation()
- playButton.isActivated = animationView.isAnimating
+ binding.animationView.addAnimatorListener(animatorListener)
+ binding.controlBarPlayerControls.playButton.setOnClickListener {
+ if (binding.animationView.isAnimating) binding.animationView.pauseAnimation() else binding.animationView.resumeAnimation()
+ binding.controlBarPlayerControls.playButton.isActivated = binding.animationView.isAnimating
postInvalidate()
}
- animationView.setOnClickListener {
+ binding.animationView.setOnClickListener {
// Click the animation view to re-render it for debugging purposes.
- animationView.invalidate()
+ binding.animationView.invalidate()
}
- scaleSeekBar.setOnSeekBarChangeListener(OnSeekBarChangeListenerAdapter(
+ binding.controlBarScale.scaleSeekBar.setOnSeekBarChangeListener(OnSeekBarChangeListenerAdapter(
onProgressChanged = { _, progress, _ ->
val minScale = minScale()
val maxScale = maxScale()
val scale = minScale + progress / 100f * (maxScale - minScale)
- animationView.scale = scale
- scaleText.text = "%.0f%%".format(scale * 100)
+ binding.animationView.scale = scale
+ binding.controlBarScale.scaleText.text = "%.0f%%".format(scale * 100)
}
))
- arrayOf<BackgroundColorView>(
- backgroundButton1,
- backgroundButton2,
- backgroundButton3,
- backgroundButton4,
- backgroundButton5,
- backgroundButton6
+ arrayOf(
+ binding.controlBarBackgroundColor.backgroundButton1,
+ binding.controlBarBackgroundColor.backgroundButton2,
+ binding.controlBarBackgroundColor.backgroundButton3,
+ binding.controlBarBackgroundColor.backgroundButton4,
+ binding.controlBarBackgroundColor.backgroundButton5,
+ binding.controlBarBackgroundColor.backgroundButton6
).forEach { bb ->
bb.setOnClickListener {
- animationContainer.setBackgroundColor(bb.getColor())
+ binding.animationContainer.setBackgroundColor(bb.getColor())
invertColor(bb.getColor())
}
}
- renderTimesGraph.apply {
+ binding.controlBarPlayerControls.renderTimesGraph.apply {
setTouchEnabled(false)
axisRight.isEnabled = false
xAxis.isEnabled = false
@@ -329,17 +320,17 @@
axisLeft.addLimitLine(ll2)
}
- renderTimesPerLayerButton.setOnClickListener {
+ binding.controlBarPlayerControls.renderTimesPerLayerButton.setOnClickListener {
updateRenderTimesPerLayer()
renderTimesBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
}
- closeRenderTimesBottomSheetButton.setOnClickListener {
+ binding.bottomSheetRenderTimes.closeRenderTimesBottomSheetButton.setOnClickListener {
renderTimesBehavior.state = BottomSheetBehavior.STATE_HIDDEN
}
renderTimesBehavior.state = BottomSheetBehavior.STATE_HIDDEN
- warningsButton.setOnClickListener {
+ binding.controlBar.warningsButton.setOnClickListener {
withState(viewModel) { state ->
if (state.composition()?.warnings?.isEmpty() != true) {
warningsBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
@@ -348,16 +339,16 @@
}
}
- closeWarningsBottomSheetButton.setOnClickListener {
+ binding.bottomSheetWarnings.closeWarningsBottomSheetButton.setOnClickListener {
warningsBehavior.state = BottomSheetBehavior.STATE_HIDDEN
}
warningsBehavior.state = BottomSheetBehavior.STATE_HIDDEN
- keyPathsToggle.setOnClickListener {
+ binding.controlBar.keyPathsToggle.setOnClickListener {
keyPathsBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
}
- closeKeyPathsBottomSheetButton.setOnClickListener {
+ binding.bottomSheetKeyPaths.closeKeyPathsBottomSheetButton.setOnClickListener {
keyPathsBehavior.state = BottomSheetBehavior.STATE_HIDDEN
}
keyPathsBehavior.state = BottomSheetBehavior.STATE_HIDDEN
@@ -365,7 +356,7 @@
private fun showMinFrameDialog() {
val minFrameView = EditText(context)
- minFrameView.setText(animationView.minFrame.toInt().toString())
+ minFrameView.setText(binding.animationView.minFrame.toInt().toString())
AlertDialog.Builder(context)
.setTitle(R.string.min_frame_dialog)
.setView(minFrameView)
@@ -378,7 +369,7 @@
private fun showMaxFrameDialog() {
val maxFrameView = EditText(context)
- maxFrameView.setText(animationView.maxFrame.toInt().toString())
+ maxFrameView.setText(binding.animationView.maxFrame.toInt().toString())
AlertDialog.Builder(context)
.setTitle(R.string.max_frame_dialog)
.setView(maxFrameView)
@@ -396,8 +387,8 @@
private fun invertColor(color: Int) {
val isDarkBg = color.isDark()
- animationView.isActivated = isDarkBg
- toolbar.isActivated = isDarkBg
+ binding.animationView.isActivated = isDarkBg
+ binding.toolbar.isActivated = isDarkBg
}
private fun Int.isDark(): Boolean {
@@ -406,7 +397,7 @@
}
override fun onDestroyView() {
- animationView.removeAnimatorListener(animatorListener)
+ binding.animationView.removeAnimatorListener(animatorListener)
super.onDestroyView()
}
@@ -432,24 +423,24 @@
private fun onCompositionLoaded(composition: LottieComposition?) {
composition ?: return
- animationView.setComposition(composition)
- hardwareAccelerationToggle.isActivated = animationView.layerType == View.LAYER_TYPE_HARDWARE
- animationView.setPerformanceTrackingEnabled(true)
+ binding.animationView.setComposition(composition)
+ binding.controlBar.hardwareAccelerationToggle.isActivated = binding.animationView.layerType == View.LAYER_TYPE_HARDWARE
+ binding.animationView.setPerformanceTrackingEnabled(true)
var renderTimeGraphRange = 4f
- animationView.performanceTracker?.addFrameListener { ms ->
+ binding.animationView.performanceTracker?.addFrameListener { ms ->
if (lifecycle.currentState != Lifecycle.State.RESUMED) return@addFrameListener
- lineDataSet.getEntryForIndex((animationView.progress * 100).toInt()).y = ms
- renderTimeGraphRange = Math.max(renderTimeGraphRange, ms * 1.2f)
- renderTimesGraph.setVisibleYRange(0f, renderTimeGraphRange, YAxis.AxisDependency.LEFT)
- renderTimesGraph.invalidate()
+ lineDataSet.getEntryForIndex((binding.animationView.progress * 100).toInt()).y = ms
+ renderTimeGraphRange = renderTimeGraphRange.coerceAtLeast(ms * 1.2f)
+ binding.controlBarPlayerControls.renderTimesGraph.setVisibleYRange(0f, renderTimeGraphRange, YAxis.AxisDependency.LEFT)
+ binding.controlBarPlayerControls.renderTimesGraph.invalidate()
}
// Scale up to fill the screen
- scaleSeekBar.progress = 100
+ binding.controlBarScale.scaleSeekBar.progress = 100
- keyPathsRecyclerView.buildModelsWith(object : EpoxyRecyclerView.ModelBuilderCallback {
+ binding.bottomSheetKeyPaths.keyPathsRecyclerView.buildModelsWith(object : EpoxyRecyclerView.ModelBuilderCallback {
override fun buildModels(controller: EpoxyController) {
- animationView.resolveKeyPath(KeyPath("**")).forEachIndexed { index, keyPath ->
+ binding.animationView.resolveKeyPath(KeyPath("**")).forEachIndexed { index, keyPath ->
BottomSheetItemViewModel_()
.id(index)
.text(keyPath.keysToString())
@@ -465,36 +456,36 @@
}
private fun updateRenderTimesPerLayer() {
- renderTimesContainer.removeAllViews()
- animationView.performanceTracker?.sortedRenderTimes?.forEach {
+ binding.bottomSheetRenderTimes.renderTimesContainer.removeAllViews()
+ binding.animationView.performanceTracker?.sortedRenderTimes?.forEach {
val view = BottomSheetItemView(requireContext()).apply {
set(
it.first!!.replace("__container", "Total"),
"%.2f ms".format(it.second!!)
)
}
- renderTimesContainer.addView(view)
+ binding.bottomSheetRenderTimes.renderTimesContainer.addView(view)
}
}
private fun updateWarnings() = withState(viewModel) { state ->
// Force warning to update
- warningsContainer.removeAllViews()
+ binding.bottomSheetWarnings.warningsContainer.removeAllViews()
val warnings = state.composition()?.warnings ?: emptySet<String>()
- if (!warnings.isEmpty() && warnings.size == warningsContainer.childCount) return@withState
+ if (!warnings.isEmpty() && warnings.size == binding.bottomSheetWarnings.warningsContainer.childCount) return@withState
- warningsContainer.removeAllViews()
+ binding.bottomSheetWarnings.warningsContainer.removeAllViews()
warnings.forEach {
val view = BottomSheetItemView(requireContext()).apply {
set(it)
}
- warningsContainer.addView(view)
+ binding.bottomSheetWarnings.warningsContainer.addView(view)
}
val size = warnings.size
- warningsButton.setText(resources.getQuantityString(R.plurals.warnings, size, size))
- warningsButton.setImageResource(
+ binding.controlBar.warningsButton.setText(resources.getQuantityString(R.plurals.warnings, size, size))
+ binding.controlBar.warningsButton.setImageResource(
if (warnings.isEmpty()) R.drawable.ic_sentiment_satisfied
else R.drawable.ic_sentiment_dissatisfied
)
@@ -512,7 +503,7 @@
)
}
- private fun beginDelayedTransition() = TransitionManager.beginDelayedTransition(container, transition)
+ private fun beginDelayedTransition() = TransitionManager.beginDelayedTransition(binding.container, transition)
companion object {
const val EXTRA_ANIMATION_ARGS = "animation_args"
@@ -530,12 +521,12 @@
val currentFrame = animation.frame.toString()
val totalFrames = ("%.0f").format(animation.maxFrame)
- val animationSpeed: Float = Math.abs(animation.speed)
+ val animationSpeed: Float = abs(animation.speed)
val totalTime = ((animation.duration / animationSpeed) / 1000.0)
val totalTimeFormatted = ("%.1f").format(totalTime)
- val progress = (totalTime / 100.0) * (Math.round(animation.progress * 100.0))
+ val progress = (totalTime / 100.0) * ((animation.progress * 100.0).roundToInt())
val progressFormatted = ("%.1f").format(progress)
return "$currentFrame/$totalFrames\n$progressFormatted/$totalTimeFormatted"
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/PlayerViewModel.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/PlayerViewModel.kt
index dc7ad22..a6bce9f 100644
--- a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/PlayerViewModel.kt
+++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/PlayerViewModel.kt
@@ -7,8 +7,11 @@
import com.airbnb.lottie.LottieCompositionFactory
import com.airbnb.lottie.LottieTask
import com.airbnb.lottie.samples.model.CompositionArgs
+import com.airbnb.lottie.samples.utils.MvRxViewModel
import com.airbnb.mvrx.*
import java.io.FileInputStream
+import kotlin.math.max
+import kotlin.math.min
data class PlayerState(
val composition: Async<LottieComposition> = Uninitialized,
@@ -20,7 +23,6 @@
val scaleVisible: Boolean = false,
val speedVisible: Boolean = false,
val trimVisible: Boolean = false,
- val useHardwareAcceleration: Boolean = false,
val useMergePaths: Boolean = false,
val minFrame: Int = 0,
val maxFrame: Int = 0,
@@ -80,16 +82,14 @@
fun setTrimVisible(visible: Boolean) = setState { copy(trimVisible = visible) }
- fun toggleHardwareAcceleration() = setState { copy(useHardwareAcceleration = !useHardwareAcceleration) }
-
fun toggleMergePaths() = setState { copy(useMergePaths = !useMergePaths) }
fun setMinFrame(minFrame: Int) = setState {
- copy(minFrame = Math.max(minFrame, composition()?.startFrame?.toInt() ?: 0))
+ copy(minFrame = max(minFrame, composition()?.startFrame?.toInt() ?: 0))
}
fun setMaxFrame(maxFrame: Int) = setState {
- copy(maxFrame = Math.min(maxFrame, composition()?.endFrame?.toInt() ?: 0))
+ copy(maxFrame = min(maxFrame, composition()?.endFrame?.toInt() ?: 0))
}
fun setSpeed(speed: Float) = setState { copy(speed = speed) }
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/PreviewFragment.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/PreviewFragment.kt
index 47961ca..cdb3d1b 100644
--- a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/PreviewFragment.kt
+++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/PreviewFragment.kt
@@ -10,14 +10,11 @@
import android.widget.ArrayAdapter
import android.widget.EditText
import android.widget.Toast
-import androidx.core.app.ActivityCompat.requestPermissions
-import androidx.core.app.ActivityCompat.startActivityForResult
-import androidx.core.content.ContextCompat.startActivity
import com.airbnb.epoxy.EpoxyController
-import com.airbnb.lottie.samples.R.id.coordinatorLayout
import com.airbnb.lottie.samples.model.CompositionArgs
+import com.airbnb.lottie.samples.utils.BaseEpoxyFragment
+import com.airbnb.lottie.samples.utils.hasPermission
import com.airbnb.lottie.samples.views.marquee
-import kotlinx.android.synthetic.main.fragment_player.*
private const val RC_FILE = 1000
private const val RC_CAMERA_PERMISSION = 1001
@@ -110,7 +107,7 @@
if (grantResults.firstOrNull() == PackageManager.PERMISSION_GRANTED) {
startActivity(QRScanActivity.intent(requireContext()))
} else {
- Snackbar.make(coordinatorLayout, R.string.qr_permission_denied, Snackbar.LENGTH_LONG).show()
+ Snackbar.make(binding.root, R.string.qr_permission_denied, Snackbar.LENGTH_LONG).show()
}
}
}
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/PreviewItemView.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/PreviewItemView.kt
index 79f1c3c..42e068f 100644
--- a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/PreviewItemView.kt
+++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/PreviewItemView.kt
@@ -1,15 +1,15 @@
package com.airbnb.lottie.samples
import android.content.Context
-import androidx.annotation.DrawableRes
import android.util.AttributeSet
-import android.view.View
import android.widget.LinearLayout
+import androidx.annotation.DrawableRes
import com.airbnb.epoxy.CallbackProp
import com.airbnb.epoxy.ModelProp
import com.airbnb.epoxy.ModelView
import com.airbnb.epoxy.TextProp
-import kotlinx.android.synthetic.main.list_item_preview.view.*
+import com.airbnb.lottie.samples.databinding.ListItemPreviewBinding
+import com.airbnb.lottie.samples.utils.viewBinding
@ModelView(autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT)
class PreviewItemView @JvmOverloads constructor(
@@ -17,24 +17,24 @@
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : LinearLayout(context, attrs, defStyleAttr) {
+ private val binding: ListItemPreviewBinding by viewBinding()
init {
orientation = VERTICAL
- inflate(R.layout.list_item_preview)
}
@TextProp
fun setTitle(title: CharSequence) {
- titleView.text = title
+ binding.titleView.text = title
}
@ModelProp
fun setIcon(@DrawableRes icon: Int) {
- iconView.setImageResource(icon)
+ binding.iconView.setImageResource(icon)
}
@CallbackProp
- fun setClickListener(clickListener: View.OnClickListener?) {
- container.setOnClickListener(clickListener)
+ fun setClickListener(clickListener: OnClickListener?) {
+ binding.container.setOnClickListener(clickListener)
}
}
\ No newline at end of file
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/QRScanActivity.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/QRScanActivity.kt
index 19c654a..6789387 100644
--- a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/QRScanActivity.kt
+++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/QRScanActivity.kt
@@ -6,11 +6,14 @@
import android.os.Bundle
import android.os.Vibrator
import androidx.appcompat.app.AppCompatActivity
+import com.airbnb.lottie.samples.databinding.QrscanActivityBinding
import com.airbnb.lottie.samples.model.CompositionArgs
+import com.airbnb.lottie.samples.utils.vibrateCompat
+import com.airbnb.lottie.samples.utils.viewBinding
import com.dlazaro66.qrcodereaderview.QRCodeReaderView
-import kotlinx.android.synthetic.main.activity_qrscan.*
class QRScanActivity : AppCompatActivity(), QRCodeReaderView.OnQRCodeReadListener {
+ private val binding: QrscanActivityBinding by viewBinding()
private val vibrator by lazy { getSystemService(Context.VIBRATOR_SERVICE) as Vibrator }
// Sometimes the qr code is read twice in rapid succession. This prevents it from being read
@@ -19,24 +22,23 @@
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_qrscan)
- qrView.setQRDecodingEnabled(true)
- qrView.setAutofocusInterval(2000L)
- qrView.setBackCamera()
- qrView.setOnQRCodeReadListener(this)
- qrView.setOnClickListener { qrView.forceAutoFocus() }
+ binding.qrView.setQRDecodingEnabled(true)
+ binding.qrView.setAutofocusInterval(2000L)
+ binding.qrView.setBackCamera()
+ binding.qrView.setOnQRCodeReadListener(this)
+ binding.qrView.setOnClickListener { binding.qrView.forceAutoFocus() }
}
override fun onResume() {
super.onResume()
- qrView.startCamera()
+ binding.qrView.startCamera()
hasReadQrCode = false
}
override fun onPause() {
super.onPause()
- qrView.stopCamera()
+ binding.qrView.stopCamera()
}
override fun onQRCodeRead(url: String, pointFS: Array<PointF>) {
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/ShowcaseFragment.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/ShowcaseFragment.kt
index 5636530..f5e879a 100644
--- a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/ShowcaseFragment.kt
+++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/ShowcaseFragment.kt
@@ -2,30 +2,26 @@
import android.content.Intent
import com.airbnb.epoxy.EpoxyController
+import com.airbnb.lottie.samples.api.LottiefilesApi
import com.airbnb.lottie.samples.model.AnimationResponseV2
import com.airbnb.lottie.samples.model.CompositionArgs
import com.airbnb.lottie.samples.model.ShowcaseItem
+import com.airbnb.lottie.samples.utils.BaseEpoxyFragment
+import com.airbnb.lottie.samples.utils.MvRxViewModel
import com.airbnb.lottie.samples.views.animationItemView
import com.airbnb.lottie.samples.views.loadingView
import com.airbnb.lottie.samples.views.marquee
import com.airbnb.lottie.samples.views.showcaseCarousel
-import com.airbnb.mvrx.Async
-import com.airbnb.mvrx.MvRxState
-import com.airbnb.mvrx.MvRxViewModelFactory
-import com.airbnb.mvrx.Uninitialized
-import com.airbnb.mvrx.ViewModelContext
-import com.airbnb.mvrx.fragmentViewModel
-import com.airbnb.mvrx.withState
-import io.reactivex.schedulers.Schedulers
+import com.airbnb.mvrx.*
+import kotlinx.coroutines.Dispatchers
data class ShowcaseState(val response: Async<AnimationResponseV2> = Uninitialized) : MvRxState
class ShowcaseViewModel(initialState: ShowcaseState, api: LottiefilesApi) : MvRxViewModel<ShowcaseState>(initialState) {
init {
- api.getCollection()
- .subscribeOn(Schedulers.io())
- .retry(3)
- .execute { copy(response = it) }
+ suspend {
+ api.getCollection()
+ }.execute(Dispatchers.IO) { copy(response = it) }
}
companion object : MvRxViewModelFactory<ShowcaseViewModel, ShowcaseState> {
@@ -55,7 +51,7 @@
startActivity(Intent(requireContext(), BullseyeActivity::class.java))
},
ShowcaseItem(R.drawable.showcase_preview_lottie, R.string.showcase_item_recycler_view) {
- startActivity(Intent(requireContext(), ListActivity::class.java))
+ startActivity(Intent(requireContext(), WishListActivity::class.java))
}
)
private val viewModel: ShowcaseViewModel by fragmentViewModel()
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/SimpleAnimationActivity.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/SimpleAnimationActivity.kt
index 047dbaf..08d5185 100644
--- a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/SimpleAnimationActivity.kt
+++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/SimpleAnimationActivity.kt
@@ -6,22 +6,20 @@
import com.airbnb.lottie.LottieComposition
import com.airbnb.lottie.LottieCompositionFactory
import com.airbnb.lottie.LottieDrawable
-import com.airbnb.lottie.model.LottieCompositionCache
-import kotlinx.android.synthetic.main.activity_simple_animation.*
-import kotlinx.android.synthetic.main.activity_simple_animation.view.*
-import java.lang.IllegalArgumentException
+import com.airbnb.lottie.samples.databinding.SimpleAnimationActivityBinding
+import com.airbnb.lottie.samples.utils.viewBinding
/**
* Useful for performance debugging.
* adb shell am start -n com.airbnb.lottie/.samples.SimpleAnimationActivity --es animation LottieLogo1.json --activity-clear-top
*/
class SimpleAnimationActivity : AppCompatActivity() {
+ private val binding: SimpleAnimationActivityBinding by viewBinding()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_simple_animation)
var composition: LottieComposition? = null
- parse.setOnClickListener {
+ binding.parse.setOnClickListener {
val assetName = intent.extras?.getString("animation") ?: ""
val start = System.currentTimeMillis()
composition = LottieCompositionFactory.fromAssetSync(this, assetName, null).value
@@ -29,16 +27,16 @@
Toast.makeText(this@SimpleAnimationActivity, "Done ${System.currentTimeMillis() - start}", Toast.LENGTH_SHORT).show()
}
- setComposition.setOnClickListener {
+ binding.setComposition.setOnClickListener {
val start = System.currentTimeMillis()
val drawable = LottieDrawable()
drawable.setComposition(composition)
Toast.makeText(this@SimpleAnimationActivity, "Done ${System.currentTimeMillis() - start}", Toast.LENGTH_SHORT).show()
}
- play.setOnClickListener {
- composition?.let { animationView.setComposition(it) }
- animationView.playAnimation()
+ binding.play.setOnClickListener {
+ composition?.let { binding.animationView.setComposition(it) }
+ binding.animationView.playAnimation()
}
}
}
\ No newline at end of file
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/SnapshotTestActivity.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/SnapshotTestActivity.kt
index 60bc19a..faa86ac 100644
--- a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/SnapshotTestActivity.kt
+++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/SnapshotTestActivity.kt
@@ -1,39 +1,17 @@
package com.airbnb.lottie.samples
-import android.graphics.Bitmap
-import android.graphics.BitmapFactory
-import android.graphics.Canvas
-import android.graphics.Color
-import android.graphics.PorterDuff
-import android.graphics.Typeface
-import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
-import androidx.core.view.isVisible
-import com.airbnb.lottie.FontAssetDelegate
-import com.airbnb.lottie.ImageAssetDelegate
-import com.airbnb.lottie.LottieComposition
-import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool
-import kotlinx.android.synthetic.main.activity_film_strip_snapshots.*
-import kotlinx.android.synthetic.main.activity_snapshot_tests.*
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.async
-import kotlinx.coroutines.launch
-import kotlin.coroutines.resume
-import kotlin.coroutines.suspendCoroutine
+import com.airbnb.lottie.samples.databinding.SnapshotTestsActivityBinding
+import com.airbnb.lottie.samples.utils.viewBinding
class SnapshotTestActivity : AppCompatActivity() {
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_snapshot_tests)
- }
+ private val binding: SnapshotTestsActivityBinding by viewBinding()
fun recordSnapshot(snapshotName: String, snapshotVariant: String) {
- counterTextView.post {
- statusTextView.text = if (snapshotVariant == "default") snapshotName else "$snapshotName - $snapshotVariant"
- val count = counterTextView.text.toString().toInt()
- counterTextView.text = "${count + 1}"
+ binding.counterTextView.post {
+ binding.statusTextView.text = if (snapshotVariant == "default") snapshotName else "$snapshotName - $snapshotVariant"
+ val count = binding.counterTextView.text.toString().toInt()
+ binding.counterTextView.text = "${count + 1}"
}
}
}
\ No newline at end of file
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/TestColorFilterActivity.java b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/TestColorFilterActivity.java
deleted file mode 100644
index 7877cfb..0000000
--- a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/TestColorFilterActivity.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.airbnb.lottie.samples;
-
-import android.os.Bundle;
-import androidx.annotation.Nullable;
-import androidx.appcompat.app.AppCompatActivity;
-
-public class TestColorFilterActivity extends AppCompatActivity {
-
- @Override protected void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_test_color_filter);
- }
-}
\ No newline at end of file
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/TypographyDemoActivity.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/TypographyDemoActivity.kt
index 64cbbb8..9853911 100644
--- a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/TypographyDemoActivity.kt
+++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/TypographyDemoActivity.kt
@@ -4,22 +4,24 @@
import android.view.View
import android.view.ViewTreeObserver
import androidx.appcompat.app.AppCompatActivity
-import kotlinx.android.synthetic.main.activity_typography_demo.*
+import com.airbnb.lottie.samples.databinding.TypographyDemoActivityBinding
+import com.airbnb.lottie.samples.utils.viewBinding
class TypographyDemoActivity : AppCompatActivity() {
+ private val binding: TypographyDemoActivityBinding by viewBinding()
+
private val layoutListener = ViewTreeObserver.OnGlobalLayoutListener {
- scrollView.fullScroll(View.FOCUS_DOWN)
+ binding.scrollView.fullScroll(View.FOCUS_DOWN)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_typography_demo)
- fontView.viewTreeObserver.addOnGlobalLayoutListener(layoutListener)
+ binding.fontView.viewTreeObserver.addOnGlobalLayoutListener(layoutListener)
}
override fun onDestroy() {
- fontView.viewTreeObserver.removeOnGlobalLayoutListener(layoutListener)
+ binding.fontView.viewTreeObserver.removeOnGlobalLayoutListener(layoutListener)
super.onDestroy()
}
}
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/WishListActivity.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/WishListActivity.kt
new file mode 100644
index 0000000..d066e9d
--- /dev/null
+++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/WishListActivity.kt
@@ -0,0 +1,45 @@
+package com.airbnb.lottie.samples
+
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import com.airbnb.epoxy.EpoxyController
+import com.airbnb.epoxy.EpoxyRecyclerView
+import com.airbnb.lottie.samples.databinding.ListActivityBinding
+import com.airbnb.lottie.samples.utils.viewBinding
+import com.airbnb.lottie.samples.views.listingCard
+import com.airbnb.lottie.samples.views.marquee
+
+class WishListActivity : AppCompatActivity() {
+ private val binding: ListActivityBinding by viewBinding()
+
+ private val wishListedItems = mutableSetOf<Int>()
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding.recyclerView.buildModelsWith(object : EpoxyRecyclerView.ModelBuilderCallback {
+ override fun buildModels(controller: EpoxyController) {
+ controller.buildModels()
+ }
+ })
+ }
+
+ private fun EpoxyController.buildModels() {
+ marquee {
+ id("marquee")
+ title("List")
+ subtitle("Loading the same animation many times in a list")
+ }
+
+ repeat(100) { index ->
+ listingCard {
+ id(index)
+ isWishListed(wishListedItems.contains(index))
+ onToggled { isWishListed ->
+ if (isWishListed) wishListedItems.add(index)
+ else wishListedItems.remove(index)
+ binding.recyclerView.requestModelBuild()
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/api/LottiefilesApi.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/api/LottiefilesApi.kt
new file mode 100644
index 0000000..8f26bc8
--- /dev/null
+++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/api/LottiefilesApi.kt
@@ -0,0 +1,21 @@
+package com.airbnb.lottie.samples.api
+
+import com.airbnb.lottie.samples.model.AnimationResponse
+import com.airbnb.lottie.samples.model.AnimationResponseV2
+import retrofit2.http.GET
+import retrofit2.http.Path
+import retrofit2.http.Query
+
+interface LottiefilesApi {
+ @GET("v1/recent")
+ suspend fun getRecent(@Query("page") page: Int): AnimationResponse
+
+ @GET("v1/popular")
+ suspend fun getPopular(@Query("page") page: Int): AnimationResponse
+
+ @GET("v2/featured")
+ suspend fun getCollection(): AnimationResponseV2
+
+ @GET("v1/search/{query}")
+ suspend fun search(@Path("query") query: String, @Query("page") page: Int): AnimationResponse
+}
\ No newline at end of file
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/model/AnimationData.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/model/AnimationData.kt
index c36abbb..e324c27 100644
--- a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/model/AnimationData.kt
+++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/model/AnimationData.kt
@@ -1,7 +1,7 @@
package com.airbnb.lottie.samples.model
import android.os.Parcelable
-import com.airbnb.lottie.samples.toColorIntSafe
+import com.airbnb.lottie.samples.utils.toColorIntSafe
import kotlinx.android.parcel.Parcelize
@Parcelize
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/model/AnimationDataV2.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/model/AnimationDataV2.kt
index 7c64b4a..f892d77 100644
--- a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/model/AnimationDataV2.kt
+++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/model/AnimationDataV2.kt
@@ -1,7 +1,7 @@
package com.airbnb.lottie.samples.model
import android.os.Parcelable
-import com.airbnb.lottie.samples.toColorIntSafe
+import com.airbnb.lottie.samples.utils.toColorIntSafe
import kotlinx.android.parcel.Parcelize
@Parcelize
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/FilmStripSnapshotActivity.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/testing/FilmStripSnapshotActivity.kt
similarity index 84%
rename from LottieSample/src/main/kotlin/com/airbnb/lottie/samples/FilmStripSnapshotActivity.kt
rename to LottieSample/src/main/kotlin/com/airbnb/lottie/samples/testing/FilmStripSnapshotActivity.kt
index 6157758..aab597f 100644
--- a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/FilmStripSnapshotActivity.kt
+++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/testing/FilmStripSnapshotActivity.kt
@@ -1,4 +1,4 @@
-package com.airbnb.lottie.samples
+package com.airbnb.lottie.samples.testing
import android.Manifest
import android.content.pm.PackageManager
@@ -9,27 +9,25 @@
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
-import androidx.core.view.children
import androidx.core.view.doOnNextLayout
import com.airbnb.lottie.L
-import com.airbnb.lottie.LottieAnimationView
import com.airbnb.lottie.LottieCompositionFactory
-import kotlinx.android.synthetic.main.activity_film_strip_snapshots.*
+import com.airbnb.lottie.samples.databinding.FilmStripSnapshotsActivityBinding
+import com.airbnb.lottie.samples.utils.viewBinding
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
-import kotlin.IllegalStateException
private const val RC_PERMISSION = 12345
class FilmStripSnapshotActivity : AppCompatActivity() {
+ private val binding: FilmStripSnapshotsActivityBinding by viewBinding()
// TODO: fix this.
@Suppress("DEPRECATION")
private val rootDir = "${Environment.getExternalStorageDirectory()}/lottie"
private val animationsDir = File("$rootDir/animations")
private val snapshotsDir = File("$rootDir/snapshots")
- private val dummyBitmap by lazy { BitmapFactory.decodeResource(resources, R.drawable.airbnb) }
private val bitmap = Bitmap.createBitmap(1000, 1000, Bitmap.Config.ARGB_8888)
private val canvas = Canvas(bitmap)
@@ -39,13 +37,12 @@
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_film_strip_snapshots)
Log.i(L.TAG, "Starting Snapshots")
if (!animationsDir.exists() || !animationsDir.isDirectory) throw IllegalStateException("Animations directory ($animationsDir) does not exist!")
if (!snapshotsDir.exists()) snapshotsDir.mkdirs()
- filmStripView.doOnNextLayout {
+ binding.filmStripView.doOnNextLayout {
createSnapshots()
Log.i(L.TAG, "Finished Snapshots")
finish()
@@ -78,17 +75,18 @@
return
}
- Log.d(L.TAG, "Found ${animationsDir.listFiles().size} files.")
- animationsDir.listFiles()
+ val files = animationsDir.listFiles() ?: emptyArray()
+ Log.d(L.TAG, "Found ${files.size} files.")
+ files
.filter { it.name.endsWith(".json") }
.forEach { file ->
Log.d(L.TAG, "Creating snapshotFilmstrip for ${file.name}")
val fis = FileInputStream(file)
val result = LottieCompositionFactory.fromJsonInputStreamSync(fis, file.name)
val composition = result.value ?: throw IllegalStateException("Unable to parse composition for $file", result.exception)
- filmStripView.setComposition(composition)
+ binding.filmStripView.setComposition(composition)
canvas.clear()
- filmStripView.draw(canvas)
+ binding.filmStripView.draw(canvas)
val outputFileName = file.name.replace(".json", ".png")
val outputFilePath = "${Environment.getExternalStorageDirectory()}/lottie/snapshots/$outputFileName"
diff --git a/LottieSample/src/androidTest/java/com/airbnb/lottie/samples/NoCacheLottieAnimationView.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/testing/NoCacheLottieAnimationView.kt
similarity index 90%
rename from LottieSample/src/androidTest/java/com/airbnb/lottie/samples/NoCacheLottieAnimationView.kt
rename to LottieSample/src/main/kotlin/com/airbnb/lottie/samples/testing/NoCacheLottieAnimationView.kt
index eb148d6..e87fc90 100644
--- a/LottieSample/src/androidTest/java/com/airbnb/lottie/samples/NoCacheLottieAnimationView.kt
+++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/testing/NoCacheLottieAnimationView.kt
@@ -1,4 +1,4 @@
-package com.airbnb.lottie.samples
+package com.airbnb.lottie.samples.testing
import android.content.Context
import android.util.AttributeSet
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/utils/ActivityViewBindingDelegate.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/utils/ActivityViewBindingDelegate.kt
new file mode 100644
index 0000000..3393702
--- /dev/null
+++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/utils/ActivityViewBindingDelegate.kt
@@ -0,0 +1,33 @@
+package com.airbnb.lottie.samples.utils
+
+import android.app.Activity
+import android.view.LayoutInflater
+import androidx.viewbinding.ViewBinding
+import kotlin.properties.ReadOnlyProperty
+import kotlin.reflect.KProperty
+
+/**
+ * Create bindings for a view similar to bindView.
+ *
+ * To use, just call:
+ * private val binding: HomeWorkoutDetailsActivityBinding by viewBinding()
+ * with your binding class and access it as you normally would.
+ */
+inline fun <reified T : ViewBinding> Activity.viewBinding() = ActivityViewBindingDelegate(T::class.java, this)
+
+class ActivityViewBindingDelegate<T : ViewBinding>(
+ private val bindingClass: Class<T>,
+ val activity: Activity
+) : ReadOnlyProperty<Activity, T> {
+ private var binding: T? = null
+
+ override fun getValue(thisRef: Activity, property: KProperty<*>): T {
+ binding?.let { return it }
+
+ val inflateMethod = bindingClass.getMethod("inflate", LayoutInflater::class.java)
+ @Suppress("UNCHECKED_CAST")
+ binding = inflateMethod.invoke(null, thisRef.layoutInflater) as T
+ thisRef.setContentView(binding!!.root)
+ return binding!!
+ }
+}
\ No newline at end of file
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/utils/BaseEpoxyFragment.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/utils/BaseEpoxyFragment.kt
new file mode 100644
index 0000000..04889ad
--- /dev/null
+++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/utils/BaseEpoxyFragment.kt
@@ -0,0 +1,32 @@
+package com.airbnb.lottie.samples.utils
+
+import android.os.Bundle
+import android.view.View
+import com.airbnb.epoxy.AsyncEpoxyController
+import com.airbnb.epoxy.EpoxyController
+import com.airbnb.lottie.samples.R
+import com.airbnb.lottie.samples.databinding.BaseFragmentBinding
+import com.airbnb.mvrx.BaseMvRxFragment
+
+
+private class BaseEpoxyController(
+ private val buildModelsCallback: EpoxyController.() -> Unit
+) : AsyncEpoxyController() {
+ override fun buildModels() {
+ buildModelsCallback()
+ }
+}
+
+abstract class BaseEpoxyFragment : BaseMvRxFragment(R.layout.base_fragment) {
+ protected val binding: BaseFragmentBinding by viewBinding()
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ binding.recyclerView.setController(BaseEpoxyController { buildModels() })
+ }
+
+ override fun invalidate() {
+ binding.recyclerView.requestModelBuild()
+ }
+
+ abstract fun EpoxyController.buildModels()
+}
\ No newline at end of file
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/utils/FragmentViewBindingDelegate.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/utils/FragmentViewBindingDelegate.kt
new file mode 100644
index 0000000..e69610a
--- /dev/null
+++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/utils/FragmentViewBindingDelegate.kt
@@ -0,0 +1,58 @@
+package com.airbnb.lottie.samples.utils
+
+import android.os.Handler
+import android.os.Looper
+import android.view.View
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.LifecycleObserver
+import androidx.lifecycle.OnLifecycleEvent
+import androidx.viewbinding.ViewBinding
+import kotlin.properties.ReadOnlyProperty
+import kotlin.reflect.KProperty
+
+/**
+ * Create bindings for a view similar to bindView.
+ *
+ * To use, just call
+ * private val binding: FHomeWorkoutDetailsBinding by viewBinding()
+ * with your binding class and access it as you normally would.
+ */
+inline fun <reified T : ViewBinding> Fragment.viewBinding() = FragmentViewBindingDelegate(T::class.java, this)
+
+class FragmentViewBindingDelegate<T : ViewBinding>(
+ bindingClass: Class<T>,
+ val fragment: Fragment
+) : ReadOnlyProperty<Fragment, T> {
+ private val clearBindingHandler by lazy(LazyThreadSafetyMode.NONE) { Handler(Looper.getMainLooper()) }
+ private var binding: T? = null
+
+ private val bindMethod = bindingClass.getMethod("bind", View::class.java)
+
+ init {
+ fragment.viewLifecycleOwnerLiveData.observe(fragment) { viewLifecycleOwner ->
+ viewLifecycleOwner.lifecycle.addObserver(object : LifecycleObserver {
+ @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
+ fun onDestroy() {
+ // Lifecycle listeners are called before onDestroyView in a Fragment.
+ // However, we want views to be able to use bindings in onDestroyView
+ // to do cleanup so we clear the reference one frame later.
+ clearBindingHandler.post { binding = null }
+ }
+ })
+ }
+ }
+
+ @Suppress("UNCHECKED_CAST")
+ override fun getValue(thisRef: Fragment, property: KProperty<*>): T {
+ binding?.let { return it }
+
+ val lifecycle = fragment.viewLifecycleOwner.lifecycle
+ if (!lifecycle.currentState.isAtLeast(Lifecycle.State.INITIALIZED)) {
+ error("Cannot access view bindings. View lifecycle is ${lifecycle.currentState}!")
+ }
+
+ binding = bindMethod.invoke(null, thisRef.requireView()) as T
+ return binding!!
+ }
+}
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/utils/MvRxViewModel.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/utils/MvRxViewModel.kt
new file mode 100644
index 0000000..bcc1883
--- /dev/null
+++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/utils/MvRxViewModel.kt
@@ -0,0 +1,28 @@
+package com.airbnb.lottie.samples.utils
+
+import androidx.lifecycle.viewModelScope
+import com.airbnb.lottie.samples.BuildConfig
+import com.airbnb.mvrx.*
+import kotlinx.coroutines.*
+
+abstract class MvRxViewModel<S : MvRxState>(initialState: S) : BaseMvRxViewModel<S>(initialState, BuildConfig.DEBUG) {
+ /**
+ * This uses [Dispatchers.Main.immediate] by default to mimic [viewModelScope].
+ */
+ fun <T : Any?> (suspend () -> T).execute(
+ dispatcher: CoroutineDispatcher = Dispatchers.Main.immediate,
+ reducer: S.(Async<T>) -> S
+ ): Job {
+ setState { reducer(Loading()) }
+ return viewModelScope.launch(dispatcher) {
+ try {
+ val result = invoke()
+ setState { reducer(Success(result)) }
+ } catch (e: CancellationException) {
+ throw e
+ } catch (e: Exception) {
+ setState { reducer(Fail(e)) }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/TypeExtensions.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/utils/TypeExtensions.kt
similarity index 98%
rename from LottieSample/src/main/kotlin/com/airbnb/lottie/samples/TypeExtensions.kt
rename to LottieSample/src/main/kotlin/com/airbnb/lottie/samples/utils/TypeExtensions.kt
index 2a72e7f..cbf297c 100644
--- a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/TypeExtensions.kt
+++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/utils/TypeExtensions.kt
@@ -1,4 +1,4 @@
-package com.airbnb.lottie.samples
+package com.airbnb.lottie.samples.utils
import android.app.Activity
import android.content.Context
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/utils/ViewViewBindingDelegate.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/utils/ViewViewBindingDelegate.kt
new file mode 100644
index 0000000..49123a2
--- /dev/null
+++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/utils/ViewViewBindingDelegate.kt
@@ -0,0 +1,37 @@
+package com.airbnb.lottie.samples.utils
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.viewbinding.ViewBinding
+import kotlin.properties.ReadOnlyProperty
+import kotlin.reflect.KProperty
+
+/**
+ * Create bindings for a view similar to bindView.
+ *
+ * To use, just call:
+ * private val binding: FHomeWorkoutDetailsBinding by viewBinding()
+ * with your binding class and access it as you normally would.
+ */
+inline fun <reified T : ViewBinding> ViewGroup.viewBinding() = ViewBindingDelegate(T::class.java, this)
+
+class ViewBindingDelegate<T : ViewBinding>(
+ private val bindingClass: Class<T>,
+ val view: ViewGroup
+) : ReadOnlyProperty<ViewGroup, T> {
+ private var binding: T? = null
+
+ override fun getValue(thisRef: ViewGroup, property: KProperty<*>): T {
+ binding?.let { return it }
+
+ @Suppress("UNCHECKED_CAST")
+ binding = try {
+ val inflateMethod = bindingClass.getMethod("inflate", LayoutInflater::class.java, ViewGroup::class.java)
+ inflateMethod.invoke(null, LayoutInflater.from(thisRef.context), thisRef)
+ } catch (e: NoSuchMethodException) {
+ val inflateMethod = bindingClass.getMethod("inflate", LayoutInflater::class.java, ViewGroup::class.java, Boolean::class.java)
+ inflateMethod.invoke(null, LayoutInflater.from(thisRef.context), thisRef, true) as T
+ } as T
+ return binding!!
+ }
+}
\ No newline at end of file
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/AnimationItemView.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/AnimationItemView.kt
index e94c588..c372e09 100644
--- a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/AnimationItemView.kt
+++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/AnimationItemView.kt
@@ -8,9 +8,9 @@
import com.airbnb.epoxy.ModelView
import com.airbnb.epoxy.TextProp
import com.airbnb.lottie.samples.R
-import com.airbnb.lottie.samples.inflate
-import com.airbnb.lottie.samples.setImageUrl
-import kotlinx.android.synthetic.main.item_view_showcase_animation.view.*
+import com.airbnb.lottie.samples.databinding.ItemViewShowcaseAnimationBinding
+import com.airbnb.lottie.samples.utils.setImageUrl
+import com.airbnb.lottie.samples.utils.viewBinding
@ModelView(autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT)
class AnimationItemView @JvmOverloads constructor(
@@ -18,33 +18,30 @@
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : FrameLayout(context, attrs, defStyleAttr) {
-
- init {
- inflate(R.layout.item_view_showcase_animation)
- }
+ private val binding: ItemViewShowcaseAnimationBinding by viewBinding()
@ModelProp
fun setPreviewUrl(url: String?) {
- imageView.setImageUrl(url)
+ binding.imageView.setImageUrl(url)
}
@TextProp
fun setTitle(title: CharSequence?) {
- titleView.text = title
+ binding.titleView.text = title
}
@ModelProp
fun setPreviewBackgroundColor(@ColorInt bgColor: Int?) {
if (bgColor == null) {
- imageView.setBackgroundResource(R.color.loading_placeholder)
- imageView.setImageDrawable(null)
+ binding.imageView.setBackgroundResource(R.color.loading_placeholder)
+ binding.imageView.setImageDrawable(null)
} else {
- imageView.setBackgroundColor(bgColor)
+ binding.imageView.setBackgroundColor(bgColor)
}
}
@ModelProp(options = [ModelProp.Option.DoNotHash])
override fun setOnClickListener(l: OnClickListener?) {
- container.setOnClickListener(l)
+ binding.container.setOnClickListener(l)
}
}
\ No newline at end of file
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/BottomSheetItemView.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/BottomSheetItemView.kt
index 6dc4352..4986ea1 100644
--- a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/BottomSheetItemView.kt
+++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/BottomSheetItemView.kt
@@ -8,9 +8,8 @@
import androidx.core.view.isVisible
import com.airbnb.epoxy.ModelProp
import com.airbnb.epoxy.ModelView
-import com.airbnb.lottie.samples.R
-import com.airbnb.lottie.samples.inflate
-import kotlinx.android.synthetic.main.item_view_bottom_sheet.view.*
+import com.airbnb.lottie.samples.databinding.ItemViewBottomSheetBinding
+import com.airbnb.lottie.samples.utils.viewBinding
@ModelView(autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT)
class BottomSheetItemView @JvmOverloads constructor(
@@ -18,16 +17,13 @@
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : FrameLayout(context, attrs, defStyleAttr) {
-
- init {
- inflate(R.layout.item_view_bottom_sheet)
- }
+ private val binding: ItemViewBottomSheetBinding by viewBinding()
@SuppressLint("SetTextI18n")
fun set(left: String, right: String? = null) {
- leftTextView.text = left
- rightTextView.isVisible = !TextUtils.isEmpty(right)
- rightTextView.text = right
+ binding.leftTextView.text = left
+ binding.rightTextView.isVisible = !TextUtils.isEmpty(right)
+ binding.rightTextView.text = right
}
@ModelProp
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/ControlBarItemToggleView.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/ControlBarItemToggleView.kt
index 60a1941..0b2d990 100644
--- a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/ControlBarItemToggleView.kt
+++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/ControlBarItemToggleView.kt
@@ -2,27 +2,28 @@
import android.content.Context
import android.graphics.Color
-import androidx.annotation.DrawableRes
-import androidx.core.content.ContextCompat
-import androidx.core.graphics.drawable.DrawableCompat
import android.util.AttributeSet
import android.view.View
import android.widget.ImageView
import android.widget.LinearLayout
+import androidx.annotation.DrawableRes
+import androidx.core.content.ContextCompat
+import androidx.core.graphics.drawable.DrawableCompat
import androidx.core.view.isVisible
import androidx.core.view.setPadding
import com.airbnb.lottie.samples.R
-import com.airbnb.lottie.samples.getText
-import kotlinx.android.synthetic.main.item_view_control_bar.view.*
+import com.airbnb.lottie.samples.databinding.ItemViewControlBarBinding
+import com.airbnb.lottie.samples.utils.getText
+import com.airbnb.lottie.samples.utils.viewBinding
class ControlBarItemToggleView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : LinearLayout(context, attrs, defStyleAttr) {
+ private val binding: ItemViewControlBarBinding by viewBinding()
init {
- inflate(context, R.layout.item_view_control_bar, this)
orientation = HORIZONTAL
setBackgroundResource(R.drawable.control_bar_item_view_background)
setPadding(resources.getDimensionPixelSize(R.dimen.control_bar_button_padding))
@@ -31,14 +32,14 @@
val textRes = typedArray.getResourceId(R.styleable.ControlBarItemToggleView_text, 0)
if (textRes != 0) {
- textView.text = getText(textRes)
+ binding.textView.text = getText(textRes)
}
val drawableRes = typedArray.getResourceId(R.styleable.ControlBarItemToggleView_src, 0)
if (drawableRes == 0) {
- imageView.isVisible = false
+ binding.imageView.isVisible = false
} else {
- imageView.setImageResource(drawableRes)
+ binding.imageView.setImageResource(drawableRes)
}
typedArray.recycle()
@@ -55,14 +56,14 @@
}
}
- fun getText() = textView.text.toString()
+ fun getText() = binding.textView.text.toString()
fun setText(text: String) {
- textView.text = text
+ binding.textView.text = text
}
fun setImageResource(@DrawableRes drawableRes: Int) {
- imageView.setImageResource(drawableRes)
- childDrawableStateChanged(imageView)
+ binding.imageView.setImageResource(drawableRes)
+ childDrawableStateChanged(binding.imageView)
}
}
\ No newline at end of file
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/FilmStripView.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/FilmStripView.kt
index bfd045b..99bb21a 100644
--- a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/FilmStripView.kt
+++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/FilmStripView.kt
@@ -2,28 +2,24 @@
import android.content.Context
import android.util.AttributeSet
-import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.core.view.children
import com.airbnb.lottie.FontAssetDelegate
import com.airbnb.lottie.ImageAssetDelegate
import com.airbnb.lottie.LottieAnimationView
import com.airbnb.lottie.LottieComposition
-import com.airbnb.lottie.samples.R
-import com.airbnb.lottie.samples.inflate
+import com.airbnb.lottie.samples.databinding.FilmStripViewBinding
+import com.airbnb.lottie.samples.utils.viewBinding
class FilmStripView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : FrameLayout(context, attrs, defStyleAttr) {
+ private val binding: FilmStripViewBinding by viewBinding()
private val animationViews by lazy {
- findViewById<ViewGroup>(R.id.grid_layout).children.filterIsInstance(LottieAnimationView::class.java)
- }
-
- init {
- inflate(R.layout.film_strip_view)
+ binding.gridLayout.children.filterIsInstance(LottieAnimationView::class.java)
}
fun setComposition(composition: LottieComposition) {
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/ListingCard.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/ListingCard.kt
index 8191327..01fc7a8 100644
--- a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/ListingCard.kt
+++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/ListingCard.kt
@@ -2,25 +2,44 @@
import android.content.Context
import android.util.AttributeSet
-import android.view.View
import android.widget.FrameLayout
import com.airbnb.epoxy.CallbackProp
import com.airbnb.epoxy.ModelProp
import com.airbnb.epoxy.ModelView
-import com.airbnb.lottie.samples.R
-import kotlinx.android.synthetic.main.listing_card.view.*
+import com.airbnb.epoxy.OnViewRecycled
+import com.airbnb.lottie.samples.databinding.ListingCardBinding
+import com.airbnb.lottie.samples.utils.viewBinding
@ModelView(autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT)
class ListingCard @JvmOverloads constructor(
- context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
+ context: Context,
+ attrs: AttributeSet? = null,
+ defStyleAttr: Int = 0
) : FrameLayout(context, attrs, defStyleAttr) {
-
- init {
- inflate(context, R.layout.listing_card, this)
- }
+ private val binding: ListingCardBinding by viewBinding()
@CallbackProp
- fun setClickListener(listener: View.OnClickListener?) {
- wishListIcon.setOnClickListener(listener)
+ fun onToggled(listener: ((isWishListed: Boolean) -> Unit)?) {
+ binding.wishListIcon.setOnClickListener(when (listener) {
+ null -> null
+ else -> { _ ->
+ listener(binding.wishListIcon.progress == 0f)
+ }
+ })
+ }
+
+ @ModelProp
+ fun isWishListed(isWishListed: Boolean) {
+ val targetProgress = if (isWishListed) 1f else 0f
+ binding.wishListIcon.speed = if (isWishListed) 1f else -1f
+ if (binding.wishListIcon.progress != targetProgress) {
+ binding.wishListIcon.playAnimation()
+ }
+ }
+
+ @OnViewRecycled
+ fun onRecycled() {
+ binding.wishListIcon.pauseAnimation()
+ binding.wishListIcon.progress = 0f
}
}
\ No newline at end of file
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/LoadingView.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/LoadingView.kt
index 0d4fd97..37ee501 100644
--- a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/LoadingView.kt
+++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/LoadingView.kt
@@ -5,7 +5,7 @@
import android.widget.FrameLayout
import com.airbnb.epoxy.ModelView
import com.airbnb.lottie.samples.R
-import com.airbnb.lottie.samples.inflate
+import com.airbnb.lottie.samples.utils.inflate
@ModelView(autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT)
class LoadingView @JvmOverloads constructor(
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/LottiefilesTabBar.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/LottiefilesTabBar.kt
index 35b0eff..f2ab393 100644
--- a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/LottiefilesTabBar.kt
+++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/LottiefilesTabBar.kt
@@ -7,9 +7,8 @@
import com.airbnb.epoxy.ModelProp
import com.airbnb.epoxy.ModelView
import com.airbnb.lottie.samples.LottiefilesMode
-import com.airbnb.lottie.samples.R
-import com.airbnb.lottie.samples.inflate
-import kotlinx.android.synthetic.main.lottiefiles_tab_bar.view.*
+import com.airbnb.lottie.samples.databinding.LottiefilesTabBarBinding
+import com.airbnb.lottie.samples.utils.viewBinding
@ModelView(autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT)
class LottiefilesTabBar @JvmOverloads constructor(
@@ -17,30 +16,27 @@
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : LinearLayout(context, attrs, defStyleAttr) {
-
- init {
- inflate(R.layout.lottiefiles_tab_bar)
- }
+ private val binding: LottiefilesTabBarBinding by viewBinding()
@ModelProp
fun setMode(mode: LottiefilesMode) {
- popularView.isActivated = mode == LottiefilesMode.Popular
- recentView.isActivated = mode == LottiefilesMode.Recent
- searchView.isActivated = mode == LottiefilesMode.Search
+ binding.popularView.isActivated = mode == LottiefilesMode.Popular
+ binding.recentView.isActivated = mode == LottiefilesMode.Recent
+ binding.searchView.isActivated = mode == LottiefilesMode.Search
}
@ModelProp(options = [ModelProp.Option.DoNotHash])
fun setPopularClickListener(listener: View.OnClickListener) {
- popularView.setOnClickListener(listener)
+ binding.popularView.setOnClickListener(listener)
}
@ModelProp(options = [ModelProp.Option.DoNotHash])
- fun setRecentClickListener(listener: View.OnClickListener) {
- recentView.setOnClickListener(listener)
+ fun setRecentClickListener(listener: OnClickListener) {
+ binding.recentView.setOnClickListener(listener)
}
@ModelProp(options = [ModelProp.Option.DoNotHash])
- fun setSearchClickListener(listener: View.OnClickListener) {
- searchView.setOnClickListener(listener)
+ fun setSearchClickListener(listener: OnClickListener) {
+ binding.searchView.setOnClickListener(listener)
}
}
\ No newline at end of file
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/Marquee.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/Marquee.kt
index f7a4908..350c504 100644
--- a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/Marquee.kt
+++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/Marquee.kt
@@ -6,10 +6,10 @@
import com.airbnb.epoxy.ModelView
import com.airbnb.epoxy.TextProp
import com.airbnb.lottie.samples.R
-import com.airbnb.lottie.samples.getText
-import com.airbnb.lottie.samples.inflate
-import com.airbnb.lottie.samples.setVisibleIf
-import kotlinx.android.synthetic.main.marquee.view.*
+import com.airbnb.lottie.samples.databinding.MarqueeBinding
+import com.airbnb.lottie.samples.utils.getText
+import com.airbnb.lottie.samples.utils.setVisibleIf
+import com.airbnb.lottie.samples.utils.viewBinding
@ModelView(autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT)
class Marquee @JvmOverloads constructor(
@@ -17,9 +17,9 @@
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : LinearLayout(context, attrs, defStyleAttr) {
+ private val binding: MarqueeBinding by viewBinding()
init {
- inflate(R.layout.marquee)
orientation = VERTICAL
attrs?.let {
val typedArray = context.obtainStyledAttributes(it, R.styleable.Marquee, 0, 0)
@@ -40,12 +40,12 @@
@TextProp
fun setTitle(title: CharSequence) {
- titleView.text = title
+ binding.titleView.text = title
}
@TextProp
fun setSubtitle(subtitle: CharSequence?) {
- subtitleView.text = subtitle
- subtitleView.setVisibleIf(!subtitle.isNullOrEmpty())
+ binding.subtitleView.text = subtitle
+ binding.subtitleView.setVisibleIf(!subtitle.isNullOrEmpty())
}
}
\ No newline at end of file
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/SearchInputItemView.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/SearchInputItemView.kt
index 0037c64..d384a60 100644
--- a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/SearchInputItemView.kt
+++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/SearchInputItemView.kt
@@ -2,44 +2,26 @@
import android.content.Context
import android.util.AttributeSet
-import android.view.KeyEvent
-import android.view.inputmethod.EditorInfo
-import android.view.inputmethod.InputMethodManager
import android.widget.FrameLayout
-import androidx.core.content.getSystemService
-import com.airbnb.epoxy.ModelProp
-import com.airbnb.epoxy.ModelView
-import com.airbnb.lottie.samples.R
-import com.airbnb.lottie.samples.inflate
-import kotlinx.android.synthetic.main.item_view_search_input.view.*
+import androidx.core.widget.doAfterTextChanged
+import com.airbnb.lottie.samples.databinding.ItemViewSearchInputBinding
+import com.airbnb.lottie.samples.utils.viewBinding
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
-@ModelView(autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT)
class SearchInputItemView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : FrameLayout(context, attrs, defStyleAttr) {
+ private val binding: ItemViewSearchInputBinding by viewBinding()
+
+ private val _query = MutableStateFlow("")
+ val query: StateFlow<String> = _query
init {
- inflate(R.layout.item_view_search_input)
- searchEditText.setOnEditorActionListener { _, actionId, event ->
- if (actionId == EditorInfo.IME_ACTION_SEARCH && event?.action == KeyEvent.ACTION_DOWN) {
- searchButton.callOnClick()
- return@setOnEditorActionListener true
- } else if (event?.keyCode == KeyEvent.KEYCODE_ENTER && event.action == KeyEvent.ACTION_DOWN) {
- searchButton.callOnClick()
- return@setOnEditorActionListener true
- }
- return@setOnEditorActionListener false
- }
- }
-
- @ModelProp(options = [ModelProp.Option.DoNotHash])
- fun setSearchClickListener(listener: (String) -> Unit) {
- searchButton.setOnClickListener {
- val inputMethodManager = context.getSystemService<InputMethodManager>()!!
- inputMethodManager.hideSoftInputFromWindow(windowToken, 0)
- listener(searchEditText.text.toString())
+ binding.searchEditText.doAfterTextChanged { text ->
+ _query.value = text?.toString() ?: ""
}
}
}
\ No newline at end of file
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/SectionHeaderView.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/SectionHeaderView.kt
index 47a4806..a9dc8fe 100644
--- a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/SectionHeaderView.kt
+++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/SectionHeaderView.kt
@@ -2,14 +2,12 @@
import android.content.Context
import android.util.AttributeSet
-import android.view.View
import android.widget.FrameLayout
import com.airbnb.epoxy.ModelProp
import com.airbnb.epoxy.ModelView
import com.airbnb.epoxy.TextProp
-import com.airbnb.lottie.samples.R
-import com.airbnb.lottie.samples.inflate
-import kotlinx.android.synthetic.main.marquee.view.*
+import com.airbnb.lottie.samples.databinding.SectionHeaderViewBinding
+import com.airbnb.lottie.samples.utils.viewBinding
@ModelView(autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT)
class SectionHeaderView @JvmOverloads constructor(
@@ -17,14 +15,11 @@
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : FrameLayout(context, attrs, defStyleAttr) {
-
- init {
- inflate(R.layout.section_header_view)
- }
+ private val binding: SectionHeaderViewBinding by viewBinding()
@TextProp
fun setTitle(title: CharSequence) {
- titleView.text = title
+ binding.titleView.text = title
}
@ModelProp(options = [ModelProp.Option.DoNotHash])
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/ShowcaseDemoItemView.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/ShowcaseDemoItemView.kt
index 1b27347..7f2b743 100644
--- a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/ShowcaseDemoItemView.kt
+++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/ShowcaseDemoItemView.kt
@@ -5,10 +5,9 @@
import android.widget.FrameLayout
import com.airbnb.epoxy.ModelProp
import com.airbnb.epoxy.ModelView
-import com.airbnb.lottie.samples.R
-import com.airbnb.lottie.samples.inflate
+import com.airbnb.lottie.samples.databinding.ItemViewShowcaseDemoBinding
import com.airbnb.lottie.samples.model.ShowcaseItem
-import kotlinx.android.synthetic.main.item_view_showcase_demo.view.*
+import com.airbnb.lottie.samples.utils.viewBinding
@ModelView(autoLayout = ModelView.Size.WRAP_WIDTH_WRAP_HEIGHT)
class ShowcaseDemoItemView @JvmOverloads constructor(
@@ -16,17 +15,14 @@
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : FrameLayout(context, attrs, defStyleAttr) {
-
- init {
- inflate(R.layout.item_view_showcase_demo)
- }
+ private val binding: ItemViewShowcaseDemoBinding by viewBinding()
@ModelProp
fun setShowcaseItem(item: ShowcaseItem) {
- imageView.setImageResource(item.drawableRes)
+ binding.imageView.setImageResource(item.drawableRes)
- titleView.text = resources.getText(item.titleRes)
+ binding.titleView.text = resources.getText(item.titleRes)
- cardView.setOnClickListener({ item.clickListener() })
+ binding.cardView.setOnClickListener { item.clickListener() }
}
}
\ No newline at end of file
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/TabBarItemView.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/TabBarItemView.kt
index a8b85c7..9151da6 100644
--- a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/TabBarItemView.kt
+++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/TabBarItemView.kt
@@ -3,30 +3,25 @@
import android.content.Context
import android.util.AttributeSet
import android.widget.LinearLayout
+import androidx.core.content.withStyledAttributes
import com.airbnb.lottie.samples.R
-import com.airbnb.lottie.samples.getText
-import com.airbnb.lottie.samples.inflate
-import kotlinx.android.synthetic.main.tab_item.view.*
+import com.airbnb.lottie.samples.databinding.TabItemBinding
+import com.airbnb.lottie.samples.utils.viewBinding
class TabBarItemView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : LinearLayout(context, attrs, defStyleAttr) {
+ private val binding: TabItemBinding by viewBinding()
init {
- inflate(R.layout.tab_item)
orientation = VERTICAL
- attrs?.let {
- val ta = context.obtainStyledAttributes(it, R.styleable.TabBarItemView, 0, 0)
-
- val titleRes = ta.getResourceId(R.styleable.TabBarItemView_titleText, 0)
- if (titleRes != 0) {
- titleView.text = getText(titleRes)
+ context.withStyledAttributes(attrs, R.styleable.TabBarItemView) {
+ if (hasValue(R.styleable.TabBarItemView_titleText)) {
+ binding.titleView.text = getText(R.styleable.TabBarItemView_titleText)
}
-
- ta.recycle()
}
}
}
\ No newline at end of file
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/WishListIconView.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/WishListIconView.kt
index a741cd9..1a78533 100644
--- a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/WishListIconView.kt
+++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/WishListIconView.kt
@@ -2,10 +2,7 @@
import android.content.Context
import android.util.AttributeSet
-import com.airbnb.epoxy.ModelProp
-import com.airbnb.epoxy.ModelView
import com.airbnb.lottie.LottieAnimationView
-import kotlinx.android.synthetic.main.listing_card.view.*
class WishListIconView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
diff --git a/LottieSample/src/main/res/layout/activity_test_color_filter.xml b/LottieSample/src/main/res/layout/activity_test_color_filter.xml
deleted file mode 100644
index b0e7efe..0000000
--- a/LottieSample/src/main/res/layout/activity_test_color_filter.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
-
- <com.airbnb.lottie.LottieAnimationView
- android:id="@+id/yellow_color_filter"
- android:layout_width="50dp"
- android:layout_height="50dp"
- android:background="#ffffff"
- app:lottie_colorFilter="#ffff00"
- app:lottie_rawRes="@raw/hamburger_arrow"/>
-
-
- <com.airbnb.lottie.LottieAnimationView
- android:id="@+id/null_color_filter"
- android:layout_width="50dp"
- android:layout_height="50dp"
- android:background="#ffffff"
- app:lottie_colorFilter="@null"
- app:lottie_fileName="HamburgerArrow.json"/>
-
-</LinearLayout>
\ No newline at end of file
diff --git a/LottieSample/src/main/res/layout/fragment_base.xml b/LottieSample/src/main/res/layout/base_fragment.xml
similarity index 100%
rename from LottieSample/src/main/res/layout/fragment_base.xml
rename to LottieSample/src/main/res/layout/base_fragment.xml
diff --git a/LottieSample/src/main/res/layout/activity_bullseye.xml b/LottieSample/src/main/res/layout/bullseye_activity.xml
similarity index 100%
rename from LottieSample/src/main/res/layout/activity_bullseye.xml
rename to LottieSample/src/main/res/layout/bullseye_activity.xml
diff --git a/LottieSample/src/main/res/layout/fragment_choose_asset.xml b/LottieSample/src/main/res/layout/choose_asset_fragment.xml
similarity index 100%
rename from LottieSample/src/main/res/layout/fragment_choose_asset.xml
rename to LottieSample/src/main/res/layout/choose_asset_fragment.xml
diff --git a/LottieSample/src/main/res/layout/activity_dynamic.xml b/LottieSample/src/main/res/layout/dynamic_activity.xml
similarity index 100%
rename from LottieSample/src/main/res/layout/activity_dynamic.xml
rename to LottieSample/src/main/res/layout/dynamic_activity.xml
diff --git a/LottieSample/src/main/res/layout/activity_dynamic_text.xml b/LottieSample/src/main/res/layout/dynamic_text_activity.xml
similarity index 100%
rename from LottieSample/src/main/res/layout/activity_dynamic_text.xml
rename to LottieSample/src/main/res/layout/dynamic_text_activity.xml
diff --git a/LottieSample/src/main/res/layout/activity_empty.xml b/LottieSample/src/main/res/layout/empty_activity.xml
similarity index 100%
rename from LottieSample/src/main/res/layout/activity_empty.xml
rename to LottieSample/src/main/res/layout/empty_activity.xml
diff --git a/LottieSample/src/main/res/layout/fragment_empty.xml b/LottieSample/src/main/res/layout/empty_fragment.xml
similarity index 100%
rename from LottieSample/src/main/res/layout/fragment_empty.xml
rename to LottieSample/src/main/res/layout/empty_fragment.xml
diff --git a/LottieSample/src/main/res/layout/fragment_epoxy_recycler_view.xml b/LottieSample/src/main/res/layout/epoxy_recycler_view_fragment.xml
similarity index 100%
rename from LottieSample/src/main/res/layout/fragment_epoxy_recycler_view.xml
rename to LottieSample/src/main/res/layout/epoxy_recycler_view_fragment.xml
diff --git a/LottieSample/src/main/res/layout/activity_film_strip_snapshots.xml b/LottieSample/src/main/res/layout/film_strip_snapshots_activity.xml
similarity index 100%
rename from LottieSample/src/main/res/layout/activity_film_strip_snapshots.xml
rename to LottieSample/src/main/res/layout/film_strip_snapshots_activity.xml
diff --git a/LottieSample/src/main/res/layout/film_strip_view.xml b/LottieSample/src/main/res/layout/film_strip_view.xml
index ddc889a..a019ab2 100644
--- a/LottieSample/src/main/res/layout/film_strip_view.xml
+++ b/LottieSample/src/main/res/layout/film_strip_view.xml
@@ -6,127 +6,127 @@
android:layout_gravity="center"
android:columnCount="5">
- <com.airbnb.lottie.samples.NoCacheLottieAnimationView
+ <com.airbnb.lottie.samples.testing.NoCacheLottieAnimationView
android:id="@+id/animation_1"
android:layout_width="@dimen/film_strip_size"
android:layout_height="@dimen/film_strip_size" />
- <com.airbnb.lottie.samples.NoCacheLottieAnimationView
+ <com.airbnb.lottie.samples.testing.NoCacheLottieAnimationView
android:id="@+id/animation_2"
android:layout_width="@dimen/film_strip_size"
android:layout_height="@dimen/film_strip_size" />
- <com.airbnb.lottie.samples.NoCacheLottieAnimationView
+ <com.airbnb.lottie.samples.testing.NoCacheLottieAnimationView
android:id="@+id/animation_3"
android:layout_width="@dimen/film_strip_size"
android:layout_height="@dimen/film_strip_size" />
- <com.airbnb.lottie.samples.NoCacheLottieAnimationView
+ <com.airbnb.lottie.samples.testing.NoCacheLottieAnimationView
android:id="@+id/animation_4"
android:layout_width="@dimen/film_strip_size"
android:layout_height="@dimen/film_strip_size" />
- <com.airbnb.lottie.samples.NoCacheLottieAnimationView
+ <com.airbnb.lottie.samples.testing.NoCacheLottieAnimationView
android:id="@+id/animation_5"
android:layout_width="@dimen/film_strip_size"
android:layout_height="@dimen/film_strip_size" />
- <com.airbnb.lottie.samples.NoCacheLottieAnimationView
+ <com.airbnb.lottie.samples.testing.NoCacheLottieAnimationView
android:id="@+id/animation_6"
android:layout_width="@dimen/film_strip_size"
android:layout_height="@dimen/film_strip_size" />
- <com.airbnb.lottie.samples.NoCacheLottieAnimationView
+ <com.airbnb.lottie.samples.testing.NoCacheLottieAnimationView
android:id="@+id/animation_7"
android:layout_width="@dimen/film_strip_size"
android:layout_height="@dimen/film_strip_size" />
- <com.airbnb.lottie.samples.NoCacheLottieAnimationView
+ <com.airbnb.lottie.samples.testing.NoCacheLottieAnimationView
android:id="@+id/animation_8"
android:layout_width="@dimen/film_strip_size"
android:layout_height="@dimen/film_strip_size" />
- <com.airbnb.lottie.samples.NoCacheLottieAnimationView
+ <com.airbnb.lottie.samples.testing.NoCacheLottieAnimationView
android:id="@+id/animation_9"
android:layout_width="@dimen/film_strip_size"
android:layout_height="@dimen/film_strip_size" />
- <com.airbnb.lottie.samples.NoCacheLottieAnimationView
+ <com.airbnb.lottie.samples.testing.NoCacheLottieAnimationView
android:id="@+id/animation_10"
android:layout_width="@dimen/film_strip_size"
android:layout_height="@dimen/film_strip_size" />
- <com.airbnb.lottie.samples.NoCacheLottieAnimationView
+ <com.airbnb.lottie.samples.testing.NoCacheLottieAnimationView
android:id="@+id/animation_11"
android:layout_width="@dimen/film_strip_size"
android:layout_height="@dimen/film_strip_size" />
- <com.airbnb.lottie.samples.NoCacheLottieAnimationView
+ <com.airbnb.lottie.samples.testing.NoCacheLottieAnimationView
android:id="@+id/animation_12"
android:layout_width="@dimen/film_strip_size"
android:layout_height="@dimen/film_strip_size" />
- <com.airbnb.lottie.samples.NoCacheLottieAnimationView
+ <com.airbnb.lottie.samples.testing.NoCacheLottieAnimationView
android:id="@+id/animation_13"
android:layout_width="@dimen/film_strip_size"
android:layout_height="@dimen/film_strip_size" />
- <com.airbnb.lottie.samples.NoCacheLottieAnimationView
+ <com.airbnb.lottie.samples.testing.NoCacheLottieAnimationView
android:id="@+id/animation_14"
android:layout_width="@dimen/film_strip_size"
android:layout_height="@dimen/film_strip_size" />
- <com.airbnb.lottie.samples.NoCacheLottieAnimationView
+ <com.airbnb.lottie.samples.testing.NoCacheLottieAnimationView
android:id="@+id/animation_15"
android:layout_width="@dimen/film_strip_size"
android:layout_height="@dimen/film_strip_size" />
- <com.airbnb.lottie.samples.NoCacheLottieAnimationView
+ <com.airbnb.lottie.samples.testing.NoCacheLottieAnimationView
android:id="@+id/animation_16"
android:layout_width="@dimen/film_strip_size"
android:layout_height="@dimen/film_strip_size" />
- <com.airbnb.lottie.samples.NoCacheLottieAnimationView
+ <com.airbnb.lottie.samples.testing.NoCacheLottieAnimationView
android:id="@+id/animation_17"
android:layout_width="@dimen/film_strip_size"
android:layout_height="@dimen/film_strip_size" />
- <com.airbnb.lottie.samples.NoCacheLottieAnimationView
+ <com.airbnb.lottie.samples.testing.NoCacheLottieAnimationView
android:id="@+id/animation_18"
android:layout_width="@dimen/film_strip_size"
android:layout_height="@dimen/film_strip_size" />
- <com.airbnb.lottie.samples.NoCacheLottieAnimationView
+ <com.airbnb.lottie.samples.testing.NoCacheLottieAnimationView
android:id="@+id/animation_19"
android:layout_width="@dimen/film_strip_size"
android:layout_height="@dimen/film_strip_size" />
- <com.airbnb.lottie.samples.NoCacheLottieAnimationView
+ <com.airbnb.lottie.samples.testing.NoCacheLottieAnimationView
android:id="@+id/animation_20"
android:layout_width="@dimen/film_strip_size"
android:layout_height="@dimen/film_strip_size" />
- <com.airbnb.lottie.samples.NoCacheLottieAnimationView
+ <com.airbnb.lottie.samples.testing.NoCacheLottieAnimationView
android:id="@+id/animation_21"
android:layout_width="@dimen/film_strip_size"
android:layout_height="@dimen/film_strip_size" />
- <com.airbnb.lottie.samples.NoCacheLottieAnimationView
+ <com.airbnb.lottie.samples.testing.NoCacheLottieAnimationView
android:id="@+id/animation_22"
android:layout_width="@dimen/film_strip_size"
android:layout_height="@dimen/film_strip_size" />
- <com.airbnb.lottie.samples.NoCacheLottieAnimationView
+ <com.airbnb.lottie.samples.testing.NoCacheLottieAnimationView
android:id="@+id/animation_23"
android:layout_width="@dimen/film_strip_size"
android:layout_height="@dimen/film_strip_size" />
- <com.airbnb.lottie.samples.NoCacheLottieAnimationView
+ <com.airbnb.lottie.samples.testing.NoCacheLottieAnimationView
android:id="@+id/animation_24"
android:layout_width="@dimen/film_strip_size"
android:layout_height="@dimen/film_strip_size" />
- <com.airbnb.lottie.samples.NoCacheLottieAnimationView
+ <com.airbnb.lottie.samples.testing.NoCacheLottieAnimationView
android:id="@+id/animation_25"
android:layout_width="@dimen/film_strip_size"
android:layout_height="@dimen/film_strip_size" />
diff --git a/LottieSample/src/main/res/layout/fragment_font.xml b/LottieSample/src/main/res/layout/font_fragment.xml
similarity index 100%
rename from LottieSample/src/main/res/layout/fragment_font.xml
rename to LottieSample/src/main/res/layout/font_fragment.xml
diff --git a/LottieSample/src/main/res/layout/fragment_full_screen.xml b/LottieSample/src/main/res/layout/fragment_full_screen.xml
deleted file mode 100644
index 12e3234..0000000
--- a/LottieSample/src/main/res/layout/fragment_full_screen.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<com.airbnb.lottie.LottieAnimationView xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:scaleType="centerCrop"
- app:lottie_rawRes="@raw/full_screen"
- app:lottie_loop="true"
- app:lottie_autoPlay="true" />
\ No newline at end of file
diff --git a/LottieSample/src/main/res/layout/fragment_player.xml b/LottieSample/src/main/res/layout/fragment_player.xml
deleted file mode 100644
index 468fe4e..0000000
--- a/LottieSample/src/main/res/layout/fragment_player.xml
+++ /dev/null
@@ -1,60 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<androidx.coordinatorlayout.widget.CoordinatorLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:id="@+id/coordinatorLayout"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@android:color/white">
- <LinearLayout
- android:id="@+id/container"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
- <FrameLayout
- android:id="@+id/animationContainer"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1">
-
- <com.airbnb.lottie.LottieAnimationView
- android:id="@+id/animationView"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:background="@drawable/outline"
- app:lottie_autoPlay="true"/>
-
- <ProgressBar
- android:id="@+id/loadingView"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"/>
-
- <View
- android:layout_width="match_parent"
- android:layout_height="@dimen/divider_height"
- android:layout_gravity="bottom"
- android:background="@color/divider"/>
- </FrameLayout>
-
- <include layout="@layout/control_bar_speed" />
- <include layout="@layout/control_bar_scale" />
- <include layout="@layout/control_bar_background_color" />
- <include layout="@layout/control_bar_trim" />
- <include layout="@layout/control_bar_player_controls" />
- <include layout="@layout/control_bar" />
- </LinearLayout>
-
- <androidx.appcompat.widget.Toolbar
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:layout_gravity="top"
- app:navigationIcon="@drawable/ic_nav_close_selector"
- app:title=""/>
-
- <include layout="@layout/bottom_sheet_render_times" />
- <include layout="@layout/bottom_sheet_warnings" />
- <include layout="@layout/bottom_sheet_key_paths" />
-</androidx.coordinatorlayout.widget.CoordinatorLayout>
\ No newline at end of file
diff --git a/LottieSample/src/main/res/layout/fragment_todo.xml b/LottieSample/src/main/res/layout/fragment_todo.xml
deleted file mode 100644
index e3c78e8..0000000
--- a/LottieSample/src/main/res/layout/fragment_todo.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<FrameLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:text="TODO" />
-
-</FrameLayout>
\ No newline at end of file
diff --git a/LottieSample/src/main/res/layout/item_view_search_input.xml b/LottieSample/src/main/res/layout/item_view_search_input.xml
index e731a42..b9c5e87 100644
--- a/LottieSample/src/main/res/layout/item_view_search_input.xml
+++ b/LottieSample/src/main/res/layout/item_view_search_input.xml
@@ -1,34 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:parentTag="android.widget.FrameLayout">
- <LinearLayout
+ <EditText
+ android:id="@+id/searchEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
- android:orientation="horizontal">
-
- <EditText
- android:id="@+id/searchEditText"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:backgroundTint="@color/divider"
- android:hint="@string/search"
- android:inputType="text"
- android:imeOptions="actionSearch"
- android:textColorHint="@color/text_color_placeholder"/>
-
- <ImageButton
- android:id="@+id/searchButton"
- android:layout_width="24dp"
- android:layout_height="24dp"
- android:layout_gravity="center_vertical"
- android:background="?attr/selectableItemBackgroundBorderless"
- app:srcCompat="@drawable/ic_search"/>
- </LinearLayout>
-
+ android:layout_weight="1"
+ android:backgroundTint="@color/divider"
+ android:hint="@string/search"
+ android:imeOptions="actionSearch"
+ android:inputType="text"
+ android:textColorHint="@color/text_color_placeholder" />
</merge>
\ No newline at end of file
diff --git a/LottieSample/src/main/res/layout/activity_list.xml b/LottieSample/src/main/res/layout/list_activity.xml
similarity index 65%
rename from LottieSample/src/main/res/layout/activity_list.xml
rename to LottieSample/src/main/res/layout/list_activity.xml
index 7a3f48d..7293bf8 100644
--- a/LottieSample/src/main/res/layout/activity_list.xml
+++ b/LottieSample/src/main/res/layout/list_activity.xml
@@ -9,10 +9,4 @@
android:layout_width="match_parent"
android:layout_height="match_parent"/>
- <androidx.appcompat.widget.Toolbar
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- app:navigationIcon="@drawable/ic_back_black"/>
-
</FrameLayout>
\ No newline at end of file
diff --git a/LottieSample/src/main/res/layout/lottiefiles_fragment.xml b/LottieSample/src/main/res/layout/lottiefiles_fragment.xml
new file mode 100644
index 0000000..715791c
--- /dev/null
+++ b/LottieSample/src/main/res/layout/lottiefiles_fragment.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <com.airbnb.lottie.samples.views.Marquee
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ app:subtitleText="@string/lottiefiles_airbnb"
+ app:titleText="@string/lottiefiles" />
+
+ <com.airbnb.lottie.samples.views.LottiefilesTabBar
+ android:id="@+id/tab_bar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ <com.airbnb.lottie.samples.views.SearchInputItemView
+ android:id="@+id/search_view"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/recyclerView"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ app:layoutManager="LinearLayoutManager" />
+</LinearLayout>
\ No newline at end of file
diff --git a/LottieSample/src/main/res/layout/activity_main.xml b/LottieSample/src/main/res/layout/main_activity.xml
similarity index 100%
rename from LottieSample/src/main/res/layout/activity_main.xml
rename to LottieSample/src/main/res/layout/main_activity.xml
diff --git a/LottieSample/src/main/res/layout/activity_player.xml b/LottieSample/src/main/res/layout/player_activity.xml
similarity index 100%
rename from LottieSample/src/main/res/layout/activity_player.xml
rename to LottieSample/src/main/res/layout/player_activity.xml
diff --git a/LottieSample/src/main/res/layout/player_fragment.xml b/LottieSample/src/main/res/layout/player_fragment.xml
new file mode 100644
index 0000000..6fb6857
--- /dev/null
+++ b/LottieSample/src/main/res/layout/player_fragment.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/coordinatorLayout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@android:color/white">
+
+ <LinearLayout
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <FrameLayout
+ android:id="@+id/animationContainer"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1">
+
+ <com.airbnb.lottie.LottieAnimationView
+ android:id="@+id/animationView"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:background="@drawable/outline"
+ app:lottie_autoPlay="true" />
+
+ <ProgressBar
+ android:id="@+id/loadingView"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center" />
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/divider_height"
+ android:layout_gravity="bottom"
+ android:background="@color/divider" />
+ </FrameLayout>
+
+ <include
+ android:id="@+id/control_bar_speed"
+ layout="@layout/control_bar_speed" />
+
+ <include
+ android:id="@+id/control_bar_scale"
+ layout="@layout/control_bar_scale" />
+
+ <include
+ android:id="@+id/control_bar_background_color"
+ layout="@layout/control_bar_background_color" />
+
+ <include
+ android:id="@+id/control_bar_trim"
+ layout="@layout/control_bar_trim" />
+
+ <include
+ android:id="@+id/control_bar_player_controls"
+ layout="@layout/control_bar_player_controls" />
+
+ <include
+ android:id="@+id/control_bar"
+ layout="@layout/control_bar" />
+ </LinearLayout>
+
+ <androidx.appcompat.widget.Toolbar
+ android:id="@+id/toolbar"
+ android:layout_width="match_parent"
+ android:layout_height="?attr/actionBarSize"
+ android:layout_gravity="top"
+ app:navigationIcon="@drawable/ic_nav_close_selector"
+ app:title="" />
+
+ <include
+ android:id="@+id/bottom_sheet_render_times"
+ layout="@layout/bottom_sheet_render_times" />
+
+ <include
+ android:id="@+id/bottom_sheet_warnings"
+ layout="@layout/bottom_sheet_warnings" />
+
+ <include
+ android:id="@+id/bottom_sheet_key_paths"
+ layout="@layout/bottom_sheet_key_paths" />
+</androidx.coordinatorlayout.widget.CoordinatorLayout>
\ No newline at end of file
diff --git a/LottieSample/src/main/res/layout/activity_qrscan.xml b/LottieSample/src/main/res/layout/qrscan_activity.xml
similarity index 100%
rename from LottieSample/src/main/res/layout/activity_qrscan.xml
rename to LottieSample/src/main/res/layout/qrscan_activity.xml
diff --git a/LottieSample/src/main/res/layout/activity_simple_animation.xml b/LottieSample/src/main/res/layout/simple_animation_activity.xml
similarity index 100%
rename from LottieSample/src/main/res/layout/activity_simple_animation.xml
rename to LottieSample/src/main/res/layout/simple_animation_activity.xml
diff --git a/LottieSample/src/main/res/layout/activity_snapshot_tests.xml b/LottieSample/src/main/res/layout/snapshot_tests_activity.xml
similarity index 100%
rename from LottieSample/src/main/res/layout/activity_snapshot_tests.xml
rename to LottieSample/src/main/res/layout/snapshot_tests_activity.xml
diff --git a/LottieSample/src/main/res/layout/activity_typography_demo.xml b/LottieSample/src/main/res/layout/typography_demo_activity.xml
similarity index 100%
rename from LottieSample/src/main/res/layout/activity_typography_demo.xml
rename to LottieSample/src/main/res/layout/typography_demo_activity.xml
diff --git a/LottieSample/src/main/res/layout/fragment_warnings.xml b/LottieSample/src/main/res/layout/warnings_fragment.xml
similarity index 100%
rename from LottieSample/src/main/res/layout/fragment_warnings.xml
rename to LottieSample/src/main/res/layout/warnings_fragment.xml
diff --git a/LottieSample/src/main/res/values/attrs.xml b/LottieSample/src/main/res/values/attrs.xml
index 94acd1a..57a674c 100644
--- a/LottieSample/src/main/res/values/attrs.xml
+++ b/LottieSample/src/main/res/values/attrs.xml
@@ -7,7 +7,7 @@
</declare-styleable>
<declare-styleable name="Marquee">
<attr name="titleText" />
- <attr name="subtitleText" />
+ <attr name="subtitleText" format="string"/>
</declare-styleable>
<declare-styleable name="TabBarItemView">
<attr name="titleText" />
diff --git a/build.gradle b/build.gradle
index b9600ba..a29dbd9 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,7 +1,7 @@
import org.ajoberstar.grgit.Grgit
buildscript {
- ext.kotlinVersion = '1.3.61'
+ ext.kotlinVersion = '1.4.0'
repositories {
jcenter()
@@ -12,7 +12,7 @@
}
dependencies {
classpath 'org.ajoberstar:grgit:1.9.3'
- classpath 'com.android.tools.build:gradle:3.5.3'
+ classpath 'com.android.tools.build:gradle:4.1.0-rc02'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlinVersion"
classpath 'org.ajoberstar:grgit:1.9.3'
@@ -37,7 +37,7 @@
}
ext {
- git = Grgit.open()
+ git = Grgit.open(currentDir: project.rootDir)
gitSha = git.head().id
gitBranch = git.branch.getCurrent().name
}
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index feee4a3..4999dc7 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.0.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-all.zip
diff --git a/issue-repro/src/main/java/com/airbnb/lottie/issues/MainActivity.kt b/issue-repro/src/main/java/com/airbnb/lottie/issues/MainActivity.kt
index adc07e2..ba04542 100755
--- a/issue-repro/src/main/java/com/airbnb/lottie/issues/MainActivity.kt
+++ b/issue-repro/src/main/java/com/airbnb/lottie/issues/MainActivity.kt
@@ -1,16 +1,11 @@
package com.airbnb.lottie.issues
-import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
-import androidx.core.app.ActivityOptionsCompat
-import com.airbnb.lottie.issues.R
-import kotlinx.android.synthetic.main.activity_main.*
-class MainActivity : AppCompatActivity() {
+class MainActivity : AppCompatActivity(R.layout.activity_main) {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_main)
// Reproduce any issues here.
}
}