1 /*
<lambda>null2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
15 */
16
17 package com.android.systemui.util.kotlin
18
19 import android.content.Context
20 import kotlinx.coroutines.CoroutineScope
21 import kotlinx.coroutines.flow.Flow
22 import kotlinx.coroutines.flow.SharingStarted
23 import kotlinx.coroutines.flow.StateFlow
24 import kotlinx.coroutines.flow.combine
25 import kotlinx.coroutines.flow.filter
26 import kotlinx.coroutines.flow.map
27 import kotlinx.coroutines.flow.stateIn
28
29 class Utils {
30 companion object {
31 fun <A, B, C> toTriple(a: A, bc: Pair<B, C>) = Triple(a, bc.first, bc.second)
32
33 fun <A, B, C> toTriple(ab: Pair<A, B>, c: C) = Triple(ab.first, ab.second, c)
34
35 fun <A, B, C, D> toQuad(a: A, b: B, c: C, d: D) = Quad(a, b, c, d)
36
37 fun <A, B, C, D> toQuad(a: A, bcd: Triple<B, C, D>) =
38 Quad(a, bcd.first, bcd.second, bcd.third)
39
40 fun <A, B, C, D> toQuad(abc: Triple<A, B, C>, d: D) =
41 Quad(abc.first, abc.second, abc.third, d)
42
43 fun <A, B, C, D, E> toQuint(a: A, b: B, c: C, d: D, e: E) = Quint(a, b, c, d, e)
44
45 fun <A, B, C, D, E> toQuint(a: A, bcde: Quad<B, C, D, E>) =
46 Quint(a, bcde.first, bcde.second, bcde.third, bcde.fourth)
47
48 fun <A, B, C, D, E, F> toSextuple(a: A, bcdef: Quint<B, C, D, E, F>) =
49 Sextuple(a, bcdef.first, bcdef.second, bcdef.third, bcdef.fourth, bcdef.fifth)
50
51 fun <A, B, C, D, E, F, G> toSeptuple(a: A, bcdefg: Sextuple<B, C, D, E, F, G>) =
52 Septuple(
53 a,
54 bcdefg.first,
55 bcdefg.second,
56 bcdefg.third,
57 bcdefg.fourth,
58 bcdefg.fifth,
59 bcdefg.sixth,
60 )
61
62 /**
63 * Samples the provided flow, performs a filter on the sampled value, then returns the
64 * original value.
65 */
66 fun <A, B> Flow<A>.sampleFilter(b: Flow<B>, predicate: (B) -> Boolean): Flow<A> {
67 return this.sample(b, ::Pair).filter { (_, b) -> predicate(b) }.map { (a, _) -> a }
68 }
69
70 /**
71 * Samples the provided flows, emitting a tuple of the original flow's value as well as each
72 * of the combined flows' values.
73 *
74 * Flow<A>.sample(Flow<B>, Flow<C>) -> (A, B, C)
75 */
76 fun <A, B, C> Flow<A>.sample(b: Flow<B>, c: Flow<C>): Flow<Triple<A, B, C>> {
77 return this.sample(combine(b, c, ::Pair), ::toTriple)
78 }
79
80 /**
81 * Samples the provided flows, emitting a tuple of the original flow's value as well as each
82 * of the combined flows' values.
83 *
84 * Flow<A>.sample(Flow<B>, Flow<C>, Flow<D>) -> (A, B, C, D)
85 */
86 fun <A, B, C, D> Flow<A>.sample(
87 b: Flow<B>,
88 c: Flow<C>,
89 d: Flow<D>,
90 ): Flow<Quad<A, B, C, D>> {
91 return this.sample(combine(b, c, d, ::Triple), ::toQuad)
92 }
93
94 /**
95 * Samples the provided flows, emitting a tuple of the original flow's value as well as each
96 * of the combined flows' values.
97 *
98 * Flow<A>.sample(Flow<B>, Flow<C>, Flow<D>, Flow<E>) -> (A, B, C, D, E)
99 */
100 fun <A, B, C, D, E> Flow<A>.sample(
101 b: Flow<B>,
102 c: Flow<C>,
103 d: Flow<D>,
104 e: Flow<E>,
105 ): Flow<Quint<A, B, C, D, E>> {
106 return this.sample(combine(b, c, d, e, ::Quad), ::toQuint)
107 }
108
109 /**
110 * Samples the provided flows, emitting a tuple of the original flow's value as well as each
111 * of the combined flows' values.
112 *
113 * Flow<A>.sample(Flow<B>, Flow<C>, Flow<D>, Flow<E>, Flow<F>) -> (A, B, C, D, E, F)
114 */
115 fun <A, B, C, D, E, F> Flow<A>.sample(
116 b: Flow<B>,
117 c: Flow<C>,
118 d: Flow<D>,
119 e: Flow<E>,
120 f: Flow<F>,
121 ): Flow<Sextuple<A, B, C, D, E, F>> {
122 return this.sample(combine(b, c, d, e, f, ::Quint), ::toSextuple)
123 }
124
125 /**
126 * Samples the provided flows, emitting a tuple of the original flow's value as well as each
127 * of the combined flows' values.
128 *
129 * Flow<A>.sample(Flow<B>, Flow<C>, Flow<D>, Flow<E>, Flow<F>, Flow<G>) -> (A, B, C, D, E,
130 * F, G)
131 */
132 fun <A, B, C, D, E, F, G> Flow<A>.sample(
133 b: Flow<B>,
134 c: Flow<C>,
135 d: Flow<D>,
136 e: Flow<E>,
137 f: Flow<F>,
138 g: Flow<G>,
139 ): Flow<Septuple<A, B, C, D, E, F, G>> {
140 return this.sample(combine(b, c, d, e, f, g, ::Sextuple), ::toSeptuple)
141 }
142
143 /**
144 * Combines 2 state flows, applying [transform] between the initial values to set the
145 * initial value of the resulting StateFlow.
146 */
147 fun <A, B, R> combineState(
148 f1: StateFlow<A>,
149 f2: StateFlow<B>,
150 scope: CoroutineScope,
151 sharingStarted: SharingStarted,
152 transform: (A, B) -> R,
153 ): StateFlow<R> =
154 combine(f1, f2) { a, b -> transform(a, b) }
155 .stateIn(scope, sharingStarted, transform(f1.value, f2.value))
156 }
157 }
158
159 data class Quad<A, B, C, D>(val first: A, val second: B, val third: C, val fourth: D)
160
161 data class Quint<A, B, C, D, E>(
162 val first: A,
163 val second: B,
164 val third: C,
165 val fourth: D,
166 val fifth: E,
167 )
168
169 data class Sextuple<A, B, C, D, E, F>(
170 val first: A,
171 val second: B,
172 val third: C,
173 val fourth: D,
174 val fifth: E,
175 val sixth: F,
176 )
177
178 data class Septuple<A, B, C, D, E, F, G>(
179 val first: A,
180 val second: B,
181 val third: C,
182 val fourth: D,
183 val fifth: E,
184 val sixth: F,
185 val seventh: G,
186 )
187
toPxnull188 fun Int.toPx(context: Context): Int {
189 return (this * context.resources.displayMetrics.density).toInt()
190 }
191
toDpnull192 fun Int.toDp(context: Context): Int {
193 return (this / context.resources.displayMetrics.density).toInt()
194 }
195