Skip to content

Commit

Permalink
🎉 Complete show full image on tap (#269)
Browse files Browse the repository at this point in the history
  • Loading branch information
tvc12 committed Jun 26, 2020
1 parent f983152 commit 83defc5
Show file tree
Hide file tree
Showing 13 changed files with 203 additions and 102 deletions.
38 changes: 23 additions & 15 deletions lib/common/widgets/avatar_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,31 @@ part of petisland.common.widgets;
class AvatarWidget extends StatelessWidget {
final String url;
final EdgeInsetsGeometry paddingDefaultImage;

const AvatarWidget({
final bool fullScreenOnTap;
AvatarWidget({
Key key,
this.url,
this.paddingDefaultImage = const EdgeInsets.all(2.0),
this.fullScreenOnTap = false,
}) : super(key: key);

@override
Widget build(BuildContext context) {
Widget child;
if (url != null) {
final type = StringUtils.isImageUrlFormat(url)
? ImageSources.Server
: ImageSources.Local;
child = _buildImage(type, url);
if (fullScreenOnTap == true) {
return PostImageWidget(
isSquare: false,
imageUrl: url,
shape: BoxShape.circle,
backGroundColor: TColors.white,
);
} else {
ImageSources type = StringUtils.isImageUrlFormat(url) ? ImageSources.Server : ImageSources.Local;
return _buildImage(type, url);
}
} else {
child = buildDefaultAvatar();
return buildDefaultAvatar();
}
return child;
}

Widget buildDefaultAvatar() {
Expand All @@ -38,11 +44,13 @@ class AvatarWidget extends StatelessWidget {
}

Widget _buildImage(ImageSources type, String url) {
return type == ImageSources.Server
? TCacheImageWidget(
url: url,
shape: BoxShape.circle,
)
: Image.file(File(url));
if (type == ImageSources.Server) {
return TCacheImageWidget(
url: url,
shape: BoxShape.circle,
);
} else {
return Image.file(File(url));
}
}
}
94 changes: 94 additions & 0 deletions lib/common/widgets/preview_image_widget.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
part of petisland.common.widgets;

class PreviewImage extends StatelessWidget {
static const String name = '/_PreviewImage';

final ImageProvider imageProvider;
final Object heroTag;
final bool usePhotoView;

PreviewImage(this.imageProvider, this.heroTag, {Key key, this.usePhotoView = false})
: super(key: key);

@override
Widget build(BuildContext context) {
final Widget background = _backgroundGradient();
final Widget image = _imageWidget();
final Widget appbar = _appbar(context);
return Scaffold(
backgroundColor: TColors.transparent,
body: Stack(
fit: StackFit.passthrough,
children: <Widget>[
image,
background,
appbar,
],
),
);
}

Widget _backgroundGradient() {
return Container(
height: kToolbarHeight + 30,
foregroundDecoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment(0.5, 0.07),
end: Alignment(0.5, 3),
colors: [const Color(0x00000000), const Color(0x4d000000)],
),
),
);
}

void _onClosePressed(BuildContext context) {
Navigator.of(context).pop();
}

Widget _imageWidget() {
if (usePhotoView) {
return Container(
child: PhotoView(
heroAttributes: PhotoViewHeroAttributes(tag: heroTag),
filterQuality: FilterQuality.high,
imageProvider: imageProvider,
minScale: PhotoViewComputedScale.contained * 0.8,
maxScale: PhotoViewComputedScale.covered * 1.8,
initialScale: PhotoViewComputedScale.contained * 1.1,
),
);
} else {
return Hero(
tag: heroTag,
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: imageProvider,
fit: BoxFit.contain,
),
),
),
);
}
}

Widget _appbar(BuildContext context) {
return SizedBox(
height: kToolbarHeight + 30,
child: AppBar(
backgroundColor: TColors.transparent,
elevation: 0,
automaticallyImplyLeading: false,
leading: IconButton(
color: TColors.white,
onPressed: () => _onClosePressed(context),
icon: Icon(
Icons.close,
size: 30,
color: TColors.white,
),
),
),
);
}
}
39 changes: 31 additions & 8 deletions lib/common/widgets/t_cached_image_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ class TCacheImageWidget extends StatelessWidget {
final double width;
final double height;
final String url;
final ValueChanged<ImageProvider> onTapImage;
final Object heroTag;
final BoxFit fit;

//default border radius = 4
final BorderRadius borderRadius;
Expand All @@ -116,25 +119,45 @@ class TCacheImageWidget extends StatelessWidget {
this.borderRadius,
this.defaultBackgroundColor = TColors.duck_egg_blue,
this.shape = BoxShape.rectangle,
this.onTapImage,
this.heroTag,
this.fit = BoxFit.cover,
}) : super(key: key);

@override
Widget build(BuildContext context) {
if (heroTag == null)
return _buildImage();
else {
return Hero(
tag: heroTag,
child: _buildImage(),
);
}
}

Widget _buildImage() {
final BoxShape shape = this.shape ?? BoxShape.rectangle;
BorderRadius borderRadius;
if (shape == BoxShape.rectangle)
borderRadius = this.borderRadius ?? BorderRadius.circular(4);

return TBaseCachedImageWidget(
url: url,
imageBuilder: (_, ImageProvider imageProvider) {
return Container(
width: width,
height: height,
decoration: BoxDecoration(
image: DecorationImage(image: imageProvider, fit: BoxFit.cover),
borderRadius: borderRadius,
color: defaultBackgroundColor,
shape: shape,
return GestureDetector(
onTap: () {
if (onTapImage != null) onTapImage(imageProvider);
},
child: Container(
width: width,
height: height,
decoration: BoxDecoration(
image: DecorationImage(image: imageProvider, fit: fit),
borderRadius: borderRadius,
color: defaultBackgroundColor,
shape: shape,
),
),
);
},
Expand Down
2 changes: 2 additions & 0 deletions lib/common/widgets/widgets.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import 'package:flutter_template/pet_feed/widget/post/post.dart';
import 'package:petisland_core/module/module.dart';
import 'package:petisland_core/petisland_core.dart' hide Mode;
import 'package:petisland_core/utils/utils.dart';
import 'package:photo_view/photo_view.dart';
import 'package:shimmer/shimmer.dart';

part 'avatar_widget.dart';
Expand All @@ -33,3 +34,4 @@ part 'title_input_widget.dart';
part 'title_widget.dart';
part 'user_input_widget.dart';
part 'location_selector_widget.dart';
part 'preview_image_widget.dart';
59 changes: 41 additions & 18 deletions lib/pet_feed/widget/post/post_image_widget.dart
Original file line number Diff line number Diff line change
@@ -1,34 +1,57 @@
part of petisland.pet_feed.widget.post;

class PostImageWidget extends StatelessWidget {
class PostImageWidget extends TStatelessWidget {
final String imageUrl;
final bool isSquare;
final TapImage onTapImage;
final Widget imageDefault = DefaultPetImage();
final Object heroTag = ThinId.randomId();
final BoxFit fit;
final BoxShape shape;
final Color backGroundColor;

PostImageWidget(
{Key key, this.imageUrl, this.isSquare = true, this.onTapImage})
: super(key: key);
PostImageWidget({Key key, this.imageUrl, this.isSquare = true, this.fit: BoxFit.cover, this.shape, this.backGroundColor = TColors.duck_egg_blue}) : super(key: key);

@override
Widget build(BuildContext context) {
final onTap = onTapImage != null
? () => onTapImage(imageUrl, ImageSources.Server)
: null;
final Widget image = imageUrl != null
? GestureDetector(
child: _buildImage(imageUrl),
onTap: onTap,
)
: imageDefault;
final Widget image = imageUrl != null ? _buildImage(imageUrl, context) : imageDefault;
return isSquare ? AspectRatio(child: image, aspectRatio: 1) : image;
}

Widget _buildImage(String imageUrl) {
Widget _buildImage(String imageUrl, BuildContext context) {
final bool isFromServer = StringUtils.isImageUrlFormat(imageUrl);
return isFromServer
? TCacheImageWidget(url: imageUrl)
: Image.file(File(imageUrl));
if (isFromServer) {
return TCacheImageWidget(
url: imageUrl,
heroTag: heroTag,
onTapImage: (_) => onTapImge(_, context),
fit: fit,
shape: shape,
defaultBackgroundColor: backGroundColor,
);
} else {
final imageProvider = FileImage(File(imageUrl));
return GestureDetector(
onTap: () => onTapImge(imageProvider, context),
child: Hero(
tag: heroTag,
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: imageProvider,
fit: fit,
),
),
),
),
);
}
}

void onTapImge(ImageProvider provider, BuildContext context) {
navigateToScreen(
context: context,
screen: PreviewImage(provider, heroTag, usePhotoView: true),
);
}
}

Expand Down
5 changes: 2 additions & 3 deletions lib/pet_feed/widget/post/preview_post_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@ enum ImageSources {

class PreviewPostWidget extends StatelessWidget {
final Post item;
final TapImage onTapImage;

const PreviewPostWidget({Key key, @required this.item, this.onTapImage})
const PreviewPostWidget({Key key, @required this.item})
: super(key: key);

@override
Expand All @@ -20,7 +19,7 @@ class PreviewPostWidget extends StatelessWidget {
flex: 3,
child: Container(
margin: const EdgeInsets.only(left: 5),
child: PostImageWidget(imageUrl: item.firstImage, onTapImage: onTapImage),
child: PostImageWidget(imageUrl: item.firstImage),
alignment: Alignment.centerLeft,
),
);
Expand Down
13 changes: 2 additions & 11 deletions lib/post/post_detail/widget/post/image_slider_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ class ImageSliderWidget extends StatelessWidget {
final List<String> images;
final String description;

const ImageSliderWidget(
{Key key, @required this.images, @required this.description})
const ImageSliderWidget({Key key, @required this.images, @required this.description})
: super(key: key);

@override
Expand All @@ -26,10 +25,7 @@ class ImageSliderWidget extends StatelessWidget {
physics: const BouncingScrollPhysics(),
itemBuilder: (_, index) {
final url = images[index];
return AspectRatio(
aspectRatio: 1,
child: _buildImage(url),
);
return PostImageWidget(imageUrl: url);
},
separatorBuilder: (BuildContext context, int index) {
return const SizedBox(width: 15);
Expand All @@ -39,11 +35,6 @@ class ImageSliderWidget extends StatelessWidget {
],
);
}

Widget _buildImage(String url) {
final bool isFromServer = StringUtils.isImageUrlFormat(url);
return isFromServer ? TCacheImageWidget(url: url) : Image.file(File(url));
}
}

Widget buildTextDescription(BuildContext context, String text) {
Expand Down
6 changes: 1 addition & 5 deletions lib/post/post_edit/widget/image_post_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,14 @@ class ImagePostWidget extends StatelessWidget {

@override
Widget build(BuildContext context) {
Widget child = type == ImageSources.Server
? TCacheImageWidget(borderRadius: BorderRadius.circular(0), url: url)
: Image.file(File(url), fit: BoxFit.cover);

return ClipRRect(
borderRadius: BorderRadius.circular(4),
child: AspectRatio(
aspectRatio: 1,
child: Stack(
children: <Widget>[
imageDefaultWidget(),
AspectRatio(aspectRatio: 1, child: child),
PostImageWidget(imageUrl: url, fit: BoxFit.cover),
Positioned(
top: 2,
right: 2,
Expand Down
Loading

0 comments on commit 83defc5

Please sign in to comment.