Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
57 changes: 38 additions & 19 deletions app/shared/forever-ui/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
plugins {
id("hedvig.android.library")
id("hedvig.multiplatform.library")
id("hedvig.multiplatform.library.android")
id("hedvig.gradle.plugin")
}

Expand All @@ -10,22 +11,40 @@ hedvig {
viewModels()
}

dependencies {
implementation(libs.androidx.other.core)
implementation(libs.apollo.normalizedCache)
implementation(libs.arrow.core)
implementation(libs.coroutines.core)
implementation(libs.jetbrains.lifecycle.runtime.compose)
implementation(projects.apolloCore)
implementation(projects.apolloOctopusPublic)
implementation(projects.composeUi)
implementation(projects.coreBuildConstants)
implementation(projects.coreCommonPublic)
implementation(projects.coreDemoMode)
implementation(projects.coreResources)
implementation(projects.coreUiData)
implementation(projects.designSystemHedvig)
implementation(projects.languageCore)
implementation(projects.moleculePublic)
implementation(projects.pullrefresh)
kotlin {
sourceSets {
commonMain.dependencies {
implementation(libs.apollo.api)
implementation(libs.apollo.normalizedCache)
implementation(libs.apollo.runtime)
implementation(libs.arrow.core)
implementation(libs.coroutines.core)
implementation(libs.jetbrains.compose.animation)
implementation(libs.jetbrains.compose.foundation)
implementation(libs.jetbrains.compose.runtime)
implementation(libs.jetbrains.compose.ui)
implementation(libs.jetbrains.compose.ui.tooling.preview)
implementation(libs.jetbrains.lifecycle.runtime.compose)
implementation(libs.uri.kmp)
implementation(projects.apolloCore)
implementation(projects.apolloOctopusPublic)
implementation(projects.composeUi)
implementation(projects.coreBuildConstants)
implementation(projects.coreCommonPublic)
implementation(projects.coreDemoMode)
implementation(projects.coreResources)
implementation(projects.coreUiData)
implementation(projects.designSystemHedvig)
implementation(projects.languageCore)
implementation(projects.moleculePublic)
implementation(projects.pullrefresh)
}
androidMain.dependencies {
implementation(libs.androidx.other.core)
}
jvmTest.dependencies {
implementation(libs.assertK)
implementation(libs.junit)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.hedvig.android.shared.foreverui.ui.ui

import android.content.Intent
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
import hedvig.resources.REFERRALS_SHARE_SHEET_TITLE
import hedvig.resources.Res
import org.jetbrains.compose.resources.stringResource

@Composable
internal actual fun rememberShareHandler(): (text: String) -> Unit {
val context = LocalContext.current
val shareSheetTitle = stringResource(Res.string.REFERRALS_SHARE_SHEET_TITLE)
return remember(context, shareSheetTitle) {
{ text ->
context.showShareSheet(shareSheetTitle) { intent ->
intent.putExtra(
Intent.EXTRA_TEXT,
text,
)
intent.type = "text/plain"
}
}
}
}

@Composable
internal actual fun rememberCopyToClipboard(): (text: String) -> Unit {
val context = LocalContext.current
return remember(context) {
{ text -> context.copyToClipboard(text) }
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.hedvig.android.shared.foreverui.ui.ui

import android.content.Intent
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
Expand Down Expand Up @@ -35,7 +34,6 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.heading
Expand Down Expand Up @@ -86,7 +84,6 @@ import com.hedvig.android.shared.foreverui.ui.ui.ForeverUiState.Success
import hedvig.resources.FOREVER_TAB_MONTHLY_DISCOUNT
import hedvig.resources.OFFER_COST_AND_PREMIUM_PERIOD_ABBREVIATION
import hedvig.resources.REFERRALS_INFO_BUTTON_CONTENT_DESCRIPTION
import hedvig.resources.REFERRALS_SHARE_SHEET_TITLE
import hedvig.resources.REFERRAL_SMS_MESSAGE
import hedvig.resources.Res
import hedvig.resources.TAB_REFERRALS_TITLE
Expand All @@ -106,8 +103,7 @@ import org.jetbrains.compose.resources.stringResource
@Composable
fun ForeverDestination(viewModel: ForeverViewModel) {
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
val context = LocalContext.current
val shareSheetTitle = stringResource(Res.string.REFERRALS_SHARE_SHEET_TITLE)
val shareText = rememberShareHandler()
val coroutineScope = rememberCoroutineScope()
val resourceEnvironment = rememberResourceEnvironment()
ForeverScreen(
Expand All @@ -126,13 +122,7 @@ fun ForeverDestination(viewModel: ForeverViewModel) {
incentive.toString(),
viewModel.referralShareUrl(code),
)
context.showShareSheet(shareSheetTitle) { intent ->
intent.putExtra(
Intent.EXTRA_TEXT,
string,
)
intent.type = "text/plain"
}
shareText(string)
}
},
)
Expand Down Expand Up @@ -465,10 +455,10 @@ private fun ForeverScrollableContent(

@Composable
internal fun ReferralCodeCard(campaignCode: String, modifier: Modifier = Modifier) {
val context = LocalContext.current
val copyToClipboard = rememberCopyToClipboard()
HedvigBigCard(
onClick = {
context.copyToClipboard(campaignCode)
copyToClipboard(campaignCode)
},
enabled = true,
modifier = modifier.fillMaxWidth(),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.hedvig.android.shared.foreverui.ui.ui

import android.net.Uri
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
Expand All @@ -9,6 +8,7 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import arrow.core.raise.either
import com.eygraber.uri.Uri
import com.hedvig.android.core.buildconstants.HedvigBuildConstants
import com.hedvig.android.core.common.di.ActivityRetainedScope
import com.hedvig.android.core.common.di.HedvigViewModel
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.hedvig.android.shared.foreverui.ui.ui

import androidx.compose.runtime.Composable

@Composable
internal expect fun rememberShareHandler(): (text: String) -> Unit

@Composable
internal expect fun rememberCopyToClipboard(): (text: String) -> Unit
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.hedvig.android.shared.foreverui.ui.ui

import androidx.compose.runtime.Composable
import java.awt.Toolkit
import java.awt.datatransfer.StringSelection

/**
* There is no system share sheet on the JVM, so sharing puts the text on the system clipboard.
*/
@Composable
internal actual fun rememberShareHandler(): (text: String) -> Unit = ::copyToSystemClipboard

@Composable
internal actual fun rememberCopyToClipboard(): (text: String) -> Unit = ::copyToSystemClipboard

private fun copyToSystemClipboard(text: String) {
Toolkit.getDefaultToolkit().systemClipboard.setContents(StringSelection(text), null)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.hedvig.android.shared.foreverui.ui.ui

import assertk.assertThat
import assertk.assertions.isEqualTo
import com.eygraber.uri.Uri
import org.junit.Test

/**
* [ForeverViewModel.referralShareUrl] percent-encodes the referral code with [Uri.encode]. The expected values are what
* `android.net.Uri.encode` produces: letters, digits and `_-!.~'()*` stay as they are, everything else becomes UTF-8
* percent-encoded, and a space becomes `%20`.
*/
class ReferralCodeUrlEncodingTest {
@Test
fun `letters and digits are unchanged`() {
assertThat(Uri.encode("HEDV1G")).isEqualTo("HEDV1G")
assertThat(Uri.encode("abc123")).isEqualTo("abc123")
}

@Test
fun `unreserved punctuation is unchanged`() {
assertThat(Uri.encode("_-!.~'()*")).isEqualTo("_-!.~'()*")
}

@Test
fun `space becomes percent 20`() {
assertThat(Uri.encode("MY CODE")).isEqualTo("MY%20CODE")
}

@Test
fun `reserved characters are percent-encoded`() {
assertThat(Uri.encode("A+B")).isEqualTo("A%2BB")
assertThat(Uri.encode("A/B")).isEqualTo("A%2FB")
assertThat(Uri.encode("A&B")).isEqualTo("A%26B")
assertThat(Uri.encode("A%B")).isEqualTo("A%25B")
}

@Test
fun `non-ASCII characters are percent-encoded as UTF-8`() {
assertThat(Uri.encode("KÖD")).isEqualTo("K%C3%96D")
assertThat(Uri.encode("å")).isEqualTo("%C3%A5")
}
}
Loading