mirror of
https://gitlab.com/nkming2/nc-photos.git
synced 2025-02-24 18:38:48 +01:00
Add a cloud-shaped progress indicator
This commit is contained in:
parent
76e804dc8b
commit
173817dadf
3 changed files with 154 additions and 8 deletions
148
app/lib/widget/cloud_progress_indicator.dart
Normal file
148
app/lib/widget/cloud_progress_indicator.dart
Normal file
|
@ -0,0 +1,148 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
/// A progress indicator that looks like a cloud
|
||||
class CloudProgressIndicator extends StatefulWidget {
|
||||
const CloudProgressIndicator({
|
||||
super.key,
|
||||
required this.size,
|
||||
this.value,
|
||||
});
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _CloudProgressIndicatorState();
|
||||
|
||||
final double size;
|
||||
final double? value;
|
||||
}
|
||||
|
||||
class _CloudProgressIndicatorState extends State<CloudProgressIndicator>
|
||||
with SingleTickerProviderStateMixin {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
if (widget.value == null) {
|
||||
_startIntermediateAnimation();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(CloudProgressIndicator oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
if (widget.value == null && !_controller.isAnimating) {
|
||||
_startIntermediateAnimation();
|
||||
} else if (widget.value != null && _controller.isAnimating) {
|
||||
_controller.stop();
|
||||
_isInvert = false;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _Indicator(
|
||||
size: widget.size,
|
||||
value: widget.value,
|
||||
controller: _controller,
|
||||
isInvert: _isInvert,
|
||||
);
|
||||
}
|
||||
|
||||
void _startIntermediateAnimation() {
|
||||
_controller
|
||||
..forward(from: 0)
|
||||
..addStatusListener((status) {
|
||||
if (mounted) {
|
||||
if (status == AnimationStatus.completed) {
|
||||
setState(() {
|
||||
_isInvert = true;
|
||||
});
|
||||
_controller.reverse(from: 1);
|
||||
} else if (status == AnimationStatus.dismissed) {
|
||||
setState(() {
|
||||
_isInvert = false;
|
||||
});
|
||||
_controller.forward(from: 0);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
late final _controller = AnimationController(
|
||||
vsync: this,
|
||||
duration: const Duration(milliseconds: 3500),
|
||||
);
|
||||
|
||||
var _isInvert = false;
|
||||
}
|
||||
|
||||
class _Indicator extends AnimatedWidget {
|
||||
const _Indicator({
|
||||
required this.size,
|
||||
required this.value,
|
||||
required this.isInvert,
|
||||
required AnimationController controller,
|
||||
}) : super(listenable: controller);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final thisValue = value ?? _progress.value;
|
||||
final stroke = size / 12;
|
||||
const curve = Curves.easeInOutQuad;
|
||||
return Transform.scale(
|
||||
scaleX: isInvert ? -1 : 1,
|
||||
child: Container(
|
||||
width: size,
|
||||
padding: EdgeInsets.all(stroke / 2),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: AspectRatio(
|
||||
aspectRatio: 1,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: stroke,
|
||||
value: curve.transform((thisValue * 3).clamp(0, 1)),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(width: stroke / 2),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: AspectRatio(
|
||||
aspectRatio: 1,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: stroke,
|
||||
value: curve.transform((thisValue * 3 - 1).clamp(0, 1)),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(width: stroke / 2),
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: AspectRatio(
|
||||
aspectRatio: 1,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: stroke,
|
||||
value: curve.transform((thisValue * 3 - 2).clamp(0, 1)),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Animation<double> get _progress => listenable as Animation<double>;
|
||||
|
||||
final double size;
|
||||
final double? value;
|
||||
final bool isInvert;
|
||||
}
|
|
@ -20,6 +20,7 @@ import 'package:nc_photos/snack_bar_manager.dart';
|
|||
import 'package:nc_photos/string_extension.dart';
|
||||
import 'package:nc_photos/url_launcher_util.dart';
|
||||
import 'package:nc_photos/use_case/ls_single_file.dart';
|
||||
import 'package:nc_photos/widget/cloud_progress_indicator.dart';
|
||||
|
||||
class ConnectArguments {
|
||||
ConnectArguments(this.uri);
|
||||
|
@ -88,15 +89,12 @@ class _ConnectState extends State<Connect> {
|
|||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.cloud,
|
||||
size: 128,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
const CloudProgressIndicator(size: 192),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
L10n.global().connectingToServer(widget.uri),
|
||||
textAlign: TextAlign.center,
|
||||
style: Theme.of(context).textTheme.headline6,
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
)
|
||||
],
|
||||
),
|
||||
|
|
|
@ -9,8 +9,8 @@ import 'package:nc_photos/pref.dart';
|
|||
import 'package:nc_photos/theme.dart';
|
||||
import 'package:nc_photos/url_launcher_util.dart';
|
||||
import 'package:nc_photos/widget/account_picker_dialog.dart';
|
||||
import 'package:nc_photos/widget/app_bar_circular_progress_indicator.dart';
|
||||
import 'package:nc_photos/widget/app_bar_title_container.dart';
|
||||
import 'package:nc_photos/widget/cloud_progress_indicator.dart';
|
||||
import 'package:nc_photos/widget/settings.dart';
|
||||
import 'package:nc_photos/widget/translucent_sliver_app_bar.dart';
|
||||
|
||||
|
@ -42,7 +42,7 @@ class HomeSliverAppBar extends StatelessWidget {
|
|||
title: Text(accountLabel ?? account.address),
|
||||
subtitle: accountLabel == null ? Text(account.username2) : null,
|
||||
icon: isShowProgressIcon
|
||||
? const AppBarCircularProgressIndicator()
|
||||
? const CloudProgressIndicator(size: 36)
|
||||
: (account.scheme == "http"
|
||||
? Icon(
|
||||
Icons.no_encryption_outlined,
|
||||
|
|
Loading…
Reference in a new issue