Skip to content

Commit

Permalink
Add Sticker Editor for Enhanced Widget Integration
Browse files Browse the repository at this point in the history
- Introduce Sticker Editor functionality for loading stickers and widgets in the editor.
- Update documentation in CHANGELOG.md and README.md.
- Add new assets and models for sticker editor configurations.
- Refactor existing models and modules to support sticker editor integration.
- Update tests and pubspec.yaml to reflect changes.
  • Loading branch information
hm21 committed Jan 13, 2024
1 parent 9b879e4 commit 6cbd589
Show file tree
Hide file tree
Showing 22 changed files with 784 additions and 322 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Changelog

## Version 2.0.0
- Introducing the "Sticker" editor for seamless loading of stickers and widgets directly into the editor.

## Version 1.0.3
- Update README.md with improved preview image

Expand Down
237 changes: 198 additions & 39 deletions README.md

Large diffs are not rendered by default.

Binary file added assets/sticker-editor.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
123 changes: 103 additions & 20 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,7 @@ class _MyHomePageState extends State<MyHomePage> {
if (!kIsWeb) ...[
OutlinedButton.icon(
onPressed: () async {
FilePickerResult? result =
await FilePicker.platform.pickFiles(
FilePickerResult? result = await FilePicker.platform.pickFiles(
type: FileType.image,
);

Expand Down Expand Up @@ -134,8 +133,7 @@ class _MyHomePageState extends State<MyHomePage> {
various: I18nVarious(
loadingDialogMsg: 'Please wait...',
closeEditorWarningTitle: 'Close Image Editor?',
closeEditorWarningMessage:
'Are you sure you want to close the Image Editor? Your changes will not be saved.',
closeEditorWarningMessage: 'Are you sure you want to close the Image Editor? Your changes will not be saved.',
closeEditorWarningConfirmBtn: 'OK',
closeEditorWarningCancelBtn: 'Cancel',
),
Expand Down Expand Up @@ -177,8 +175,7 @@ class _MyHomePageState extends State<MyHomePage> {
smallScreenMoreTooltip: 'More',
),
filterEditor: I18nFilterEditor(
applyFilterDialogMsg:
'Filter is being applied.',
applyFilterDialogMsg: 'Filter is being applied.',
bottomNavigationBarText: 'Filter',
back: 'Back',
done: 'Done',
Expand Down Expand Up @@ -231,6 +228,9 @@ class _MyHomePageState extends State<MyHomePage> {
emojiEditor: I18nEmojiEditor(
bottomNavigationBarText: 'Emoji',
),
stickerEditor: I18nStickerEditor(
bottomNavigationBarText: 'I18nStickerEditor',
),
cancel: 'Cancel',
undo: 'Undo',
redo: 'Redo',
Expand Down Expand Up @@ -288,13 +288,13 @@ class _MyHomePageState extends State<MyHomePage> {
skinToneDialogBgColor: Color(0xFF252728),
skinToneIndicatorColor: Color(0xFF9E9E9E),
),
stickerEditor: StickerEditorTheme(),
background: Color.fromARGB(255, 22, 22, 22),
loadingDialogTextColor: Color(0xFFE1E1E1),
uiOverlayStyle: SystemUiOverlayStyle(
statusBarColor: Color(0x42000000),
statusBarIconBrightness: Brightness.light,
systemNavigationBarIconBrightness:
Brightness.light,
systemNavigationBarIconBrightness: Brightness.light,
statusBarBrightness: Brightness.dark,
systemNavigationBarColor: Color(0xFF000000),
),
Expand All @@ -315,10 +315,8 @@ class _MyHomePageState extends State<MyHomePage> {
textEditor: IconsTextEditor(
bottomNavBar: Icons.text_fields,
alignLeft: Icons.align_horizontal_left_rounded,
alignCenter:
Icons.align_horizontal_center_rounded,
alignRight:
Icons.align_horizontal_right_rounded,
alignCenter: Icons.align_horizontal_center_rounded,
alignRight: Icons.align_horizontal_right_rounded,
backgroundMode: Icons.layers_rounded,
),
cropRotateEditor: IconsCropRotateEditor(
Expand All @@ -330,8 +328,10 @@ class _MyHomePageState extends State<MyHomePage> {
bottomNavBar: Icons.filter,
),
emojiEditor: IconsEmojiEditor(
bottomNavBar:
Icons.sentiment_satisfied_alt_rounded,
bottomNavBar: Icons.sentiment_satisfied_alt_rounded,
),
stickerEditor: IconsStickerEditor(
bottomNavBar: Icons.layers_outlined,
),
closeEditor: Icons.clear,
doneIcon: Icons.done,
Expand Down Expand Up @@ -364,11 +364,9 @@ class _MyHomePageState extends State<MyHomePage> {
canToggleBackgroundMode: true,
initFontSize: 24.0,
initialTextAlign: TextAlign.center,
initialBackgroundColorMode:
LayerBackgroundColorModeE.backgroundAndColor,
initialBackgroundColorMode: LayerBackgroundColorModeE.backgroundAndColor,
),
cropRotateEditorConfigs:
const CropRotateEditorConfigs(
cropRotateEditorConfigs: const CropRotateEditorConfigs(
enabled: true,
canRotate: true,
canChangeAspectRatio: true,
Expand All @@ -384,8 +382,7 @@ class _MyHomePageState extends State<MyHomePage> {
recentTabBehavior: RecentTabBehavior.RECENT,
enableSkinTones: true,
recentsLimit: 28,
textStyle: TextStyle(
fontFamilyFallback: ['Apple Color Emoji']),
textStyle: TextStyle(fontFamilyFallback: ['Apple Color Emoji']),
checkPlatformCompatibility: true,
emojiSet:
null /* [
Expand Down Expand Up @@ -439,6 +436,92 @@ class _MyHomePageState extends State<MyHomePage> {
icon: const Icon(Icons.public_outlined),
label: const Text('Editor from network'),
),
const SizedBox(height: 30),
OutlinedButton.icon(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => ProImageEditor.network(
'https://picsum.photos/2000',
onImageEditingComplete: (bytes) async {
Navigator.pop(context);
},
configs: ProImageEditorConfigs(
stickerEditorConfigs: StickerEditorConfigs(
enabled: true,
buildStickers: (setLayer) {
return ClipRRect(
borderRadius: const BorderRadius.vertical(top: Radius.circular(20)),
child: Container(
color: const Color.fromARGB(255, 224, 239, 251),
child: GridView.builder(
padding: const EdgeInsets.all(16),
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 150,
mainAxisSpacing: 10,
crossAxisSpacing: 10,
),
itemCount: 21,
shrinkWrap: true,
itemBuilder: (context, index) {
Widget widget = ClipRRect(
borderRadius: BorderRadius.circular(7),
child: Image.network(
'https://picsum.photos/id/${(index + 3) * 3}/2000',
width: 120,
height: 120,
fit: BoxFit.cover,
loadingBuilder: (context, child, loadingProgress) {
return AnimatedSwitcher(
layoutBuilder: (currentChild, previousChildren) {
return SizedBox(
width: 120,
height: 120,
child: Stack(
fit: StackFit.expand,
alignment: Alignment.center,
children: <Widget>[
...previousChildren,
if (currentChild != null) currentChild,
],
),
);
},
duration: const Duration(milliseconds: 200),
child: loadingProgress == null
? child
: Center(
child: CircularProgressIndicator(
value: loadingProgress.expectedTotalBytes != null
? loadingProgress.cumulativeBytesLoaded / loadingProgress.expectedTotalBytes!
: null,
),
),
);
},
),
);
return GestureDetector(
onTap: () => setLayer(widget),
child: MouseRegion(
cursor: SystemMouseCursors.click,
child: widget,
),
);
},
),
),
);
},
),
),
),
),
);
},
icon: const Icon(Icons.layers_outlined),
label: const Text('Editor with Stickers'),
),
],
),
),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

import '../models/custom_widgets.dart';
import '../models/editor_configs/crop_rotate_editor_configs.dart';
import '../models/editor_configs/emoji_editor_configs.dart';
import '../models/editor_configs/filter_editor_configs.dart';
import '../models/editor_configs/paint_editor_configs.dart';
import '../models/editor_configs/text_editor_configs.dart';
import '../models/helper_lines.dart';
import '../models/i18n/i18n.dart';
import '../models/icons/icons.dart';
import '../models/theme/theme.dart';
import 'design_mode.dart';
import 'package:pro_image_editor/models/editor_configs/sticker_editor_configs.dart';

import '../custom_widgets.dart';
import 'crop_rotate_editor_configs.dart';
import 'emoji_editor_configs.dart';
import 'filter_editor_configs.dart';
import 'paint_editor_configs.dart';
import 'text_editor_configs.dart';
import '../helper_lines.dart';
import '../i18n/i18n.dart';
import '../icons/icons.dart';
import '../theme/theme.dart';
import '../../utils/design_mode.dart';

/// A class representing configuration options for the Image Editor.
class ProImageEditorConfigs {
Expand Down Expand Up @@ -54,6 +55,9 @@ class ProImageEditorConfigs {
/// Configuration options for the Emoji Editor.
final EmojiEditorConfigs emojiEditorConfigs;

/// Configuration options for the Sticker Editor.
final StickerEditorConfigs? stickerEditorConfigs;

/// The design mode for the Image Editor.
final ImageEditorDesignModeE designMode;

Expand All @@ -71,6 +75,7 @@ class ProImageEditorConfigs {
/// - The `cropRotateEditorConfigs` configures the Crop and Rotate Editor. By default, it uses an empty `CropRotateEditorConfigs` instance.
/// - The `filterEditorConfigs` configures the Filter Editor. By default, it uses an empty `FilterEditorConfigs` instance.
/// - The `emojiEditorConfigs` configures the Emoji Editor. By default, it uses an empty `EmojiEditorConfigs` instance.
/// - The `stickerEditorConfigs` configures the Sticker Editor. By default, it uses an empty `stickerEditorConfigs` instance.
/// - The `designMode` specifies the design mode for the Image Editor. By default, it is `ImageEditorDesignMode.material`.
const ProImageEditorConfigs({
this.theme,
Expand All @@ -91,6 +96,7 @@ class ProImageEditorConfigs {
this.cropRotateEditorConfigs = const CropRotateEditorConfigs(),
this.filterEditorConfigs = const FilterEditorConfigs(),
this.emojiEditorConfigs = const EmojiEditorConfigs(),
this.stickerEditorConfigs,
this.designMode = ImageEditorDesignModeE.material,
});
}
51 changes: 51 additions & 0 deletions lib/models/editor_configs/sticker_editor_configs.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import 'package:flutter/widgets.dart';

/// Configuration options for a sticker editor.
///
/// `StickerEditorConfigs` allows you to define various settings for a sticker
/// editor. You can configure features like enabling/disabling the editor,
/// initial sticker width, and a custom method to build stickers.
///
/// Example usage:
/// ```dart
/// StickerEditorConfigs(
/// enabled: false,
/// initWidth: 150,
/// buildStickers: (setLayer) {
/// return Container(); // Replace with your builder to load and display stickers.
/// },
/// );
/// ```
class StickerEditorConfigs {
/// Indicates whether the sticker editor is enabled.
///
/// When set to `true`, the sticker editor is active and users can interact with it.
/// If `false`, the editor is disabled and does not respond to user inputs.
final bool enabled;

/// The initial width of the stickers in the editor.
///
/// Specifies the starting width of the stickers when they are first placed
/// in the editor. This value is in logical pixels.
final double initWidth;

/// A callback that builds the stickers.
///
/// This typedef is a function that takes a function as a parameter and
/// returns a Widget. The function parameter `setLayer` is used to set a
/// layer in the editor. This callback allows for customizing the appearance
/// and behavior of stickers in the editor.
final BuildStickers buildStickers;

/// Creates an instance of StickerEditorConfigs with optional settings.
///
/// By default, the editor is disabled (if not specified), and other properties
/// are set to reasonable defaults.
const StickerEditorConfigs({
required this.buildStickers,
this.initWidth = 100,
this.enabled = false,
});
}

typedef BuildStickers = Widget Function(Function(Widget) setLayer);
6 changes: 6 additions & 0 deletions lib/models/i18n/i18n.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'i18n_crop_rotate_editor.dart';
import 'i18n_emoji_editor.dart';
import 'i18n_filter_editor.dart';
import 'i18n_painting_editor.dart';
import 'i18n_sticker_editor.dart';
import 'i18n_text_editor.dart';
import 'i18n_various.dart';

Expand All @@ -10,6 +11,7 @@ export 'i18n_text_editor.dart';
export 'i18n_painting_editor.dart';
export 'i18n_filter_editor.dart';
export 'i18n_emoji_editor.dart';
export 'i18n_sticker_editor.dart';
export 'i18n_crop_rotate_editor.dart';

/// The `I18n` class provides internationalization settings for the image editor
Expand Down Expand Up @@ -106,6 +108,9 @@ class I18n {
/// Translations and messages specific to the emoji editor.
final I18nEmojiEditor emojiEditor;

/// Translations and messages specific to the sticker editor.
final I18nStickerEditor stickerEditor;

/// Translations and messages specific to the crop and rotate editor.
final I18nCropRotateEditor cropRotateEditor;

Expand Down Expand Up @@ -167,6 +172,7 @@ class I18n {
this.cropRotateEditor = const I18nCropRotateEditor(),
this.filterEditor = const I18nFilterEditor(),
this.emojiEditor = const I18nEmojiEditor(),
this.stickerEditor = const I18nStickerEditor(),
this.various = const I18nVarious(),
this.cancel = 'Cancel',
this.undo = 'Undo',
Expand Down
21 changes: 21 additions & 0 deletions lib/models/i18n/i18n_sticker_editor.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/// Internationalization (i18n) settings for the I18nStickerEditor Editor component.
class I18nStickerEditor {
/// Text for the bottom navigation bar item that opens the I18nStickerEditor Editor.
final String bottomNavigationBarText;

/// Creates an instance of [I18nStickerEditor] with customizable internationalization settings.
///
/// You can provide translations and messages specifically for the I18nStickerEditor Editor
/// component of your application.
///
/// Example:
///
/// ```dart
/// I18nStickerEditor(
/// bottomNavigationBarText: 'I18nStickerEditor',
/// )
/// ```
const I18nStickerEditor({
this.bottomNavigationBarText = 'Stickers',
});
}
Loading

0 comments on commit 6cbd589

Please sign in to comment.