mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-08-24 15:16:42 +00:00
* refact(oidc): manually open the browser Signed-off-by: fufesou <linlong1266@gmail.com> * refact(oidc): allow copying OIDC authentication links Signed-off-by: fufesou <linlong1266@gmail.com> * Remove unused translation in ko.rs Signed-off-by: fufesou <linlong1266@gmail.com> * refact(oidc): better hint on browser didn't open Signed-off-by: fufesou <linlong1266@gmail.com> * refact(oidc): login handle exception Signed-off-by: fufesou <linlong1266@gmail.com> * refact(oidc): remove unused translations Signed-off-by: fufesou <linlong1266@gmail.com> * refact(oidc): login handle error Signed-off-by: fufesou <linlong1266@gmail.com> * refact(oidc): login in flight Signed-off-by: fufesou <linlong1266@gmail.com> * refact(translation): move "Continue" to the end of template.rs Signed-off-by: fufesou <linlong1266@gmail.com> * refact(oidc): var rename Signed-off-by: fufesou <linlong1266@gmail.com> * refact(oidc): remove useless "open sign-in page" Signed-off-by: fufesou <linlong1266@gmail.com> * Remove unecessary translation contents Signed-off-by: fufesou <linlong1266@gmail.com> * refact(oidc): better way to show&expand the url Signed-off-by: fufesou <linlong1266@gmail.com> * refact(oidc): better login ui Signed-off-by: fufesou <linlong1266@gmail.com> * fix(oidc): discard stale auth results after cancellation Signed-off-by: fufesou <linlong1266@gmail.com> * fix(oidc): handle auth status query failures safely Signed-off-by: fufesou <linlong1266@gmail.com> * fix(oidc): prevent concurrent login operations - reuse the active login dialog and block duplicate password submissions - cancel only active OIDC operations when closing the dialog - preserve authentication state until failure cancellation succeeds Signed-off-by: fufesou <linlong1266@gmail.com> * fix(oidc): refine login options error feedback Preserve typed errors to hide the network tip for HTTP failures and clarify the login-options API contract. Signed-off-by: fufesou <linlong1266@gmail.com> --------- Signed-off-by: fufesou <linlong1266@gmail.com>
158 lines
4.5 KiB
Dart
158 lines
4.5 KiB
Dart
import 'package:flutter/material.dart';
|
|
|
|
const _statusFontSize = 12.0;
|
|
const _statusSpacing = 4.0;
|
|
const _messageActionSpacing = 8.0;
|
|
const _desktopActionSize = 28.0;
|
|
const _touchPlatforms = <TargetPlatform>{
|
|
TargetPlatform.android,
|
|
TargetPlatform.iOS,
|
|
TargetPlatform.fuchsia,
|
|
};
|
|
|
|
class OidcAuthStatus extends StatelessWidget {
|
|
final String message;
|
|
final String browserFallbackPrompt;
|
|
final String authUrl;
|
|
final String copyLabel;
|
|
final VoidCallback? onCopy;
|
|
|
|
const OidcAuthStatus({
|
|
super.key,
|
|
required this.message,
|
|
required this.browserFallbackPrompt,
|
|
required this.authUrl,
|
|
required this.copyLabel,
|
|
this.onCopy,
|
|
});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final messageStyle =
|
|
DefaultTextStyle.of(context).style.copyWith(fontSize: _statusFontSize);
|
|
return Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
SelectableText(message, style: messageStyle),
|
|
if (authUrl.isNotEmpty)
|
|
Padding(
|
|
padding: const EdgeInsets.only(top: _messageActionSpacing),
|
|
child: _OidcAuthFallback(
|
|
browserFallbackPrompt: browserFallbackPrompt,
|
|
authUrl: authUrl,
|
|
copyLabel: copyLabel,
|
|
onCopy: onCopy,
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|
|
|
|
class _OidcAuthFallback extends StatefulWidget {
|
|
final String browserFallbackPrompt;
|
|
final String authUrl;
|
|
final String copyLabel;
|
|
final VoidCallback? onCopy;
|
|
|
|
const _OidcAuthFallback({
|
|
required this.browserFallbackPrompt,
|
|
required this.authUrl,
|
|
required this.copyLabel,
|
|
required this.onCopy,
|
|
});
|
|
|
|
@override
|
|
State<_OidcAuthFallback> createState() => _OidcAuthFallbackState();
|
|
}
|
|
|
|
class _OidcAuthFallbackState extends State<_OidcAuthFallback> {
|
|
bool _expanded = false;
|
|
|
|
@override
|
|
void didUpdateWidget(covariant _OidcAuthFallback oldWidget) {
|
|
super.didUpdateWidget(oldWidget);
|
|
if (oldWidget.authUrl != widget.authUrl) {
|
|
_expanded = false;
|
|
}
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final theme = Theme.of(context);
|
|
final helperStyle = DefaultTextStyle.of(context).style.copyWith(
|
|
fontSize: _statusFontSize,
|
|
color: theme.colorScheme.onSurfaceVariant,
|
|
);
|
|
final linkColor = theme.brightness == Brightness.dark
|
|
? Colors.blue.shade300
|
|
: Colors.blue.shade800;
|
|
final isTouchPlatform = _touchPlatforms.contains(theme.platform);
|
|
final actionSize =
|
|
isTouchPlatform ? kMinInteractiveDimension : _desktopActionSize;
|
|
final urlStyle =
|
|
DefaultTextStyle.of(context).style.copyWith(fontSize: _statusFontSize);
|
|
return Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Text(
|
|
widget.browserFallbackPrompt,
|
|
style: helperStyle,
|
|
textAlign: TextAlign.center,
|
|
),
|
|
Padding(
|
|
padding: const EdgeInsets.only(top: _statusSpacing),
|
|
child: _buildUrl(urlStyle, linkColor, actionSize),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
void _copyAndExpand() {
|
|
setState(() => _expanded = true);
|
|
widget.onCopy?.call();
|
|
}
|
|
|
|
Widget _buildUrl(TextStyle urlStyle, Color linkColor, double actionSize) {
|
|
final collapsedUrl = SizedBox(
|
|
width: double.infinity,
|
|
child: TextButton(
|
|
style: TextButton.styleFrom(
|
|
foregroundColor: linkColor,
|
|
minimumSize: Size(0, actionSize),
|
|
padding: EdgeInsets.zero,
|
|
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
|
visualDensity: VisualDensity.standard,
|
|
),
|
|
onPressed: _copyAndExpand,
|
|
child: Text(
|
|
widget.authUrl,
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis,
|
|
softWrap: false,
|
|
style: urlStyle.copyWith(
|
|
color: linkColor,
|
|
decoration: TextDecoration.underline,
|
|
),
|
|
),
|
|
),
|
|
);
|
|
final collapsedChild = widget.onCopy == null
|
|
? collapsedUrl
|
|
: Tooltip(message: widget.copyLabel, child: collapsedUrl);
|
|
return Container(
|
|
width: double.infinity,
|
|
constraints: BoxConstraints(minHeight: actionSize),
|
|
alignment: Alignment.centerLeft,
|
|
padding: const EdgeInsets.symmetric(horizontal: _messageActionSpacing),
|
|
decoration: BoxDecoration(
|
|
border: Border.all(color: Theme.of(context).dividerColor),
|
|
borderRadius: BorderRadius.circular(_statusSpacing),
|
|
),
|
|
child: _expanded
|
|
? SelectableText(widget.authUrl, style: urlStyle)
|
|
: collapsedChild,
|
|
);
|
|
}
|
|
}
|