Browse Source

horizontal list view for media helper

master
daivph 5 years ago
parent
commit
e5ad9e9cb3
5 changed files with 264 additions and 57 deletions
  1. +44
    -0
      lib/presentation/custom_widgets/hoz_list_view.dart
  2. +68
    -0
      lib/presentation/custom_widgets/shimmer_image.dart
  3. +144
    -57
      lib/presentation/custom_widgets/widget_media_helper.dart
  4. +7
    -0
      pubspec.lock
  5. +1
    -0
      pubspec.yaml

+ 44
- 0
lib/presentation/custom_widgets/hoz_list_view.dart View File

@@ -0,0 +1,44 @@
import 'package:farm_tpf/presentation/custom_widgets/shimmer_image.dart';
import 'package:flutter/material.dart';

class WrapContentHozListView<T> extends StatefulWidget {
List<T> list;
IndexedWidgetBuilder itemBuilder;
IndexedWidgetBuilder separatorBuilder;

WrapContentHozListView({
@required this.list,
@required this.itemBuilder,
this.separatorBuilder,
});

@override
_WrapContentHozListViewState createState() => _WrapContentHozListViewState();
}

class _WrapContentHozListViewState extends State<WrapContentHozListView> {
List<Widget> _generateItemWidgets() {
List<Widget> items = [];
for (int i = 0; i < widget.list.length; i++) {
items.add(widget.itemBuilder(context, i));
if (widget.separatorBuilder != null) {
items.add(widget.separatorBuilder(context, i));
}
}

return items;
}

@override
Widget build(BuildContext context) {
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
physics: BouncingScrollPhysics(),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: _generateItemWidgets(),
),
);
}
}

+ 68
- 0
lib/presentation/custom_widgets/shimmer_image.dart View File

@@ -0,0 +1,68 @@
import 'package:flutter/material.dart';
import 'package:shimmer/shimmer.dart';

class ShimmerImage extends StatelessWidget {
String url;
BoxFit fit;
double width;
double height;
double aspectRatio;
double iconHolderSize = 40;

ShimmerImage(
this.url, {
this.fit,
this.width,
this.height,
this.aspectRatio,
this.iconHolderSize,
});

@override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
Shimmer.fromColors(
baseColor: Colors.grey[200],
highlightColor: Colors.grey[100],
child: this.aspectRatio != null
? AspectRatio(
aspectRatio: aspectRatio,
child: Container(
child: _buildIcon(),
),
)
: Container(
width: this.width,
height: this.height,
child: _buildIcon(),
),
),
this.aspectRatio != null
? AspectRatio(
aspectRatio: aspectRatio,
child: Image.network(
url,
fit: fit ?? BoxFit.contain,
),
)
: Image.network(
url,
width: this.width,
height: this.height,
fit: fit ?? BoxFit.contain,
),
],
);
}

_buildIcon() {
return Center(
child: Icon(
Icons.crop_original,
color: Colors.red,
size: iconHolderSize,
),
);
}
}

+ 144
- 57
lib/presentation/custom_widgets/widget_media_helper.dart View File

@@ -1,6 +1,9 @@
import 'dart:io';
import 'dart:async';

import 'package:farm_tpf/presentation/custom_widgets/hoz_list_view.dart';
import 'package:farm_tpf/presentation/custom_widgets/shimmer_image.dart';
import 'package:farm_tpf/presentation/custom_widgets/widget_item_media.dart';
import 'package:farm_tpf/utils/const_color.dart';
import 'package:farm_tpf/utils/const_string.dart';
import 'package:flutter/cupertino.dart';
@@ -22,44 +25,71 @@ class _WidgetMediaHelperState extends State<WidgetMediaHelper> {
String _retrieveDataError;

final ImagePicker _picker = ImagePicker();
List<ItemMediaVM> items = [
ItemMediaVM('http://lorempixel.com/640/480', true),
ItemMediaVM(
'https://s3.amazonaws.com/uifaces/faces/twitter/rickdt/128.jpg', true),
ItemMediaVM('http://lorempixel.com/640/480/food', true),
ItemMediaVM('http://lorempixel.com/640/480/animals', true),
ItemMediaVM('http://lorempixel.com/640/480/fashion', true),
];

@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(8),
child: Column(
children: <Widget>[
_actionButton(),
1 == 1
? FutureBuilder<void>(
future: retrieveLostData(),
builder: (BuildContext context, AsyncSnapshot<void> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
return const Text(
'You have not yet picked an image.',
textAlign: TextAlign.center,
);
case ConnectionState.done:
return isVideo ? _previewVideo() : _previewImage();
default:
if (snapshot.hasError) {
return Text(
'Pick image/video error: ${snapshot.error}}',
textAlign: TextAlign.center,
);
} else {
return const Text(
'You have not yet picked an image.',
textAlign: TextAlign.center,
);
children: <Widget>[
_actionButton(),
SizedBox(
height: 4.0,
),
_buildListPoster(),
1 == 1
? FutureBuilder<void>(
future: retrieveLostData(),
builder:
(BuildContext context, AsyncSnapshot<void> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
return const Text(
'You have not yet picked an image.',
textAlign: TextAlign.center,
);
case ConnectionState.done:
return isVideo ? _previewVideo() : _previewImage();
default:
if (snapshot.hasError) {
return Text(
'Pick image/video error: ${snapshot.error}}',
textAlign: TextAlign.center,
);
} else {
return const Text(
'You have not yet picked an image.',
textAlign: TextAlign.center,
);
}
}
}
},
)
: (isVideo ? _previewVideo() : _previewImage()),
],
));
},
)
: (isVideo ? _previewVideo() : _previewImage()),
],
));
}

_buildListPoster() {
return WrapContentHozListView(
itemBuilder: (context, index) {
var item = items[index];
return _WidgetItemMedia(item);
},
separatorBuilder: (context, index) {
return SizedBox(width: 14);
},
list: items,
);
}

Widget viewResult() {
@@ -138,32 +168,37 @@ class _WidgetMediaHelperState extends State<WidgetMediaHelper> {
Widget _actionButton() {
return SizedBox(
width: double.infinity,
height: 55,
height: 44,
child: FlatButton(
onPressed: () {
showDialog(
context: context,
barrierDismissible: true,
builder: (context) => Opacity(
child: multipleChoice(),
opacity: 1,
));
},
color: COLOR_CONST.DEFAULT,
shape: RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(7.0),
),
child: Row(
children: <Widget>[
Icon(Icons.image),
Text(
button_add_media,
style: TextStyle(
fontWeight: FontWeight.bold, color: COLOR_CONST.WHITE),
)
],
),
),
onPressed: () {
showDialog(
context: context,
barrierDismissible: true,
builder: (context) => Opacity(
child: multipleChoice(),
opacity: 1,
));
},
color: COLOR_CONST.DEFAULT,
shape: RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(7.0),
),
child: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(Icons.image, color: Colors.white),
SizedBox(
width: 8.0,
),
Text(
button_add_media,
style: TextStyle(
fontWeight: FontWeight.bold, color: COLOR_CONST.WHITE),
)
],
),
)),
);
}

@@ -358,3 +393,55 @@ class AspectRatioVideoState extends State<AspectRatioVideo> {
}
}
}

class _WidgetItemMedia extends StatelessWidget {
final ItemMediaVM item;

_WidgetItemMedia(this.item);

BuildContext _context;

@override
Widget build(BuildContext context) {
_context = context;
return GestureDetector(
onTap: () {
print("Show preview image or video");
},
child: Stack(
alignment: Alignment.bottomCenter,
overflow: Overflow.visible,
children: <Widget>[
Positioned(
child: ClipRRect(
borderRadius: BorderRadius.circular(8),
child: ShimmerImage(
item.photo,
width: 93,
height: 124,
fit: BoxFit.cover,
),
)),
Positioned(
top: -5,
right: -5,
child: IconButton(
icon: Icon(
Icons.cancel,
color: Colors.redAccent,
),
onPressed: () {
print("On tap delete media");
}),
)
],
));
}
}

class ItemMediaVM {
String photo;
bool isVideo;

ItemMediaVM(this.photo, this.isVideo);
}

+ 7
- 0
pubspec.lock View File

@@ -590,6 +590,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.3"
shimmer:
dependency: "direct main"
description:
name: shimmer
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.1"
sky_engine:
dependency: transitive
description: flutter

+ 1
- 0
pubspec.yaml View File

@@ -28,6 +28,7 @@ dependencies:
image_picker: ^0.6.2+3
video_player: ^0.10.11+2
flutter_plugin_android_lifecycle: ^1.0.4
shimmer: ^1.1.1

dev_dependencies:
flutter_test:

Loading…
Cancel
Save