11package com.raival.compose.file.explorer.screen.main.tab.apps.compose
22
3+ import androidx.activity.compose.BackHandler
4+ import androidx.compose.animation.AnimatedVisibility
35import androidx.compose.foundation.layout.Arrangement
46import androidx.compose.foundation.layout.Box
57import androidx.compose.foundation.layout.Column
68import androidx.compose.foundation.layout.ColumnScope
79import androidx.compose.foundation.layout.Row
810import androidx.compose.foundation.layout.fillMaxSize
911import androidx.compose.foundation.layout.fillMaxWidth
12+ import androidx.compose.foundation.layout.height
1013import androidx.compose.foundation.layout.padding
1114import androidx.compose.foundation.layout.size
1215import androidx.compose.foundation.lazy.LazyColumn
1316import androidx.compose.foundation.lazy.items
17+ import androidx.compose.foundation.shape.CircleShape
1418import androidx.compose.foundation.shape.RoundedCornerShape
19+ import androidx.compose.foundation.text.KeyboardActions
20+ import androidx.compose.foundation.text.KeyboardOptions
21+ import androidx.compose.material.icons.Icons
22+ import androidx.compose.material.icons.automirrored.rounded.ArrowBack
23+ import androidx.compose.material.icons.rounded.Cancel
24+ import androidx.compose.material.icons.rounded.Pause
25+ import androidx.compose.material.icons.rounded.Search
26+ import androidx.compose.material3.AlertDialogDefaults
1527import androidx.compose.material3.CircularProgressIndicator
28+ import androidx.compose.material3.FloatingActionButton
29+ import androidx.compose.material3.Icon
30+ import androidx.compose.material3.IconButton
1631import androidx.compose.material3.SegmentedButton
1732import androidx.compose.material3.SegmentedButtonDefaults
1833import androidx.compose.material3.SingleChoiceSegmentedButtonRow
1934import androidx.compose.material3.Text
2035import androidx.compose.material3.TextButton
36+ import androidx.compose.material3.TextField
37+ import androidx.compose.material3.TextFieldDefaults
2138import androidx.compose.runtime.Composable
2239import androidx.compose.runtime.LaunchedEffect
2340import androidx.compose.ui.Alignment
2441import androidx.compose.ui.Modifier
2542import androidx.compose.ui.draw.alpha
2643import androidx.compose.ui.draw.clip
44+ import androidx.compose.ui.graphics.Color
2745import androidx.compose.ui.graphics.FilterQuality
2846import androidx.compose.ui.layout.ContentScale
2947import androidx.compose.ui.res.painterResource
3048import androidx.compose.ui.res.stringResource
3149import androidx.compose.ui.text.font.FontWeight
50+ import androidx.compose.ui.text.input.ImeAction
3251import androidx.compose.ui.unit.dp
3352import androidx.compose.ui.unit.sp
3453import coil3.compose.AsyncImage
3554import com.raival.compose.file.explorer.App.Companion.globalClass
3655import com.raival.compose.file.explorer.R
3756import com.raival.compose.file.explorer.common.compose.BottomSheetDialog
3857import com.raival.compose.file.explorer.common.compose.Space
58+ import com.raival.compose.file.explorer.common.compose.block
59+ import com.raival.compose.file.explorer.common.extension.emptyString
3960import com.raival.compose.file.explorer.common.extension.toFormattedSize
4061import com.raival.compose.file.explorer.screen.main.tab.apps.AppsTab
62+ import com.raival.compose.file.explorer.screen.main.tab.apps.modal.AppHolder
4163import com.raival.compose.file.explorer.screen.main.tab.files.compose.ItemRow
4264import com.raival.compose.file.explorer.screen.main.tab.files.compose.ItemRowIcon
4365import com.raival.compose.file.explorer.screen.main.tab.files.modal.DocumentHolder
4466import com.raival.compose.file.explorer.screen.main.tab.files.task.CopyTask
67+ import kotlinx.coroutines.CoroutineScope
68+ import kotlinx.coroutines.Dispatchers
69+ import kotlinx.coroutines.delay
70+ import kotlinx.coroutines.launch
4571import java.io.File
4672
4773@Composable
@@ -65,6 +91,27 @@ fun ColumnScope.AppsTabContentView(tab: AppsTab) {
6591 }
6692 }
6793
94+ BackHandler (tab.isSearchPanelOpen || tab.isSearching || tab.isLoading) {
95+ if (tab.isSearching) {
96+ tab.isSearching = false
97+ }
98+
99+ if (tab.isSearchPanelOpen) {
100+ tab.isSearchPanelOpen = false
101+ }
102+
103+ tab.appsList.clear()
104+
105+ when (tab.selectedChoice) {
106+ 0 -> tab.appsList.addAll(tab.userApps)
107+ 1 -> tab.appsList.addAll(tab.systemApps)
108+ 2 -> {
109+ tab.appsList.addAll(tab.userApps)
110+ tab.appsList.addAll(tab.systemApps)
111+ }
112+ }
113+ }
114+
68115 if (tab.previewAppDialog != null ) {
69116 val selectedApp = tab.previewAppDialog!!
70117 val details = arrayListOf<Pair <String , String >>().apply {
@@ -170,53 +217,165 @@ fun ColumnScope.AppsTabContentView(tab: AppsTab) {
170217 }
171218
172219 item {
173- Space (70 .dp)
220+ Space (150 .dp)
174221 }
175222 }
176223
177- SingleChoiceSegmentedButtonRow (
224+ Column (
178225 modifier = Modifier
179226 .fillMaxWidth()
180- .padding(16 .dp)
181227 .align(Alignment .BottomCenter ),
228+ horizontalAlignment = Alignment .End
182229 ) {
183- SegmentedButton (
184- selected = tab.selectedChoice == 0 ,
185- onClick = {
186- tab.selectedChoice = 0
187- },
188- shape = SegmentedButtonDefaults .itemShape(index = 0 , count = 3 ),
189- label = {
190- Text (text = stringResource(R .string.user_apps))
230+ AnimatedVisibility (! tab.isSearchPanelOpen) {
231+ FloatingActionButton (
232+ modifier = Modifier .padding(horizontal = 16 .dp),
233+ onClick = {
234+ tab.isSearchPanelOpen = true
235+ }
236+ ) {
237+ Icon (
238+ imageVector = Icons .Rounded .Search ,
239+ contentDescription = null
240+ )
191241 }
192- )
242+ }
193243
194- SegmentedButton (
195- selected = tab.selectedChoice == 1 ,
196- onClick = {
197- tab.selectedChoice = 1
198- },
199- shape = SegmentedButtonDefaults .itemShape(index = 1 , count = 3 ),
200- label = {
201- Text (text = stringResource(R .string.system_apps))
202- }
203- )
244+ SingleChoiceSegmentedButtonRow (
245+ modifier = Modifier
246+ .fillMaxWidth()
247+ .padding(16 .dp)
248+ ) {
249+ SegmentedButton (
250+ selected = tab.selectedChoice == 0 ,
251+ onClick = {
252+ tab.selectedChoice = 0
253+ },
254+ shape = SegmentedButtonDefaults .itemShape(index = 0 , count = 3 ),
255+ label = {
256+ Text (text = stringResource(R .string.user_apps))
257+ }
258+ )
259+
260+ SegmentedButton (
261+ selected = tab.selectedChoice == 1 ,
262+ onClick = {
263+ tab.selectedChoice = 1
264+ },
265+ shape = SegmentedButtonDefaults .itemShape(index = 1 , count = 3 ),
266+ label = {
267+ Text (text = stringResource(R .string.system_apps))
268+ }
269+ )
270+
271+ SegmentedButton (
272+ selected = tab.selectedChoice == 2 ,
273+ onClick = {
274+ tab.selectedChoice = 2
275+ },
276+ shape = SegmentedButtonDefaults .itemShape(index = 2 , count = 3 ),
277+ label = {
278+ Text (text = stringResource(R .string.all))
279+ }
280+ )
281+ }
204282
205- SegmentedButton (
206- selected = tab.selectedChoice == 2 ,
207- onClick = {
208- tab.selectedChoice = 2
209- },
210- shape = SegmentedButtonDefaults .itemShape(index = 2 , count = 3 ),
211- label = {
212- Text (text = stringResource(R .string.all))
283+ AnimatedVisibility (tab.isSearchPanelOpen) {
284+ Row (
285+ Modifier
286+ .fillMaxWidth()
287+ .padding(horizontal = 16 .dp)
288+ .padding(bottom = 16 .dp)
289+ .height(56 .dp)
290+ .block(
291+ borderSize = 0 .dp,
292+ shape = CircleShape
293+ ),
294+ verticalAlignment = Alignment .CenterVertically
295+ ) {
296+ TextField (
297+ modifier = Modifier
298+ .fillMaxWidth(),
299+ colors = TextFieldDefaults .colors(
300+ focusedContainerColor = AlertDialogDefaults .containerColor,
301+ unfocusedContainerColor = AlertDialogDefaults .containerColor,
302+ disabledContainerColor = AlertDialogDefaults .containerColor,
303+ focusedIndicatorColor = Color .Transparent ,
304+ unfocusedIndicatorColor = Color .Transparent ,
305+ ),
306+ value = tab.searchQuery,
307+ onValueChange = {
308+ tab.searchQuery = it
309+ },
310+ placeholder = {
311+ Text (
312+ modifier = Modifier .alpha(0.75f ),
313+ text = stringResource(R .string.search_query),
314+ )
315+ },
316+ leadingIcon = {
317+ IconButton (onClick = { tab.isSearchPanelOpen = false }) {
318+ Icon (
319+ imageVector = Icons .AutoMirrored .Rounded .ArrowBack ,
320+ contentDescription = null
321+ )
322+ }
323+ },
324+ trailingIcon = {
325+ AnimatedVisibility (visible = tab.searchQuery.isNotEmpty()) {
326+ IconButton (
327+ onClick = {
328+ if (tab.isSearching) {
329+ tab.isSearching = false
330+ } else {
331+ tab.searchQuery = emptyString
332+ tab.isSearching = false
333+ }
334+ }
335+ ) {
336+ Icon (
337+ imageVector = if (tab.isSearching) Icons .Rounded .Pause
338+ else Icons .Rounded .Cancel , contentDescription = null
339+ )
340+ }
341+ }
342+ },
343+ keyboardOptions = KeyboardOptions (imeAction = ImeAction .Search ),
344+ keyboardActions = KeyboardActions (
345+ onSearch = {
346+ CoroutineScope (Dispatchers .IO ).launch {
347+ if (tab.isSearching) {
348+ tab.isSearching = false
349+ delay(200 )
350+ }
351+
352+ tab.isSearching = true
353+
354+ val list = arrayListOf<AppHolder >().apply {
355+ when (tab.selectedChoice) {
356+ 0 -> addAll(tab.userApps)
357+ 1 -> addAll(tab.systemApps)
358+ else -> addAll(tab.userApps + tab.systemApps)
359+ }
360+ }
361+
362+ tab.appsList.clear()
363+ tab.appsList.addAll(list.filter {
364+ it.name.contains(tab.searchQuery, true )
365+ })
366+
367+ tab.isSearching = false
368+ }
369+ }
370+ )
371+ )
213372 }
214- )
373+ }
215374 }
216375
217376 androidx.compose.animation.AnimatedVisibility (
218377 modifier = Modifier .align(Alignment .Center ),
219- visible = tab.isLoading
378+ visible = tab.isLoading || tab.isSearching
220379 ) {
221380 CircularProgressIndicator (
222381 modifier = Modifier .align(Alignment .Center )
0 commit comments