Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor splash screen and reimplement existing deep links #347

Merged
merged 22 commits into from
Feb 28, 2025
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
ee22f8d
Migrate custom splash screen to SplashScreen API
markocic Feb 26, 2025
60bbd29
Handle primal profile deep links
markocic Feb 26, 2025
36db369
Handle primal note deep links
markocic Feb 26, 2025
da49a5c
Delete empty line
markocic Feb 26, 2025
6c43510
Handle primal article deep links
markocic Feb 26, 2025
4f50509
Handle nwc deep links
markocic Feb 26, 2025
1251265
nip19: Allow null kind in nevents
markocic Feb 26, 2025
6c97485
Handle primal nwc deep links
markocic Feb 26, 2025
7cdf19f
Handle advanced search deep links
markocic Feb 26, 2025
7a11eeb
Remove old deep linking implementation
markocic Feb 26, 2025
510215a
Handle ACTION_SEND and ACTION_SEND_MULTIPLE action intents
markocic Feb 28, 2025
a8f781c
Update detekt baseline
markocic Feb 28, 2025
ba55f40
Improve splash screen init & change background to black
AleksandarIlic Feb 28, 2025
ae783df
Handle all primal static deep links
markocic Feb 28, 2025
ca86537
Implement fetchProfileId endpoint
markocic Feb 28, 2025
a1eab37
Handle primalName deep links
markocic Feb 28, 2025
56e6a71
logout: let ViewModel decide how to navigate after successful logout
markocic Feb 28, 2025
c5e1123
Handle deep links of articles by verified users
markocic Feb 28, 2025
424377f
Fix formatting
AleksandarIlic Feb 28, 2025
1aa2002
Do not throw error for invalid event in ThreadViewModel
AleksandarIlic Feb 28, 2025
27777c4
Make callback nullable in PrimalWalletNwc;
AleksandarIlic Feb 28, 2025
24fbdd7
Improve LinkPrimalWalletViewModel
AleksandarIlic Feb 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions app/detekt-baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
<ID>CyclomaticComplexMethod:NotificationsSettingsScreen.kt$@Composable private fun NotificationType.toTitle(): String</ID>
<ID>CyclomaticComplexMethod:OnboardingViewModel.kt$OnboardingViewModel$private fun observeEvents()</ID>
<ID>CyclomaticComplexMethod:PremiumOrderHistoryScreen.kt$@Composable private fun SubscriptionHeader( modifier: Modifier, state: PremiumOrderHistoryContract.UiState, onExtendSubscription: (primalName: String) -&gt; Unit, onCancelSubscription: () -&gt; Unit, )</ID>
<ID>CyclomaticComplexMethod:PrimalAppNavigation.kt$@OptIn(ExperimentalSharedTransitionApi::class) @Composable fun SharedTransitionScope.PrimalAppNavigation()</ID>
<ID>CyclomaticComplexMethod:ReceivePaymentScreen.kt$@Composable private fun ReceivePaymentViewer( paddingValues: PaddingValues, state: UiState, onBuyPremium: () -&gt; Unit, onCopyClick: () -&gt; Unit, onEditClick: () -&gt; Unit, )</ID>
<ID>CyclomaticComplexMethod:TransactionEditor.kt$@Composable private fun TransactionHeaderColumn( modifier: Modifier, uiMode: UiDensityMode, state: CreateTransactionContract.UiState, keyboardVisible: Boolean, onAmountClick: () -&gt; Unit, )</ID>
<ID>CyclomaticComplexMethod:TransactionEditor.kt$@ExperimentalMaterial3Api @ExperimentalComposeUiApi @Composable fun TransactionEditor( modifier: Modifier, state: CreateTransactionContract.UiState, paddingValues: PaddingValues, eventPublisher: (CreateTransactionContract.UiEvent) -&gt; Unit, onCancelClick: () -&gt; Unit, )</ID>
Expand Down Expand Up @@ -69,7 +68,7 @@
<ID>LongMethod:PremiumOrderHistoryScreen.kt$@Composable private fun SubscriptionHeader( modifier: Modifier, state: PremiumOrderHistoryContract.UiState, onExtendSubscription: (primalName: String) -&gt; Unit, onCancelSubscription: () -&gt; Unit, )</ID>
<ID>LongMethod:PremiumOrderHistoryScreen.kt$@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class) @Composable private fun PremiumOrderHistoryScreen( state: PremiumOrderHistoryContract.UiState, eventPublisher: (PremiumOrderHistoryContract.UiEvent) -&gt; Unit, onExtendSubscription: (primalName: String) -&gt; Unit, onClose: () -&gt; Unit, )</ID>
<ID>LongMethod:PremiumPurchaseStage.kt$@ExperimentalMaterial3Api @Composable fun PremiumPurchaseStage( state: PremiumBuyingContract.UiState, onBack: () -&gt; Unit, onLearnMoreClick: () -&gt; Unit, eventPublisher: (PremiumBuyingContract.UiEvent) -&gt; Unit, )</ID>
<ID>LongMethod:PrimalAppNavigation.kt$@OptIn(ExperimentalSharedTransitionApi::class) @Composable fun SharedTransitionScope.PrimalAppNavigation()</ID>
<ID>LongMethod:PrimalAppNavigation.kt$@OptIn(ExperimentalSharedTransitionApi::class) @Composable fun SharedTransitionScope.PrimalAppNavigation(startDestination: String)</ID>
<ID>LongMethod:PrimalDrawerScaffold.kt$@OptIn(ExperimentalMaterial3Api::class) @Composable fun PrimalDrawerScaffold( modifier: Modifier = Modifier, drawerState: DrawerState, activeDestination: PrimalTopLevelDestination, onPrimaryDestinationChanged: (PrimalTopLevelDestination) -&gt; Unit, onDrawerDestinationClick: (DrawerScreenDestination) -&gt; Unit, onDrawerQrCodeClick: () -&gt; Unit, badges: Badges = Badges(), onActiveDestinationClick: () -&gt; Unit = {}, topAppBarState: TopAppBarState = remember { TopAppBarState( initialHeightOffsetLimit = -Float.MAX_VALUE, initialHeightOffset = 0f, initialContentOffset = 0f, ) }, topAppBar: @Composable (TopAppBarScrollBehavior?) -&gt; Unit = {}, content: @Composable (PaddingValues) -&gt; Unit = {}, floatingNewDataHost: @Composable () -&gt; Unit = {}, floatingActionButton: @Composable () -&gt; Unit = {}, snackbarHost: @Composable () -&gt; Unit = {}, focusModeEnabled: Boolean = true, accountSwitcherCallbacks: AccountSwitcherCallbacks, )</ID>
<ID>LongMethod:PrimalNavigationBar.kt$@Composable fun PrimalNavigationBarLightningBolt( modifier: Modifier = Modifier, activeDestination: PrimalTopLevelDestination, onTopLevelDestinationChanged: (PrimalTopLevelDestination) -&gt; Unit, onActiveDestinationClick: (() -&gt; Unit)? = null, badges: Badges = Badges(), )</ID>
<ID>LongMethod:PrimalTopAppBar.kt$@OptIn(ExperimentalFoundationApi::class) @ExperimentalMaterial3Api @Composable fun PrimalTopAppBar( modifier: Modifier = Modifier, title: String = "", titleFontWeight: FontWeight? = null, subtitle: String? = null, titleTrailingIcon: ImageVector? = null, textColor: Color = LocalContentColor.current, navigationIcon: ImageVector? = null, navigationIconTintColor: Color = LocalContentColor.current, navigationIconContentDescription: String? = null, onNavigationIconClick: (() -&gt; Unit)? = null, autoCloseKeyboardOnNavigationIconClick: Boolean = true, avatarCdnImage: CdnImage? = null, legendaryCustomization: LegendaryCustomization? = null, actions: (@Composable RowScope.() -&gt; Unit)? = null, showDivider: Boolean = true, scrollBehavior: TopAppBarScrollBehavior? = null, onTitleClick: (() -&gt; Unit)? = null, onTitleLongClick: (() -&gt; Unit)? = null, colors: TopAppBarColors = TopAppBarDefaults.centerAlignedTopAppBarColors( containerColor = AppTheme.colorScheme.surface, scrolledContainerColor = AppTheme.colorScheme.surface, ), footer: @Composable () -&gt; Unit = {}, )</ID>
Expand Down Expand Up @@ -99,6 +98,7 @@
<ID>LongParameterList:NostrResources.kt$( refNote: PostData?, refPostAuthor: ProfileData?, cdnResources: Map&lt;String, CdnResource&gt;, linkPreviews: Map&lt;String, LinkPreviewData&gt;, videoThumbnails: Map&lt;String, String&gt;, eventIdToNostrEvent: Map&lt;String, NostrEvent&gt;, postIdToPostDataMap: Map&lt;String, PostData&gt;, articleIdToArticle: Map&lt;String, ArticleData&gt;, profileIdToProfileDataMap: Map&lt;String, ProfileData&gt;, )</ID>
<ID>LongParameterList:NoteEditorViewModel.kt$NoteEditorViewModel$( @Assisted private val args: NoteEditorArgs, private val fileAnalyser: FileAnalyser, private val activeAccountStore: ActiveAccountStore, private val feedRepository: FeedRepository, private val notePublishHandler: NotePublishHandler, private val attachmentRepository: AttachmentsRepository, private val highlightRepository: HighlightRepository, private val exploreRepository: ExploreRepository, private val profileRepository: ProfileRepository, private val articleRepository: ArticleRepository, private val relayRepository: RelayRepository, private val relayHintsRepository: RelayHintsRepository, )</ID>
<ID>LongParameterList:ProfileDetailsViewModel.kt$ProfileDetailsViewModel$( savedStateHandle: SavedStateHandle, private val dispatcherProvider: CoroutineDispatcherProvider, private val activeAccountStore: ActiveAccountStore, private val feedsRepository: FeedsRepository, private val profileRepository: ProfileRepository, private val mutedUserRepository: MutedUserRepository, private val zapHandler: ZapHandler, )</ID>
<ID>LongParameterList:ProfileRepository.kt$ProfileRepository$( private val dispatchers: CoroutineDispatcherProvider, private val database: PrimalDatabase, private val usersApi: UsersApi, private val wellKnownApi: WellKnownApi, private val userRepository: UserRepository, private val userAccountFetcher: UserAccountFetcher, private val nostrPublisher: NostrPublisher, )</ID>
<ID>LongParameterList:SubscriptionsManager.kt$SubscriptionsManager$( dispatcherProvider: CoroutineDispatcherProvider, private val activeAccountStore: ActiveAccountStore, private val userRepository: UserRepository, private val nostrNotary: NostrNotary, private val appConfigProvider: AppConfigProvider, @PrimalCacheApiClient private val cacheApiClient: PrimalApiClient, @PrimalWalletApiClient private val walletApiClient: PrimalApiClient, )</ID>
<ID>LongParameterList:TransactionDetailsViewModel.kt$TransactionDetailsViewModel$( savedStateHandle: SavedStateHandle, private val dispatcherProvider: CoroutineDispatcherProvider, private val activeAccountStore: ActiveAccountStore, private val walletRepository: WalletRepository, private val feedRepository: FeedRepository, private val articleRepository: ArticleRepository, private val exchangeRateHandler: ExchangeRateHandler, )</ID>
<ID>LongParameterList:UserDataUpdater.kt$UserDataUpdater$( @Assisted val userId: String, private val settingsRepository: SettingsRepository, private val userRepository: UserRepository, private val walletRepository: WalletRepository, private val relayRepository: RelayRepository, private val bookmarksRepository: BookmarksRepository, private val premiumRepository: PremiumRepository, )</ID>
Expand Down
154 changes: 153 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,130 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>

<intent-filter
android:autoVerify="true"
android:label="Primal Home">
<action android:name="android.intent.action.VIEW" />

<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<data android:scheme="https"/>
<data android:host="primal.net"/>
</intent-filter>

<intent-filter
android:autoVerify="true"
android:label="Primal Home">
<action android:name="android.intent.action.VIEW" />

<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<data
android:host="primal.net"
android:pathPrefix="/home"
android:scheme="https" />
</intent-filter>

<intent-filter
android:autoVerify="true"
android:label="Primal Reads">
<action android:name="android.intent.action.VIEW" />

<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<data
android:host="primal.net"
android:pathPrefix="/reads"
android:scheme="https" />
</intent-filter>

<intent-filter
android:autoVerify="true"
android:label="Primal Notifications">
<action android:name="android.intent.action.VIEW" />

<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<data
android:host="primal.net"
android:pathPrefix="/notifications"
android:scheme="https" />
</intent-filter>

<intent-filter
android:autoVerify="true"
android:label="Primal Explore">
<action android:name="android.intent.action.VIEW" />

<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<data
android:host="primal.net"
android:pathPrefix="/explore"
android:scheme="https" />
</intent-filter>

<intent-filter
android:autoVerify="true"
android:label="Primal DMs">
<action android:name="android.intent.action.VIEW" />

<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<data
android:host="primal.net"
android:pathPrefix="/dms"
android:scheme="https" />
</intent-filter>

<intent-filter
android:autoVerify="true"
android:label="Primal Bookmarks">
<action android:name="android.intent.action.VIEW" />

<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<data
android:host="primal.net"
android:pathPrefix="/bookmarks"
android:scheme="https" />
</intent-filter>

<intent-filter
android:autoVerify="true"
android:label="Primal Premium">
<action android:name="android.intent.action.VIEW" />

<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<data
android:host="primal.net"
android:pathPrefix="/premium"
android:scheme="https" />
</intent-filter>

<intent-filter
android:autoVerify="true"
android:label="Primal Legends">
<action android:name="android.intent.action.VIEW" />

<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<data
android:host="primal.net"
android:pathPrefix="/legends"
android:scheme="https" />
</intent-filter>

<intent-filter
android:autoVerify="true"
android:label="Primal Note">
Expand Down Expand Up @@ -75,6 +199,20 @@
android:scheme="https" />
</intent-filter>

<intent-filter
android:autoVerify="true"
android:label="Primal Article">
<action android:name="android.intent.action.VIEW" />

<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<data
android:host="primal.net"
android:pathPrefix="/.+/.+"
android:scheme="https" />
</intent-filter>

<intent-filter
android:autoVerify="true"
android:label="Primal Profile">
Expand All @@ -89,6 +227,20 @@
android:scheme="https" />
</intent-filter>

<intent-filter
android:autoVerify="true"
android:label="Primal Profile">
<action android:name="android.intent.action.VIEW" />

<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<data
android:host="primal.net"
android:pathPrefix="/.+"
android:scheme="https" />
</intent-filter>

<intent-filter
android:autoVerify="true"
android:label="Advanced Search">
Expand All @@ -99,7 +251,7 @@

<data
android:host="primal.net"
android:pathPrefix="/asearch/"
android:pathPrefix="/search/"
android:scheme="https" />
</intent-filter>

Expand Down
13 changes: 10 additions & 3 deletions app/src/main/kotlin/net/primal/android/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package net.primal.android
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.compose.animation.ExperimentalSharedTransitionApi
import androidx.compose.animation.SharedTransitionLayout
import androidx.compose.material3.ExperimentalMaterial3Api
Expand All @@ -24,6 +25,7 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import net.primal.android.core.compose.ApplyEdgeToEdge
import net.primal.android.navigation.PrimalAppNavigation
import net.primal.android.navigation.splash.SplashViewModel
import net.primal.android.theme.AppTheme
import net.primal.android.theme.PrimalTheme
import net.primal.android.theme.active.ActiveThemeStore
Expand All @@ -41,11 +43,15 @@ class MainActivity : FragmentActivity() {
@Inject
lateinit var activeAccountStore: ActiveAccountStore

lateinit var primalTheme: PrimalTheme
private lateinit var primalTheme: PrimalTheme

private val splashViewModel: SplashViewModel by viewModels()

@OptIn(ExperimentalMaterial3Api::class, ExperimentalSharedTransitionApi::class)
override fun onCreate(savedInstanceState: Bundle?) {
installSplashScreen()
installSplashScreen().apply {
setKeepOnScreenCondition { !splashViewModel.isAuthCheckComplete.value }
}
super.onCreate(savedInstanceState)
observeThemeChanges()
primalTheme = savedInstanceState.restoreOrDefaultPrimalTheme()
Expand Down Expand Up @@ -75,8 +81,9 @@ class MainActivity : FragmentActivity() {
) {
ApplyEdgeToEdge()

val isLoggedIn = splashViewModel.isLoggedIn.collectAsState()
SharedTransitionLayout {
PrimalAppNavigation()
PrimalAppNavigation(startDestination = if (isLoggedIn.value) "home" else "welcome")
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ package net.primal.android.auth.logout
interface LogoutContract {

sealed class UiEvent {
object LogoutConfirmed : UiEvent()
data object LogoutConfirmed : UiEvent()
}

sealed class SideEffect {
data object UserAccountLogoutSuccessful : SideEffect()
data object ActiveAccountLogoutSuccessful : SideEffect()
data object Close : SideEffect()
data object NavigateToWelcome : SideEffect()
data object NavigateToHome : SideEffect()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,28 @@ fun LogoutScreen(
viewModel: LogoutViewModel,
onClose: () -> Unit,
navigateToHome: () -> Unit,
navigateToWelcome: () -> Unit,
) {
LaunchedEffect(viewModel, viewModel.effects) {
viewModel.effects.collect {
when (it) {
LogoutContract.SideEffect.UserAccountLogoutSuccessful -> onClose()
LogoutContract.SideEffect.ActiveAccountLogoutSuccessful -> {
LogoutContract.SideEffect.NavigateToHome -> {
onClose()
navigateToHome()
}
LogoutContract.SideEffect.NavigateToWelcome -> {
onClose()
navigateToWelcome()
}

LogoutContract.SideEffect.Close -> onClose()
}
}
}

LogoutScreen(
onClose = onClose,
onLogoutRequested = {
viewModel.setEvent(LogoutContract.UiEvent.LogoutConfirmed)
},
onLogoutRequested = { viewModel.setEvent(LogoutContract.UiEvent.LogoutConfirmed) },
)
}

Expand Down
Loading