Skip to content

Commit c4f3b56

Browse files
login: Link to doc for what "server URL" is and how to find it
Fixes: zulip#109
1 parent 695a31f commit c4f3b56

File tree

3 files changed

+55
-2
lines changed

3 files changed

+55
-2
lines changed

Diff for: assets/l10n/app_en.arb

+4
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,10 @@
308308
"@loginServerUrlInputLabel": {
309309
"description": "Input label in login page for Zulip server URL entry."
310310
},
311+
"serverUrlDocLinkLabel": "What's this?",
312+
"@serverUrlDocLinkLabel": {
313+
"description": "Link to doc to help users understand what a server URL is and how to find theirs."
314+
},
311315
"errorUnableToOpenLinkTitle": "Unable to open link",
312316
"@errorUnableToOpenLinkTitle": {
313317
"description": "Error title when a link fails to open."

Diff for: lib/widgets/login.dart

+11-2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import '../model/store.dart';
1515
import 'app.dart';
1616
import 'dialog.dart';
1717
import 'input.dart';
18+
import 'launch_url.dart';
1819
import 'page.dart';
1920
import 'store.dart';
2021
import 'text.dart';
@@ -108,6 +109,8 @@ class ServerUrlTextEditingController extends TextEditingController {
108109
class AddAccountPage extends StatefulWidget {
109110
const AddAccountPage({super.key});
110111

112+
static const String serverUrlHelpUrl = 'https://zulip.com/help/logging-in#find-the-zulip-log-in-url';
113+
111114
static Route<void> buildRoute() {
112115
return _LoginSequenceRoute(page: const AddAccountPage());
113116
}
@@ -213,7 +216,6 @@ class _AddAccountPageState extends State<AddAccountPage> {
213216
child: ConstrainedBox(
214217
constraints: const BoxConstraints(maxWidth: 400),
215218
child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
216-
// TODO(#109) Link to doc about what a "server URL" is and how to find it
217219
// TODO(#111) Perhaps give tappable realm URL suggestions based on text typed so far
218220
TextField(
219221
controller: _controller,
@@ -229,7 +231,14 @@ class _AddAccountPageState extends State<AddAccountPage> {
229231
decoration: InputDecoration(
230232
labelText: zulipLocalizations.loginServerUrlInputLabel,
231233
errorText: errorText,
232-
helperText: kLayoutPinningHelperText,
234+
helper: GestureDetector(
235+
onTap: () {
236+
launchUrlWithoutRealm(context, Uri.parse(AddAccountPage.serverUrlHelpUrl));
237+
},
238+
child: Text(
239+
zulipLocalizations.serverUrlDocLinkLabel,
240+
style: Theme.of(context).textTheme.bodySmall!
241+
.apply(color: const HSLColor.fromAHSL(1, 200, 1, 0.4).toColor()))),
233242
hintText: 'your-org.zulipchat.com')),
234243
const SizedBox(height: 8),
235244
ElevatedButton(

Diff for: test/widgets/login_test.dart

+40
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
import 'package:checks/checks.dart';
22
import 'package:flutter/material.dart';
33
import 'package:flutter/services.dart';
4+
import 'package:flutter_gen/gen_l10n/zulip_localizations.dart';
45
import 'package:flutter_test/flutter_test.dart';
56
import 'package:http/http.dart' as http;
7+
import 'package:url_launcher/url_launcher.dart';
8+
69
import 'package:zulip/api/model/web_auth.dart';
710
import 'package:zulip/api/route/account.dart';
811
import 'package:zulip/api/route/realm.dart';
@@ -218,4 +221,41 @@ void main() {
218221
// WebAuthPayload.realm doesn't match the realm the UI is about
219222
});
220223
});
224+
225+
group('Server URL Helper Text', () {
226+
Future<void> prepareAddAccountPage(WidgetTester tester) async {
227+
await tester.pumpWidget(const MaterialApp(
228+
localizationsDelegates: ZulipLocalizations.localizationsDelegates,
229+
supportedLocales: ZulipLocalizations.supportedLocales,
230+
home: AddAccountPage(),
231+
));
232+
}
233+
234+
final zulipLocalizations = GlobalLocalizations.zulipLocalizations;
235+
236+
Future<Finder> findHelperText(WidgetTester tester) async {
237+
return find.text(zulipLocalizations.serverUrlDocLinkLabel);
238+
}
239+
240+
testWidgets('launches URL when helper text is tapped', (tester) async {
241+
await prepareAddAccountPage(tester);
242+
final helper = await findHelperText(tester);
243+
await tester.tap(helper);
244+
245+
check(testBinding.takeLaunchUrlCalls())
246+
.single.equals((url: Uri.parse(AddAccountPage.serverUrlHelpUrl), mode: LaunchMode.platformDefault));
247+
});
248+
249+
testWidgets('shows error dialog when URL fails to open', (tester) async {
250+
await prepareAddAccountPage(tester);
251+
testBinding.launchUrlResult = false;
252+
final helper = await findHelperText(tester);
253+
await tester.tap(helper);
254+
await tester.pump();
255+
256+
checkErrorDialog(tester,
257+
expectedTitle: zulipLocalizations.errorUnableToOpenLinkTitle,
258+
expectedMessage: zulipLocalizations.errorLinkCouldNotBeOpened(AddAccountPage.serverUrlHelpUrl));
259+
});
260+
});
221261
}

0 commit comments

Comments
 (0)