-
Notifications
You must be signed in to change notification settings - Fork 326
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Thumbs-up function 👍 #626
Thumbs-up function 👍 #626
Changes from 34 commits
44b8b10
b49b8b0
4a2de25
286d6bd
bf57b49
da8e92f
075e3b2
a4c3287
6f6b1c0
3cf94b8
0b0483b
0cd8484
707fb7b
f0db2dd
856e3ac
6ebcbfa
e478ca9
ab883b9
3bac614
8e26ef0
59aad5a
67e699a
6f07494
7d102fd
ea1e3d4
8c64427
54940d7
035602c
5f1c524
c88056a
f9d5066
7e54b27
bc6dad4
6d1c674
5889f99
e1cba55
dbe94a2
e556cac
489fb21
69c94e9
521ba2d
eb5daa5
48c71ba
3d4c670
808f2b2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package io.github.droidkaigi.confsched2020.ext | ||
|
||
import android.animation.Animator | ||
import android.animation.AnimatorListenerAdapter | ||
import kotlinx.coroutines.suspendCancellableCoroutine | ||
import kotlin.coroutines.resume | ||
|
||
// This function is copied from https://medium.com/androiddevelopers/suspending-over-views-19de9ebd7020 | ||
|
||
suspend fun Animator.awaitEnd() = suspendCancellableCoroutine<Unit> { cont -> | ||
// Add an invokeOnCancellation listener. If the coroutine is | ||
// cancelled, cancel the animation too that will notify | ||
// listener's onAnimationCancel() function | ||
cont.invokeOnCancellation { cancel() } | ||
|
||
addListener(object : AnimatorListenerAdapter() { | ||
private var endedSuccessfully = true | ||
|
||
override fun onAnimationCancel(animation: Animator) { | ||
// Animator has been cancelled, so flip the success flag | ||
endedSuccessfully = false | ||
} | ||
|
||
override fun onAnimationEnd(animation: Animator) { | ||
// Make sure we remove the listener so we don't keep | ||
// leak the coroutine continuation | ||
animation.removeListener(this) | ||
|
||
if (cont.isActive) { | ||
// If the coroutine is still active... | ||
if (endedSuccessfully) { | ||
// ...and the Animator ended successfully, resume the coroutine | ||
cont.resume(Unit) | ||
} else { | ||
// ...and the Animator was cancelled, cancel the coroutine too | ||
cont.cancel() | ||
} | ||
} | ||
} | ||
}) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package io.github.droidkaigi.confsched2020.ext | ||
|
||
import android.view.View | ||
import kotlinx.coroutines.suspendCancellableCoroutine | ||
import kotlin.coroutines.resume | ||
|
||
// This function is copied from https://medium.com/androiddevelopers/suspending-over-views-19de9ebd7020 | ||
|
||
suspend fun View.awaitNextLayout() = suspendCancellableCoroutine<Unit> { cont -> | ||
// This lambda is invoked immediately, allowing us to create | ||
// a callback/listener | ||
|
||
val listener = object : View.OnLayoutChangeListener { | ||
override fun onLayoutChange( | ||
v: View?, | ||
left: Int, | ||
top: Int, | ||
right: Int, | ||
bottom: Int, | ||
oldLeft: Int, | ||
oldTop: Int, | ||
oldRight: Int, | ||
oldBottom: Int | ||
) { | ||
// The next layout has happened! | ||
// First remove the listener to not leak the coroutine | ||
v?.removeOnLayoutChangeListener(this) | ||
// Finally resume the continuation, and | ||
// wake the coroutine up | ||
cont.resume(Unit) | ||
} | ||
} | ||
// If the coroutine is cancelled, remove the listener | ||
cont.invokeOnCancellation { removeOnLayoutChangeListener(listener) } | ||
// And finally add the listener to view | ||
addOnLayoutChangeListener(listener) | ||
|
||
// The coroutine will now be suspended. It will only be resumed | ||
// when calling cont.resume() in the listener above | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,7 @@ | |
<item name="textAppearanceBody1">@style/TextAppearance.DroidKaigi.Body1</item> | ||
<item name="textAppearanceBody2">@style/TextAppearance.DroidKaigi.Body2</item> | ||
<item name="textAppearanceCaption">@style/TextAppearance.DroidKaigi.Caption</item> | ||
<item name="textAppearanceButton">@style/TextAppearance.DroidKaigi.Button</item> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
|
||
<!-- Widget styles --> | ||
<item name="filterChipStyle">@style/Widget.DroidKaigi.FilterChip</item> | ||
|
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
@@ -0,0 +1,59 @@ | ||||
package io.github.droidkaigi.confsched2020.data.firestore.internal | ||||
|
||||
import kotlinx.coroutines.GlobalScope | ||||
import kotlinx.coroutines.channels.BroadcastChannel | ||||
import kotlinx.coroutines.delay | ||||
import kotlinx.coroutines.flow.asFlow | ||||
import kotlinx.coroutines.flow.collect | ||||
import kotlinx.coroutines.flow.debounce | ||||
import kotlinx.coroutines.flow.map | ||||
import kotlinx.coroutines.flow.withIndex | ||||
import kotlinx.coroutines.launch | ||||
import kotlinx.coroutines.runBlocking | ||||
import org.junit.Ignore | ||||
import org.junit.Test | ||||
|
||||
class FirestoreImplTest { | ||||
@Ignore | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry please remove this 🙇 |
||||
@Test | ||||
fun thumbsUpIncrement() { | ||||
val channel = BroadcastChannel<Unit>(10000) | ||||
GlobalScope.launch { | ||||
delay(100) | ||||
println("send") | ||||
channel.send(Unit) | ||||
println("send") | ||||
channel.send(Unit) | ||||
println("send") | ||||
channel.send(Unit) | ||||
delay(600) | ||||
println("send") | ||||
channel.send(Unit) | ||||
delay(200) | ||||
println("send") | ||||
channel.send(Unit) | ||||
delay(200) | ||||
println("send") | ||||
channel.send(Unit) | ||||
delay(200) | ||||
println("send") | ||||
channel.send(Unit) | ||||
delay(600) | ||||
channel.cancel() | ||||
} | ||||
runBlocking { | ||||
var lastIndex = -1 | ||||
channel.asFlow() | ||||
.withIndex() | ||||
.debounce(300) | ||||
.map { | ||||
val result = minOf(it.index - lastIndex, 50) | ||||
lastIndex = it.index | ||||
result | ||||
} | ||||
.collect { | ||||
println(it) | ||||
} | ||||
} | ||||
} | ||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍