Merge pull request #5431 from 21pages/ab
don't use Offstage as widget of animated loading, reuse refresh as loading
This commit is contained in:
commit
d26d680390
@ -10,7 +10,6 @@ import 'package:get/get.dart';
|
|||||||
|
|
||||||
import '../../common.dart';
|
import '../../common.dart';
|
||||||
import 'dialog.dart';
|
import 'dialog.dart';
|
||||||
import 'loading_dot_widget.dart';
|
|
||||||
import 'login.dart';
|
import 'login.dart';
|
||||||
|
|
||||||
final hideAbTagsPanel = false.obs;
|
final hideAbTagsPanel = false.obs;
|
||||||
@ -47,8 +46,7 @@ class _AddressBookState extends State<AddressBook> {
|
|||||||
}
|
}
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
_buildNotEmptyLoading(),
|
if (gFFI.abModel.retrying.value) LinearProgressIndicator(),
|
||||||
_buildRetryProgress(),
|
|
||||||
_buildErrorBanner(
|
_buildErrorBanner(
|
||||||
err: gFFI.abModel.pullError,
|
err: gFFI.abModel.pullError,
|
||||||
retry: null,
|
retry: null,
|
||||||
@ -121,29 +119,6 @@ class _AddressBookState extends State<AddressBook> {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildNotEmptyLoading() {
|
|
||||||
double size = 15;
|
|
||||||
return Obx(() => Offstage(
|
|
||||||
offstage: !(gFFI.abModel.abLoading.value && !gFFI.abModel.emtpy),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
SizedBox(
|
|
||||||
height: size,
|
|
||||||
child: Center(child: LoadingDotWidget(size: size)))
|
|
||||||
.marginSymmetric(vertical: 10)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildRetryProgress() {
|
|
||||||
return Obx(() => Offstage(
|
|
||||||
offstage: !gFFI.abModel.retrying.value,
|
|
||||||
child: LinearProgressIndicator(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildAddressBookDesktop() {
|
Widget _buildAddressBookDesktop() {
|
||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
|
@ -1,11 +1,17 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
class AnimatedRotationWidget extends StatefulWidget {
|
class AnimatedRotationWidget extends StatefulWidget {
|
||||||
final VoidCallback onPressed;
|
final VoidCallback onPressed;
|
||||||
final ValueChanged<bool>? onHover;
|
final ValueChanged<bool>? onHover;
|
||||||
final Widget child;
|
final Widget child;
|
||||||
|
final RxBool? spinning;
|
||||||
const AnimatedRotationWidget(
|
const AnimatedRotationWidget(
|
||||||
{super.key, required this.onPressed, required this.child, this.onHover});
|
{super.key,
|
||||||
|
required this.onPressed,
|
||||||
|
required this.child,
|
||||||
|
this.spinning,
|
||||||
|
this.onHover});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<AnimatedRotationWidget> createState() => AnimatedRotationWidgetState();
|
State<AnimatedRotationWidget> createState() => AnimatedRotationWidgetState();
|
||||||
@ -14,14 +20,31 @@ class AnimatedRotationWidget extends StatefulWidget {
|
|||||||
class AnimatedRotationWidgetState extends State<AnimatedRotationWidget> {
|
class AnimatedRotationWidgetState extends State<AnimatedRotationWidget> {
|
||||||
double turns = 0.0;
|
double turns = 0.0;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
widget.spinning?.listen((v) {
|
||||||
|
if (v && mounted) {
|
||||||
|
setState(() {
|
||||||
|
turns += 1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AnimatedRotation(
|
return AnimatedRotation(
|
||||||
turns: turns,
|
turns: turns,
|
||||||
duration: const Duration(milliseconds: 200),
|
duration: const Duration(milliseconds: 200),
|
||||||
|
onEnd: () {
|
||||||
|
if (widget.spinning?.value == true && mounted) {
|
||||||
|
setState(() => turns += 1.0);
|
||||||
|
}
|
||||||
|
},
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
setState(() => turns += 1.0);
|
if (mounted) setState(() => turns += 1.0);
|
||||||
widget.onPressed();
|
widget.onPressed();
|
||||||
},
|
},
|
||||||
onHover: widget.onHover,
|
onHover: widget.onHover,
|
||||||
|
@ -1,65 +0,0 @@
|
|||||||
import 'dart:async';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:get/get.dart';
|
|
||||||
|
|
||||||
class LoadingDotWidget extends StatefulWidget {
|
|
||||||
final int count;
|
|
||||||
final double size;
|
|
||||||
final int duration;
|
|
||||||
LoadingDotWidget(
|
|
||||||
{Key? key, required this.size, this.count = 3, this.duration = 200})
|
|
||||||
: super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<LoadingDotWidget> createState() => _LoadingDotWidgetState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _LoadingDotWidgetState extends State<LoadingDotWidget> {
|
|
||||||
int counter = 0;
|
|
||||||
Timer? timer;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
startAnimation();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
timer?.cancel();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
void startAnimation() {
|
|
||||||
timer = Timer.periodic(Duration(milliseconds: widget.duration), (timer) {
|
|
||||||
if (mounted) {
|
|
||||||
setState(() {
|
|
||||||
counter = (counter + 1) % widget.count;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
getChild(int index) {
|
|
||||||
return AnimatedContainer(
|
|
||||||
duration: Duration(milliseconds: widget.duration),
|
|
||||||
width: counter == index ? widget.size : widget.size / 2,
|
|
||||||
height: counter == index ? widget.size : widget.size / 2,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
shape: BoxShape.circle,
|
|
||||||
color: Colors.grey,
|
|
||||||
),
|
|
||||||
).marginSymmetric(horizontal: widget.size);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Center(
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: List.generate(widget.count, (e) => e)
|
|
||||||
.map((e) => getChild(e))
|
|
||||||
.toList()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -219,6 +219,7 @@ class _PeerTabPageState extends State<PeerTabPage>
|
|||||||
entries[gFFI.peerTabModel.currentTab].load();
|
entries[gFFI.peerTabModel.currentTab].load();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
spinning: gFFI.abModel.abLoading,
|
||||||
child: RotatedBox(
|
child: RotatedBox(
|
||||||
quarterTurns: 2,
|
quarterTurns: 2,
|
||||||
child: Tooltip(
|
child: Tooltip(
|
||||||
|
@ -59,7 +59,6 @@ class AbModel {
|
|||||||
if (!gFFI.userModel.isLogin) return;
|
if (!gFFI.userModel.isLogin) return;
|
||||||
if (abLoading.value) return;
|
if (abLoading.value) return;
|
||||||
if (!force && initialized) return;
|
if (!force && initialized) return;
|
||||||
DateTime startTime = DateTime.now();
|
|
||||||
if (pushError.isNotEmpty) {
|
if (pushError.isNotEmpty) {
|
||||||
try {
|
try {
|
||||||
// push to retry
|
// push to retry
|
||||||
@ -120,14 +119,7 @@ class AbModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
var ms =
|
abLoading.value = false;
|
||||||
(Duration(milliseconds: 300) - DateTime.now().difference(startTime))
|
|
||||||
.inMilliseconds;
|
|
||||||
ms = ms > 0 ? ms : 0;
|
|
||||||
Future.delayed(Duration(milliseconds: ms), () {
|
|
||||||
abLoading.value = false;
|
|
||||||
});
|
|
||||||
|
|
||||||
initialized = true;
|
initialized = true;
|
||||||
_syncAllFromRecent = true;
|
_syncAllFromRecent = true;
|
||||||
_timerCounter = 0;
|
_timerCounter = 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user