TF-1884 Support RTL mode for TextFormField

(cherry picked from commit 7c12f65a037bb5a1b6cef91938af1ec1dac20a9b)
This commit is contained in:
dab246
2023-06-14 12:29:22 +07:00
committed by Dat H. Pham
parent df19b979a2
commit 9064d95483
7 changed files with 138 additions and 200 deletions
@@ -1,186 +0,0 @@
import 'package:core/presentation/extensions/color_extension.dart';
import 'package:core/presentation/views/button/icon_button_web.dart';
import 'package:core/presentation/views/text/text_field_builder.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),
TextFieldBuilder(
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();
}
}
}
@@ -1,6 +1,8 @@
import 'dart:async';
import 'package:core/core.dart';
import 'package:core/presentation/extensions/color_extension.dart';
import 'package:core/presentation/resources/image_paths.dart';
import 'package:core/presentation/views/text/text_form_field_builder.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
@@ -122,21 +124,21 @@ class LoginTextInputBuilder {
child: Stack(
alignment: AlignmentDirectional.centerEnd,
children: [
TextFormField(
onFieldSubmitted: _onSubmitted,
onChanged: (value) => _onTextChanged(value, setState),
TextFormFieldBuilder(
onTextSubmitted: _onSubmitted,
onTextChange: (value) => _onTextChanged(value, setState),
obscureText: _obscureText ?? false,
textInputAction: _textInputAction,
autofillHints: autofillHints,
autocorrect: autocorrect,
controller: _textEditingController,
cursorColor: AppColor.primaryColor,
style: const TextStyle(color: AppColor.loginTextFieldHintColor, fontSize: 16, fontWeight: FontWeight.normal),
textStyle: const TextStyle(color: AppColor.loginTextFieldHintColor, fontSize: 16, fontWeight: FontWeight.normal),
focusNode: _focusNode,
decoration: (LoginInputDecorationBuilder()
..setHintText(_hintText)
..setPrefixText(_prefixText)
..setErrorText(_errorText)
..setContentPadding(const EdgeInsetsDirectional.only(start: 25, top: 15, bottom: 15, end: 40))
..setHintStyle(const TextStyle(color: AppColor.loginTextFieldHintColor, fontSize: 16, fontWeight: FontWeight.normal))
..setPrefixStyle(const TextStyle(color: AppColor.loginTextFieldHintColor, fontSize: 16, fontWeight: FontWeight.normal))
..setErrorTextStyle(const TextStyle(color: AppColor.loginTextFieldErrorBorder, fontSize: 13, fontWeight: FontWeight.normal))