Skip to content

Commit 8d570e6

Browse files
committed
content [nfc]: Follow browser preference setting when opening links
This preserves the previous behavior (external application on iOS, and in-app browser on Android) when browserPreference is `null`. There is no way for the client to update the setting for now, hence the NFC. The helper could have been a static method instead of an extension, similar to ThemeSetting.displayName, but that will be a lot more verbose for the caller. Signed-off-by: Zixuan James Li <[email protected]>
1 parent 817c4a2 commit 8d570e6

File tree

4 files changed

+45
-7
lines changed

4 files changed

+45
-7
lines changed

lib/model/settings.dart

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ enum BrowserPreference {
4545
}
4646

4747
extension GlobalSettingsHelpers on GlobalSettingsData {
48-
BrowserPreference get defaultBrowserPreference {
48+
BrowserPreference get effectiveBrowserPreference {
49+
if (browserPreference != null) return browserPreference!;
4950
return switch (defaultTargetPlatform) {
5051
// On iOS we prefer UrlLaunchMode.externalApplication because (for
5152
// HTTP URLs) UrlLaunchMode.platformDefault uses SFSafariViewController,
@@ -61,7 +62,7 @@ extension GlobalSettingsHelpers on GlobalSettingsData {
6162
}
6263

6364
UrlLaunchMode getUrlLaunchMode(Uri url) {
64-
switch (defaultBrowserPreference) {
65+
switch (effectiveBrowserPreference) {
6566
case BrowserPreference.inApp:
6667
if (!(url.scheme == 'https' || url.scheme == 'http')) {
6768
// For URLs on non-HTTP schemes such as `mailto`,

test/model/settings_test.dart

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import 'package:checks/checks.dart';
22
import 'package:flutter/foundation.dart';
33
import 'package:flutter_test/flutter_test.dart';
44
import 'package:zulip/model/binding.dart';
5+
import 'package:zulip/model/settings.dart';
56

67
import '../example_data.dart' as eg;
78
import 'store_checks.dart';
@@ -12,18 +13,41 @@ void main() {
1213
final nonHttpLink = Uri.parse('mailto:[email protected]');
1314

1415
group('getUrlLaunchMode', () {
15-
testAndroidIos('use our per-platform defaults for HTTP links', () {
16-
final globalStore = eg.globalStore(globalSettings: eg.globalSettings());
16+
testAndroidIos('globalSettings.browserPreference is null; use our per-platform defaults for HTTP links', () {
17+
final globalStore = eg.globalStore(globalSettings: eg.globalSettings(
18+
browserPreference: null));
1719
check(globalStore).globalSettings.getUrlLaunchMode(httpLink).equals(
1820
defaultTargetPlatform == TargetPlatform.android
1921
? UrlLaunchMode.inAppBrowserView : UrlLaunchMode.externalApplication);
2022
});
2123

22-
testAndroidIos('use our per-platform defaults for non-HTTP links', () {
23-
final globalStore = eg.globalStore(globalSettings: eg.globalSettings());
24+
testAndroidIos('globalSettings.browserPreference is null; use our per-platform defaults for non-HTTP links', () {
25+
final globalStore = eg.globalStore(globalSettings: eg.globalSettings(
26+
browserPreference: null));
2427
check(globalStore).globalSettings.getUrlLaunchMode(nonHttpLink).equals(
2528
defaultTargetPlatform == TargetPlatform.android
2629
? UrlLaunchMode.platformDefault : UrlLaunchMode.externalApplication);
2730
});
31+
32+
testAndroidIos('globalSettings.browserPreference is inApp; follow the user preference for http links', () {
33+
final globalStore = eg.globalStore(globalSettings: eg.globalSettings(
34+
browserPreference: BrowserPreference.inApp));
35+
check(globalStore).globalSettings.getUrlLaunchMode(httpLink).equals(
36+
UrlLaunchMode.inAppBrowserView);
37+
});
38+
39+
testAndroidIos('globalSettings.browserPreference is inApp; use platform default for non-http links', () {
40+
final globalStore = eg.globalStore(globalSettings: eg.globalSettings(
41+
browserPreference: BrowserPreference.inApp));
42+
check(globalStore).globalSettings.getUrlLaunchMode(nonHttpLink).equals(
43+
UrlLaunchMode.platformDefault);
44+
});
45+
46+
testAndroidIos('globalSettings.browserPreference is external; follow the user preference', () {
47+
final globalStore = eg.globalStore(globalSettings: eg.globalSettings(
48+
browserPreference: BrowserPreference.external));
49+
check(globalStore).globalSettings.getUrlLaunchMode(httpLink).equals(
50+
UrlLaunchMode.externalApplication);
51+
});
2852
});
2953
}

test/model/store_checks.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ extension GlobalStoreChecks on Subject<GlobalStore> {
3333
extension GlobalSettingsDataChecks on Subject<GlobalSettingsData> {
3434
Subject<ThemeSetting?> get themeSetting => has((x) => x.themeSetting, 'themeSetting');
3535
Subject<BrowserPreference?> get browserPreference => has((x) => x.browserPreference, 'browserPreference');
36-
Subject<BrowserPreference> get defaultBrowserPreference => has((x) => x.defaultBrowserPreference, 'defaultBrowserPreference');
36+
Subject<BrowserPreference> get effectiveBrowserPreference => has((x) => x.effectiveBrowserPreference, 'effectiveBrowserPreference');
3737
Subject<UrlLaunchMode> getUrlLaunchMode(Uri url) => has((x) => x.getUrlLaunchMode(url), 'getUrlLaunchMode');
3838
}
3939

test/widgets/content_test.dart

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import 'package:url_launcher/url_launcher.dart';
99
import 'package:zulip/api/core.dart';
1010
import 'package:zulip/model/content.dart';
1111
import 'package:zulip/model/narrow.dart';
12+
import 'package:zulip/model/settings.dart';
1213
import 'package:zulip/model/store.dart';
1314
import 'package:zulip/widgets/content.dart';
1415
import 'package:zulip/widgets/icons.dart';
@@ -798,6 +799,18 @@ void main() {
798799
.single.equals((url: Uri.parse('https://example/'), mode: expectedLaunchMode));
799800
}, variant: const TargetPlatformVariant({TargetPlatform.android, TargetPlatform.iOS}));
800801

802+
testWidgets('follow browser preference setting to open URL', (tester) async {
803+
await testBinding.globalStore.updateGlobalSettings(
804+
eg.globalSettings(
805+
browserPreference: BrowserPreference.inApp).toCompanion(false));
806+
await prepare(tester,
807+
'<p><a href="https://example/">hello</a></p>');
808+
809+
await tapText(tester, find.text('hello'));
810+
check(testBinding.takeLaunchUrlCalls()).single.equals((
811+
url: Uri.parse('https://example/'), mode: LaunchMode.inAppBrowserView));
812+
}, variant: const TargetPlatformVariant({TargetPlatform.android, TargetPlatform.iOS}));
813+
801814
testWidgets('multiple links in paragraph', (tester) async {
802815
const fontSize = kBaseFontSize;
803816

0 commit comments

Comments
 (0)