Skip to content

Commit 6c70ee5

Browse files
committed
🐛: fix: #16; refactor: useInterval, a new overloaded function has been added. Now you can control the execution of pause and resume through the ready state.
1 parent 2c672bf commit 6c70ee5

File tree

2 files changed

+271
-56
lines changed

2 files changed

+271
-56
lines changed
Lines changed: 212 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,42 @@
11
package xyz.junerver.composehooks.example
22

3+
import androidx.compose.foundation.background
4+
import androidx.compose.foundation.clickable
5+
import androidx.compose.foundation.layout.Box
36
import androidx.compose.foundation.layout.Column
7+
import androidx.compose.foundation.layout.Row
8+
import androidx.compose.foundation.layout.fillMaxWidth
9+
import androidx.compose.foundation.layout.height
10+
import androidx.compose.foundation.layout.padding
11+
import androidx.compose.foundation.layout.width
12+
import androidx.compose.foundation.shape.RoundedCornerShape
13+
import androidx.compose.foundation.text.BasicTextField
14+
import androidx.compose.foundation.text.KeyboardActions
15+
import androidx.compose.foundation.text.KeyboardOptions
16+
import androidx.compose.material3.HorizontalDivider
417
import androidx.compose.material3.Surface
518
import androidx.compose.material3.Text
619
import androidx.compose.runtime.Composable
7-
import androidx.compose.runtime.getValue
20+
import androidx.compose.runtime.mutableStateOf
21+
import androidx.compose.runtime.remember
22+
import androidx.compose.ui.Alignment
23+
import androidx.compose.ui.Modifier
24+
import androidx.compose.ui.draw.clip
25+
import androidx.compose.ui.graphics.Color
26+
import androidx.compose.ui.text.TextStyle
27+
import androidx.compose.ui.text.font.FontWeight
28+
import androidx.compose.ui.text.input.ImeAction
29+
import androidx.compose.ui.text.input.KeyboardType
30+
import androidx.compose.ui.text.style.TextAlign
31+
import androidx.compose.ui.unit.dp
32+
import androidx.compose.ui.unit.sp
833
import kotlin.time.Duration.Companion.seconds
934
import xyz.junerver.compose.hooks.optionsOf
35+
import xyz.junerver.compose.hooks.useBoolean
1036
import xyz.junerver.compose.hooks.useEffect
37+
import xyz.junerver.compose.hooks.useGetState
1138
import xyz.junerver.compose.hooks.useInterval
12-
import xyz.junerver.compose.hooks.useLatestState
13-
import xyz.junerver.compose.hooks.useState
39+
import xyz.junerver.composehooks.ui.component.TButton
1440

1541
/**
1642
* Description:
@@ -21,22 +47,194 @@ import xyz.junerver.compose.hooks.useState
2147
*/
2248
@Composable
2349
fun UseIntervalExample() {
24-
val (countDown, setCountDown) = useState(60)
25-
val currentCount by useLatestState(value = countDown)
26-
val (_, cancel) = useInterval(
50+
Surface {
51+
Column {
52+
Manual()
53+
HorizontalDivider(
54+
modifier = Modifier
55+
.fillMaxWidth()
56+
.padding(20.dp)
57+
)
58+
ByReady()
59+
HorizontalDivider(
60+
modifier = Modifier
61+
.fillMaxWidth()
62+
.padding(20.dp)
63+
)
64+
val (text, setText) = remember { mutableStateOf("") }
65+
CustomTextField(
66+
text = text,
67+
onTextChanged = { setText(it) },
68+
onSendClicked = { /* Handle send button click */ }
69+
)
70+
}
71+
}
72+
}
73+
74+
@Composable
75+
private fun Manual() {
76+
// if you prefer to this usage, use `useGetState`
77+
val (countDown, setCountDown) = useGetState(60)
78+
val (resume, pause, isActive) = useInterval(
2779
optionsOf {
28-
initialDelay = 5.seconds
29-
period = 2.seconds
80+
initialDelay = 2.seconds
81+
period = 1.seconds
3082
}
3183
) {
32-
setCountDown(currentCount - 1)
84+
setCountDown(countDown - 1)
3385
}
34-
useEffect(currentCount) {
35-
if (currentCount == 0) cancel()
86+
useEffect(countDown) {
87+
if (countDown == 0) pause()
3688
}
37-
Surface {
38-
Column {
39-
Text(text = "current: $countDown")
89+
Column {
90+
Text(text = "You can get the function by destructuring the return value")
91+
Text(text = "current: $countDown")
92+
Text(text = "isActive: $isActive")
93+
94+
TButton(text = "resume", onClick = { resume() })
95+
TButton(text = "pause", onClick = { pause() })
96+
}
97+
}
98+
99+
@Composable
100+
private fun ByReady() {
101+
val (countDown, setCountDown) = useGetState(60)
102+
val (isReady, toggle, setReady) = useBoolean(false)
103+
useInterval(
104+
options = optionsOf {
105+
initialDelay = 2.seconds
106+
period = 1.seconds
107+
},
108+
ready = isReady
109+
) {
110+
setCountDown(countDown - 1)
111+
}
112+
useEffect(countDown) {
113+
if (countDown == 0) setReady(false)
114+
}
115+
Column {
116+
Text(text = "You can also control it by switching the `ready` state:")
117+
Text(text = "current: $countDown")
118+
Text(text = "isReady: $isReady")
119+
TButton(text = "toggle Ready", onClick = { toggle() })
120+
}
121+
}
122+
123+
@Composable
124+
fun CustomTextField(
125+
text: String,
126+
onTextChanged: (String) -> Unit,
127+
onSendClicked: () -> Unit,
128+
placeholderText: String = "请输入手机号",
129+
buttonText: String = "获取验证码",
130+
) {
131+
BasicTextField(
132+
value = text,
133+
onValueChange = { onTextChanged(it) },
134+
keyboardOptions = KeyboardOptions(
135+
keyboardType = KeyboardType.Number,
136+
imeAction = ImeAction.Send
137+
),
138+
keyboardActions = KeyboardActions(
139+
onSend = { onSendClicked() }
140+
),
141+
textStyle = TextStyle(
142+
fontSize = 12.sp,
143+
color = Color(0xFF222222)
144+
),
145+
decorationBox = { innerTextField ->
146+
MyDecorationBox(
147+
innerTextField = innerTextField,
148+
text = text,
149+
placeholderText = placeholderText,
150+
buttonText = buttonText,
151+
onSendClicked = onSendClicked
152+
)
153+
}
154+
)
155+
}
156+
157+
@Composable
158+
fun MyDecorationBox(
159+
innerTextField: @Composable () -> Unit,
160+
countDownTimer: Int = 10,
161+
text: String,
162+
placeholderText: String,
163+
buttonText: String,
164+
onSendClicked: () -> Unit,
165+
) {
166+
val (isReady, _, _, setReadyTrue, setReadyFalse) = useBoolean(false)
167+
val (countdown, setCountdown) = useGetState(countDownTimer)
168+
useInterval(
169+
optionsOf {
170+
initialDelay = 1.seconds
171+
period = 1.seconds
172+
},
173+
ready = isReady
174+
) {
175+
setCountdown(countdown - 1)
176+
}
177+
useEffect(countdown) {
178+
if (countdown == 0) {
179+
setCountdown(countDownTimer)
180+
setReadyFalse()
181+
}
182+
}
183+
Row(
184+
modifier = Modifier
185+
.width(235.dp)
186+
.height(40.dp)
187+
.background(color = Color(0xFFF7F7F7), shape = RoundedCornerShape(size = 4.dp)),
188+
verticalAlignment = Alignment.CenterVertically
189+
) {
190+
Box(
191+
modifier = Modifier
192+
.weight(1f)
193+
.padding(start = 12.dp, end = 12.dp)
194+
) {
195+
innerTextField()
196+
if (text.isEmpty()) {
197+
Text(
198+
text = placeholderText,
199+
style = TextStyle(
200+
fontSize = 12.sp,
201+
color = Color(0xFFBBBBBB)
202+
)
203+
)
204+
}
205+
}
206+
if (isReady) {
207+
Text(
208+
text = "${countdown}s",
209+
modifier = Modifier
210+
.width(40.dp)
211+
.padding(end = 12.dp),
212+
style = TextStyle(
213+
fontSize = 12.sp,
214+
lineHeight = 20.sp,
215+
fontWeight = FontWeight(600),
216+
color = Color(0xFFBBBBBB),
217+
textAlign = TextAlign.End
218+
)
219+
)
220+
} else {
221+
Text(
222+
text = buttonText,
223+
style = TextStyle(
224+
fontSize = 12.sp,
225+
color = Color(0xFF045FFE),
226+
fontWeight = FontWeight.SemiBold
227+
),
228+
modifier = Modifier
229+
.clickable(onClick = {
230+
if (!isReady) {
231+
setReadyTrue()
232+
}
233+
onSendClicked()
234+
})
235+
.clip(RoundedCornerShape(size = 4.dp))
236+
.padding(12.dp, 10.dp, 12.dp, 10.dp)
237+
)
40238
}
41239
}
42240
}

0 commit comments

Comments
 (0)