mirror of
https://github.com/Myzel394/quid_faciam_hodie.git
synced 2025-06-19 15:45:26 +02:00
improved UI & UX & DX
This commit is contained in:
parent
b146957c69
commit
4bcafd991d
@ -1 +1,3 @@
|
|||||||
const DURATION_INFINITY = Duration(days: 999);
|
const DURATION_INFINITY = Duration(days: 999);
|
||||||
|
const SECONDARY_BUTTONS_DURATION_MULTIPLIER = 1.8;
|
||||||
|
const PHOTO_SHOW_AFTER_CREATION_DURATION = Duration(milliseconds: 500);
|
||||||
|
@ -2,6 +2,7 @@ import 'package:camera/camera.dart';
|
|||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:share_location/constants/apis.dart';
|
import 'package:share_location/constants/apis.dart';
|
||||||
|
import 'package:share_location/screens/grant_permission_screen.dart';
|
||||||
import 'package:share_location/screens/login_screen.dart';
|
import 'package:share_location/screens/login_screen.dart';
|
||||||
import 'package:share_location/screens/main_screen.dart';
|
import 'package:share_location/screens/main_screen.dart';
|
||||||
import 'package:share_location/screens/timeline_screen.dart';
|
import 'package:share_location/screens/timeline_screen.dart';
|
||||||
@ -60,6 +61,7 @@ class MyApp extends StatelessWidget {
|
|||||||
MainScreen.ID: (context) => const MainScreen(),
|
MainScreen.ID: (context) => const MainScreen(),
|
||||||
LoginScreen.ID: (context) => const LoginScreen(),
|
LoginScreen.ID: (context) => const LoginScreen(),
|
||||||
TimelineScreen.ID: (context) => const TimelineScreen(),
|
TimelineScreen.ID: (context) => const TimelineScreen(),
|
||||||
|
GrantPermissionScreen.ID: (context) => const GrantPermissionScreen(),
|
||||||
},
|
},
|
||||||
initialRoute: initialPage,
|
initialRoute: initialPage,
|
||||||
);
|
);
|
||||||
|
26
lib/screens/grant_permission_screen.dart
Normal file
26
lib/screens/grant_permission_screen.dart
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:share_location/screens/main_screen.dart';
|
||||||
|
|
||||||
|
import 'main_screen/permissions_required_page.dart';
|
||||||
|
|
||||||
|
class GrantPermissionScreen extends StatelessWidget {
|
||||||
|
static const ID = 'grant_permission';
|
||||||
|
|
||||||
|
const GrantPermissionScreen({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: const Text('Grant Permission'),
|
||||||
|
),
|
||||||
|
body: Center(
|
||||||
|
child: PermissionsRequiredPage(
|
||||||
|
onPermissionsGranted: () {
|
||||||
|
Navigator.pushReplacementNamed(context, MainScreen.ID);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -4,14 +4,16 @@ import 'dart:typed_data';
|
|||||||
import 'package:camera/camera.dart';
|
import 'package:camera/camera.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:share_location/constants/spacing.dart';
|
import 'package:share_location/constants/spacing.dart';
|
||||||
|
import 'package:share_location/constants/values.dart';
|
||||||
import 'package:share_location/extensions/snackbar.dart';
|
import 'package:share_location/extensions/snackbar.dart';
|
||||||
import 'package:share_location/managers/file_manager.dart';
|
import 'package:share_location/managers/file_manager.dart';
|
||||||
import 'package:share_location/managers/global_values_manager.dart';
|
import 'package:share_location/managers/global_values_manager.dart';
|
||||||
import 'package:share_location/screens/main_screen/permissions_required_page.dart';
|
|
||||||
import 'package:share_location/utils/auth_required.dart';
|
import 'package:share_location/utils/auth_required.dart';
|
||||||
import 'package:share_location/utils/loadable.dart';
|
import 'package:share_location/utils/loadable.dart';
|
||||||
|
import 'package:share_location/widgets/animate_in_builder.dart';
|
||||||
import 'package:share_location/widgets/camera_button.dart';
|
import 'package:share_location/widgets/camera_button.dart';
|
||||||
import 'package:share_location/widgets/change_camera_button.dart';
|
import 'package:share_location/widgets/change_camera_button.dart';
|
||||||
|
import 'package:share_location/widgets/fade_and_move_in_animation.dart';
|
||||||
import 'package:share_location/widgets/today_photo_button.dart';
|
import 'package:share_location/widgets/today_photo_button.dart';
|
||||||
import 'package:share_location/widgets/uploading_photo.dart';
|
import 'package:share_location/widgets/uploading_photo.dart';
|
||||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||||
@ -27,7 +29,6 @@ class MainScreen extends StatefulWidget {
|
|||||||
|
|
||||||
class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
|
class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
|
||||||
bool isRecording = false;
|
bool isRecording = false;
|
||||||
bool hasGrantedPermissions = false;
|
|
||||||
bool lockCamera = false;
|
bool lockCamera = false;
|
||||||
List? lastPhoto;
|
List? lastPhoto;
|
||||||
Uint8List? uploadingPhotoAnimation;
|
Uint8List? uploadingPhotoAnimation;
|
||||||
@ -45,6 +46,7 @@ class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
|
|||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
callWithLoading(getLastPhoto);
|
callWithLoading(getLastPhoto);
|
||||||
|
onNewCameraSelected(GlobalValuesManager.cameras[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -55,6 +57,10 @@ class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||||
|
_updateCamera(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _updateCamera(final AppLifecycleState state) {
|
||||||
final CameraController? cameraController = controller;
|
final CameraController? cameraController = controller;
|
||||||
|
|
||||||
// App state changed before we got the chance to initialize.
|
// App state changed before we got the chance to initialize.
|
||||||
@ -109,6 +115,7 @@ class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
|
|||||||
if (!mounted) {
|
if (!mounted) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setState(() {});
|
setState(() {});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -203,20 +210,6 @@ class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
|
|||||||
backgroundColor: Colors.black,
|
backgroundColor: Colors.black,
|
||||||
body: SafeArea(
|
body: SafeArea(
|
||||||
child: () {
|
child: () {
|
||||||
if (!hasGrantedPermissions) {
|
|
||||||
return Center(
|
|
||||||
child: PermissionsRequiredPage(
|
|
||||||
onPermissionsGranted: () {
|
|
||||||
onNewCameraSelected(GlobalValuesManager.cameras[0]);
|
|
||||||
|
|
||||||
setState(() {
|
|
||||||
hasGrantedPermissions = true;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return const Center(
|
return const Center(
|
||||||
child: CircularProgressIndicator(),
|
child: CircularProgressIndicator(),
|
||||||
@ -229,57 +222,93 @@ class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
|
|||||||
child: Stack(
|
child: Stack(
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
controller!.buildPreview(),
|
|
||||||
Column(
|
Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Padding(
|
AnimateInBuilder(
|
||||||
padding: const EdgeInsets.all(LARGE_SPACE),
|
builder: (showPreview) => AnimatedOpacity(
|
||||||
child: Row(
|
opacity: showPreview ? 1.0 : 0.0,
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
duration: const Duration(milliseconds: 1100),
|
||||||
|
curve: Curves.easeOutQuad,
|
||||||
|
child: ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(SMALL_SPACE),
|
||||||
|
child: AspectRatio(
|
||||||
|
aspectRatio: 1 / controller!.value.aspectRatio,
|
||||||
|
child: controller!.buildPreview(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
ChangeCameraButton(
|
Padding(
|
||||||
onChangeCamera: () {
|
padding: const EdgeInsets.symmetric(
|
||||||
final currentCameraIndex = GlobalValuesManager
|
horizontal: LARGE_SPACE),
|
||||||
.cameras
|
child: Row(
|
||||||
.indexOf(controller!.description);
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
final availableCameras =
|
children: <Widget>[
|
||||||
GlobalValuesManager.cameras.length;
|
FadeAndMoveInAnimation(
|
||||||
|
translationDuration:
|
||||||
|
DEFAULT_TRANSLATION_DURATION *
|
||||||
|
SECONDARY_BUTTONS_DURATION_MULTIPLIER,
|
||||||
|
opacityDuration: DEFAULT_OPACITY_DURATION *
|
||||||
|
SECONDARY_BUTTONS_DURATION_MULTIPLIER,
|
||||||
|
child: ChangeCameraButton(
|
||||||
|
onChangeCamera: () {
|
||||||
|
final currentCameraIndex =
|
||||||
|
GlobalValuesManager.cameras
|
||||||
|
.indexOf(controller!.description);
|
||||||
|
final availableCameras =
|
||||||
|
GlobalValuesManager.cameras.length;
|
||||||
|
|
||||||
onNewCameraSelected(
|
onNewCameraSelected(
|
||||||
GlobalValuesManager.cameras[
|
GlobalValuesManager.cameras[
|
||||||
(currentCameraIndex + 1) %
|
(currentCameraIndex + 1) %
|
||||||
availableCameras],
|
availableCameras],
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
CameraButton(
|
|
||||||
disabled: lockCamera,
|
|
||||||
active: isRecording,
|
|
||||||
onVideoBegin: () async {
|
|
||||||
setState(() {
|
|
||||||
isRecording = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (controller!.value.isRecordingVideo) {
|
|
||||||
// A recording has already started, do nothing.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await controller!.startVideoRecording();
|
|
||||||
},
|
|
||||||
onVideoEnd: takeVideo,
|
|
||||||
onPhotoShot: takePhoto,
|
|
||||||
),
|
|
||||||
lastPhoto == null
|
|
||||||
? const TodayPhotoButton()
|
|
||||||
: TodayPhotoButton(
|
|
||||||
data: lastPhoto![0],
|
|
||||||
type: lastPhoto![1],
|
|
||||||
),
|
),
|
||||||
|
FadeAndMoveInAnimation(
|
||||||
|
child: CameraButton(
|
||||||
|
disabled: lockCamera,
|
||||||
|
active: isRecording,
|
||||||
|
onVideoBegin: () async {
|
||||||
|
setState(() {
|
||||||
|
isRecording = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (controller!.value.isRecordingVideo) {
|
||||||
|
// A recording has already started, do nothing.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await controller!.startVideoRecording();
|
||||||
|
},
|
||||||
|
onVideoEnd: takeVideo,
|
||||||
|
onPhotoShot: takePhoto,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
FadeAndMoveInAnimation(
|
||||||
|
translationDuration:
|
||||||
|
DEFAULT_TRANSLATION_DURATION *
|
||||||
|
SECONDARY_BUTTONS_DURATION_MULTIPLIER,
|
||||||
|
opacityDuration: DEFAULT_OPACITY_DURATION *
|
||||||
|
SECONDARY_BUTTONS_DURATION_MULTIPLIER,
|
||||||
|
child: lastPhoto == null
|
||||||
|
? const TodayPhotoButton()
|
||||||
|
: TodayPhotoButton(
|
||||||
|
data: lastPhoto![0],
|
||||||
|
type: lastPhoto![1],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
if (uploadingPhotoAnimation != null)
|
if (uploadingPhotoAnimation != null)
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:share_location/constants/spacing.dart';
|
import 'package:share_location/constants/spacing.dart';
|
||||||
import 'package:share_location/managers/startup_page_manager.dart';
|
import 'package:share_location/managers/startup_page_manager.dart';
|
||||||
import 'package:share_location/screens/main_screen.dart';
|
|
||||||
import 'package:share_location/widgets/logo.dart';
|
import 'package:share_location/widgets/logo.dart';
|
||||||
|
|
||||||
|
import 'grant_permission_screen.dart';
|
||||||
|
|
||||||
class WelcomeScreen extends StatelessWidget {
|
class WelcomeScreen extends StatelessWidget {
|
||||||
static const ID = 'welcome';
|
static const ID = 'welcome';
|
||||||
|
|
||||||
@ -43,7 +44,10 @@ class WelcomeScreen extends StatelessWidget {
|
|||||||
icon: const Icon(Icons.arrow_right),
|
icon: const Icon(Icons.arrow_right),
|
||||||
label: const Text('Start'),
|
label: const Text('Start'),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
StartupPageManager.navigateToNewPage(context, MainScreen.ID);
|
StartupPageManager.navigateToNewPage(
|
||||||
|
context,
|
||||||
|
GrantPermissionScreen.ID,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
33
lib/widgets/animate_in_builder.dart
Normal file
33
lib/widgets/animate_in_builder.dart
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class AnimateInBuilder extends StatefulWidget {
|
||||||
|
final Widget Function(bool isActive) builder;
|
||||||
|
|
||||||
|
const AnimateInBuilder({
|
||||||
|
Key? key,
|
||||||
|
required this.builder,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<AnimateInBuilder> createState() => _AnimateInBuilderState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _AnimateInBuilderState extends State<AnimateInBuilder> {
|
||||||
|
bool isActive = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
setState(() {
|
||||||
|
isActive = true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return widget.builder(isActive);
|
||||||
|
}
|
||||||
|
}
|
49
lib/widgets/delay_render.dart
Normal file
49
lib/widgets/delay_render.dart
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class DelayRender extends StatefulWidget {
|
||||||
|
final Widget child;
|
||||||
|
final Widget placeholder;
|
||||||
|
final Duration delay;
|
||||||
|
|
||||||
|
const DelayRender({
|
||||||
|
Key? key,
|
||||||
|
required this.child,
|
||||||
|
this.placeholder = const SizedBox(),
|
||||||
|
this.delay = const Duration(milliseconds: 120),
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<DelayRender> createState() => _DelayRenderState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DelayRenderState extends State<DelayRender> {
|
||||||
|
bool allowRendering = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
|
||||||
|
startTimer();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> startTimer() async {
|
||||||
|
await Future.delayed(widget.delay);
|
||||||
|
|
||||||
|
if (!mounted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
allowRendering = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (!allowRendering) {
|
||||||
|
return widget.placeholder;
|
||||||
|
}
|
||||||
|
|
||||||
|
return widget.child;
|
||||||
|
}
|
||||||
|
}
|
94
lib/widgets/fade_and_move_in_animation.dart
Normal file
94
lib/widgets/fade_and_move_in_animation.dart
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
const DEFAULT_TRANSLATION_DURATION = Duration(milliseconds: 500);
|
||||||
|
const DEFAULT_OPACITY_DURATION = Duration(milliseconds: 800);
|
||||||
|
|
||||||
|
class FadeAndMoveInAnimation extends StatefulWidget {
|
||||||
|
final Widget child;
|
||||||
|
final bool active;
|
||||||
|
|
||||||
|
final Offset translationOffset;
|
||||||
|
final Duration translationDuration;
|
||||||
|
final Curve translationCurve;
|
||||||
|
|
||||||
|
final Duration opacityDuration;
|
||||||
|
final Curve opacityCurve;
|
||||||
|
|
||||||
|
const FadeAndMoveInAnimation({
|
||||||
|
Key? key,
|
||||||
|
required this.child,
|
||||||
|
this.active = true,
|
||||||
|
this.translationOffset = const Offset(0, 60),
|
||||||
|
this.translationDuration = DEFAULT_TRANSLATION_DURATION,
|
||||||
|
this.translationCurve = Curves.easeOutQuad,
|
||||||
|
this.opacityDuration = DEFAULT_OPACITY_DURATION,
|
||||||
|
this.opacityCurve = Curves.linearToEaseOut,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<FadeAndMoveInAnimation> createState() => _FadeAndMoveInAnimationState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _FadeAndMoveInAnimationState extends State<FadeAndMoveInAnimation>
|
||||||
|
with TickerProviderStateMixin {
|
||||||
|
late final AnimationController translationController;
|
||||||
|
late final Animation<double> translationAnimation;
|
||||||
|
|
||||||
|
bool opacityEnabled = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
|
||||||
|
translationController = AnimationController(
|
||||||
|
vsync: this,
|
||||||
|
duration: widget.translationDuration,
|
||||||
|
);
|
||||||
|
translationAnimation = Tween<double>(
|
||||||
|
begin: 1,
|
||||||
|
end: 0,
|
||||||
|
).animate(
|
||||||
|
CurvedAnimation(
|
||||||
|
parent: translationController,
|
||||||
|
curve: widget.translationCurve,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didChangeDependencies() {
|
||||||
|
super.didChangeDependencies();
|
||||||
|
|
||||||
|
if (widget.active) {
|
||||||
|
translationController.forward();
|
||||||
|
} else {
|
||||||
|
translationController.reverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
setState(() {
|
||||||
|
opacityEnabled = widget.active;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return AnimatedBuilder(
|
||||||
|
animation: translationController,
|
||||||
|
child: widget.child,
|
||||||
|
builder: (context, child) => Transform.translate(
|
||||||
|
offset: Offset(
|
||||||
|
widget.translationOffset.dx * translationAnimation.value,
|
||||||
|
widget.translationOffset.dy * translationAnimation.value,
|
||||||
|
),
|
||||||
|
child: AnimatedOpacity(
|
||||||
|
duration: widget.opacityDuration,
|
||||||
|
curve: widget.opacityCurve,
|
||||||
|
opacity: opacityEnabled ? 1 : 0,
|
||||||
|
child: child,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@ import 'dart:typed_data';
|
|||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:share_location/constants/spacing.dart';
|
import 'package:share_location/constants/spacing.dart';
|
||||||
|
import 'package:share_location/constants/values.dart';
|
||||||
|
|
||||||
class UploadingPhoto extends StatefulWidget {
|
class UploadingPhoto extends StatefulWidget {
|
||||||
final Uint8List data;
|
final Uint8List data;
|
||||||
@ -39,7 +40,7 @@ class _UploadingPhotoState extends State<UploadingPhoto>
|
|||||||
|
|
||||||
controller.addStatusListener((status) {
|
controller.addStatusListener((status) {
|
||||||
if (status == AnimationStatus.completed) {
|
if (status == AnimationStatus.completed) {
|
||||||
Future.delayed(const Duration(milliseconds: 500), () {
|
Future.delayed(PHOTO_SHOW_AFTER_CREATION_DURATION, () {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
widget.onDone();
|
widget.onDone();
|
||||||
}
|
}
|
||||||
@ -67,9 +68,9 @@ class _UploadingPhotoState extends State<UploadingPhoto>
|
|||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
width: 15,
|
width: 12,
|
||||||
),
|
),
|
||||||
borderRadius: BorderRadius.circular(SMALL_SPACE),
|
borderRadius: BorderRadius.circular(MEDIUM_SPACE),
|
||||||
),
|
),
|
||||||
child: Image.memory(widget.data, fit: BoxFit.cover),
|
child: Image.memory(widget.data, fit: BoxFit.cover),
|
||||||
),
|
),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user