1 /*
<lambda>null2 * Copyright 2021 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 * https://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.google.accompanist.sample.swiperefresh
18
19 import android.os.Bundle
20 import androidx.activity.ComponentActivity
21 import androidx.activity.compose.setContent
22 import androidx.compose.foundation.Image
23 import androidx.compose.foundation.layout.Row
24 import androidx.compose.foundation.layout.Spacer
25 import androidx.compose.foundation.layout.WindowInsets
26 import androidx.compose.foundation.layout.WindowInsetsSides
27 import androidx.compose.foundation.layout.asPaddingValues
28 import androidx.compose.foundation.layout.fillMaxWidth
29 import androidx.compose.foundation.layout.only
30 import androidx.compose.foundation.layout.padding
31 import androidx.compose.foundation.layout.size
32 import androidx.compose.foundation.layout.systemBars
33 import androidx.compose.foundation.layout.width
34 import androidx.compose.foundation.layout.windowInsetsPadding
35 import androidx.compose.foundation.lazy.LazyColumn
36 import androidx.compose.foundation.lazy.items
37 import androidx.compose.foundation.shape.RoundedCornerShape
38 import androidx.compose.material.MaterialTheme
39 import androidx.compose.material.Text
40 import androidx.compose.runtime.Composable
41 import androidx.compose.runtime.LaunchedEffect
42 import androidx.compose.runtime.SideEffect
43 import androidx.compose.runtime.getValue
44 import androidx.compose.runtime.mutableStateOf
45 import androidx.compose.runtime.remember
46 import androidx.compose.runtime.setValue
47 import androidx.compose.ui.Alignment
48 import androidx.compose.ui.Modifier
49 import androidx.compose.ui.draw.clip
50 import androidx.compose.ui.graphics.Color
51 import androidx.compose.ui.res.stringResource
52 import androidx.compose.ui.unit.dp
53 import androidx.core.view.WindowCompat
54 import coil.annotation.ExperimentalCoilApi
55 import coil.compose.rememberImagePainter
56 import com.google.accompanist.insets.ui.Scaffold
57 import com.google.accompanist.insets.ui.TopAppBarContent
58 import com.google.accompanist.insets.ui.TopAppBarSurface
59 import com.google.accompanist.sample.AccompanistSampleTheme
60 import com.google.accompanist.sample.R
61 import com.google.accompanist.sample.randomSampleImageUrl
62 import com.google.accompanist.swiperefresh.SwipeRefresh
63 import com.google.accompanist.swiperefresh.SwipeRefreshIndicator
64 import com.google.accompanist.swiperefresh.rememberSwipeRefreshState
65 import com.google.accompanist.systemuicontroller.rememberSystemUiController
66 import kotlinx.coroutines.delay
67
68 class SwipeRefreshContentPaddingSample : ComponentActivity() {
69 override fun onCreate(savedInstanceState: Bundle?) {
70 super.onCreate(savedInstanceState)
71
72 // Turn off the decor fitting system windows, which means we need to through handling
73 // insets
74 WindowCompat.setDecorFitsSystemWindows(window, false)
75
76 setContent {
77 AccompanistSampleTheme {
78 Sample()
79 }
80 }
81 }
82 }
83
<lambda>null84 private val listItems = List(40) { randomSampleImageUrl(it) }
85
86 @Suppress("DEPRECATION")
87 @Composable
Samplenull88 private fun Sample() {
89 val systemUiController = rememberSystemUiController()
90 val useDarkIcons = MaterialTheme.colors.isLight
91 SideEffect {
92 systemUiController.setSystemBarsColor(Color.Transparent, darkIcons = useDarkIcons)
93 }
94
95 // Simulate a fake 2-second 'load'. Ideally this 'refreshing' value would
96 // come from a ViewModel or similar
97 var refreshing by remember { mutableStateOf(false) }
98 LaunchedEffect(refreshing) {
99 if (refreshing) {
100 delay(2000)
101 refreshing = false
102 }
103 }
104
105 Scaffold(
106 topBar = {
107 TopAppBarSurface(
108 backgroundColor = MaterialTheme.colors.surface.copy(alpha = 0.9f),
109 modifier = Modifier.fillMaxWidth()
110 ) {
111 TopAppBarContent(
112 title = {
113 Text(stringResource(R.string.swiperefresh_title_content_padding))
114 },
115 modifier = Modifier.windowInsetsPadding(
116 WindowInsets.systemBars.only(
117 WindowInsetsSides.Horizontal + WindowInsetsSides.Top
118 )
119 )
120 )
121 }
122 },
123 contentPadding = WindowInsets.systemBars
124 .only(WindowInsetsSides.Horizontal + WindowInsetsSides.Bottom)
125 .asPaddingValues()
126 ) { contentPadding ->
127 SwipeRefresh(
128 state = rememberSwipeRefreshState(refreshing),
129 onRefresh = { refreshing = true },
130 // Shift the indicator to match the list content padding
131 indicatorPadding = contentPadding,
132 // We want the indicator to draw within the padding
133 clipIndicatorToPadding = false,
134 // Tweak the indicator to scale up/down
135 indicator = { state, refreshTriggerDistance ->
136 SwipeRefreshIndicator(
137 state = state,
138 refreshTriggerDistance = refreshTriggerDistance,
139 scale = true
140 )
141 }
142 ) {
143 LazyColumn(contentPadding = contentPadding) {
144 items(items = listItems) { imageUrl ->
145 ListItem(imageUrl, Modifier.fillMaxWidth())
146 }
147 }
148 }
149 }
150 }
151
152 @OptIn(ExperimentalCoilApi::class)
153 @Composable
ListItemnull154 fun ListItem(
155 imageUrl: String,
156 modifier: Modifier = Modifier
157 ) {
158 Row(modifier.padding(horizontal = 16.dp, vertical = 8.dp)) {
159 Image(
160 painter = rememberImagePainter(imageUrl),
161 contentDescription = null,
162 modifier = Modifier
163 .size(64.dp)
164 .clip(RoundedCornerShape(4.dp)),
165 )
166
167 Spacer(Modifier.width(16.dp))
168
169 Text(
170 text = "Text",
171 style = MaterialTheme.typography.subtitle2,
172 modifier = Modifier.weight(1f)
173 .align(Alignment.CenterVertically)
174 )
175 }
176 }
177