Refactor ShareFileDialog to improve UI layout, error handling, and share link management
This commit is contained in:
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import '../services/api_client.dart';
|
import '../services/api_client.dart';
|
||||||
import '../theme/app_theme.dart';
|
import '../theme/app_theme.dart';
|
||||||
|
import '../theme/modern_glass_button.dart';
|
||||||
import '../injection.dart';
|
import '../injection.dart';
|
||||||
|
|
||||||
class ShareFileDialog extends StatefulWidget {
|
class ShareFileDialog extends StatefulWidget {
|
||||||
@@ -24,7 +25,6 @@ class _ShareFileDialogState extends State<ShareFileDialog> {
|
|||||||
bool _isLoading = true;
|
bool _isLoading = true;
|
||||||
String? _shareUrl;
|
String? _shareUrl;
|
||||||
String? _error;
|
String? _error;
|
||||||
late final TextEditingController _urlController = TextEditingController();
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@@ -32,12 +32,6 @@ class _ShareFileDialogState extends State<ShareFileDialog> {
|
|||||||
_loadShareLink();
|
_loadShareLink();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
_urlController.dispose();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _loadShareLink() async {
|
Future<void> _loadShareLink() async {
|
||||||
setState(() {
|
setState(() {
|
||||||
_isLoading = true;
|
_isLoading = true;
|
||||||
@@ -53,7 +47,6 @@ class _ShareFileDialogState extends State<ShareFileDialog> {
|
|||||||
if (response['exists'] == true) {
|
if (response['exists'] == true) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_shareUrl = response['url'];
|
_shareUrl = response['url'];
|
||||||
_urlController.text = _shareUrl!;
|
|
||||||
_isLoading = false;
|
_isLoading = false;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@@ -81,7 +74,6 @@ class _ShareFileDialogState extends State<ShareFileDialog> {
|
|||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
_shareUrl = response['url'];
|
_shareUrl = response['url'];
|
||||||
_urlController.text = _shareUrl!;
|
|
||||||
_isLoading = false;
|
_isLoading = false;
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -106,7 +98,6 @@ class _ShareFileDialogState extends State<ShareFileDialog> {
|
|||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
_shareUrl = null;
|
_shareUrl = null;
|
||||||
_urlController.clear();
|
|
||||||
_isLoading = false;
|
_isLoading = false;
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -129,78 +120,108 @@ class _ShareFileDialogState extends State<ShareFileDialog> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Dialog(
|
return Dialog(
|
||||||
backgroundColor: Colors.transparent,
|
backgroundColor: AppTheme.primaryBackground,
|
||||||
child: ConstrainedBox(
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
|
||||||
constraints: const BoxConstraints(maxWidth: 500),
|
child: Container(
|
||||||
child: Container(
|
width: 500,
|
||||||
decoration: AppTheme.glassDecoration,
|
constraints: const BoxConstraints(maxHeight: 400),
|
||||||
padding: const EdgeInsets.all(24),
|
padding: const EdgeInsets.all(24),
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
children: [
|
||||||
children: [
|
// Header
|
||||||
Text(
|
Row(
|
||||||
'Share "${widget.fileName}"',
|
children: [
|
||||||
style: TextStyle(
|
Text(
|
||||||
color: AppTheme.primaryText,
|
'Share "${widget.fileName}"',
|
||||||
fontSize: 20,
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.bold,
|
color: AppTheme.primaryText,
|
||||||
),
|
fontSize: 20,
|
||||||
),
|
fontWeight: FontWeight.bold,
|
||||||
const SizedBox(height: 16),
|
|
||||||
if (_isLoading)
|
|
||||||
const Center(
|
|
||||||
child: CircularProgressIndicator(
|
|
||||||
valueColor: AlwaysStoppedAnimation<Color>(
|
|
||||||
AppTheme.accentColor,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
else if (_error != null)
|
const Spacer(),
|
||||||
Text(_error!, style: TextStyle(color: Colors.red[400]))
|
IconButton(
|
||||||
else
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
Column(
|
icon: Icon(Icons.close, color: AppTheme.secondaryText),
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
splashColor: Colors.transparent,
|
||||||
|
highlightColor: Colors.transparent,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
if (_isLoading)
|
||||||
|
const Center(
|
||||||
|
child: CircularProgressIndicator(
|
||||||
|
valueColor: AlwaysStoppedAnimation<Color>(
|
||||||
|
AppTheme.accentColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
else if (_error != null)
|
||||||
|
Center(
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Share link created. Anyone with this link can view and download the file.',
|
_error!,
|
||||||
style: TextStyle(color: AppTheme.secondaryText),
|
style: TextStyle(color: AppTheme.errorColor),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
TextField(
|
ModernGlassButton(
|
||||||
controller: _urlController,
|
onPressed: _loadShareLink,
|
||||||
readOnly: true,
|
child: const Text('Retry'),
|
||||||
maxLines: 2,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
labelText: 'Share link',
|
|
||||||
border: const OutlineInputBorder(),
|
|
||||||
suffixIcon: IconButton(
|
|
||||||
icon: const Icon(Icons.copy),
|
|
||||||
onPressed: _copyToClipboard,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 16),
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
TextButton(
|
|
||||||
onPressed: _revokeShareLink,
|
|
||||||
style: TextButton.styleFrom(
|
|
||||||
foregroundColor: Colors.red[400],
|
|
||||||
),
|
|
||||||
child: const Text('Revoke Link'),
|
|
||||||
),
|
|
||||||
const Spacer(),
|
|
||||||
TextButton(
|
|
||||||
onPressed: () => Navigator.of(context).pop(),
|
|
||||||
child: const Text('Close'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
)
|
||||||
),
|
else
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'Share link created. Anyone with this link can view and download the file.',
|
||||||
|
style: TextStyle(color: AppTheme.secondaryText),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
_shareUrl!,
|
||||||
|
maxLines: 2,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
style: TextStyle(color: AppTheme.primaryText),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 16),
|
||||||
|
ModernGlassButton(
|
||||||
|
onPressed: _copyToClipboard,
|
||||||
|
child: const Icon(Icons.content_copy),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
ModernGlassButton(
|
||||||
|
onPressed: _revokeShareLink,
|
||||||
|
child: Text(
|
||||||
|
'Revoke Link',
|
||||||
|
style: TextStyle(color: AppTheme.errorColor),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Spacer(),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
|
child: const Text('Close'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user