import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:yumi/ui_kit/components/sc_debounce_widget.dart'; import 'package:yumi/ui_kit/theme/socialchat_theme.dart'; typedef RoomPasswordSubmit = Future Function(String password); class RoomPasswordDialog extends StatefulWidget { static const String dialogTag = 'showRoomPasswordDialog'; const RoomPasswordDialog({ super.key, required this.onSubmit, required this.onCancel, required this.onSuccess, }); final RoomPasswordSubmit onSubmit; final VoidCallback onCancel; final ValueChanged onSuccess; static Future show({required RoomPasswordSubmit onSubmit}) { final completer = Completer(); var isCompleted = false; void complete(String? password) { if (isCompleted) { return; } isCompleted = true; completer.complete(password); } SmartDialog.dismiss(tag: dialogTag); SmartDialog.show( tag: dialogTag, alignment: Alignment.center, animationType: SmartAnimationType.fade, backType: SmartBackType.block, clickMaskDismiss: false, maskColor: Colors.black.withValues(alpha: 0.58), onDismiss: () { complete(null); }, builder: (_) { return RoomPasswordDialog( onSubmit: onSubmit, onCancel: () { complete(null); SmartDialog.dismiss(tag: dialogTag); }, onSuccess: (password) { complete(password); SmartDialog.dismiss(tag: dialogTag); }, ); }, ); return completer.future; } @override State createState() => _RoomPasswordDialogState(); } class _RoomPasswordDialogState extends State { final TextEditingController _passwordController = TextEditingController(); String _errorText = ""; bool _isSubmitting = false; @override void dispose() { _passwordController.dispose(); super.dispose(); } Future _handleEnter() async { if (_isSubmitting) { return; } final password = _passwordController.text.trim(); if (password.isEmpty) { setState(() { _errorText = "Please enter password"; }); return; } setState(() { _errorText = ""; _isSubmitting = true; }); final errorText = await widget.onSubmit(password); if (!mounted) { return; } if ((errorText ?? "").trim().isNotEmpty) { setState(() { _errorText = errorText!.trim(); _isSubmitting = false; }); return; } widget.onSuccess(password); } @override Widget build(BuildContext context) { return Material( type: MaterialType.transparency, child: Center( child: Container( width: 316.w, padding: EdgeInsets.fromLTRB(18.w, 18.w, 18.w, 16.w), decoration: BoxDecoration( color: const Color(0xff09372E), borderRadius: BorderRadius.circular(12.w), ), child: Column( mainAxisSize: MainAxisSize.min, children: [ Text( "Room lock", textAlign: TextAlign.center, style: TextStyle( color: Colors.white, fontSize: 16.sp, fontWeight: FontWeight.w600, height: 1, ), ), SizedBox(height: 18.w), _buildPasswordInput(), SizedBox(height: _errorText.isEmpty ? 14.w : 8.w), if (_errorText.isNotEmpty) _buildErrorText(), SizedBox(height: 12.w), Row( children: [ Expanded( child: _buildButton( label: "cancel", filled: false, onTap: _isSubmitting ? null : widget.onCancel, ), ), SizedBox(width: 12.w), Expanded( child: _buildButton( label: "enter", filled: true, onTap: _isSubmitting ? null : _handleEnter, ), ), ], ), ], ), ), ), ); } Widget _buildPasswordInput() { return Container( height: 44.w, decoration: BoxDecoration( color: const Color(0xff08251E), borderRadius: BorderRadius.circular(8.w), border: Border.all(color: const Color(0xffB2FBCC), width: 1), ), child: TextField( controller: _passwordController, autofocus: true, obscureText: true, cursorColor: SocialChatTheme.primaryColor, keyboardType: TextInputType.visiblePassword, textInputAction: TextInputAction.done, inputFormatters: [LengthLimitingTextInputFormatter(24)], onSubmitted: (_) { _handleEnter(); }, textAlignVertical: TextAlignVertical.center, decoration: InputDecoration( hintText: "Please enter password", hintStyle: TextStyle( color: Colors.white.withValues(alpha: 0.55), fontSize: 14.sp, height: 16 / 14, ), filled: true, fillColor: Colors.transparent, border: InputBorder.none, enabledBorder: InputBorder.none, focusedBorder: InputBorder.none, disabledBorder: InputBorder.none, errorBorder: InputBorder.none, focusedErrorBorder: InputBorder.none, isDense: true, contentPadding: EdgeInsets.symmetric(horizontal: 12.w), ), style: TextStyle( color: Colors.white, backgroundColor: Colors.transparent, fontSize: 14.sp, fontWeight: FontWeight.w400, height: 16 / 14, ), ), ); } Widget _buildErrorText() { return SizedBox( width: double.infinity, child: Text( _errorText, maxLines: 2, overflow: TextOverflow.ellipsis, style: TextStyle( color: const Color(0xffff4d4d), fontSize: 12.sp, fontWeight: FontWeight.w400, height: 14 / 12, ), ), ); } Widget _buildButton({ required String label, required bool filled, required VoidCallback? onTap, }) { final child = Container( height: 38.w, alignment: Alignment.center, decoration: BoxDecoration( color: filled ? SocialChatTheme.primaryColor : Colors.transparent, borderRadius: BorderRadius.circular(19.w), border: Border.all( color: filled ? SocialChatTheme.primaryColor : Colors.white, width: 1.w, ), ), child: Text( label, textAlign: TextAlign.center, style: TextStyle( color: filled ? Colors.black : Colors.white, fontSize: 14.sp, fontWeight: FontWeight.w600, height: 1, ), ), ); return Opacity( opacity: onTap == null ? 0.55 : 1, child: SCDebounceWidget(onTap: onTap ?? () {}, child: child), ); } }