|
1 | 1 | package dev.arkbuilders.drop.app.presentation.send |
2 | 2 |
|
3 | | -import android.content.ClipData |
4 | | -import android.content.ClipboardManager |
5 | | -import android.content.Context |
6 | | -import android.graphics.Bitmap |
7 | 3 | import androidx.activity.compose.rememberLauncherForActivityResult |
8 | 4 | import androidx.activity.result.contract.ActivityResultContracts |
9 | | -import androidx.compose.foundation.Image |
10 | | -import androidx.compose.foundation.layout.Arrangement |
11 | 5 | import androidx.compose.foundation.layout.Column |
12 | | -import androidx.compose.foundation.layout.Row |
13 | | -import androidx.compose.foundation.layout.Spacer |
14 | 6 | import androidx.compose.foundation.layout.fillMaxSize |
15 | | -import androidx.compose.foundation.layout.height |
16 | | -import androidx.compose.foundation.layout.padding |
17 | | -import androidx.compose.foundation.layout.size |
18 | | -import androidx.compose.foundation.layout.width |
19 | | -import androidx.compose.foundation.lazy.rememberLazyListState |
20 | 7 | import androidx.compose.foundation.rememberScrollState |
21 | | -import androidx.compose.foundation.shape.RoundedCornerShape |
22 | 8 | import androidx.compose.foundation.verticalScroll |
23 | | -import androidx.compose.material3.AlertDialog |
24 | 9 | import androidx.compose.material3.ExperimentalMaterial3Api |
25 | | -import androidx.compose.material3.Icon |
26 | | -import androidx.compose.material3.MaterialTheme |
27 | | -import androidx.compose.material3.Surface |
28 | | -import androidx.compose.material3.Text |
29 | | -import androidx.compose.material3.TextButton |
30 | 10 | import androidx.compose.runtime.Composable |
31 | 11 | import androidx.compose.runtime.getValue |
32 | | -import androidx.compose.runtime.mutableStateOf |
33 | | -import androidx.compose.runtime.remember |
34 | | -import androidx.compose.runtime.rememberCoroutineScope |
35 | | -import androidx.compose.runtime.setValue |
36 | | -import androidx.compose.ui.Alignment |
37 | 12 | import androidx.compose.ui.Modifier |
38 | | -import androidx.compose.ui.graphics.Color |
39 | | -import androidx.compose.ui.graphics.asImageBitmap |
40 | | -import androidx.compose.ui.platform.LocalContext |
41 | | -import androidx.compose.ui.platform.LocalHapticFeedback |
42 | | -import androidx.compose.ui.text.font.FontWeight |
43 | | -import androidx.compose.ui.text.style.TextAlign |
44 | | -import androidx.compose.ui.unit.dp |
45 | 13 | import androidx.navigation.NavController |
46 | | -import compose.icons.TablerIcons |
47 | | -import compose.icons.tablericons.Copy |
48 | | -import compose.icons.tablericons.Qrcode |
49 | 14 | import dev.arkbuilders.drop.app.presentation.components.DropErrorCard |
50 | 15 | import dev.arkbuilders.drop.app.presentation.components.DropTopBarBack |
51 | | -import dev.arkbuilders.drop.app.presentation.send.components.ButtonSize |
52 | | -import dev.arkbuilders.drop.app.presentation.send.components.ButtonVariant |
53 | | -import dev.arkbuilders.drop.app.presentation.send.components.SendButton |
54 | | -import dev.arkbuilders.drop.app.presentation.send.components.SendLoadingIndicator |
55 | 16 | import dev.arkbuilders.drop.app.presentation.send.components.phase.FileSelectionPhase |
56 | 17 | import dev.arkbuilders.drop.app.presentation.send.components.phase.GeneratingQRPhase |
57 | 18 | import dev.arkbuilders.drop.app.presentation.send.components.phase.TransferCompletePhase |
58 | 19 | import dev.arkbuilders.drop.app.presentation.send.components.phase.TransferringPhase |
59 | 20 | import dev.arkbuilders.drop.app.presentation.send.components.phase.WaitingForReceiverPhase |
60 | | -import kotlinx.coroutines.delay |
61 | | -import kotlinx.coroutines.launch |
62 | 21 | import org.koin.compose.koinInject |
63 | 22 | import org.orbitmvi.orbit.compose.collectAsState |
64 | 23 | import org.orbitmvi.orbit.compose.collectSideEffect |
65 | 24 |
|
66 | 25 | @OptIn(ExperimentalMaterial3Api::class) |
67 | 26 | @Composable |
68 | 27 | fun Send(navController: NavController) { |
69 | | - val haptic = LocalHapticFeedback.current |
70 | | - val listState = rememberLazyListState() |
71 | 28 | val viewModel: SendViewModel = koinInject() |
72 | 29 |
|
73 | 30 | val state by viewModel.collectAsState() |
@@ -127,6 +84,8 @@ fun Send(navController: NavController) { |
127 | 84 |
|
128 | 85 | is SendScreenState.WaitingForReceiver -> { |
129 | 86 | WaitingForReceiverPhase( |
| 87 | + qrBitmap = sendScreenState.qrBitmap, |
| 88 | + copyString = sendScreenState.copyString, |
130 | 89 | fileCount = sendScreenState.files.size, |
131 | 90 | onCancel = { viewModel.onCancelTransfer() }, |
132 | 91 | ) |
@@ -163,176 +122,9 @@ fun Send(navController: NavController) { |
163 | 122 | ) |
164 | 123 | } |
165 | 124 | } |
166 | | - |
167 | | - if (sendScreenState is SendScreenState.WaitingForReceiver) { |
168 | | - SendQRDialog( |
169 | | - qrBitmap = sendScreenState.qrBitmap, |
170 | | - fileCount = sendScreenState.files.size, |
171 | | - copyString = sendScreenState.copyString, |
172 | | - onDismiss = { }, |
173 | | - onCancel = {}, |
174 | | - ) |
175 | | - } |
176 | 125 | } |
177 | 126 | } |
178 | 127 |
|
179 | | -private fun copyToClipboard( |
180 | | - context: Context, |
181 | | - text: String, |
182 | | - label: String = "Transfer Info", |
183 | | -) { |
184 | | - val clipboardManager = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager |
185 | | - val clipData = ClipData.newPlainText(label, text) |
186 | | - clipboardManager.setPrimaryClip(clipData) |
187 | | -} |
188 | | - |
189 | | -@Composable |
190 | | -private fun SendQRDialog( |
191 | | - qrBitmap: Bitmap, |
192 | | - fileCount: Int, |
193 | | - copyString: String?, |
194 | | - onDismiss: () -> Unit, |
195 | | - onCancel: () -> Unit, |
196 | | -) { |
197 | | - val context = LocalContext.current |
198 | | - val scope = rememberCoroutineScope() |
199 | | - var showCopySuccess by remember { mutableStateOf(false) } |
200 | | - |
201 | | - AlertDialog( |
202 | | - onDismissRequest = onDismiss, |
203 | | - title = { |
204 | | - Row( |
205 | | - verticalAlignment = Alignment.CenterVertically, |
206 | | - horizontalArrangement = Arrangement.spacedBy(12.dp), |
207 | | - ) { |
208 | | - Icon( |
209 | | - TablerIcons.Qrcode, |
210 | | - contentDescription = null, |
211 | | - modifier = Modifier.size(24.dp), |
212 | | - tint = MaterialTheme.colorScheme.primary, |
213 | | - ) |
214 | | - Text( |
215 | | - "QR Code for Transfer", |
216 | | - style = |
217 | | - MaterialTheme.typography.headlineSmall.copy( |
218 | | - fontWeight = FontWeight.Bold, |
219 | | - ), |
220 | | - ) |
221 | | - } |
222 | | - }, |
223 | | - text = { |
224 | | - Column( |
225 | | - horizontalAlignment = Alignment.CenterHorizontally, |
226 | | - ) { |
227 | | - Surface( |
228 | | - shape = RoundedCornerShape(16.dp), |
229 | | - color = Color.White, |
230 | | - shadowElevation = 4.dp, |
231 | | - ) { |
232 | | - Image( |
233 | | - bitmap = qrBitmap.asImageBitmap(), |
234 | | - contentDescription = "QR code for file transfer", |
235 | | - modifier = |
236 | | - Modifier |
237 | | - .size(220.dp) |
238 | | - .padding(16.dp), |
239 | | - ) |
240 | | - } |
241 | | - |
242 | | - Spacer(modifier = Modifier.height(20.dp)) |
243 | | - |
244 | | - Text( |
245 | | - text = "Show this QR code to the receiver", |
246 | | - style = |
247 | | - MaterialTheme.typography.bodyLarge.copy( |
248 | | - fontWeight = FontWeight.Medium, |
249 | | - ), |
250 | | - color = MaterialTheme.colorScheme.onSurfaceVariant, |
251 | | - textAlign = TextAlign.Center, |
252 | | - ) |
253 | | - |
254 | | - Spacer(modifier = Modifier.height(8.dp)) |
255 | | - |
256 | | - Text( |
257 | | - text = "$fileCount file${if (fileCount != 1) "s" else ""} ready to transfer", |
258 | | - style = MaterialTheme.typography.bodyMedium, |
259 | | - color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.8f), |
260 | | - textAlign = TextAlign.Center, |
261 | | - ) |
262 | | - |
263 | | - // Copy functionality |
264 | | - if (!copyString.isNullOrEmpty()) { |
265 | | - Spacer(modifier = Modifier.height(16.dp)) |
266 | | - |
267 | | - SendButton( |
268 | | - onClick = { |
269 | | - copyToClipboard(context, copyString, "Transfer Code") |
270 | | - showCopySuccess = true |
271 | | - scope.launch { |
272 | | - delay(2000) |
273 | | - showCopySuccess = false |
274 | | - } |
275 | | - }, |
276 | | - variant = ButtonVariant.Secondary, |
277 | | - size = ButtonSize.Medium, |
278 | | - ) { |
279 | | - Icon( |
280 | | - TablerIcons.Copy, |
281 | | - contentDescription = null, |
282 | | - modifier = Modifier.size(16.dp), |
283 | | - ) |
284 | | - Spacer(modifier = Modifier.width(8.dp)) |
285 | | - Text( |
286 | | - if (showCopySuccess) "Copied!" else "Copy Code", |
287 | | - fontWeight = FontWeight.Medium, |
288 | | - ) |
289 | | - } |
290 | | - |
291 | | - if (showCopySuccess) { |
292 | | - Spacer(modifier = Modifier.height(8.dp)) |
293 | | - Text( |
294 | | - text = "Transfer code copied to clipboard", |
295 | | - style = MaterialTheme.typography.bodySmall, |
296 | | - color = MaterialTheme.colorScheme.primary, |
297 | | - textAlign = TextAlign.Center, |
298 | | - ) |
299 | | - } |
300 | | - } |
301 | | - |
302 | | - Spacer(modifier = Modifier.height(16.dp)) |
303 | | - |
304 | | - Row( |
305 | | - verticalAlignment = Alignment.CenterVertically, |
306 | | - horizontalArrangement = Arrangement.spacedBy(8.dp), |
307 | | - ) { |
308 | | - SendLoadingIndicator() |
309 | | - Text( |
310 | | - text = "Waiting for receiver to scan...", |
311 | | - style = |
312 | | - MaterialTheme.typography.bodyMedium.copy( |
313 | | - fontWeight = FontWeight.Medium, |
314 | | - ), |
315 | | - color = MaterialTheme.colorScheme.primary, |
316 | | - ) |
317 | | - } |
318 | | - } |
319 | | - }, |
320 | | - confirmButton = {}, |
321 | | - dismissButton = { |
322 | | - TextButton( |
323 | | - onClick = onCancel, |
324 | | - shape = RoundedCornerShape(8.dp), |
325 | | - ) { |
326 | | - Text( |
327 | | - "Cancel Transfer", |
328 | | - fontWeight = FontWeight.Medium, |
329 | | - ) |
330 | | - } |
331 | | - }, |
332 | | - shape = RoundedCornerShape(20.dp), |
333 | | - ) |
334 | | -} |
335 | | - |
336 | 128 | private fun SendException.toMessage() = |
337 | 129 | when (this) { |
338 | 130 | SendException.TransferInitializationFailed -> "Transfer initialization failed" |
|
0 commit comments