Save image option (#593)

* Save image option

* Update android versions

* Refactor code
pull/596/head
X Code 3 years ago committed by GitHub
parent 379f35d71f
commit 565f6316cd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      example/android/app/build.gradle
  2. 2
      example/android/build.gradle
  3. 1076
      example/assets/sample_data.json
  4. 33
      lib/src/utils/simple_dialog_item.dart
  5. 68
      lib/src/widgets/editor.dart
  6. 39
      lib/src/widgets/embeds/image.dart
  7. 1
      pubspec.yaml

@ -44,7 +44,7 @@ android {
defaultConfig { defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.example.app" applicationId "com.example.app"
minSdkVersion 17 minSdkVersion 21
targetSdkVersion flutter.targetSdkVersion targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger() versionCode flutterVersionCode.toInteger()
versionName flutterVersionName versionName flutterVersionName

@ -1,5 +1,5 @@
buildscript { buildscript {
ext.kotlin_version = '1.3.50' ext.kotlin_version = '1.6.10'
repositories { repositories {
google() google()
mavenCentral() mavenCentral()

File diff suppressed because one or more lines are too long

@ -0,0 +1,33 @@
import 'package:flutter/material.dart';
class SimpleDialogItem extends StatelessWidget {
const SimpleDialogItem(
{required this.icon,
required this.color,
required this.text,
required this.onPressed,
Key? key})
: super(key: key);
final IconData icon;
final Color color;
final String text;
final VoidCallback onPressed;
@override
Widget build(BuildContext context) {
return SimpleDialogOption(
onPressed: onPressed,
child: Row(
children: [
Icon(icon, size: 36, color: color),
Padding(
padding: const EdgeInsetsDirectional.only(start: 16),
child:
Text(text, style: const TextStyle(fontWeight: FontWeight.bold)),
),
],
),
);
}
}

@ -1,5 +1,3 @@
import 'dart:convert';
import 'dart:io' as io;
import 'dart:math' as math; import 'dart:math' as math;
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
@ -8,13 +6,14 @@ import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:string_validator/string_validator.dart'; import 'package:gallery_saver/gallery_saver.dart';
import '../models/documents/document.dart'; import '../models/documents/document.dart';
import '../models/documents/nodes/container.dart' as container_node; import '../models/documents/nodes/container.dart' as container_node;
import '../models/documents/nodes/leaf.dart' as leaf; import '../models/documents/nodes/leaf.dart' as leaf;
import '../models/documents/nodes/line.dart'; import '../models/documents/nodes/line.dart';
import '../utils/platform_helper.dart'; import '../utils/platform_helper.dart';
import '../utils/simple_dialog_item.dart';
import '../utils/string_helper.dart'; import '../utils/string_helper.dart';
import 'box.dart'; import 'box.dart';
import 'controller.dart'; import 'controller.dart';
@ -187,38 +186,53 @@ Widget defaultEmbedBuilder(
final a = getAlignment(_attrs['mobileAlignment']); final a = getAlignment(_attrs['mobileAlignment']);
image = Padding( image = Padding(
padding: EdgeInsets.all(m), padding: EdgeInsets.all(m),
child: imageUrl.startsWith('http') child: imageByUrl(imageUrl, width: w, height: h, alignment: a));
? Image.network(imageUrl, width: w, height: h, alignment: a)
: isBase64(imageUrl)
? Image.memory(base64.decode(imageUrl),
width: w, height: h, alignment: a)
: Image.file(io.File(imageUrl),
width: w, height: h, alignment: a));
} }
} }
image ??= imageUrl.startsWith('http') image ??= imageByUrl(imageUrl);
? Image.network(imageUrl)
: isBase64(imageUrl)
? Image.memory(base64.decode(imageUrl))
: Image.file(io.File(imageUrl));
if (!readOnly) { if (!readOnly || !isMobile() || isImageBase64(imageUrl)) {
return image; return image;
} }
/// We provide option menu only for mobile platform excluding base64
return GestureDetector( return GestureDetector(
onTap: () { onTap: () {
Navigator.push( showDialog(
context, context: context,
MaterialPageRoute( builder: (context) => Padding(
builder: (context) => ImageTapWrapper( padding: const EdgeInsets.fromLTRB(50, 0, 50, 0),
imageProvider: imageUrl.startsWith('http') child: SimpleDialog(
? NetworkImage(imageUrl) shape: const RoundedRectangleBorder(
: isBase64(imageUrl) borderRadius:
? Image.memory(base64.decode(imageUrl)) BorderRadius.all(Radius.circular(10))),
as ImageProvider<Object>? children: [
: FileImage(io.File(imageUrl)), SimpleDialogItem(
))); icon: Icons.save,
color: Colors.greenAccent,
text: 'Save',
onPressed: () {
// TODO: improve this
GallerySaver.saveImage(imageUrl).then((_) =>
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Saved'))));
},
),
SimpleDialogItem(
icon: Icons.zoom_in,
color: Colors.cyanAccent,
text: 'Zoom',
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ImageTapWrapper(
imageUrl: imageUrl)));
},
)
]),
));
}, },
child: image); child: image);
case 'video': case 'video':

@ -1,12 +1,45 @@
import 'dart:convert';
import 'dart:io' as io;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:photo_view/photo_view.dart'; import 'package:photo_view/photo_view.dart';
import 'package:string_validator/string_validator.dart';
bool isImageBase64(String imageUrl) {
return !imageUrl.startsWith('http') && isBase64(imageUrl);
}
Widget imageByUrl(String imageUrl,
{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);
}
class ImageTapWrapper extends StatelessWidget { class ImageTapWrapper extends StatelessWidget {
const ImageTapWrapper({ const ImageTapWrapper({
this.imageProvider, required this.imageUrl,
}); });
final ImageProvider? imageProvider; final String imageUrl;
ImageProvider _imageProviderByUrl(String imageUrl) {
if (imageUrl.startsWith('http')) {
return NetworkImage(imageUrl);
}
return FileImage(io.File(imageUrl));
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -18,7 +51,7 @@ class ImageTapWrapper extends StatelessWidget {
child: Stack( child: Stack(
children: [ children: [
PhotoView( PhotoView(
imageProvider: imageProvider, imageProvider: _imageProviderByUrl(imageUrl),
loadingBuilder: (context, event) { loadingBuilder: (context, event) {
return Container( return Container(
color: Colors.black, color: Colors.black,

@ -27,6 +27,7 @@ dependencies:
youtube_player_flutter: ^8.0.0 youtube_player_flutter: ^8.0.0
diff_match_patch: ^0.4.1 diff_match_patch: ^0.4.1
i18n_extension: ^4.1.3 i18n_extension: ^4.1.3
gallery_saver: ^2.3.2
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:

Loading…
Cancel
Save