From 52b4ce654547b76c3bfa85ef2e06d091a0a0799b Mon Sep 17 00:00:00 2001 From: v3DJG6GL <72495210+v3DJG6GL@users.noreply.github.com> Date: Mon, 9 Mar 2026 18:43:10 +0100 Subject: [PATCH 1/4] feat: add "Open Jellyfin QuickConnect" link to login code dialog --- lib/screens/login/login_code_dialog.dart | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/lib/screens/login/login_code_dialog.dart b/lib/screens/login/login_code_dialog.dart index 61121ce01..c7dccaabf 100644 --- a/lib/screens/login/login_code_dialog.dart +++ b/lib/screens/login/login_code_dialog.dart @@ -4,11 +4,14 @@ import 'package:async/async.dart'; import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; import 'package:fladder/providers/api_provider.dart'; import 'package:fladder/providers/auth_provider.dart'; +import 'package:fladder/screens/shared/media/external_urls.dart' as ext; import 'package:fladder/util/clipboard_helper.dart'; +import 'package:fladder/util/fladder_config.dart'; import 'package:fladder/util/list_padding.dart'; import 'package:fladder/util/localization_helper.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:iconsax_plus/iconsax_plus.dart'; Future openLoginCodeDialog( BuildContext context, { @@ -120,6 +123,18 @@ class _LoginCodeDialogState extends ConsumerState { ), ), ), + TextButton.icon( + onPressed: () async { + final baseUrl = + FladderConfig.baseUrl ?? ref.read(authProvider).serverLoginModel?.tempCredentials.url; + if (baseUrl != null && baseUrl.isNotEmpty) { + await ext.launchUrl(context, '$baseUrl/web/#/quickconnect'); + timer?.reset(); + } + }, + icon: const Icon(IconsaxPlusLinear.export_1), + label: Text(context.localized.openJellyfinQuickConnect), + ), ], FilledButton( onPressed: () async { From 9d8f7f9a4b19378eaeb9895f260d82222b52181f Mon Sep 17 00:00:00 2001 From: v3DJG6GL <72495210+v3DJG6GL@users.noreply.github.com> Date: Mon, 9 Mar 2026 18:43:44 +0100 Subject: [PATCH 2/4] feat: add openJellyfinQuickConnect localization string --- lib/l10n/app_en.arb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 2b3b7344b..664f8fbd5 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -1546,6 +1546,8 @@ "quickConnectPostFailed": "Failed to get quick connect code", "quickConnectLoginUsingCode": "Using quick connect", "quickConnectEnterCodeDescription": "Enter the code below to login", + "openJellyfinQuickConnect": "Open Jellyfin QuickConnect", + "@openJellyfinQuickConnect": {}, "showMore": "Show more", "showLess": "Show less", "itemColorsTitle": "Item colors", From e302cc9df47a6398cc99a180b9a1686f2cb086f6 Mon Sep 17 00:00:00 2001 From: v3DJG6GL <72495210+v3DJG6GL@users.noreply.github.com> Date: Thu, 23 Apr 2026 06:17:47 +0200 Subject: [PATCH 3/4] fix(login): strip trailing slashes from baseUrl before building Jellyfin QuickConnect URL --- lib/screens/login/login_code_dialog.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/screens/login/login_code_dialog.dart b/lib/screens/login/login_code_dialog.dart index c7dccaabf..84aba66ce 100644 --- a/lib/screens/login/login_code_dialog.dart +++ b/lib/screens/login/login_code_dialog.dart @@ -126,7 +126,8 @@ class _LoginCodeDialogState extends ConsumerState { TextButton.icon( onPressed: () async { final baseUrl = - FladderConfig.baseUrl ?? ref.read(authProvider).serverLoginModel?.tempCredentials.url; + (FladderConfig.baseUrl ?? ref.read(authProvider).serverLoginModel?.tempCredentials.url) + ?.replaceAll(RegExp(r'/+$'), ''); if (baseUrl != null && baseUrl.isNotEmpty) { await ext.launchUrl(context, '$baseUrl/web/#/quickconnect'); timer?.reset(); From 09ce04f75f65cecd86180c6f4d362161f3dac2b1 Mon Sep 17 00:00:00 2001 From: v3DJG6GL <72495210+v3DJG6GL@users.noreply.github.com> Date: Wed, 29 Apr 2026 01:39:25 +0200 Subject: [PATCH 4/4] refactor: use serverUrlProvider and URL builder helper --- lib/screens/login/login_code_dialog.dart | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/screens/login/login_code_dialog.dart b/lib/screens/login/login_code_dialog.dart index 84aba66ce..4365a353b 100644 --- a/lib/screens/login/login_code_dialog.dart +++ b/lib/screens/login/login_code_dialog.dart @@ -6,7 +6,6 @@ import 'package:fladder/providers/api_provider.dart'; import 'package:fladder/providers/auth_provider.dart'; import 'package:fladder/screens/shared/media/external_urls.dart' as ext; import 'package:fladder/util/clipboard_helper.dart'; -import 'package:fladder/util/fladder_config.dart'; import 'package:fladder/util/list_padding.dart'; import 'package:fladder/util/localization_helper.dart'; import 'package:flutter/material.dart'; @@ -125,11 +124,15 @@ class _LoginCodeDialogState extends ConsumerState { ), TextButton.icon( onPressed: () async { - final baseUrl = - (FladderConfig.baseUrl ?? ref.read(authProvider).serverLoginModel?.tempCredentials.url) - ?.replaceAll(RegExp(r'/+$'), ''); - if (baseUrl != null && baseUrl.isNotEmpty) { - await ext.launchUrl(context, '$baseUrl/web/#/quickconnect'); + final baseUrl = ref.read(serverUrlProvider); + if (baseUrl == null || baseUrl.isEmpty) return; + final url = buildServerUriFromBase( + baseUrl, + pathSegments: ['web'], + relativeUrl: '#/quickconnect', + )?.toString(); + if (url != null && url.isNotEmpty) { + await ext.launchUrl(context, url); timer?.reset(); } },