dartlangeditorflutterflutter-appsflutter-examplesflutter-packageflutter-widgetquillquill-deltaquilljsreactquillrich-textrich-text-editorwysiwygwysiwyg-editor
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
146 lines
4.0 KiB
146 lines
4.0 KiB
3 years ago
|
import 'dart:convert';
|
||
|
import 'dart:io' as io;
|
||
|
|
||
4 years ago
|
import 'package:flutter/material.dart';
|
||
3 years ago
|
import 'package:flutter_quill/flutter_quill.dart';
|
||
4 years ago
|
import 'package:photo_view/photo_view.dart';
|
||
3 years ago
|
|
||
3 years ago
|
import '../utils.dart';
|
||
3 years ago
|
|
||
3 years ago
|
const List<String> imageFileExtensions = [
|
||
|
'.jpeg',
|
||
|
'.png',
|
||
|
'.jpg',
|
||
|
'.gif',
|
||
|
'.webp',
|
||
|
'.tif',
|
||
|
'.heic'
|
||
|
];
|
||
|
|
||
3 years ago
|
String getImageStyleString(QuillController controller) {
|
||
|
final String? s = controller
|
||
|
.getAllSelectionStyles()
|
||
|
.firstWhere((s) => s.attributes.containsKey(Attribute.style.key),
|
||
|
orElse: () => Style())
|
||
|
.attributes[Attribute.style.key]
|
||
|
?.value;
|
||
|
return s ?? '';
|
||
|
}
|
||
|
|
||
3 years ago
|
Image imageByUrl(String imageUrl,
|
||
3 years ago
|
{double? width,
|
||
|
double? height,
|
||
|
AlignmentGeometry alignment = Alignment.center}) {
|
||
|
if (isImageBase64(imageUrl)) {
|
||
|
return Image.memory(base64.decode(imageUrl),
|
||
|
width: width, height: height, alignment: alignment);
|
||
|
}
|
||
|
|
||
|
if (imageUrl.startsWith('http')) {
|
||
|
return Image.network(imageUrl,
|
||
|
width: width, height: height, alignment: alignment);
|
||
|
}
|
||
|
return Image.file(io.File(imageUrl),
|
||
|
width: width, height: height, alignment: alignment);
|
||
3 years ago
|
}
|
||
|
|
||
|
String standardizeImageUrl(String url) {
|
||
|
if (url.contains('base64')) {
|
||
|
return url.split(',')[1];
|
||
|
}
|
||
|
return url;
|
||
3 years ago
|
}
|
||
|
|
||
|
/// This is a bug of Gallery Saver Package.
|
||
|
/// It can not save image that's filename does not end with it's file extension
|
||
|
/// like below.
|
||
|
// "https://firebasestorage.googleapis.com/v0/b/eventat-4ba96.appspot.com/o/2019-Metrology-Events.jpg?alt=media&token=bfc47032-5173-4b3f-86bb-9659f46b362a"
|
||
|
/// If imageUrl does not end with it's file extension,
|
||
|
/// file extension is added to image url for saving.
|
||
|
String appendFileExtensionToImageUrl(String url) {
|
||
|
final endsWithImageFileExtension = imageFileExtensions
|
||
|
.firstWhere((s) => url.toLowerCase().endsWith(s), orElse: () => '');
|
||
|
if (endsWithImageFileExtension.isNotEmpty) {
|
||
|
return url;
|
||
|
}
|
||
|
|
||
|
final imageFileExtension = imageFileExtensions
|
||
|
.firstWhere((s) => url.toLowerCase().contains(s), orElse: () => '');
|
||
|
|
||
|
return url + imageFileExtension;
|
||
3 years ago
|
}
|
||
4 years ago
|
|
||
|
class ImageTapWrapper extends StatelessWidget {
|
||
|
const ImageTapWrapper({
|
||
3 years ago
|
required this.imageUrl,
|
||
4 years ago
|
});
|
||
|
|
||
3 years ago
|
final String imageUrl;
|
||
|
|
||
|
ImageProvider _imageProviderByUrl(String imageUrl) {
|
||
|
if (imageUrl.startsWith('http')) {
|
||
|
return NetworkImage(imageUrl);
|
||
|
}
|
||
|
|
||
|
return FileImage(io.File(imageUrl));
|
||
|
}
|
||
4 years ago
|
|
||
3 years ago
|
@override
|
||
4 years ago
|
Widget build(BuildContext context) {
|
||
|
return Scaffold(
|
||
|
body: Container(
|
||
|
constraints: BoxConstraints.expand(
|
||
|
height: MediaQuery.of(context).size.height,
|
||
|
),
|
||
3 years ago
|
child: Stack(
|
||
|
children: [
|
||
|
PhotoView(
|
||
3 years ago
|
imageProvider: _imageProviderByUrl(imageUrl),
|
||
3 years ago
|
loadingBuilder: (context, event) {
|
||
|
return Container(
|
||
|
color: Colors.black,
|
||
3 years ago
|
child: const Center(
|
||
3 years ago
|
child: CircularProgressIndicator(),
|
||
|
),
|
||
|
);
|
||
|
},
|
||
|
),
|
||
|
Positioned(
|
||
3 years ago
|
right: 10,
|
||
3 years ago
|
top: MediaQuery.of(context).padding.top + 10.0,
|
||
|
child: InkWell(
|
||
|
onTap: () {
|
||
|
Navigator.pop(context);
|
||
|
},
|
||
|
child: Stack(
|
||
|
children: [
|
||
|
Opacity(
|
||
|
opacity: 0.2,
|
||
|
child: Container(
|
||
3 years ago
|
height: 30,
|
||
|
width: 30,
|
||
|
decoration: const BoxDecoration(
|
||
3 years ago
|
shape: BoxShape.circle,
|
||
|
color: Colors.black87,
|
||
|
),
|
||
|
),
|
||
|
),
|
||
|
Positioned(
|
||
|
top: 0,
|
||
|
bottom: 0,
|
||
|
left: 0,
|
||
|
right: 0,
|
||
3 years ago
|
child:
|
||
|
Icon(Icons.close, color: Colors.grey[400], size: 28),
|
||
3 years ago
|
)
|
||
|
],
|
||
|
),
|
||
|
),
|
||
|
),
|
||
|
],
|
||
4 years ago
|
),
|
||
|
),
|
||
|
);
|
||
|
}
|
||
|
}
|