feat: add more animations

This commit is contained in:
Tien Do Nam
2022-12-28 23:01:39 +01:00
parent 6f7739b30e
commit ead270f993
7 changed files with 142 additions and 31 deletions

View File

@@ -107,6 +107,10 @@
"title": "Changelog"
},
"dialogs": {
"noFiles": {
"title": "No file selected",
"content": "Please select at least one file."
},
"cancelSession": {
"title": "Cancel file transfer",
"content": "Do you really want to cancel the file transfer?"

View File

@@ -107,6 +107,10 @@
"title": "Changelog"
},
"dialogs": {
"noFiles": {
"title": "Keine Datei ausgewählt",
"content": "Bitte wähle mindestens eine Datei aus."
},
"cancelSession": {
"title": "Dateiübertragung abbrechen",
"content": "Möchtest du wirklich die Dateiübertragung abbrechen?"

View File

@@ -6,6 +6,7 @@ import 'package:localsend_app/model/session_status.dart';
import 'package:localsend_app/provider/device_info_provider.dart';
import 'package:localsend_app/provider/network/send_provider.dart';
import 'package:localsend_app/util/sleep.dart';
import 'package:localsend_app/widget/animations/initial_fade_transition.dart';
import 'package:localsend_app/widget/list_tile/device_list_tile.dart';
import 'package:routerino/routerino.dart';
@@ -81,7 +82,11 @@ class _SendPageState extends ConsumerState<SendPage> {
),
),
const SizedBox(height: 20),
const Icon(Icons.arrow_downward),
const InitialFadeTransition(
duration: Duration(milliseconds: 300),
delay: Duration(milliseconds: 400),
child: Icon(Icons.arrow_downward),
),
const SizedBox(height: 20),
Hero(
tag: 'device-${(sendState?.target ?? _targetDevice)?.ip}',
@@ -93,28 +98,34 @@ class _SendPageState extends ConsumerState<SendPage> {
),
),
if (sendState != null)
...[
if (sendState.status == SessionStatus.waiting)
Padding(
padding: const EdgeInsets.only(bottom: 20),
child: Text(t.sendPage.waiting, textAlign: TextAlign.center),
)
else if (sendState.status == SessionStatus.declined)
Padding(
padding: const EdgeInsets.only(bottom: 20),
child: Text(t.sendPage.rejected, style: const TextStyle(color: Colors.orange), textAlign: TextAlign.center),
),
Center(
child: ElevatedButton.icon(
onPressed: () {
_cancel();
context.pop();
},
icon: Icon(sendState.status == SessionStatus.declined ? Icons.check_circle : Icons.close),
label: Text(sendState.status == SessionStatus.declined ? t.general.close : t.general.cancel),
),
InitialFadeTransition(
duration: const Duration(milliseconds: 300),
delay: const Duration(milliseconds: 400),
child: Column(
children: [
if (sendState.status == SessionStatus.waiting)
Padding(
padding: const EdgeInsets.only(bottom: 20),
child: Text(t.sendPage.waiting, textAlign: TextAlign.center),
)
else if (sendState.status == SessionStatus.declined)
Padding(
padding: const EdgeInsets.only(bottom: 20),
child: Text(t.sendPage.rejected, style: const TextStyle(color: Colors.orange), textAlign: TextAlign.center),
),
Center(
child: ElevatedButton.icon(
onPressed: () {
_cancel();
context.pop();
},
icon: Icon(sendState.status == SessionStatus.declined ? Icons.check_circle : Icons.close),
label: Text(sendState.status == SessionStatus.declined ? t.general.close : t.general.cancel),
),
),
],
),
],
),
],
),
),

View File

@@ -6,6 +6,7 @@ import 'package:localsend_app/provider/network_info_provider.dart';
import 'package:localsend_app/provider/network/server_provider.dart';
import 'package:localsend_app/provider/settings_provider.dart';
import 'package:localsend_app/util/ip_helper.dart';
import 'package:localsend_app/widget/animations/initial_fade_transition.dart';
import 'package:localsend_app/widget/rotating_widget.dart';
class ReceiveTab extends ConsumerStatefulWidget {
@@ -15,11 +16,16 @@ class ReceiveTab extends ConsumerStatefulWidget {
ConsumerState<ReceiveTab> createState() => _ReceiveTagState();
}
class _ReceiveTagState extends ConsumerState<ReceiveTab> {
class _ReceiveTagState extends ConsumerState<ReceiveTab> with AutomaticKeepAliveClientMixin {
bool _advanced = false;
@override
bool get wantKeepAlive => true;
@override
Widget build(BuildContext context) {
super.build(context);
final settings = ref.watch(settingsProvider);
final networkInfo = ref.watch(networkInfoProvider);
final serverState = ref.watch(serverProvider);
@@ -35,15 +41,26 @@ class _ReceiveTagState extends ConsumerState<ReceiveTab> {
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
RotatingWidget(
duration: const Duration(seconds: 15),
spinning: serverState != null,
child: Assets.img.logo512.image(width: 200),
InitialFadeTransition(
duration: const Duration(milliseconds: 300),
delay: const Duration(milliseconds: 200),
child: RotatingWidget(
duration: const Duration(seconds: 15),
spinning: serverState != null,
child: SizedBox(
height: 200,
child: Assets.img.logo512.image(height: 200),
),
),
),
Text(serverState?.alias ?? settings.alias, style: const TextStyle(fontSize: 48)),
Text(
serverState == null ? t.general.offline : '#${networkInfo?.localIp?.visualId ?? '?'}',
style: const TextStyle(fontSize: 24),
InitialFadeTransition(
duration: const Duration(milliseconds: 300),
delay: const Duration(milliseconds: 500),
child: Text(
serverState == null ? t.general.offline : '#${networkInfo?.localIp?.visualId ?? '?'}',
style: const TextStyle(fontSize: 24),
),
),
],
),

View File

@@ -12,6 +12,7 @@ import 'package:localsend_app/provider/settings_provider.dart';
import 'package:localsend_app/util/file_size_helper.dart';
import 'package:localsend_app/widget/big_button.dart';
import 'package:localsend_app/widget/dialogs/add_file_dialog.dart';
import 'package:localsend_app/widget/dialogs/no_files_dialog.dart';
import 'package:localsend_app/widget/list_tile/device_list_tile.dart';
import 'package:localsend_app/widget/rotating_widget.dart';
import 'package:routerino/routerino.dart';
@@ -211,9 +212,15 @@ class _SendTabState extends ConsumerState<SendTab> {
child: DeviceListTile(
device: device,
onTap: () {
final files = ref.read(selectedFilesProvider);
if (files.isEmpty) {
context.pushBottomSheet(() => const NoFilesDialog());
return;
}
ref.read(sendProvider.notifier).startSession(
target: device,
files: ref.read(selectedFilesProvider),
files: files,
);
},
),

View File

@@ -0,0 +1,46 @@
import 'package:flutter/material.dart';
import 'package:localsend_app/util/sleep.dart';
class InitialFadeTransition extends StatefulWidget {
final Widget child;
final Duration duration;
final Duration delay;
const InitialFadeTransition({
required this.child,
required this.duration,
this.delay = Duration.zero,
Key? key,
}) : super(key: key);
@override
State<InitialFadeTransition> createState() => _InitialFadeTransitionState();
}
class _InitialFadeTransitionState extends State<InitialFadeTransition> {
double _opacity = 0;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) async {
await sleepAsync(widget.delay.inMilliseconds);
if (!mounted) {
return;
}
setState(() {
_opacity = 1;
});
});
}
@override
Widget build(BuildContext context) {
return AnimatedOpacity(
opacity: _opacity,
duration: widget.duration,
child: widget.child,
);
}
}

View File

@@ -0,0 +1,22 @@
import 'package:flutter/material.dart';
import 'package:localsend_app/gen/strings.g.dart';
import 'package:localsend_app/widget/dialogs/custom_bottom_sheet.dart';
import 'package:routerino/routerino.dart';
class NoFilesDialog extends StatelessWidget {
const NoFilesDialog({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return CustomBottomSheet(
title: t.dialogs.noFiles.title,
description: t.dialogs.noFiles.content,
child: Center(
child: ElevatedButton(
onPressed: () => context.popUntilRoot(),
child: Text(t.general.close),
),
),
);
}
}