forked from baron/baron-sso
린트 적용
This commit is contained in:
@@ -15,7 +15,7 @@ class _CreateUserScreenState extends State<CreateUserScreen> {
|
||||
final TextEditingController _emailController = TextEditingController();
|
||||
final TextEditingController _phoneController = TextEditingController();
|
||||
final TextEditingController _nameController = TextEditingController();
|
||||
|
||||
|
||||
bool _isLoading = false;
|
||||
bool _isAuthorized = false;
|
||||
String? _verifiedAdminPassword;
|
||||
@@ -28,7 +28,7 @@ class _CreateUserScreenState extends State<CreateUserScreen> {
|
||||
|
||||
Future<void> _verifyAccess() async {
|
||||
final passwordController = TextEditingController();
|
||||
|
||||
|
||||
// Show blocking dialog
|
||||
final String? inputPassword = await showDialog<String>(
|
||||
context: context,
|
||||
@@ -86,7 +86,10 @@ class _CreateUserScreenState extends State<CreateUserScreen> {
|
||||
} else {
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Invalid Password. Access Denied.'), backgroundColor: Colors.red),
|
||||
const SnackBar(
|
||||
content: Text('Invalid Password. Access Denied.'),
|
||||
backgroundColor: Colors.red,
|
||||
),
|
||||
);
|
||||
context.go('/'); // Kick out
|
||||
}
|
||||
@@ -116,7 +119,9 @@ class _CreateUserScreenState extends State<CreateUserScreen> {
|
||||
}
|
||||
}
|
||||
|
||||
String? phone = _phoneController.text.trim().isEmpty ? null : _phoneController.text.trim();
|
||||
String? phone = _phoneController.text.trim().isEmpty
|
||||
? null
|
||||
: _phoneController.text.trim();
|
||||
if (phone != null && !phone.contains('@')) {
|
||||
phone = phone.replaceAll(RegExp(r'[-\s]'), '');
|
||||
if (phone.startsWith('010')) {
|
||||
@@ -128,14 +133,21 @@ class _CreateUserScreenState extends State<CreateUserScreen> {
|
||||
await AuthProxyService.createUser(
|
||||
loginId: loginId,
|
||||
adminPassword: _verifiedAdminPassword!,
|
||||
email: _emailController.text.trim().isEmpty ? null : _emailController.text.trim(),
|
||||
email: _emailController.text.trim().isEmpty
|
||||
? null
|
||||
: _emailController.text.trim(),
|
||||
phone: phone,
|
||||
displayName: _nameController.text.trim().isEmpty ? null : _nameController.text.trim(),
|
||||
displayName: _nameController.text.trim().isEmpty
|
||||
? null
|
||||
: _nameController.text.trim(),
|
||||
);
|
||||
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('User created successfully!'), backgroundColor: Colors.green),
|
||||
const SnackBar(
|
||||
content: Text('User created successfully!'),
|
||||
backgroundColor: Colors.green,
|
||||
),
|
||||
);
|
||||
_formKey.currentState!.reset();
|
||||
_loginIdController.clear();
|
||||
@@ -158,9 +170,7 @@ class _CreateUserScreenState extends State<CreateUserScreen> {
|
||||
Widget build(BuildContext context) {
|
||||
// Hide content until authorized
|
||||
if (!_isAuthorized) {
|
||||
return const Scaffold(
|
||||
body: Center(child: CircularProgressIndicator()),
|
||||
);
|
||||
return const Scaffold(body: Center(child: CircularProgressIndicator()));
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
@@ -186,7 +196,7 @@ class _CreateUserScreenState extends State<CreateUserScreen> {
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 32),
|
||||
|
||||
|
||||
TextFormField(
|
||||
controller: _loginIdController,
|
||||
decoration: const InputDecoration(
|
||||
@@ -194,10 +204,12 @@ class _CreateUserScreenState extends State<CreateUserScreen> {
|
||||
border: OutlineInputBorder(),
|
||||
helperText: "Unique identifier (Email or Phone)",
|
||||
),
|
||||
validator: (value) => value == null || value.isEmpty ? 'Please enter Login ID' : null,
|
||||
validator: (value) => value == null || value.isEmpty
|
||||
? 'Please enter Login ID'
|
||||
: null,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
|
||||
TextFormField(
|
||||
controller: _nameController,
|
||||
decoration: const InputDecoration(
|
||||
@@ -207,7 +219,7 @@ class _CreateUserScreenState extends State<CreateUserScreen> {
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
|
||||
TextFormField(
|
||||
controller: _emailController,
|
||||
decoration: const InputDecoration(
|
||||
@@ -217,7 +229,7 @@ class _CreateUserScreenState extends State<CreateUserScreen> {
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
|
||||
TextFormField(
|
||||
controller: _phoneController,
|
||||
decoration: const InputDecoration(
|
||||
@@ -228,14 +240,14 @@ class _CreateUserScreenState extends State<CreateUserScreen> {
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 32),
|
||||
|
||||
|
||||
FilledButton(
|
||||
onPressed: _isLoading ? null : _submit,
|
||||
style: FilledButton.styleFrom(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
),
|
||||
child: _isLoading
|
||||
? const CircularProgressIndicator(color: Colors.white)
|
||||
child: _isLoading
|
||||
? const CircularProgressIndicator(color: Colors.white)
|
||||
: const Text("Create User"),
|
||||
),
|
||||
],
|
||||
@@ -245,4 +257,4 @@ class _CreateUserScreenState extends State<CreateUserScreen> {
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,8 @@ class UserManagementScreen extends StatefulWidget {
|
||||
State<UserManagementScreen> createState() => _UserManagementScreenState();
|
||||
}
|
||||
|
||||
class _UserManagementScreenState extends State<UserManagementScreen> with SingleTickerProviderStateMixin {
|
||||
class _UserManagementScreenState extends State<UserManagementScreen>
|
||||
with SingleTickerProviderStateMixin {
|
||||
late TabController _tabController;
|
||||
bool _isAuthorized = false;
|
||||
String? _verifiedAdminPassword;
|
||||
@@ -23,7 +24,8 @@ class _UserManagementScreenState extends State<UserManagementScreen> with Single
|
||||
|
||||
// --- Create Tab Controllers ---
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
final TextEditingController _createLoginIdController = TextEditingController();
|
||||
final TextEditingController _createLoginIdController =
|
||||
TextEditingController();
|
||||
final TextEditingController _createEmailController = TextEditingController();
|
||||
final TextEditingController _createPhoneController = TextEditingController();
|
||||
final TextEditingController _createNameController = TextEditingController();
|
||||
@@ -50,7 +52,7 @@ class _UserManagementScreenState extends State<UserManagementScreen> with Single
|
||||
// --- Authentication ---
|
||||
Future<void> _verifyAccess() async {
|
||||
final passwordController = TextEditingController();
|
||||
|
||||
|
||||
final String? inputPassword = await showDialog<String>(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
@@ -64,15 +66,24 @@ class _UserManagementScreenState extends State<UserManagementScreen> with Single
|
||||
TextField(
|
||||
controller: passwordController,
|
||||
obscureText: true,
|
||||
decoration: const InputDecoration(labelText: "Password", border: OutlineInputBorder()),
|
||||
decoration: const InputDecoration(
|
||||
labelText: "Password",
|
||||
border: OutlineInputBorder(),
|
||||
),
|
||||
autofocus: true,
|
||||
onSubmitted: (value) => Navigator.pop(context, value),
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
TextButton(onPressed: () => Navigator.pop(context, null), child: const Text("Cancel")),
|
||||
FilledButton(onPressed: () => Navigator.pop(context, passwordController.text), child: const Text("Enter")),
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context, null),
|
||||
child: const Text("Cancel"),
|
||||
),
|
||||
FilledButton(
|
||||
onPressed: () => Navigator.pop(context, passwordController.text),
|
||||
child: const Text("Enter"),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
@@ -96,7 +107,12 @@ class _UserManagementScreenState extends State<UserManagementScreen> with Single
|
||||
}
|
||||
} else {
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('Invalid Password'), backgroundColor: Colors.red));
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('Invalid Password'),
|
||||
backgroundColor: Colors.red,
|
||||
),
|
||||
);
|
||||
context.go('/');
|
||||
}
|
||||
}
|
||||
@@ -107,7 +123,10 @@ class _UserManagementScreenState extends State<UserManagementScreen> with Single
|
||||
if (_verifiedAdminPassword == null) return;
|
||||
setState(() => _isLoading = true);
|
||||
try {
|
||||
final users = await AuthProxyService.listUsers(_verifiedAdminPassword!, query: query);
|
||||
final users = await AuthProxyService.listUsers(
|
||||
_verifiedAdminPassword!,
|
||||
query: query,
|
||||
);
|
||||
setState(() => _users = users);
|
||||
} catch (e) {
|
||||
_showError("Failed to load users: $e");
|
||||
@@ -125,18 +144,23 @@ class _UserManagementScreenState extends State<UserManagementScreen> with Single
|
||||
|
||||
Future<void> _deleteUser(String loginId) async {
|
||||
if (_verifiedAdminPassword == null) return;
|
||||
|
||||
|
||||
final confirm = await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text("Delete User"),
|
||||
content: Text("Are you sure you want to delete $loginId? This cannot be undone."),
|
||||
content: Text(
|
||||
"Are you sure you want to delete $loginId? This cannot be undone.",
|
||||
),
|
||||
actions: [
|
||||
TextButton(onPressed: () => Navigator.pop(context, false), child: const Text("Cancel")),
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context, false),
|
||||
child: const Text("Cancel"),
|
||||
),
|
||||
FilledButton(
|
||||
style: FilledButton.styleFrom(backgroundColor: Colors.red),
|
||||
onPressed: () => Navigator.pop(context, true),
|
||||
child: const Text("Delete")
|
||||
onPressed: () => Navigator.pop(context, true),
|
||||
child: const Text("Delete"),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -158,11 +182,17 @@ class _UserManagementScreenState extends State<UserManagementScreen> with Single
|
||||
|
||||
Future<void> _toggleStatus(String loginId, String currentStatus) async {
|
||||
if (_verifiedAdminPassword == null) return;
|
||||
final newStatus = (currentStatus == "enabled" || currentStatus == "active") ? "disabled" : "enabled";
|
||||
|
||||
final newStatus = (currentStatus == "enabled" || currentStatus == "active")
|
||||
? "disabled"
|
||||
: "enabled";
|
||||
|
||||
setState(() => _isLoading = true);
|
||||
try {
|
||||
await AuthProxyService.updateUserStatus(_verifiedAdminPassword!, loginId, newStatus);
|
||||
await AuthProxyService.updateUserStatus(
|
||||
_verifiedAdminPassword!,
|
||||
loginId,
|
||||
newStatus,
|
||||
);
|
||||
_showSuccess("User status updated to $newStatus");
|
||||
_loadUsers(query: _searchController.text);
|
||||
} catch (e) {
|
||||
@@ -174,14 +204,20 @@ class _UserManagementScreenState extends State<UserManagementScreen> with Single
|
||||
|
||||
Future<void> _editUser(Map user) async {
|
||||
if (_verifiedAdminPassword == null) return;
|
||||
|
||||
|
||||
final loginIDs = (user['loginIds'] as List?) ?? [];
|
||||
final loginId = loginIDs.isNotEmpty ? loginIDs.first.toString() : "";
|
||||
if (loginId.isEmpty) return;
|
||||
|
||||
final nameController = TextEditingController(text: user['name'] ?? user['user']?['name'] ?? "");
|
||||
final emailController = TextEditingController(text: user['user']?['email'] ?? "");
|
||||
final phoneController = TextEditingController(text: user['user']?['phone'] ?? "");
|
||||
final nameController = TextEditingController(
|
||||
text: user['name'] ?? user['user']?['name'] ?? "",
|
||||
);
|
||||
final emailController = TextEditingController(
|
||||
text: user['user']?['email'] ?? "",
|
||||
);
|
||||
final phoneController = TextEditingController(
|
||||
text: user['user']?['phone'] ?? "",
|
||||
);
|
||||
|
||||
final confirm = await showDialog<bool>(
|
||||
context: context,
|
||||
@@ -190,14 +226,29 @@ class _UserManagementScreenState extends State<UserManagementScreen> with Single
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
TextField(controller: nameController, decoration: const InputDecoration(labelText: "Name")),
|
||||
TextField(controller: emailController, decoration: const InputDecoration(labelText: "Email")),
|
||||
TextField(controller: phoneController, decoration: const InputDecoration(labelText: "Phone")),
|
||||
TextField(
|
||||
controller: nameController,
|
||||
decoration: const InputDecoration(labelText: "Name"),
|
||||
),
|
||||
TextField(
|
||||
controller: emailController,
|
||||
decoration: const InputDecoration(labelText: "Email"),
|
||||
),
|
||||
TextField(
|
||||
controller: phoneController,
|
||||
decoration: const InputDecoration(labelText: "Phone"),
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
TextButton(onPressed: () => Navigator.pop(context, false), child: const Text("Cancel")),
|
||||
FilledButton(onPressed: () => Navigator.pop(context, true), child: const Text("Save")),
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context, false),
|
||||
child: const Text("Cancel"),
|
||||
),
|
||||
FilledButton(
|
||||
onPressed: () => Navigator.pop(context, true),
|
||||
child: const Text("Save"),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
@@ -206,7 +257,9 @@ class _UserManagementScreenState extends State<UserManagementScreen> with Single
|
||||
|
||||
setState(() => _isLoading = true);
|
||||
|
||||
String? phone = phoneController.text.trim().isEmpty ? null : phoneController.text.trim();
|
||||
String? phone = phoneController.text.trim().isEmpty
|
||||
? null
|
||||
: phoneController.text.trim();
|
||||
if (phone != null && !phone.contains('@')) {
|
||||
phone = phone.replaceAll(RegExp(r'[-\s]'), '');
|
||||
if (phone.startsWith('010')) {
|
||||
@@ -246,7 +299,9 @@ class _UserManagementScreenState extends State<UserManagementScreen> with Single
|
||||
}
|
||||
}
|
||||
|
||||
String? phone = _createPhoneController.text.trim().isEmpty ? null : _createPhoneController.text.trim();
|
||||
String? phone = _createPhoneController.text.trim().isEmpty
|
||||
? null
|
||||
: _createPhoneController.text.trim();
|
||||
if (phone != null && !phone.contains('@')) {
|
||||
phone = phone.replaceAll(RegExp(r'[-\s]'), '');
|
||||
if (phone.startsWith('010')) {
|
||||
@@ -258,9 +313,13 @@ class _UserManagementScreenState extends State<UserManagementScreen> with Single
|
||||
await AuthProxyService.createUser(
|
||||
loginId: loginId,
|
||||
adminPassword: _verifiedAdminPassword!,
|
||||
email: _createEmailController.text.trim().isEmpty ? null : _createEmailController.text.trim(),
|
||||
email: _createEmailController.text.trim().isEmpty
|
||||
? null
|
||||
: _createEmailController.text.trim(),
|
||||
phone: phone,
|
||||
displayName: _createNameController.text.trim().isEmpty ? null : _createNameController.text.trim(),
|
||||
displayName: _createNameController.text.trim().isEmpty
|
||||
? null
|
||||
: _createNameController.text.trim(),
|
||||
);
|
||||
|
||||
_showSuccess("User created successfully");
|
||||
@@ -269,11 +328,10 @@ class _UserManagementScreenState extends State<UserManagementScreen> with Single
|
||||
_createEmailController.clear();
|
||||
_createPhoneController.clear();
|
||||
_createNameController.clear();
|
||||
|
||||
|
||||
// Switch to list tab and reload
|
||||
_tabController.animateTo(0);
|
||||
_loadUsers();
|
||||
|
||||
} catch (e) {
|
||||
_showError("Error: $e");
|
||||
} finally {
|
||||
@@ -284,12 +342,16 @@ class _UserManagementScreenState extends State<UserManagementScreen> with Single
|
||||
// --- UI Helpers ---
|
||||
void _showError(String msg) {
|
||||
if (!mounted) return;
|
||||
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(msg), backgroundColor: Colors.red));
|
||||
ScaffoldMessenger.of(
|
||||
context,
|
||||
).showSnackBar(SnackBar(content: Text(msg), backgroundColor: Colors.red));
|
||||
}
|
||||
|
||||
void _showSuccess(String msg) {
|
||||
if (!mounted) return;
|
||||
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(msg), backgroundColor: Colors.green));
|
||||
ScaffoldMessenger.of(
|
||||
context,
|
||||
).showSnackBar(SnackBar(content: Text(msg), backgroundColor: Colors.green));
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -315,10 +377,7 @@ class _UserManagementScreenState extends State<UserManagementScreen> with Single
|
||||
),
|
||||
body: TabBarView(
|
||||
controller: _tabController,
|
||||
children: [
|
||||
_buildUserListTab(),
|
||||
_buildCreateUserTab(),
|
||||
],
|
||||
children: [_buildUserListTab(), _buildCreateUserTab()],
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -341,32 +400,49 @@ class _UserManagementScreenState extends State<UserManagementScreen> with Single
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: _users.isEmpty
|
||||
? const Center(child: Text("No users found."))
|
||||
child: _users.isEmpty
|
||||
? const Center(child: Text("No users found."))
|
||||
: ListView.separated(
|
||||
itemCount: _users.length,
|
||||
separatorBuilder: (context, index) => const Divider(),
|
||||
itemBuilder: (context, index) {
|
||||
final user = _users[index];
|
||||
// 일부 응답은 최상위 또는 user 하위에 필드를 포함합니다.
|
||||
|
||||
|
||||
final loginIDs = (user['loginIds'] as List?) ?? [];
|
||||
final loginId = loginIDs.isNotEmpty ? loginIDs.first.toString() : "Unknown ID";
|
||||
final name = user['name'] ?? user['user']?['name'] ?? "No Name";
|
||||
final loginId = loginIDs.isNotEmpty
|
||||
? loginIDs.first.toString()
|
||||
: "Unknown ID";
|
||||
final name =
|
||||
user['name'] ?? user['user']?['name'] ?? "No Name";
|
||||
final status = user['status'] ?? "unknown";
|
||||
final isEnabled = status == "enabled" || status == "active";
|
||||
|
||||
return ListTile(
|
||||
leading: CircleAvatar(
|
||||
backgroundColor: isEnabled ? Colors.green.shade100 : Colors.grey.shade300,
|
||||
child: Icon(Icons.person, color: isEnabled ? Colors.green : Colors.grey),
|
||||
backgroundColor: isEnabled
|
||||
? Colors.green.shade100
|
||||
: Colors.grey.shade300,
|
||||
child: Icon(
|
||||
Icons.person,
|
||||
color: isEnabled ? Colors.green : Colors.grey,
|
||||
),
|
||||
),
|
||||
title: Text(name),
|
||||
subtitle: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(loginId, style: const TextStyle(fontWeight: FontWeight.bold)),
|
||||
Text("Status: $status", style: TextStyle(color: isEnabled ? Colors.green : Colors.red, fontSize: 12)),
|
||||
Text(
|
||||
loginId,
|
||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
Text(
|
||||
"Status: $status",
|
||||
style: TextStyle(
|
||||
color: isEnabled ? Colors.green : Colors.red,
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
trailing: Row(
|
||||
@@ -378,7 +454,10 @@ class _UserManagementScreenState extends State<UserManagementScreen> with Single
|
||||
onPressed: () => _editUser(user),
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(isEnabled ? Icons.block : Icons.check_circle, color: isEnabled ? Colors.orange : Colors.green),
|
||||
icon: Icon(
|
||||
isEnabled ? Icons.block : Icons.check_circle,
|
||||
color: isEnabled ? Colors.orange : Colors.green,
|
||||
),
|
||||
tooltip: isEnabled ? "Disable User" : "Enable User",
|
||||
onPressed: () => _toggleStatus(loginId, status),
|
||||
),
|
||||
@@ -417,27 +496,44 @@ class _UserManagementScreenState extends State<UserManagementScreen> with Single
|
||||
border: OutlineInputBorder(),
|
||||
helperText: "Unique identifier (Email or Phone)",
|
||||
),
|
||||
validator: (value) => value == null || value.isEmpty ? 'Please enter Login ID' : null,
|
||||
validator: (value) => value == null || value.isEmpty
|
||||
? 'Please enter Login ID'
|
||||
: null,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextFormField(
|
||||
controller: _createNameController,
|
||||
decoration: const InputDecoration(labelText: "Display Name", border: OutlineInputBorder(), prefixIcon: Icon(Icons.person)),
|
||||
decoration: const InputDecoration(
|
||||
labelText: "Display Name",
|
||||
border: OutlineInputBorder(),
|
||||
prefixIcon: Icon(Icons.person),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextFormField(
|
||||
controller: _createEmailController,
|
||||
decoration: const InputDecoration(labelText: "Email", border: OutlineInputBorder(), prefixIcon: Icon(Icons.email)),
|
||||
decoration: const InputDecoration(
|
||||
labelText: "Email",
|
||||
border: OutlineInputBorder(),
|
||||
prefixIcon: Icon(Icons.email),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextFormField(
|
||||
controller: _createPhoneController,
|
||||
decoration: const InputDecoration(labelText: "Phone Number", border: OutlineInputBorder(), prefixIcon: Icon(Icons.phone), helperText: "010-xxxx-xxxx"),
|
||||
decoration: const InputDecoration(
|
||||
labelText: "Phone Number",
|
||||
border: OutlineInputBorder(),
|
||||
prefixIcon: Icon(Icons.phone),
|
||||
helperText: "010-xxxx-xxxx",
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 32),
|
||||
FilledButton(
|
||||
onPressed: _isLoading ? null : _createUserSubmit,
|
||||
style: FilledButton.styleFrom(padding: const EdgeInsets.symmetric(vertical: 16)),
|
||||
style: FilledButton.styleFrom(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
),
|
||||
child: const Text("Create User"),
|
||||
),
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user