๐Ÿ”— Redirect Bluesky links to your preferred client
3
fork

Configure Feed

Select the types of activity you want to include in your feed.

Fix installation checks and launching on Android 13

+49 -18
+1 -4
lemmyredirect/src/main/java/dev/zwander/lemmyredirect/util/LaunchStrategy.kt
··· 79 79 LaunchIntentCreator.ComponentIntentCreator.ViewIntentCreator( 80 80 pkg = "com.liftoffapp.liftoff", 81 81 component = "com.liftoffapp.liftoff.MainActivity", 82 - transformUrl = { url -> 83 - url.replace("https://", "liftoff://") 84 - .replace("http://", "liftoff://") 85 - }, 82 + scheme = "liftoff", 86 83 ), 87 84 ) 88 85 }
+6
mastodonredirect/src/main/java/dev/zwander/mastodonredirect/util/LaunchStrategy.kt
··· 2 2 3 3 package dev.zwander.mastodonredirect.util 4 4 5 + import android.content.Context 5 6 import androidx.annotation.Keep 6 7 import androidx.annotation.StringRes 7 8 import dev.zwander.mastodonredirect.R ··· 79 80 LaunchIntentCreator.ComponentIntentCreator.ViewIntentCreator( 80 81 pkg = "com.xmflsct.app.tooot", 81 82 component = "com.xmflsct.app.tooot.MainActivity", 83 + scheme = "tooot", 82 84 ), 83 85 ) 84 86 } ··· 170 172 @Keep 171 173 data object ElkCanary : 172 174 ElkBase("ELK_CANARY", dev.zwander.shared.R.string.canary, "https://main.elk.zone") 175 + 176 + override fun Context.isInstalled(): Boolean { 177 + return true 178 + } 173 179 } 174 180 } 175 181
+4 -8
shared/src/main/java/dev/zwander/shared/LaunchIntentCreator.kt
··· 6 6 import android.net.Uri 7 7 8 8 sealed interface LaunchIntentCreator { 9 - val transformUrl: (String) -> String 10 - 11 9 fun Context.createIntents(url: String): List<Intent> 12 10 13 11 sealed interface ComponentIntentCreator : LaunchIntentCreator { ··· 17 15 data class ViewIntentCreator( 18 16 override val pkg: String, 19 17 override val component: String, 20 - override val transformUrl: (String) -> String = { it }, 18 + val scheme: String = "https", 21 19 ) : ComponentIntentCreator { 22 20 override fun Context.createIntents(url: String): List<Intent> { 23 21 return listOf( ··· 25 23 pkg = pkg, 26 24 component = component, 27 25 url = url, 26 + scheme = scheme, 28 27 ), 29 28 ) 30 29 } ··· 33 32 data class ShareIntentCreator( 34 33 override val pkg: String, 35 34 override val component: String, 36 - override val transformUrl: (String) -> String = { it }, 35 + val type: String = "*/*", 37 36 ) : ComponentIntentCreator { 38 37 override fun Context.createIntents(url: String): List<Intent> { 39 38 return listOf( ··· 41 40 pkg = pkg, 42 41 component = component, 43 42 url = url, 43 + type = type, 44 44 ), 45 45 ) 46 46 } ··· 49 49 50 50 data class BaseUrlIntentCreator( 51 51 val baseUrl: String, 52 - override val transformUrl: (String) -> String = { it }, 53 52 ) : LaunchIntentCreator { 54 53 override fun Context.createIntents(url: String): List<Intent> { 55 54 return listOf(Intent(Intent.ACTION_VIEW, Uri.parse("$baseUrl/$url"))) ··· 57 56 } 58 57 59 58 data class CustomIntentCreator( 60 - override val transformUrl: (String) -> String = { it }, 61 59 val creator: Context.(url: String) -> List<Intent>, 62 60 ) : LaunchIntentCreator { 63 61 override fun Context.createIntents(url: String): List<Intent> { ··· 69 67 val components: List<ComponentName>, 70 68 val launchAction: String, 71 69 ) : LaunchIntentCreator { 72 - override val transformUrl: (String) -> String = { it } 73 - 74 70 override fun Context.createIntents(url: String): List<Intent> { 75 71 return components.map { cmp -> 76 72 Intent(launchAction).apply {
+29 -4
shared/src/main/java/dev/zwander/shared/LaunchStrategy.kt
··· 4 4 import android.content.Context 5 5 import android.content.Intent 6 6 import androidx.annotation.StringRes 7 + import androidx.compose.runtime.Composable 8 + import androidx.compose.runtime.getValue 9 + import androidx.compose.runtime.mutableStateOf 10 + import androidx.compose.runtime.remember 11 + import androidx.compose.runtime.setValue 12 + import androidx.compose.ui.platform.LocalContext 13 + import androidx.lifecycle.Lifecycle 14 + import dev.zwander.shared.util.LifecycleEffect 7 15 import kotlin.reflect.KClass 8 16 9 17 /** ··· 31 39 return with (intentCreator) { createIntents(url) } 32 40 } 33 41 34 - fun Context.isInstalled(): Boolean { 35 - val intents = createIntents("https://") 42 + @Composable 43 + fun rememberIsInstalled(): Boolean { 44 + val context = LocalContext.current 45 + 46 + var isInstalled by remember { 47 + mutableStateOf(context.isInstalled()) 48 + } 49 + 50 + LifecycleEffect(Lifecycle.State.RESUMED) { 51 + isInstalled = context.isInstalled() 52 + } 36 53 37 - return intents.any { 38 - packageManager.queryIntentActivities(it, 0).isNotEmpty() 54 + return isInstalled 55 + } 56 + 57 + open fun Context.isInstalled(): Boolean { 58 + val pkg = createIntents("https://").firstOrNull()?.`package` ?: return false 59 + 60 + return try { 61 + packageManager.getApplicationInfo(pkg, 0) != null 62 + } catch (e: Exception) { 63 + false 39 64 } 40 65 } 41 66 }
+1 -1
shared/src/main/java/dev/zwander/shared/components/AppChooserLayout.kt
··· 186 186 selectedStrategy = selectedStrategy, 187 187 onStrategySelected = onStrategySelected, 188 188 modifier = Modifier.weight(1f), 189 - enabled = with (child) { context.isInstalled() }, 189 + enabled = child.rememberIsInstalled(), 190 190 ) 191 191 } 192 192 }
+8 -1
shared/src/main/java/dev/zwander/shared/util/BaseLaunchStrategyUtils.kt
··· 101 101 componentPkg: String = pkg, 102 102 component: String, 103 103 url: String, 104 + scheme: String = "https", 104 105 ): Intent { 105 - return Intent(Intent.ACTION_VIEW, Uri.parse(url)).apply { 106 + val originalUri = Uri.parse(url) 107 + val newUri = Uri.parse(url.replace("${originalUri.scheme}://", "${scheme}://")) 108 + 109 + return Intent(Intent.ACTION_VIEW, newUri).apply { 106 110 addCategory(Intent.CATEGORY_DEFAULT) 107 111 addCategory(Intent.CATEGORY_BROWSABLE) 108 112 ··· 118 122 componentPkg: String = pkg, 119 123 component: String, 120 124 url: String, 125 + type: String = "*/*", 121 126 ): Intent { 122 127 return Intent(Intent.ACTION_SEND).apply { 128 + addCategory(Intent.CATEGORY_DEFAULT) 123 129 putExtra(Intent.EXTRA_TEXT, url) 130 + this.type = type 124 131 125 132 `package` = pkg 126 133 this.component = ComponentName(