feat(ui): support skeleton-state loading on LunaBlock

This commit is contained in:
Jagandeep Brar
2022-02-09 00:07:40 -05:00
parent 2b778dc437
commit 8ab5f80d00
5 changed files with 123 additions and 3 deletions

View File

@@ -30,6 +30,7 @@ export 'ui/popup_menu_button.dart';
export 'ui/refresh_indicator.dart';
export 'ui/scaffold.dart';
export 'ui/shape.dart';
export 'ui/shimmer.dart';
export 'ui/snackbar.dart';
export 'ui/switch.dart';
export 'ui/table.dart';
@@ -70,8 +71,9 @@ class LunaUI {
// <--> Animations
static const int ANIMATION_SPEED = 250;
static const int ANIMATION_SPEED_IMAGES = 125;
static const int ANIMATION_SPEED_IMAGES = ANIMATION_SPEED ~/ 2;
static const int ANIMATION_SPEED_SCROLLING = ANIMATION_SPEED * 2;
static const int ANIMATION_SPEED_SHIMMER = ANIMATION_SPEED * 4;
// <--> Other
static const double BORDER_RADIUS = 10.0;

View File

@@ -5,6 +5,11 @@ class LunaBlock extends StatelessWidget {
static const TITLE_HEIGHT = LunaUI.FONT_SIZE_H2 + 4.0;
static const SUBTITLE_HEIGHT = LunaUI.FONT_SIZE_H3 + 4.0;
// If true, will load a skeleton-form version of the block.
final bool skeletonEnabled;
final bool skeletonPoster;
final int skeletonSubtitles;
final bool? disabled;
final String? title;
final Color titleColor;
@@ -37,8 +42,11 @@ class LunaBlock extends StatelessWidget {
const LunaBlock({
Key? key,
this.skeletonEnabled = false,
this.skeletonPoster = true,
this.skeletonSubtitles = 2,
this.disabled = false,
required this.title,
this.title,
this.titleColor = Colors.white,
this.body,
this.bodyLeadingIcons,
@@ -92,11 +100,36 @@ class LunaBlock extends StatelessWidget {
);
}
double _calculateSkeletonHeight() {
return calculateItemHeight(
skeletonSubtitles,
hasBottom: bottom != null,
bottomHeight: bottomHeight,
);
}
@override
Widget build(BuildContext context) {
if (skeletonEnabled) return _buildSkeletonBlock(context);
return _buildBlock(context);
}
Widget _buildSkeletonBlock(BuildContext context) {
double _height = _calculateSkeletonHeight();
return LunaCard(
context: context,
child: LunaShimmer(
child: Row(
children: [
if (skeletonPoster) _poster(context, _height),
_tile(context, _height),
],
),
),
height: _height,
);
}
Widget _buildBlock(BuildContext context) {
double _height = _calculateHeight();
return LunaCard(
@@ -160,11 +193,29 @@ class LunaBlock extends StatelessWidget {
}
Widget _poster(BuildContext context, double height) {
double _dimension = height - LunaUI.DEFAULT_MARGIN_SIZE;
if (skeletonEnabled) {
return Padding(
padding: const EdgeInsets.only(left: LunaUI.MARGIN_SIZE_HALF),
child: Container(
height: _dimension,
width: _dimension / (posterIsSquare ? 1.0 : 1.5),
decoration: BoxDecoration(
color: Theme.of(context).canvasColor,
borderRadius: BorderRadius.circular(LunaUI.BORDER_RADIUS),
border: LunaUI.shouldUseBorder
? Border.all(color: LunaColours.white10)
: null,
),
),
);
}
if (posterUrl == null && posterPlaceholderIcon == null) {
return const SizedBox(width: 0.0, height: 0.0);
}
double _dimension = height - LunaUI.DEFAULT_MARGIN_SIZE;
return Padding(
padding: const EdgeInsets.only(left: LunaUI.MARGIN_SIZE_HALF),
child: LunaNetworkImage(
@@ -179,6 +230,44 @@ class LunaBlock extends StatelessWidget {
}
Widget _tile(BuildContext context, double height) {
if (skeletonEnabled) {
return Expanded(
child: Padding(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
height: LunaBlock.TITLE_HEIGHT - 4.0,
width: double.infinity,
decoration: BoxDecoration(
color: Theme.of(context).canvasColor,
borderRadius: BorderRadius.circular(LunaUI.BORDER_RADIUS),
border: LunaUI.shouldUseBorder
? Border.all(color: LunaColours.white10)
: null,
),
),
...List.generate(skeletonSubtitles, (_) {
return Container(
height: LunaBlock.SUBTITLE_HEIGHT - 6.0,
width: MediaQuery.of(context).size.width / 2.5,
decoration: BoxDecoration(
color: Theme.of(context).canvasColor,
borderRadius: BorderRadius.circular(LunaUI.BORDER_RADIUS),
border: LunaUI.shouldUseBorder
? Border.all(color: LunaColours.white10)
: null,
),
);
}),
],
),
padding: LunaUI.MARGIN_DEFAULT,
),
);
}
return Expanded(
// ignore: deprecated_member_use_from_same_package
child: LunaListTile(

21
lib/core/ui/shimmer.dart Normal file
View File

@@ -0,0 +1,21 @@
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:shimmer/shimmer.dart';
class LunaShimmer extends StatelessWidget {
final Widget child;
const LunaShimmer({
Key? key,
required this.child,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Shimmer.fromColors(
child: child,
baseColor: Theme.of(context).primaryColor,
highlightColor: LunaColours.accent,
);
}
}

View File

@@ -1143,6 +1143,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
shimmer:
dependency: "direct main"
description:
name: shimmer
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
simple_gesture_detector:
dependency: transitive
description:

View File

@@ -49,6 +49,7 @@ dependencies:
quick_actions: ^0.6.0+9
retrofit: ^3.0.1
share_plus: ^3.0.4
shimmer: ^2.0.0
stack_trace: ^1.10.0
stash_memory: ^4.0.1
supercharged: ^2.1.1