Skip to content

Commit

Permalink
InternalLinksOrigin Feature Flag (#5180)
Browse files Browse the repository at this point in the history
Task/Issue URL: https://app.asana.com/0/488551667048375/1208598624281034/f

### Description
Add FF for internal links origin

### Steps to test this PR

ℹ️ Wait for #5138 to be merged or merge the branch locally for testing

_MacOS, FF disabled_
- [ ] Install from branch
- [ ] Go to Settings > DuckDuckGo Mac Browser
- [ ] Tap on 'Share Link' button
- [ ] Check link doesn't have an origin attached to the link

_Windows, FF disabled_
- [ ] Install from branch
- [ ] Go to Settings > DuckDuckGo Windows Browser
- [ ] Tap on 'Share Link' button
- [ ] Check link doesn't have an origin attached to the link

_MacOS, FF enabled
- [ ] Change privacy-config link for `https://jsonblob.com/api/1279046082855034880`
- [ ] Install from branch
- [ ] Go to Settings > DuckDuckGo Mac Browser
- [ ] Tap on 'Share Link' button
- [ ] Check link have an origin attached to the link

_Windows, FF enabled
- [ ] Change privacy-config link for `https://jsonblob.com/api/1279046082855034880`
- [ ] Install from branch
- [ ] Go to Settings > DuckDuckGo Windows Browser
- [ ] Tap on 'Share Link' button
- [ ] Check link have an origin attached to the link

### No UI changes

Co-authored-by: Cristian Monforte <[email protected]>
  • Loading branch information
nalcalag and cmonfortep authored Oct 24, 2024
1 parent 19bb91a commit 53c190a
Show file tree
Hide file tree
Showing 12 changed files with 141 additions and 14 deletions.
4 changes: 4 additions & 0 deletions macos/macos-impl/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ dependencies {
testImplementation "androidx.test:runner:_"
testImplementation Testing.robolectric
testImplementation CashApp.turbine
testImplementation project(':feature-toggles-test')

coreLibraryDesugaring Android.tools.desugarJdkLibs
}
Expand All @@ -88,6 +89,9 @@ android {
includeAndroidResources = true
}
}
lint {
baseline = file("lint-baseline.xml")
}
compileOptions {
coreLibraryDesugaringEnabled = true
}
Expand Down
26 changes: 26 additions & 0 deletions macos/macos-impl/lint-baseline.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<issues format="6" by="lint 8.5.1" type="baseline" client="gradle" dependencies="false" name="AGP (8.5.1)" variant="all" version="8.5.1">

<issue
id="DenyListedApi"
message="If you find yourself using this API in production, you&apos;re doing something wrong!!"
errorLine1=" macOsDownloadLinkOrigin.self().setRawStoredState(State(enable = true))"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/test/java/com/duckduckgo/macos/impl/MacOsViewModelTest.kt"
line="55"
column="9"/>
</issue>

<issue
id="ContentDescription"
message="Missing `contentDescription` attribute on image"
errorLine1=" &lt;ImageView"
errorLine2=" ~~~~~~~~~">
<location
file="src/main/res/layout/activity_macos.xml"
line="38"
column="14"/>
</issue>

</issues>
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ class MacOsActivity : DuckDuckGoActivity() {

private fun executeCommand(command: Command) {
when (command) {
is ShareLink -> launchSharePageChooser()
is ShareLink -> launchSharePageChooser(command.originEnabled)
is GoToWindowsClientSettings -> launchWindowsClientSettings()
}
}
Expand All @@ -88,10 +88,12 @@ class MacOsActivity : DuckDuckGoActivity() {
}

@SuppressLint("UnspecifiedImmutableFlag")
private fun launchSharePageChooser() {
private fun launchSharePageChooser(addOrigin: Boolean) {
var shareText = getString(string.macos_share_text)
if (!addOrigin) { shareText = shareText.replace(ORIGIN_URL_PATH, "") }
val share = Intent(Intent.ACTION_SEND).apply {
type = "text/html"
putExtra(Intent.EXTRA_TEXT, getString(string.macos_share_text))
putExtra(Intent.EXTRA_TEXT, shareText)
putExtra(Intent.EXTRA_TITLE, getString(string.macos_share_title))
}

Expand All @@ -107,4 +109,8 @@ class MacOsActivity : DuckDuckGoActivity() {
Timber.w(e, "Activity not found")
}
}

companion object {
const val ORIGIN_URL_PATH = "?origin=funnel_browser_android_settings"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright (c) 2024 DuckDuckGo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.duckduckgo.macos.impl

import com.duckduckgo.anvil.annotations.ContributesRemoteFeature
import com.duckduckgo.di.scopes.AppScope
import com.duckduckgo.feature.toggles.api.Toggle

@ContributesRemoteFeature(
scope = AppScope::class,
featureName = "macOsDownloadLinkOrigin",
)
interface MacOsDownloadLinkOrigin {
@Toggle.DefaultValue(true)
fun self(): Toggle
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,21 +33,22 @@ import kotlinx.coroutines.launch
@ContributesViewModel(AppScope::class)
class MacOsViewModel @Inject constructor(
private val pixel: Pixel,
private val macOsDownloadLinkOrigin: MacOsDownloadLinkOrigin,
) : ViewModel() {

private val commandChannel = Channel<Command>(capacity = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST)
val commands = commandChannel.receiveAsFlow()

sealed class Command {
object ShareLink : Command()
data class ShareLink(val originEnabled: Boolean) : Command()
object GoToWindowsClientSettings : Command()
}

data class ViewState(val windowsFeatureEnabled: Boolean)

fun onShareClicked() {
viewModelScope.launch {
commandChannel.send(ShareLink)
commandChannel.send(ShareLink(originEnabled = macOsDownloadLinkOrigin.self().isEnabled()))
pixel.fire(MACOS_WAITLIST_SHARE_PRESSED)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import app.cash.turbine.test
import com.duckduckgo.app.statistics.pixels.Pixel
import com.duckduckgo.common.test.CoroutineTestRule
import com.duckduckgo.feature.toggles.api.FakeFeatureToggleFactory
import com.duckduckgo.feature.toggles.api.Toggle.State
import com.duckduckgo.macos.impl.MacOsPixelNames.MACOS_WAITLIST_SHARE_PRESSED
import com.duckduckgo.macos.impl.MacOsViewModel.Command.GoToWindowsClientSettings
import com.duckduckgo.macos.impl.MacOsViewModel.Command.ShareLink
Expand All @@ -39,18 +41,21 @@ class MacOsViewModelTest {
var coroutineRule = CoroutineTestRule()

private var mockPixel: Pixel = mock()
private var macOsDownloadLinkOrigin = FakeFeatureToggleFactory.create(MacOsDownloadLinkOrigin::class.java)

private lateinit var testee: MacOsViewModel

@Before
fun before() {
testee = MacOsViewModel(mockPixel)
testee = MacOsViewModel(mockPixel, macOsDownloadLinkOrigin)
}

@Test
fun whenOnShareClickedAndInviteCodeExistsThenEmitCommandShareInviteCodeWithCorrectCode() = runTest {
macOsDownloadLinkOrigin.self().setRawStoredState(State(enable = true))
testee.commands.test {
testee.onShareClicked()
assertEquals(ShareLink, awaitItem())
assertEquals(ShareLink(true), awaitItem())
}
}

Expand Down
1 change: 1 addition & 0 deletions windows/windows-impl/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ dependencies {
implementation project(':privacy-config-api')
implementation project(':navigation-api')
implementation project(':feature-toggles-api')
testImplementation project(':feature-toggles-test')

implementation AndroidX.appCompat
implementation Google.android.material
Expand Down
11 changes: 11 additions & 0 deletions windows/windows-impl/lint-baseline.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<issues format="6" by="lint 8.5.1" type="baseline" client="gradle" dependencies="false" name="AGP (8.5.1)" variant="all" version="8.5.1">

<issue
id="DenyListedApi"
message="If you find yourself using this API in production, you&apos;re doing something wrong!!"
errorLine1=" windowsShareLinkOrigin.self().setRawStoredState(State(enable = true))"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/test/java/com/duckduckgo/windows/impl/ui/WindowsViewModelTest.kt"
line="53"
column="9"/>
</issue>

</issues>
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright (c) 2024 DuckDuckGo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.duckduckgo.windows.impl

import com.duckduckgo.anvil.annotations.ContributesRemoteFeature
import com.duckduckgo.di.scopes.AppScope
import com.duckduckgo.feature.toggles.api.Toggle

@ContributesRemoteFeature(
scope = AppScope::class,
featureName = "windowsDownloadLinkOrigin",
)
interface WindowsDownloadLinkOrigin {
@Toggle.DefaultValue(true)
fun self(): Toggle
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,15 +78,17 @@ class WindowsActivity : DuckDuckGoActivity() {

private fun executeCommand(command: Command) {
when (command) {
is ShareLink -> launchSharePageChooser()
is ShareLink -> launchSharePageChooser(command.originEnabled)
is GoToMacClientSettings -> launchMacClientSettings()
}
}

private fun launchSharePageChooser() {
private fun launchSharePageChooser(addOrigin: Boolean) {
var shareText = getString(R.string.windows_share_text)
if (!addOrigin) { shareText = shareText.replace(ORIGIN_URL_PATH, "") }
val share = Intent(Intent.ACTION_SEND).apply {
type = "text/html"
putExtra(Intent.EXTRA_TEXT, getString(R.string.windows_share_text))
putExtra(Intent.EXTRA_TEXT, shareText)
putExtra(Intent.EXTRA_TITLE, getString(R.string.windows_share_title))
}

Expand All @@ -107,4 +109,8 @@ class WindowsActivity : DuckDuckGoActivity() {
globalActivityStarter.start(this, MacOsScreenWithEmptyParams)
finish()
}

companion object {
const val ORIGIN_URL_PATH = "?origin=funnel_browser_android_settings"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import androidx.lifecycle.viewModelScope
import com.duckduckgo.anvil.annotations.ContributesViewModel
import com.duckduckgo.app.statistics.pixels.Pixel
import com.duckduckgo.di.scopes.ActivityScope
import com.duckduckgo.windows.impl.WindowsDownloadLinkOrigin
import com.duckduckgo.windows.impl.WindowsPixelNames.WINDOWS_WAITLIST_SHARE_PRESSED
import com.duckduckgo.windows.impl.ui.WindowsViewModel.Command.ShareLink
import javax.inject.Inject
Expand All @@ -32,19 +33,20 @@ import kotlinx.coroutines.launch
@ContributesViewModel(ActivityScope::class)
class WindowsViewModel @Inject constructor(
private val pixel: Pixel,
private val windowsDownloadLinkOrigin: WindowsDownloadLinkOrigin,
) : ViewModel() {

private val commandChannel = Channel<Command>(capacity = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST)
val commands = commandChannel.receiveAsFlow()

sealed class Command {
object ShareLink : Command()
data class ShareLink(val originEnabled: Boolean) : Command()
object GoToMacClientSettings : Command()
}

fun onShareClicked() {
viewModelScope.launch {
commandChannel.send(ShareLink)
commandChannel.send(ShareLink(originEnabled = windowsDownloadLinkOrigin.self().isEnabled()))
pixel.fire(WINDOWS_WAITLIST_SHARE_PRESSED)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import app.cash.turbine.test
import com.duckduckgo.app.statistics.pixels.Pixel
import com.duckduckgo.common.test.CoroutineTestRule
import com.duckduckgo.feature.toggles.api.FakeFeatureToggleFactory
import com.duckduckgo.feature.toggles.api.Toggle.State
import com.duckduckgo.windows.impl.WindowsDownloadLinkOrigin
import com.duckduckgo.windows.impl.ui.WindowsViewModel.Command.GoToMacClientSettings
import com.duckduckgo.windows.impl.ui.WindowsViewModel.Command.ShareLink
import kotlinx.coroutines.test.runTest
Expand All @@ -36,19 +39,21 @@ internal class WindowsViewModelTest {
var coroutineRule = CoroutineTestRule()

private var mockPixel: Pixel = mock()
private var windowsShareLinkOrigin = FakeFeatureToggleFactory.create(WindowsDownloadLinkOrigin::class.java)

private lateinit var testee: WindowsViewModel

@Before
fun before() {
testee = WindowsViewModel(mockPixel)
testee = WindowsViewModel(mockPixel, windowsShareLinkOrigin)
}

@Test
fun whenOnShareClickedThenEmitShareLinkCommand() = runTest {
windowsShareLinkOrigin.self().setRawStoredState(State(enable = true))
testee.commands.test {
testee.onShareClicked()
assertEquals(ShareLink, awaitItem())
assertEquals(ShareLink(true), awaitItem())
}
}

Expand Down

0 comments on commit 53c190a

Please sign in to comment.