11package com.sameerasw.airsync.presentation.ui.activities
22
3+ import android.content.Intent
34import android.graphics.Color
45import android.graphics.drawable.ColorDrawable
56import android.os.Bundle
@@ -47,10 +48,13 @@ import androidx.compose.runtime.setValue
4748import androidx.compose.ui.Alignment
4849import androidx.compose.ui.Modifier
4950import androidx.compose.ui.layout.ContentScale
51+ import androidx.compose.ui.platform.LocalContext
5052import androidx.compose.ui.res.painterResource
5153import androidx.compose.ui.res.stringResource
5254import androidx.compose.ui.tooling.preview.Preview
5355import androidx.compose.ui.unit.dp
56+ import androidx.lifecycle.viewmodel.compose.viewModel
57+ import com.sameerasw.airsync.MainActivity
5458import com.sameerasw.airsync.R
5559import com.sameerasw.airsync.data.local.DataStoreManager
5660import com.sameerasw.airsync.domain.model.ConnectedDevice
@@ -59,6 +63,8 @@ import com.sameerasw.airsync.ui.theme.AirSyncTheme
5963import com.sameerasw.airsync.utils.ClipboardSyncManager
6064import com.sameerasw.airsync.utils.ClipboardUtil
6165import com.sameerasw.airsync.utils.DevicePreviewResolver
66+ import com.sameerasw.airsync.utils.ShortcutUtil
67+ import com.sameerasw.airsync.utils.WebSocketUtil
6268import kotlinx.coroutines.delay
6369
6470class ClipboardActionActivity : ComponentActivity () {
@@ -93,7 +99,7 @@ class ClipboardActionActivity : ComponentActivity() {
9399 AirSyncTheme (pitchBlackTheme = uiState.isPitchBlackThemeEnabled) {
94100 ClipboardActionScreen (
95101 hasWindowFocus = _windowFocus .value,
96- isShareAction = intent?.action == android.content. Intent . ACTION_SEND ,
102+ shortcutAction = intent?.action,
97103 onFinished = { finish() }
98104 )
99105 }
@@ -107,22 +113,23 @@ class ClipboardActionActivity : ComponentActivity() {
107113}
108114
109115@Composable
110- fun ClipboardActionScreen (
116+ private fun ClipboardActionScreen (
111117 hasWindowFocus : Boolean ,
112- isShareAction : Boolean ,
118+ shortcutAction : String? ,
113119 onFinished : () -> Unit
114120) {
115- val context = androidx.compose.ui.platform.LocalContext .current
116- val dataStoreManager = remember { DataStoreManager .getInstance(context) }
117- val connectedDevice by dataStoreManager.getLastConnectedDevice().collectAsState(initial = null )
121+ val context = LocalContext .current
122+ val viewModel: AirSyncViewModel = viewModel { AirSyncViewModel .create(context) }
123+ val uiStateByViewModel by viewModel.uiState.collectAsState()
124+ val connectedDevice = uiStateByViewModel.lastConnectedDevice
118125
119126 var uiState by remember { mutableStateOf<ClipboardUiState >(ClipboardUiState .Loading ) }
120127 var hasAttemptedSync by remember { mutableStateOf(false ) }
121128
122129 ClipboardActionScreenContent (
123130 uiState = uiState,
124131 connectedDevice = connectedDevice,
125- isShareAction = isShareAction ,
132+ shortcutAction = shortcutAction ,
126133 onFinished = onFinished
127134 )
128135
@@ -132,31 +139,78 @@ fun ClipboardActionScreen(
132139 delay(100 )
133140
134141 try {
135- // If this is a share action, extract text from intent
136- val activity = context as ? android.app.Activity
137- val intent = activity?.intent
138- val sharedText = if (isShareAction) {
139- intent?.getStringExtra(android.content.Intent .EXTRA_TEXT )
140- } else {
141- null
142- }
142+ when (shortcutAction) {
143+ ShortcutUtil .DASH_ACTION_LOCK -> {
144+ if (WebSocketUtil .isConnected()) {
145+ val json = org.json.JSONObject ()
146+ json.put(" type" , " remoteControl" )
147+ val data = org.json.JSONObject ()
148+ data.put(" action" , " lock_screen" )
149+ json.put(" data" , data)
150+ WebSocketUtil .sendMessage(json.toString())
151+ uiState = ClipboardUiState .Success
152+ } else {
153+ uiState = ClipboardUiState .Error (" Not connected" )
154+ }
155+ delay(1200 )
156+ onFinished()
157+ }
158+
159+ ShortcutUtil .DASH_ACTION_RECONNECT -> {
160+ val ds = DataStoreManager .getInstance(context)
161+ ds.setUserManuallyDisconnected(false )
162+ WebSocketUtil .requestAutoReconnect(context)
163+ uiState = ClipboardUiState .Success
164+ delay(1200 )
165+ onFinished()
166+ }
143167
144- // Fallback to clipboard only if not a share action or shared text is empty
145- val textToSync = sharedText ? : ClipboardUtil .getClipboardText(context)
168+ ShortcutUtil .DASH_ACTION_DISCONNECT -> {
169+ val ds = DataStoreManager .getInstance(context)
170+ ds.setUserManuallyDisconnected(true )
171+ WebSocketUtil .disconnect(context)
172+ uiState = ClipboardUiState .Success
173+ delay(1200 )
174+ onFinished()
175+ }
146176
147- if (! textToSync.isNullOrEmpty()) {
148- ClipboardSyncManager .syncTextToDesktop(textToSync)
149- uiState = ClipboardUiState .Success
150- delay(1200 )
151- onFinished()
152- } else {
153- uiState = ClipboardUiState .Error (
154- if (isShareAction) " Shared text empty" else " Clipboard empty"
155- )
156- delay(1500 )
157- onFinished()
177+ ShortcutUtil .DASH_ACTION_REMOTE -> {
178+ val mainIntent = Intent (context, MainActivity ::class .java).apply {
179+ this .action = ShortcutUtil .DASH_ACTION_REMOTE
180+ flags = Intent .FLAG_ACTIVITY_NEW_TASK or Intent .FLAG_ACTIVITY_CLEAR_TOP
181+ }
182+ context.startActivity(mainIntent)
183+ onFinished()
184+ }
185+
186+ else -> {
187+ // Default: Sync Clipboard or Shared Text
188+ val isShareAction = shortcutAction == android.content.Intent .ACTION_SEND
189+ val activity = context as ? android.app.Activity
190+ val intent = activity?.intent
191+ val sharedText = if (isShareAction) {
192+ intent?.getStringExtra(android.content.Intent .EXTRA_TEXT )
193+ } else {
194+ null
195+ }
196+
197+ val textToSync = sharedText ? : ClipboardUtil .getClipboardText(context)
198+
199+ if (! textToSync.isNullOrEmpty()) {
200+ ClipboardSyncManager .syncTextToDesktop(textToSync)
201+ uiState = ClipboardUiState .Success
202+ delay(1200 )
203+ onFinished()
204+ } else {
205+ uiState = ClipboardUiState .Error (
206+ if (isShareAction) " Shared text empty" else " Clipboard empty"
207+ )
208+ delay(1500 )
209+ onFinished()
210+ }
211+ }
158212 }
159- } catch (_ : Exception ) {
213+ } catch (e : Exception ) {
160214 uiState = ClipboardUiState .Error (" Failed" )
161215 delay(1500 )
162216 onFinished()
@@ -167,10 +221,10 @@ fun ClipboardActionScreen(
167221
168222@OptIn(ExperimentalAnimationApi ::class , ExperimentalMaterial3ExpressiveApi ::class )
169223@Composable
170- fun ClipboardActionScreenContent (
224+ private fun ClipboardActionScreenContent (
171225 uiState : ClipboardUiState ,
172226 connectedDevice : ConnectedDevice ? ,
173- isShareAction : Boolean ,
227+ shortcutAction : String? ,
174228 onFinished : () -> Unit
175229) {
176230 // Transparent background that dismisses on click
@@ -204,9 +258,16 @@ fun ClipboardActionScreenContent(
204258 tint = MaterialTheme .colorScheme.primary
205259 )
206260
207- // Device Name
261+ // Device Name / Action
262+ val label = when (shortcutAction) {
263+ ShortcutUtil .DASH_ACTION_LOCK -> " Lock Mac"
264+ ShortcutUtil .DASH_ACTION_DISCONNECT -> " Disconnected"
265+ ShortcutUtil .DASH_ACTION_RECONNECT -> " Reconnect"
266+ ShortcutUtil .DASH_ACTION_REMOTE -> " Opening Remote..."
267+ else -> connectedDevice?.name ? : stringResource(R .string.your_mac)
268+ }
208269 Text (
209- text = connectedDevice?.name ? : stringResource( R .string.your_mac) ,
270+ text = label ,
210271 style = MaterialTheme .typography.bodyLarge,
211272 color = MaterialTheme .colorScheme.onSurface
212273 )
@@ -251,11 +312,17 @@ fun ClipboardActionScreenContent(
251312
252313 else -> {
253314 // Default/Idle icon
315+ val iconPainter = when (shortcutAction) {
316+ ShortcutUtil .DASH_ACTION_LOCK -> painterResource(id = R .drawable.rounded_lock_24)
317+ ShortcutUtil .DASH_ACTION_DISCONNECT -> painterResource(id = R .drawable.rounded_mimo_disconnect_24)
318+ ShortcutUtil .DASH_ACTION_RECONNECT -> painterResource(id = R .drawable.rounded_devices_24)
319+ ShortcutUtil .DASH_ACTION_REMOTE -> painterResource(id = R .drawable.rounded_compare_arrows_24)
320+ ShortcutUtil .DASH_ACTION_CLIPBOARD -> painterResource(id = R .drawable.ic_clipboard_24)
321+ android.content.Intent .ACTION_SEND -> painterResource(id = R .drawable.rounded_sync_desktop_24)
322+ else -> painterResource(id = R .drawable.ic_clipboard_24)
323+ }
254324 Icon (
255- imageVector = if (isShareAction)
256- androidx.compose.material.icons.Icons .Rounded .ReceiptLong
257- else
258- androidx.compose.material.icons.Icons .Rounded .ContentPaste ,
325+ painter = iconPainter,
259326 contentDescription = " Sync" ,
260327 modifier = Modifier .size(24 .dp),
261328 tint = MaterialTheme .colorScheme.onSurfaceVariant
@@ -282,7 +349,7 @@ private fun ClipboardActionScreenPreviewLoading() {
282349 ClipboardActionScreenContent (
283350 uiState = ClipboardUiState .Loading ,
284351 connectedDevice = null ,
285- isShareAction = false ,
352+ shortcutAction = null ,
286353 onFinished = {})
287354 }
288355}
@@ -294,7 +361,7 @@ private fun ClipboardActionScreenPreviewSuccess() {
294361 ClipboardActionScreenContent (
295362 uiState = ClipboardUiState .Success ,
296363 connectedDevice = null ,
297- isShareAction = false ,
364+ shortcutAction = null ,
298365 onFinished = {})
299366 }
300367}
@@ -306,7 +373,7 @@ private fun ClipboardActionScreenPreviewError() {
306373 ClipboardActionScreenContent (
307374 uiState = ClipboardUiState .Error (" Failed to sync" ),
308375 connectedDevice = null ,
309- isShareAction = false ,
376+ shortcutAction = null ,
310377 onFinished = {})
311378 }
312379}
0 commit comments