-
Notifications
You must be signed in to change notification settings - Fork 32
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(neon_dashboard): Remove scrolling inside dashboard widgets
Signed-off-by: jld3103 <[email protected]>
- Loading branch information
1 parent
c3805d4
commit 62e9925
Showing
10 changed files
with
266 additions
and
123 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
33 changes: 33 additions & 0 deletions
33
packages/neon/neon_dashboard/lib/src/widgets/dry_intrinsic_height.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
// ignore_for_file: public_member_api_docs | ||
import 'package:flutter/rendering.dart'; | ||
import 'package:flutter/widgets.dart'; | ||
|
||
/// NOTE ref: https://github.com/flutter/flutter/issues/71687 & https://gist.github.com/matthew-carroll/65411529a5fafa1b527a25b7130187c6 | ||
/// Same as `IntrinsicHeight` except that when this widget is instructed | ||
/// to `computeDryLayout()`, it doesn't invoke that on its child, instead | ||
/// it computes the child's intrinsic height. | ||
/// | ||
/// This widget is useful in situations where the `child` does not | ||
/// support dry layout, e.g., `TextField` as of 01/02/2021. | ||
class DryIntrinsicHeight extends SingleChildRenderObjectWidget { | ||
const DryIntrinsicHeight({ | ||
super.key, | ||
super.child, | ||
}); | ||
|
||
@override | ||
RenderDryIntrinsicHeight createRenderObject(final BuildContext context) => RenderDryIntrinsicHeight(); | ||
} | ||
|
||
class RenderDryIntrinsicHeight extends RenderIntrinsicHeight { | ||
@override | ||
Size computeDryLayout(final BoxConstraints constraints) { | ||
if (child != null) { | ||
final height = child!.computeMinIntrinsicHeight(constraints.maxWidth); | ||
final width = child!.computeMinIntrinsicWidth(height); | ||
return Size(width, height); | ||
} else { | ||
return Size.zero; | ||
} | ||
} | ||
} |
105 changes: 7 additions & 98 deletions
105
packages/neon/neon_dashboard/lib/src/widgets/widget.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,124 +1,33 @@ | ||
import 'package:flutter/material.dart'; | ||
import 'package:go_router/go_router.dart'; | ||
import 'package:neon_dashboard/l10n/localizations.dart'; | ||
import 'package:neon_dashboard/src/widgets/widget_button.dart'; | ||
import 'package:neon_dashboard/src/widgets/widget_item.dart'; | ||
import 'package:neon_framework/theme.dart'; | ||
import 'package:neon_framework/widgets.dart'; | ||
import 'package:nextcloud/dashboard.dart' as dashboard; | ||
|
||
/// Displays a single dashboard widget and its items. | ||
class DashboardWidget extends StatelessWidget { | ||
/// Creates a new dashboard widget items. | ||
const DashboardWidget({ | ||
required this.widget, | ||
required this.items, | ||
required this.children, | ||
super.key, | ||
}); | ||
|
||
/// The dashboard widget to be displayed. | ||
final dashboard.Widget widget; | ||
|
||
/// The items of the widget to be displayed. | ||
final dashboard.WidgetItems? items; | ||
final List<Widget> children; | ||
|
||
@override | ||
Widget build(final BuildContext context) { | ||
final halfEmptyContentMessage = _renderMessage(items?.halfEmptyContentMessage); | ||
final emptyContentMessage = _renderMessage(items?.emptyContentMessage); | ||
|
||
return SizedBox( | ||
width: 320, | ||
height: 560, | ||
child: Card( | ||
Widget build(final BuildContext context) => Card( | ||
child: InkWell( | ||
onTap: widget.widgetUrl != null && widget.widgetUrl!.isNotEmpty ? () => context.go(widget.widgetUrl!) : null, | ||
borderRadius: const BorderRadius.all(Radius.circular(12)), | ||
child: ListView( | ||
child: Padding( | ||
padding: const EdgeInsets.all(8), | ||
key: PageStorageKey<String>('dashboard-${widget.id}'), | ||
children: [ | ||
ListTile( | ||
title: Text( | ||
widget.title, | ||
style: const TextStyle( | ||
fontWeight: FontWeight.bold, | ||
), | ||
), | ||
leading: SizedBox.square( | ||
dimension: largeIconSize, | ||
child: _buildWidgetIcon(context), | ||
), | ||
), | ||
const SizedBox( | ||
height: 20, | ||
), | ||
if (halfEmptyContentMessage != null) halfEmptyContentMessage, | ||
if (emptyContentMessage != null) emptyContentMessage, | ||
if (halfEmptyContentMessage == null && emptyContentMessage == null && (items?.items.isEmpty ?? true)) | ||
_renderMessage(DashboardLocalizations.of(context).noEntries)!, | ||
...?items?.items.map( | ||
(final item) => DashboardWidgetItem( | ||
item: item, | ||
roundIcon: widget.itemIconsRound, | ||
), | ||
), | ||
const SizedBox( | ||
height: 20, | ||
), | ||
...?widget.buttons?.map( | ||
(final button) => DashboardWidgetButton( | ||
button: button, | ||
), | ||
), | ||
], | ||
child: Column( | ||
children: children, | ||
), | ||
), | ||
), | ||
), | ||
); | ||
} | ||
|
||
Widget? _buildWidgetIcon(final BuildContext context) { | ||
final colorFilter = ColorFilter.mode(Theme.of(context).colorScheme.primary, BlendMode.srcIn); | ||
|
||
if (widget.iconUrl.isNotEmpty) { | ||
return NeonUrlImage( | ||
url: widget.iconUrl, | ||
svgColorFilter: colorFilter, | ||
size: const Size.square(largeIconSize), | ||
); | ||
} | ||
|
||
if (widget.iconClass.isNotEmpty) { | ||
return NeonServerIcon( | ||
icon: widget.iconClass, | ||
colorFilter: colorFilter, | ||
size: largeIconSize, | ||
); | ||
} | ||
|
||
return Icon( | ||
Icons.question_mark, | ||
color: Theme.of(context).colorScheme.primary, | ||
size: largeIconSize, | ||
); | ||
} | ||
|
||
Widget? _renderMessage(final String? message) { | ||
if (message == null || message.isEmpty) { | ||
return null; | ||
} | ||
|
||
return Center( | ||
child: Column( | ||
children: [ | ||
const Icon( | ||
Icons.check, | ||
size: largeIconSize, | ||
), | ||
Text(message), | ||
], | ||
), | ||
); | ||
} | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
-68 Bytes
(99%)
packages/neon/neon_dashboard/test/goldens/widget_not_round.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
-59 Bytes
(99%)
packages/neon/neon_dashboard/test/goldens/widget_with_empty.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
-63 Bytes
(99%)
packages/neon/neon_dashboard/test/goldens/widget_with_half_empty.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
-643 Bytes
(88%)
packages/neon/neon_dashboard/test/goldens/widget_without_buttons.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
-93 Bytes
(98%)
packages/neon/neon_dashboard/test/goldens/widget_without_items.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.