-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
310 additions
and
110 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,29 +1,112 @@ | ||
import 'package:flutter/material.dart'; | ||
import 'package:flutter_survey_js/ui/video_widget.dart'; | ||
import 'package:path/path.dart' as p; | ||
|
||
Widget urlToImage(String? link, {double width = 100, double height = 100}) { | ||
Widget urlToImage(String? link, {double? width, double? height}) { | ||
Widget inner = Container(); | ||
if (link == null) { | ||
return SizedBox( | ||
width: width, | ||
height: height, | ||
child: inner, | ||
); | ||
} else { | ||
final url = Uri.tryParse(link); | ||
if (url == null) { | ||
return SizedBox( | ||
width: width, | ||
height: height, | ||
child: inner, | ||
); | ||
} | ||
if (url.data != null && url.data!.isBase64) { | ||
return Image.memory(url.data!.contentAsBytes(), gaplessPlayback: true); | ||
inner = Image.memory(url.data!.contentAsBytes(), gaplessPlayback: true); | ||
} else if (url.isAbsolute) { | ||
if (UrlTypeHelper.getType(url) == UrlType.video) { | ||
inner = VideoWidget(uri: url); | ||
} else { | ||
inner = Image.network(link, gaplessPlayback: true); | ||
} | ||
} | ||
if (url.isAbsolute) { | ||
return Image.network(link, gaplessPlayback: true); | ||
} else { | ||
return SizedBox( | ||
width: width, | ||
height: height, | ||
); | ||
|
||
return SizedBox( | ||
width: width, | ||
height: height, | ||
child: inner, | ||
); | ||
} | ||
} | ||
|
||
enum UrlType { image, video, unknown } | ||
|
||
class UrlTypeHelper { | ||
static final List<String> _imageTypes = [ | ||
'jpg', | ||
'jpeg', | ||
'jfif', | ||
'pjpeg', | ||
'pjp', | ||
'png', | ||
'svg', | ||
'gif', | ||
'apng', | ||
'webp', | ||
'avif' | ||
]; | ||
|
||
static final List<String> _videoTypes = [ | ||
"3g2", | ||
"3gp", | ||
"aaf", | ||
"asf", | ||
"avchd", | ||
"avi", | ||
"drc", | ||
"flv", | ||
"m2v", | ||
"m3u8", | ||
"m4p", | ||
"m4v", | ||
"mkv", | ||
"mng", | ||
"mov", | ||
"mp2", | ||
"mp4", | ||
"mpe", | ||
"mpeg", | ||
"mpg", | ||
"mpv", | ||
"mxf", | ||
"nsv", | ||
"ogg", | ||
"ogv", | ||
"qt", | ||
"rm", | ||
"rmvb", | ||
"roq", | ||
"svi", | ||
"vob", | ||
"webm", | ||
"wmv", | ||
"yuv" | ||
]; | ||
|
||
static UrlType getType(Uri uri) { | ||
try { | ||
String extension = p.extension(uri.path).toLowerCase(); | ||
if (extension.isEmpty) { | ||
return UrlType.unknown; | ||
} | ||
|
||
extension = extension.split('.').last; | ||
if (_imageTypes.contains(extension)) { | ||
return UrlType.image; | ||
} else if (_videoTypes.contains(extension)) { | ||
return UrlType.video; | ||
} | ||
} catch (e) { | ||
return UrlType.unknown; | ||
} | ||
return UrlType.unknown; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,99 +1,93 @@ | ||
// import 'package:flutter/material.dart'; | ||
// import 'package:flutter_colorpicker/flutter_colorpicker.dart'; | ||
// import 'package:flutter_survey_js_model/flutter_survey_js_model.dart' as s; | ||
// import 'package:reactive_forms/reactive_forms.dart'; | ||
// | ||
// import 'image.dart'; | ||
// import 'question_title.dart'; | ||
// import 'survey_element_factory.dart'; | ||
// | ||
// final SurveyElementBuilder imagePickerBuilder = | ||
// (context, element, {ElementConfiguration? configuration}) { | ||
// return ImagePickerElement( | ||
// formControlName: element.name!, | ||
// element: element as s.ImagePicker, | ||
// ).wrapQuestionTitle(element, hasTitle: hasTitle); | ||
// }; | ||
// | ||
// class ImagePickerElement extends StatelessWidget { | ||
// final String formControlName; | ||
// final s.ImagePicker element; | ||
// const ImagePickerElement( | ||
// {Key? key, required this.formControlName, required this.element}) | ||
// : super(key: key); | ||
// @override | ||
// Widget build(BuildContext context) { | ||
// //TODO multiple select | ||
// final choices = element.choices ?? []; | ||
// return ReactiveBlockItemPicker<dynamic, s.ImageItemValue>( | ||
// formControlName: formControlName, | ||
// valueAccessor: _ValueAccessor(choices), | ||
// items: choices.map<ItemBlockValue<s.ImageItemValue>>((e) { | ||
// return ItemBlockValue<s.ImageItemValue>( | ||
// value: e, label: (_) => Text(e.text ?? e.value?.toString() ?? '')); | ||
// }).toList(), | ||
// itemBuilder: (BuildContext context, ItemBlockValue<s.ImageItemValue> item, | ||
// bool isCurrentItem, Function changeItem) { | ||
// const color = Colors.grey; | ||
// return Column( | ||
// crossAxisAlignment: CrossAxisAlignment.center, | ||
// mainAxisAlignment: MainAxisAlignment.start, | ||
// children: [ | ||
// Container( | ||
// height: 100, | ||
// width: 100, | ||
// child: Center( | ||
// child: Material( | ||
// color: Colors.transparent, | ||
// child: InkWell( | ||
// onTap: changeItem as void Function()?, | ||
// child: Stack( | ||
// children: [ | ||
// urlToImage(item.value.imageLink, width: 90, height: 90), | ||
// AnimatedOpacity( | ||
// duration: const Duration(milliseconds: 210), | ||
// opacity: isCurrentItem ? 1.0 : 0.0, | ||
// child: Icon( | ||
// Icons.done, | ||
// color: useWhiteForeground(color) | ||
// ? Colors.white | ||
// : Colors.black, | ||
// ), | ||
// ) | ||
// ], | ||
// ), | ||
// ), | ||
// ), | ||
// ), | ||
// ), | ||
// Flexible( | ||
// child: Container( | ||
// padding: EdgeInsets.only(top: 2), child: item.label(context)), | ||
// ), | ||
// ], | ||
// ); | ||
// }, | ||
// ); | ||
// } | ||
// } | ||
// | ||
// class _ValueAccessor extends ControlValueAccessor<dynamic, s.ImageItemValue> { | ||
// final List<s.ImageItemValue> choices; | ||
// | ||
// _ValueAccessor(this.choices); | ||
// | ||
// @override | ||
// s.ImageItemValue? modelToViewValue(dynamic modelValue) { | ||
// if (modelValue == null) { | ||
// return null; | ||
// } | ||
// return choices.cast<s.ImageItemValue?>().firstWhere( | ||
// (element) => element!.value == modelValue, | ||
// orElse: () => null); | ||
// } | ||
// | ||
// @override | ||
// dynamic viewToModelValue(s.ImageItemValue? viewValue) { | ||
// return viewValue?.value; | ||
// } | ||
// } | ||
import 'package:flutter/material.dart'; | ||
import 'package:flutter_colorpicker/flutter_colorpicker.dart'; | ||
import 'package:flutter_survey_js/ui/reactive/reactive_grid_item_picker.dart'; | ||
import 'package:flutter_survey_js_model/flutter_survey_js_model.dart' as s; | ||
import 'package:reactive_forms/reactive_forms.dart'; | ||
import 'package:flutter_survey_js/ui/survey_configuration.dart'; | ||
import 'image.dart'; | ||
|
||
Widget imagePickerBuilder(BuildContext context, s.Elementbase element, | ||
{ElementConfiguration? configuration}) { | ||
return ImagePickerElement( | ||
formControlName: element.name!, | ||
element: element as s.Imagepicker, | ||
).wrapQuestionTitle(context, element, configuration: configuration); | ||
} | ||
|
||
class ImagePickerElement extends StatelessWidget { | ||
final String formControlName; | ||
final s.Imagepicker element; | ||
const ImagePickerElement( | ||
{Key? key, required this.formControlName, required this.element}) | ||
: super(key: key); | ||
@override | ||
Widget build(BuildContext context) { | ||
//TODO multiple select | ||
final choices = element.choices | ||
?.map((p) => p.castToImageitemvalue()) | ||
.where((p) => p != null) | ||
.cast<s.Imageitemvalue>() | ||
.toList() ?? | ||
[]; | ||
|
||
return ReactiveGridItemPicker<Object, s.Imageitemvalue>( | ||
formControlName: formControlName, | ||
valueAccessor: _ValueAccessor(choices), | ||
items: choices, | ||
builder: (s.Imageitemvalue item, bool isCurrentItem, | ||
void Function() changeItem) { | ||
Color? foregroundColor; | ||
if (isCurrentItem) { | ||
foregroundColor = | ||
Theme.of(context).colorScheme.primary.withOpacity(0.4); | ||
} | ||
return InkWell( | ||
onTap: changeItem, | ||
child: Column( | ||
mainAxisSize: MainAxisSize.min, | ||
children: [ | ||
Stack( | ||
alignment: Alignment.center, | ||
children: [ | ||
Container( | ||
foregroundDecoration: BoxDecoration( | ||
color: foregroundColor, | ||
), | ||
child: urlToImage(item.imageLink, | ||
width: element.imageWidth?.realValue, | ||
height: element.imageHeight?.realValue)), | ||
if (isCurrentItem) const Icon(Icons.done) | ||
], | ||
), | ||
Flexible( | ||
child: Container( | ||
padding: EdgeInsets.only(top: 2), | ||
child: Text(item.text ?? item.value?.toString() ?? "")), | ||
), | ||
], | ||
)); | ||
}, | ||
); | ||
} | ||
} | ||
|
||
class _ValueAccessor extends ControlValueAccessor<Object, s.Imageitemvalue> { | ||
final List<s.Imageitemvalue> choices; | ||
|
||
_ValueAccessor(this.choices); | ||
|
||
@override | ||
s.Imageitemvalue? modelToViewValue(dynamic modelValue) { | ||
if (modelValue == null) { | ||
return null; | ||
} | ||
return choices.cast<s.Imageitemvalue?>().firstWhere( | ||
(element) => element?.value?.value == modelValue, | ||
orElse: () => null); | ||
} | ||
|
||
@override | ||
dynamic viewToModelValue(s.Imageitemvalue? viewValue) { | ||
return viewValue?.value?.value; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import 'package:flutter/widgets.dart'; | ||
import 'package:reactive_forms/reactive_forms.dart'; | ||
|
||
typedef GridItemBuilder<T, V> = Widget Function( | ||
V item, bool isCurrentValue, void Function() changeItem); | ||
|
||
class ReactiveGridItemPicker<T, V> extends ReactiveFocusableFormField<T, V> { | ||
ReactiveGridItemPicker( | ||
{Key? key, | ||
String? formControlName, | ||
FormControl<T>? formControl, | ||
Map<String, ValidationMessageFunction>? validationMessages, | ||
ShowErrorsFunction? showErrors, | ||
required ControlValueAccessor<T, V> valueAccessor, | ||
required List<V> items, | ||
required GridItemBuilder<T, V> builder}) | ||
: super( | ||
key: key, | ||
formControl: formControl, | ||
formControlName: formControlName, | ||
validationMessages: validationMessages, | ||
showErrors: showErrors, | ||
valueAccessor: valueAccessor, | ||
builder: (field) { | ||
return Column( | ||
mainAxisSize: MainAxisSize.min, | ||
children: items.map((e) { | ||
final isCurrent = field.valueAccessor.viewToModelValue(e) == | ||
field.valueAccessor.viewToModelValue(field.value); | ||
return builder(e, isCurrent, () { | ||
if (isCurrent) { | ||
field.didChange(null); | ||
} else { | ||
field.didChange(e); | ||
} | ||
}); | ||
}).toList(), | ||
); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.