fixed countdown wrap, css rgba colors, stale create-link gate and wired up reply drafts in talk

This commit is contained in:
2026-09-27 21:13:44 +02:00
parent 2664378b17
commit aca86c506a
5 changed files with 143 additions and 119 deletions
+79 -88
View File
@@ -50,10 +50,6 @@ class _ShareSheetBodyState extends State<_ShareSheetBody> {
late Future<List<Share>> _future = FileSharingApi().listForPath(_ocsPath);
bool _busy = false;
/// Last resolved share list — used by the create-link gate without depending
/// on the FutureBuilder's snapshot.
List<Share>? _lastShares;
void _reload() {
// Block body: an arrow would return the Future, which setState rejects.
setState(() {
@@ -126,103 +122,98 @@ class _ShareSheetBodyState extends State<_ShareSheetBody> {
@override
Widget build(BuildContext context) {
final caps = context.watch<NextcloudCapabilitiesCubit>();
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.min,
children: [
if (_busy) const LinearProgressIndicator(),
_shareList(),
const Divider(height: 1),
if (caps.canShareWithUsers || caps.canShareWithGroups)
ListTile(
leading: const CenteredLeading(Icon(Icons.person_add_outlined)),
title: const Text('Person oder Gruppe hinzufügen'),
enabled: !_busy,
onTap: _addSharee,
),
if (caps.canCreatePublicLinks && _canAddLink(caps))
ListTile(
leading: const CenteredLeading(Icon(Icons.add_link)),
title: const Text('Öffentlichen Link erstellen'),
enabled: !_busy,
onTap: _createPublicLink,
),
],
return FutureBuilder<List<Share>>(
future: _future,
builder: (context, snapshot) => Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.min,
children: [
if (_busy) const LinearProgressIndicator(),
_shareList(snapshot),
const Divider(height: 1),
if (caps.canShareWithUsers || caps.canShareWithGroups)
ListTile(
leading: const CenteredLeading(Icon(Icons.person_add_outlined)),
title: const Text('Person oder Gruppe hinzufügen'),
enabled: !_busy,
onTap: _addSharee,
),
if (caps.canCreatePublicLinks && _canAddLink(caps, snapshot.data))
ListTile(
leading: const CenteredLeading(Icon(Icons.add_link)),
title: const Text('Öffentlichen Link erstellen'),
enabled: !_busy,
onTap: _createPublicLink,
),
],
),
);
}
/// Whether another public link may be created — hidden once one exists on a
/// server that disallows multiple links.
bool _canAddLink(NextcloudCapabilitiesCubit caps) {
if (caps.allowsMultipleLinks) return true;
final hasLink = _lastShares?.any((s) => s.isPublicLink) ?? false;
return !hasLink;
}
bool _canAddLink(NextcloudCapabilitiesCubit caps, List<Share>? shares) =>
caps.allowsMultipleLinks ||
!(shares?.any((s) => s.isPublicLink) ?? false);
Widget _shareList() {
return FutureBuilder<List<Share>>(
future: _future,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Padding(
padding: EdgeInsets.all(24),
child: Center(child: AppProgressIndicator.medium()),
);
}
if (snapshot.hasError) {
return Padding(
padding: const EdgeInsets.all(24),
Widget _shareList(AsyncSnapshot<List<Share>> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Padding(
padding: EdgeInsets.all(24),
child: Center(child: AppProgressIndicator.medium()),
);
}
if (snapshot.hasError) {
return Padding(
padding: const EdgeInsets.all(24),
child: Column(
children: [
Text(
errorToUserMessage(snapshot.error),
textAlign: TextAlign.center,
),
const SizedBox(height: 12),
FilledButton.tonal(
onPressed: _reload,
child: const Text('Erneut versuchen'),
),
],
),
);
}
final shares = snapshot.data ?? const <Share>[];
if (shares.isEmpty) {
final theme = Theme.of(context);
return SizedBox(
height: 160,
child: Center(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
errorToUserMessage(snapshot.error),
textAlign: TextAlign.center,
Icon(
Icons.lock_outline,
size: 48,
color: theme.colorScheme.outline,
),
const SizedBox(height: 12),
FilledButton.tonal(
onPressed: _reload,
child: const Text('Erneut versuchen'),
Text(
'Diese Datei ist noch nicht freigegeben.',
textAlign: TextAlign.center,
style: theme.textTheme.bodyLarge?.copyWith(
color: theme.colorScheme.onSurfaceVariant,
),
),
],
),
);
}
final shares = snapshot.data ?? const <Share>[];
_lastShares = shares;
if (shares.isEmpty) {
final theme = Theme.of(context);
return SizedBox(
height: 160,
child: Center(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.lock_outline,
size: 48,
color: theme.colorScheme.outline,
),
const SizedBox(height: 12),
Text(
'Diese Datei ist noch nicht freigegeben.',
textAlign: TextAlign.center,
style: theme.textTheme.bodyLarge?.copyWith(
color: theme.colorScheme.onSurfaceVariant,
),
),
],
),
),
),
);
}
return Column(
mainAxisSize: MainAxisSize.min,
children: shares.map(_shareTile).toList(),
);
},
),
),
);
}
return Column(
mainAxisSize: MainAxisSize.min,
children: shares.map(_shareTile).toList(),
);
}