TF-725 Create InsertImageDialogBuilder to select image
This commit is contained in:
@@ -0,0 +1,185 @@
|
|||||||
|
|
||||||
|
import 'package:core/presentation/extensions/color_extension.dart';
|
||||||
|
import 'package:core/presentation/views/button/icon_button_web.dart';
|
||||||
|
import 'package:core/utils/build_utils.dart';
|
||||||
|
import 'package:file_picker/file_picker.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:model/upload/file_info.dart';
|
||||||
|
import 'package:pointer_interceptor/pointer_interceptor.dart';
|
||||||
|
import 'package:tmail_ui_user/features/composer/presentation/model/image_source.dart';
|
||||||
|
import 'package:tmail_ui_user/features/composer/presentation/model/inline_image.dart';
|
||||||
|
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||||
|
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
|
||||||
|
|
||||||
|
typedef InsertImageActionCallback = Function(InlineImage image);
|
||||||
|
|
||||||
|
class InsertImageDialogBuilder {
|
||||||
|
|
||||||
|
final _inputFileController = TextEditingController();
|
||||||
|
final _inputUrlController = TextEditingController();
|
||||||
|
|
||||||
|
final InsertImageActionCallback? insertActionCallback;
|
||||||
|
final BuildContext _context;
|
||||||
|
|
||||||
|
FileInfo? fileSelected;
|
||||||
|
String? validateFailed;
|
||||||
|
|
||||||
|
InsertImageDialogBuilder(this._context, {
|
||||||
|
this.insertActionCallback
|
||||||
|
});
|
||||||
|
|
||||||
|
Future show() async {
|
||||||
|
await showDialog(
|
||||||
|
context: _context,
|
||||||
|
barrierColor: AppColor.colorDefaultCupertinoActionSheet,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return PointerInterceptor(
|
||||||
|
child: StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: Text(AppLocalizations.of(context).insertImage,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: 20,
|
||||||
|
color: Colors.black)),
|
||||||
|
titleTextStyle: const TextStyle(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: 20,
|
||||||
|
color: Colors.black),
|
||||||
|
titlePadding: const EdgeInsets.symmetric(vertical: 16, horizontal: 16),
|
||||||
|
contentPadding: const EdgeInsets.symmetric(vertical: 0, horizontal: 16),
|
||||||
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)),
|
||||||
|
scrollable: true,
|
||||||
|
elevation: 10,
|
||||||
|
content: Container(
|
||||||
|
color: Colors.white,
|
||||||
|
width: 300,
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(AppLocalizations.of(context).selectFromFile,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
color: Colors.black,
|
||||||
|
fontWeight: FontWeight.w500)),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
TextFormField(
|
||||||
|
controller: _inputFileController,
|
||||||
|
readOnly: true,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
prefixIcon: buildButtonWrapText(
|
||||||
|
AppLocalizations.of(context).chooseImage,
|
||||||
|
radius: 5,
|
||||||
|
height: 30,
|
||||||
|
padding: const EdgeInsets.only(right: 8),
|
||||||
|
textStyle: const TextStyle(
|
||||||
|
color: Colors.black,
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.normal),
|
||||||
|
bgColor: AppColor.colorShadowComposer,
|
||||||
|
onTap: () => _selectFromFile(setState)),
|
||||||
|
suffixIcon: fileSelected != null
|
||||||
|
? IconButton(
|
||||||
|
splashRadius: 10,
|
||||||
|
icon: const Icon(Icons.close),
|
||||||
|
onPressed: () {
|
||||||
|
setState(() {
|
||||||
|
fileSelected = null;
|
||||||
|
_inputFileController.text = '';
|
||||||
|
});
|
||||||
|
})
|
||||||
|
: const SizedBox.shrink(),
|
||||||
|
errorText: validateFailed,
|
||||||
|
errorMaxLines: 2,
|
||||||
|
border: InputBorder.none,
|
||||||
|
)),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
Text(AppLocalizations.of(context).urlLink,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
color: Colors.black,
|
||||||
|
fontWeight: FontWeight.w500)),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
TextField(
|
||||||
|
controller: _inputUrlController,
|
||||||
|
textInputAction: TextInputAction.done,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
border: const OutlineInputBorder(),
|
||||||
|
hintText: AppLocalizations.of(context).urlLink,
|
||||||
|
errorText: validateFailed,
|
||||||
|
errorMaxLines: 2,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
actionsPadding: const EdgeInsets.symmetric(vertical: 8, horizontal: 8),
|
||||||
|
actions: [
|
||||||
|
buildButtonWrapText(
|
||||||
|
AppLocalizations.of(context).cancel,
|
||||||
|
radius: 5,
|
||||||
|
textStyle: const TextStyle(
|
||||||
|
color: Colors.black,
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.normal),
|
||||||
|
bgColor: AppColor.colorShadowComposer,
|
||||||
|
onTap: () => popBack()),
|
||||||
|
buildButtonWrapText(
|
||||||
|
AppLocalizations.of(context).insert,
|
||||||
|
radius: 5,
|
||||||
|
textStyle: const TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w500),
|
||||||
|
onTap: () => _insertImageAction(context, setState))
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void _selectFromFile(StateSetter setState) async {
|
||||||
|
final filePickerResult = await FilePicker.platform.pickFiles(
|
||||||
|
type: FileType.image,
|
||||||
|
withReadStream: true);
|
||||||
|
|
||||||
|
final platformFile = filePickerResult?.files.single;
|
||||||
|
if (platformFile != null) {
|
||||||
|
fileSelected = FileInfo(
|
||||||
|
platformFile.name,
|
||||||
|
BuildUtils.isWeb ? '' : platformFile.path ?? '',
|
||||||
|
platformFile.size,
|
||||||
|
readStream: platformFile.readStream);
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
_inputFileController.text = fileSelected!.fileName;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _insertImageAction(BuildContext context, StateSetter setState) {
|
||||||
|
final inputFile = _inputFileController.text;
|
||||||
|
final inputUrl = _inputUrlController.text;
|
||||||
|
|
||||||
|
if (inputFile.isEmpty && inputUrl.isEmpty) {
|
||||||
|
setState(() {
|
||||||
|
validateFailed = AppLocalizations.of(context).insertImageErrorFileEmpty;
|
||||||
|
});
|
||||||
|
} else if (inputFile.isNotEmpty && inputUrl.isNotEmpty) {
|
||||||
|
setState(() {
|
||||||
|
validateFailed = AppLocalizations.of(context).insertImageErrorDuplicate;
|
||||||
|
});
|
||||||
|
} else if (inputFile.isNotEmpty && fileSelected != null) {
|
||||||
|
if (insertActionCallback != null) {
|
||||||
|
insertActionCallback!.call(InlineImage(ImageSource.local, fileInfo: fileSelected));
|
||||||
|
}
|
||||||
|
popBack();
|
||||||
|
} else {
|
||||||
|
if (insertActionCallback != null) {
|
||||||
|
insertActionCallback!.call(InlineImage(ImageSource.network, link: inputUrl));
|
||||||
|
}
|
||||||
|
popBack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user