Skip to content

Commit 6d13643

Browse files
committed
Added option to open links in an adjacent window on large screens
1 parent 010a2f9 commit 6d13643

File tree

19 files changed

+242
-113
lines changed

19 files changed

+242
-113
lines changed

app/src/androidTest/java/com/nononsenseapps/feeder/model/opml/OPMLTest.kt

+2
Original file line numberDiff line numberDiff line change
@@ -715,6 +715,7 @@ class OPMLTest : DIAware {
715715
UserSettings.SETTINGS_FILTER_RECENTLY_READ -> "true"
716716
UserSettings.SETTINGS_FILTER_READ -> "false"
717717
UserSettings.SETTINGS_LIST_SHOW_ONLY_TITLES -> "true"
718+
UserSettings.SETTING_OPEN_ADJACENT -> "true"
718719
}
719720
}
720721
}
@@ -770,6 +771,7 @@ private val sampleFile: List<String> = """
770771
<feeder:setting key="pref_img_show_thumbnails" value="false"/>
771772
<feeder:setting key="pref_default_open_item_with" value="3"/>
772773
<feeder:setting key="pref_open_links_with" value="3"/>
774+
<feeder:setting key="pref_open_adjacent" value="true"/>
773775
<feeder:setting key="pref_body_text_scale" value="1.6"/>
774776
<feeder:setting key="pref_is_mark_as_read_on_scroll" value="true"/>
775777
<feeder:setting key="pref_readaloud_detect_lang" value="true"/>

app/src/main/java/com/nononsenseapps/feeder/archmodel/Repository.kt

+5
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,11 @@ class Repository(override val di: DI) : DIAware {
647647
suspend fun setCurrentlySyncingOn(feedId: Long, syncing: Boolean, lastSync: Instant? = null) =
648648
feedStore.setCurrentlySyncingOn(feedId = feedId, syncing = syncing, lastSync = lastSync)
649649

650+
val isOpenAdjacent: StateFlow<Boolean> = settingsStore.openAdjacent
651+
fun setOpenAdjacent(value: Boolean) {
652+
settingsStore.setOpenAdjacent(value)
653+
}
654+
650655
companion object {
651656
private const val LOG_TAG = "FEEDER_REPO"
652657
}

app/src/main/java/com/nononsenseapps/feeder/archmodel/SettingsStore.kt

+9
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,13 @@ class SettingsStore(override val di: DI) : DIAware {
307307
).apply()
308308
}
309309

310+
private val _openAdjacent = MutableStateFlow(sp.getBoolean(PREF_OPEN_ADJACENT, true))
311+
val openAdjacent = _openAdjacent.asStateFlow()
312+
fun setOpenAdjacent(value: Boolean) {
313+
_openAdjacent.value = value
314+
sp.edit().putBoolean(PREF_OPEN_ADJACENT, value).apply()
315+
}
316+
310317
private val _feedItemStyle = MutableStateFlow(
311318
feedItemStyleFromString(sp.getStringNonNull(PREF_FEED_ITEM_STYLE, FeedItemStyle.CARD.name)),
312319
)
@@ -484,6 +491,7 @@ const val PREF_IMG_SHOW_THUMBNAILS = "pref_img_show_thumbnails"
484491
*/
485492
const val PREF_DEFAULT_OPEN_ITEM_WITH = "pref_default_open_item_with"
486493
const val PREF_OPEN_LINKS_WITH = "pref_open_links_with"
494+
const val PREF_OPEN_ADJACENT = "pref_open_adjacent"
487495

488496
const val PREF_VAL_OPEN_WITH_READER = "0"
489497
const val PREF_VAL_OPEN_WITH_WEBVIEW = "1"
@@ -527,6 +535,7 @@ enum class UserSettings(val key: String) {
527535
SETTING_IMG_SHOW_THUMBNAILS(key = PREF_IMG_SHOW_THUMBNAILS),
528536
SETTING_DEFAULT_OPEN_ITEM_WITH(key = PREF_DEFAULT_OPEN_ITEM_WITH),
529537
SETTING_OPEN_LINKS_WITH(key = PREF_OPEN_LINKS_WITH),
538+
SETTING_OPEN_ADJACENT(key = PREF_OPEN_ADJACENT),
530539
SETTING_TEXT_SCALE(key = PREF_TEXT_SCALE),
531540
SETTING_IS_MARK_AS_READ_ON_SCROLL(
532541
key = PREF_IS_MARK_AS_READ_ON_SCROLL,

app/src/main/java/com/nononsenseapps/feeder/base/DIAwareComponentActivity.kt

+9
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,27 @@ package com.nononsenseapps.feeder.base
22

33
import android.view.MenuInflater
44
import androidx.activity.ComponentActivity
5+
import com.nononsenseapps.feeder.util.ActivityLauncher
56
import org.kodein.di.DI
67
import org.kodein.di.DIAware
78
import org.kodein.di.android.closestDI
89
import org.kodein.di.bind
10+
import org.kodein.di.direct
911
import org.kodein.di.instance
1012
import org.kodein.di.provider
13+
import org.kodein.di.singleton
1114

1215
abstract class DIAwareComponentActivity : ComponentActivity(), DIAware {
1316
private val parentDI: DI by closestDI()
1417
override val di: DI by DI.lazy {
1518
extend(parentDI)
1619
bind<MenuInflater>() with provider { menuInflater }
1720
bind<DIAwareComponentActivity>() with instance(this@DIAwareComponentActivity)
21+
bind<ActivityLauncher>() with singleton {
22+
ActivityLauncher(
23+
this@DIAwareComponentActivity,
24+
di.direct.instance(),
25+
)
26+
}
1827
}
1928
}

app/src/main/java/com/nononsenseapps/feeder/model/opml/OPMLImporter.kt

+1
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ open class OPMLImporter(override val di: DI) : OPMLParserHandler, DIAware {
7777
UserSettings.SETTINGS_FILTER_RECENTLY_READ -> settingsStore.setFeedListFilterRecentlyRead(value.toBoolean())
7878
UserSettings.SETTINGS_FILTER_READ -> settingsStore.setFeedListFilterRead(value.toBoolean())
7979
UserSettings.SETTINGS_LIST_SHOW_ONLY_TITLES -> settingsStore.setShowOnlyTitles(value.toBoolean())
80+
UserSettings.SETTING_OPEN_ADJACENT -> settingsStore.setOpenAdjacent(value.toBoolean())
8081
}
8182
}
8283

app/src/main/java/com/nononsenseapps/feeder/ui/OpenLinkInDefaultActivity.kt

+9-9
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
package com.nononsenseapps.feeder.ui
22

33
import android.content.Intent
4-
import android.net.Uri
54
import android.os.Bundle
6-
import android.provider.Browser.EXTRA_CREATE_NEW_TAB
75
import android.util.Log
86
import android.widget.Toast
97
import androidx.lifecycle.lifecycleScope
@@ -12,6 +10,7 @@ import com.nononsenseapps.feeder.base.DIAwareComponentActivity
1210
import com.nononsenseapps.feeder.db.COL_LINK
1311
import com.nononsenseapps.feeder.db.room.ID_UNSET
1412
import com.nononsenseapps.feeder.model.cancelNotification
13+
import com.nononsenseapps.feeder.util.ActivityLauncher
1514
import com.nononsenseapps.feeder.util.DEEP_LINK_HOST
1615
import kotlinx.coroutines.launch
1716
import org.kodein.di.instance
@@ -24,6 +23,7 @@ import org.kodein.di.instance
2423
*/
2524
class OpenLinkInDefaultActivity : DIAwareComponentActivity() {
2625
private val viewModel: OpenLinkInDefaultActivityViewModel by instance(arg = this)
26+
private val activityLauncher: ActivityLauncher by instance()
2727

2828
override fun onCreate(savedInstanceState: Bundle?) {
2929
super.onCreate(savedInstanceState)
@@ -39,8 +39,9 @@ class OpenLinkInDefaultActivity : DIAwareComponentActivity() {
3939

4040
viewModel.markAsNotifiedInBackground(feedItemIds.toList())
4141

42-
startActivity(
43-
Intent(
42+
activityLauncher.startActivity(
43+
openAdjacentIfSuitable = false,
44+
intent = Intent(
4445
Intent.ACTION_VIEW,
4546
uri,
4647
this,
@@ -67,15 +68,14 @@ class OpenLinkInDefaultActivity : DIAwareComponentActivity() {
6768

6869
if (link != null) {
6970
try {
70-
startActivity(
71-
Intent(Intent.ACTION_VIEW, Uri.parse(link)).also {
72-
intent.putExtra(EXTRA_CREATE_NEW_TAB, true)
73-
},
71+
activityLauncher.openLinkInBrowser(
72+
link,
73+
openAdjacentIfSuitable = false,
7474
)
7575
} catch (e: Throwable) {
7676
e.printStackTrace()
7777
Toast.makeText(this, R.string.no_activity_for_link, Toast.LENGTH_SHORT).show()
78-
Log.e("FeederOpenInWebBrowser", "Failed to start browser", e)
78+
Log.e("FEEDEROpenInWebBrowser", "Failed to start browser", e)
7979
}
8080
}
8181
}

app/src/main/java/com/nononsenseapps/feeder/ui/compose/feed/FeedScreen.kt

+18-10
Original file line numberDiff line numberDiff line change
@@ -137,11 +137,10 @@ import com.nononsenseapps.feeder.ui.compose.utils.isCompactDevice
137137
import com.nononsenseapps.feeder.ui.compose.utils.onKeyEventLikeEscape
138138
import com.nononsenseapps.feeder.ui.compose.utils.rememberIsItemMostlyVisible
139139
import com.nononsenseapps.feeder.ui.compose.utils.rememberIsItemVisible
140+
import com.nononsenseapps.feeder.util.ActivityLauncher
140141
import com.nononsenseapps.feeder.util.ToastMaker
141142
import com.nononsenseapps.feeder.util.emailBugReportIntent
142143
import com.nononsenseapps.feeder.util.logDebug
143-
import com.nononsenseapps.feeder.util.openLinkInBrowser
144-
import com.nononsenseapps.feeder.util.openLinkInCustomTab
145144
import java.time.Instant
146145
import java.time.LocalDateTime
147146
import kotlinx.coroutines.CoroutineScope
@@ -190,7 +189,7 @@ fun FeedScreen(
190189
}
191190
}
192191

193-
val context = LocalContext.current
192+
val activityLauncher: ActivityLauncher by LocalDI.current.instance()
194193

195194
// Each feed gets its own scroll state. Persists across device rotations, but is cleared when
196195
// switching feeds
@@ -293,7 +292,10 @@ fun FeedScreen(
293292
SettingsDestination.navigate(navController)
294293
},
295294
onSendFeedback = {
296-
context.startActivity(emailBugReportIntent())
295+
activityLauncher.startActivity(
296+
openAdjacentIfSuitable = true,
297+
intent = emailBugReportIntent(),
298+
)
297299
},
298300
onImport = {
299301
try {
@@ -365,10 +367,10 @@ fun FeedScreen(
365367
viewModel.openArticle(
366368
itemId = itemId,
367369
openInBrowser = { articleLink ->
368-
openLinkInBrowser(context, articleLink)
370+
activityLauncher.openLinkInBrowser(articleLink)
369371
},
370372
openInCustomTab = { articleLink ->
371-
openLinkInCustomTab(context, articleLink, toolbarColor)
373+
activityLauncher.openLinkInCustomTab(articleLink, toolbarColor)
372374
},
373375
navigateToArticle = {
374376
ArticleDestination.navigate(navController, itemId)
@@ -1015,7 +1017,7 @@ fun FeedListContent(
10151017
modifier: Modifier = Modifier,
10161018
) {
10171019
val coroutineScope = rememberCoroutineScope()
1018-
val context = LocalContext.current
1020+
val activityLauncher: ActivityLauncher by LocalDI.current.instance()
10191021

10201022
Box(modifier = modifier) {
10211023
AnimatedVisibility(
@@ -1149,7 +1151,10 @@ fun FeedListContent(
11491151
},
11501152
null,
11511153
)
1152-
context.startActivity(intent)
1154+
activityLauncher.startActivity(
1155+
openAdjacentIfSuitable = false,
1156+
intent = intent,
1157+
)
11531158
},
11541159
) {
11551160
onItemClick(previewItem.id)
@@ -1199,7 +1204,7 @@ fun FeedGridContent(
11991204
modifier: Modifier = Modifier,
12001205
) {
12011206
val coroutineScope = rememberCoroutineScope()
1202-
val context = LocalContext.current
1207+
val activityLauncher: ActivityLauncher by LocalDI.current.instance()
12031208

12041209
val screenHeightPx = with(LocalDensity.current) {
12051210
LocalConfiguration.current.screenHeightDp.dp.toPx().toInt()
@@ -1328,7 +1333,10 @@ fun FeedGridContent(
13281333
},
13291334
null,
13301335
)
1331-
context.startActivity(intent)
1336+
activityLauncher.startActivity(
1337+
openAdjacentIfSuitable = false,
1338+
intent = intent,
1339+
)
13321340
},
13331341
) {
13341342
onItemClick(previewItem.id)

app/src/main/java/com/nononsenseapps/feeder/ui/compose/feedarticle/ArticleScreen.kt

+11-12
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,8 @@ import com.nononsenseapps.feeder.ui.compose.theme.SetStatusBarColorToMatchScroll
6868
import com.nononsenseapps.feeder.ui.compose.utils.ImmutableHolder
6969
import com.nononsenseapps.feeder.ui.compose.utils.ScreenType
7070
import com.nononsenseapps.feeder.ui.compose.utils.onKeyEventLikeEscape
71+
import com.nononsenseapps.feeder.util.ActivityLauncher
7172
import com.nononsenseapps.feeder.util.FilePathProvider
72-
import com.nononsenseapps.feeder.util.openLinkInBrowser
73-
import com.nononsenseapps.feeder.util.openLinkInCustomTab
7473
import com.nononsenseapps.feeder.util.unicodeWrap
7574
import java.time.ZonedDateTime
7675
import org.kodein.di.compose.LocalDI
@@ -85,7 +84,7 @@ fun ArticleScreen(
8584
BackHandler(onBack = onNavigateUp)
8685
val viewState: FeedArticleScreenViewState by viewModel.viewState.collectAsStateWithLifecycle()
8786

88-
val context = LocalContext.current
87+
val activityLauncher: ActivityLauncher by LocalDI.current.instance()
8988

9089
// Each article gets its own scroll state. Persists across device rotations, but is cleared
9190
// when switching articles.
@@ -124,12 +123,15 @@ fun ArticleScreen(
124123
},
125124
null,
126125
)
127-
context.startActivity(intent)
126+
activityLauncher.startActivity(
127+
openAdjacentIfSuitable = false,
128+
intent = intent,
129+
)
128130
}
129131
},
130132
onOpenInCustomTab = {
131133
viewState.articleLink?.let { link ->
132-
openLinkInCustomTab(context, link, toolbarColor)
134+
activityLauncher.openLinkInCustomTab(link, toolbarColor)
133135
}
134136
},
135137
onFeedTitleClick = {
@@ -377,6 +379,7 @@ fun ArticleContent(
377379
val toolbarColor = MaterialTheme.colorScheme.surface.toArgb()
378380

379381
val context = LocalContext.current
382+
val activityLauncher: ActivityLauncher by LocalDI.current.instance()
380383

381384
if (viewState.articleId > ID_UNSET &&
382385
viewState.textToDisplay == TextToDisplay.FULLTEXT &&
@@ -392,7 +395,7 @@ fun ArticleContent(
392395
screenType = screenType,
393396
onEnclosureClick = {
394397
if (viewState.enclosure.present) {
395-
openLinkInBrowser(context, viewState.enclosure.link)
398+
activityLauncher.openLinkInBrowser(link = viewState.enclosure.link)
396399
}
397400
},
398401
onFeedTitleClick = onFeedTitleClick,
@@ -432,10 +435,8 @@ fun ArticleContent(
432435
baseUrl = viewState.articleFeedUrl ?: "",
433436
keyHolder = viewState.keyHolder,
434437
) { link ->
435-
onLinkClick(
438+
activityLauncher.openLink(
436439
link = link,
437-
linkOpener = viewState.linkOpener,
438-
context = context,
439440
toolbarColor = toolbarColor,
440441
)
441442
}
@@ -473,10 +474,8 @@ fun ArticleContent(
473474
baseUrl = viewState.articleFeedUrl ?: "",
474475
keyHolder = viewState.keyHolder,
475476
) { link ->
476-
onLinkClick(
477+
activityLauncher.openLink(
477478
link = link,
478-
linkOpener = viewState.linkOpener,
479-
context = context,
480479
toolbarColor = toolbarColor,
481480
)
482481
}

app/src/main/java/com/nononsenseapps/feeder/ui/compose/feedarticle/ReaderView.kt

-22
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package com.nononsenseapps.feeder.ui.compose.feedarticle
22

3-
import android.content.Context
43
import android.util.Log
5-
import androidx.annotation.ColorInt
64
import androidx.compose.foundation.ExperimentalFoundationApi
75
import androidx.compose.foundation.LocalIndication
86
import androidx.compose.foundation.clickable
@@ -39,15 +37,12 @@ import androidx.compose.ui.semantics.semantics
3937
import androidx.compose.ui.unit.dp
4038
import com.nononsenseapps.feeder.R
4139
import com.nononsenseapps.feeder.archmodel.Enclosure
42-
import com.nononsenseapps.feeder.archmodel.LinkOpener
4340
import com.nononsenseapps.feeder.ui.compose.text.WithBidiDeterminedLayoutDirection
4441
import com.nononsenseapps.feeder.ui.compose.theme.LinkTextStyle
4542
import com.nononsenseapps.feeder.ui.compose.theme.LocalDimens
4643
import com.nononsenseapps.feeder.ui.compose.utils.ProvideScaledText
4744
import com.nononsenseapps.feeder.ui.compose.utils.ScreenType
4845
import com.nononsenseapps.feeder.ui.compose.utils.focusableInNonTouchMode
49-
import com.nononsenseapps.feeder.util.openLinkInBrowser
50-
import com.nononsenseapps.feeder.util.openLinkInCustomTab
5146
import java.time.format.DateTimeFormatter
5247
import java.time.format.FormatStyle
5348
import java.util.Locale
@@ -207,20 +202,3 @@ fun ReaderView(
207202
}
208203
}
209204
}
210-
211-
fun onLinkClick(
212-
link: String,
213-
linkOpener: LinkOpener,
214-
context: Context,
215-
@ColorInt toolbarColor: Int,
216-
) {
217-
when (linkOpener) {
218-
LinkOpener.CUSTOM_TAB -> {
219-
openLinkInCustomTab(context, link, toolbarColor)
220-
}
221-
222-
LinkOpener.DEFAULT_BROWSER -> {
223-
openLinkInBrowser(context, link)
224-
}
225-
}
226-
}

0 commit comments

Comments
 (0)