another commit
This commit is contained in:
33
lib/widgets/boxBackgroundDecoration.dart
Normal file
33
lib/widgets/boxBackgroundDecoration.dart
Normal file
@ -0,0 +1,33 @@
|
||||
// ignore_for_file: file_names
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class BoxBackgroundDecoration extends StatelessWidget {
|
||||
final Widget? child;
|
||||
const BoxBackgroundDecoration({
|
||||
Key? key,
|
||||
this.child,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
height: MediaQuery.of(context).size.height,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
// decoration gradient
|
||||
decoration: const BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [
|
||||
Color.fromARGB(255, 199, 214, 234),
|
||||
Color.fromARGB(255, 104, 164, 164),
|
||||
Color.fromARGB(255, 4, 103, 103),
|
||||
Color.fromARGB(255, 2, 72, 72),
|
||||
],
|
||||
),
|
||||
),
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
}
|
||||
166
lib/widgets/focusToTextFormField.dart
Normal file
166
lib/widgets/focusToTextFormField.dart
Normal file
@ -0,0 +1,166 @@
|
||||
// ignore_for_file: file_names
|
||||
|
||||
import 'dart:async';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
// import 'package:meta/meta.dart';
|
||||
|
||||
///
|
||||
/// Helper class that ensures a Widget is visible when it has the focus
|
||||
/// For example, for a TextFormField when the keyboard is displayed
|
||||
///
|
||||
/// How to use it:
|
||||
///
|
||||
/// In the class that implements the Form,
|
||||
/// Instantiate a FocusNode
|
||||
/// FocusNode _focusNode = new FocusNode();
|
||||
///
|
||||
/// In the build(BuildContext context), wrap the TextFormField as follows:
|
||||
///
|
||||
/// new EnsureVisibleWhenFocused(
|
||||
/// focusNode: _focusNode,
|
||||
/// child: new TextFormField(
|
||||
/// ...
|
||||
/// focusNode: _focusNode,
|
||||
/// ),
|
||||
/// ),
|
||||
///
|
||||
/// Initial source code written by Collin Jackson.
|
||||
/// Extended (see highlighting) to cover the case when the keyboard is dismissed and the
|
||||
/// user clicks the TextFormField/TextField which still has the focus.
|
||||
///
|
||||
class EnsureVisibleWhenFocused extends StatefulWidget {
|
||||
const EnsureVisibleWhenFocused({
|
||||
Key? key,
|
||||
required this.child,
|
||||
required this.focusNode,
|
||||
this.curve = Curves.ease,
|
||||
this.duration = const Duration(milliseconds: 100),
|
||||
}) : super(key: key);
|
||||
|
||||
/// The node we will monitor to determine if the child is focused
|
||||
final FocusNode focusNode;
|
||||
|
||||
/// The child widget that we are wrapping
|
||||
final Widget child;
|
||||
|
||||
/// The curve we will use to scroll ourselves into view.
|
||||
///
|
||||
/// Defaults to Curves.ease.
|
||||
final Curve curve;
|
||||
|
||||
/// The duration we will use to scroll ourselves into view
|
||||
///
|
||||
/// Defaults to 100 milliseconds.
|
||||
final Duration duration;
|
||||
|
||||
@override
|
||||
_EnsureVisibleWhenFocusedState createState() =>
|
||||
_EnsureVisibleWhenFocusedState();
|
||||
}
|
||||
|
||||
///
|
||||
/// We implement the WidgetsBindingObserver to be notified of any change to the window metrics
|
||||
///
|
||||
class _EnsureVisibleWhenFocusedState extends State<EnsureVisibleWhenFocused>
|
||||
with WidgetsBindingObserver {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
widget.focusNode.addListener(_ensureVisible);
|
||||
WidgetsBinding.instance!.addObserver(this);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
WidgetsBinding.instance!.removeObserver(this);
|
||||
widget.focusNode.removeListener(_ensureVisible);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
///
|
||||
/// This routine is invoked when the window metrics have changed.
|
||||
/// This happens when the keyboard is open or dismissed, among others.
|
||||
/// It is the opportunity to check if the field has the focus
|
||||
/// and to ensure it is fully visible in the viewport when
|
||||
/// the keyboard is displayed
|
||||
///
|
||||
@override
|
||||
void didChangeMetrics() {
|
||||
if (widget.focusNode.hasFocus) {
|
||||
_ensureVisible();
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// This routine waits for the keyboard to come into view.
|
||||
/// In order to prevent some issues if the Widget is dismissed in the
|
||||
/// middle of the loop, we need to check the "mounted" property
|
||||
///
|
||||
/// This method was suggested by Peter Yuen (see discussion).
|
||||
///
|
||||
Future<void> _keyboardToggled() async {
|
||||
if (mounted) {
|
||||
EdgeInsets edgeInsets = MediaQuery.of(context).viewInsets;
|
||||
while (mounted && MediaQuery.of(context).viewInsets == edgeInsets) {
|
||||
await Future.delayed(const Duration(milliseconds: 10));
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Future<void> _ensureVisible() async {
|
||||
// Wait for the keyboard to come into view
|
||||
await Future.any([
|
||||
Future.delayed(const Duration(milliseconds: 300)),
|
||||
_keyboardToggled()
|
||||
]);
|
||||
|
||||
// No need to go any further if the node has not the focus
|
||||
if (!widget.focusNode.hasFocus) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the object which has the focus
|
||||
final RenderObject? object = context.findRenderObject();
|
||||
final RenderAbstractViewport? viewport = RenderAbstractViewport.of(object);
|
||||
|
||||
// If we are not working in a Scrollable, skip this routine
|
||||
if (viewport == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the Scrollable state (in order to retrieve its offset)
|
||||
ScrollableState? scrollableState = Scrollable.of(context);
|
||||
assert(scrollableState != null);
|
||||
|
||||
// Get its offset
|
||||
ScrollPosition position = scrollableState!.position;
|
||||
double alignment;
|
||||
|
||||
if (position.pixels > viewport.getOffsetToReveal(object!, 0.0).offset) {
|
||||
// Move down to the top of the viewport
|
||||
alignment = 0.0;
|
||||
} else if (position.pixels <
|
||||
viewport.getOffsetToReveal(object, 1.0).offset) {
|
||||
// Move up to the bottom of the viewport
|
||||
alignment = 1.0;
|
||||
} else {
|
||||
// No scrolling is necessary to reveal the child
|
||||
return;
|
||||
}
|
||||
|
||||
position.ensureVisible(
|
||||
object,
|
||||
alignment: alignment,
|
||||
duration: widget.duration,
|
||||
curve: widget.curve,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return widget.child;
|
||||
}
|
||||
}
|
||||
35
lib/widgets/ourContainer.dart
Normal file
35
lib/widgets/ourContainer.dart
Normal file
@ -0,0 +1,35 @@
|
||||
// ignore_for_file: file_names
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class OurContainer extends StatelessWidget {
|
||||
final Widget? child;
|
||||
|
||||
const OurContainer({Key? key, this.child}) : super(key: key);
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final double left = (MediaQuery.of(context).size.width -
|
||||
(MediaQuery.of(context).size.width * 0.9)) /
|
||||
2;
|
||||
return Container(
|
||||
width: MediaQuery.of(context).size.width * 0.9,
|
||||
margin: EdgeInsets.only(left: left, right: left),
|
||||
padding: const EdgeInsets.only(left: 20, right: 15, bottom: 20, top: 10),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
boxShadow: const [
|
||||
BoxShadow(
|
||||
color: Colors.grey,
|
||||
blurRadius: 10,
|
||||
spreadRadius: 1,
|
||||
offset: Offset(
|
||||
4,
|
||||
4,
|
||||
),
|
||||
),
|
||||
]),
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
}
|
||||
50
lib/widgets/thousandSeparator.dart
Normal file
50
lib/widgets/thousandSeparator.dart
Normal file
@ -0,0 +1,50 @@
|
||||
// ignore_for_file: file_names
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
class ThousandsSeparatorInputFormatter extends TextInputFormatter {
|
||||
static const separator = ','; // Change this to '.' for other locales
|
||||
|
||||
@override
|
||||
TextEditingValue formatEditUpdate(
|
||||
TextEditingValue oldValue, TextEditingValue newValue) {
|
||||
// Short-circuit if the new value is empty
|
||||
if (newValue.text.isEmpty) {
|
||||
return newValue.copyWith(text: '');
|
||||
}
|
||||
|
||||
// Handle "deletion" of separator character
|
||||
String oldValueText = oldValue.text.replaceAll(separator, '');
|
||||
String newValueText = newValue.text.replaceAll(separator, '');
|
||||
|
||||
if (oldValue.text.endsWith(separator) &&
|
||||
oldValue.text.length == newValue.text.length + 1) {
|
||||
newValueText = newValueText.substring(0, newValueText.length - 1);
|
||||
}
|
||||
|
||||
// Only process if the old value and new value are different
|
||||
if (oldValueText != newValueText) {
|
||||
int selectionIndex =
|
||||
newValue.text.length - newValue.selection.extentOffset;
|
||||
final chars = newValueText.split('');
|
||||
|
||||
String newString = '';
|
||||
for (int i = chars.length - 1; i >= 0; i--) {
|
||||
if ((chars.length - 1 - i) % 3 == 0 && i != chars.length - 1) {
|
||||
newString = separator + newString;
|
||||
}
|
||||
newString = chars[i] + newString;
|
||||
}
|
||||
|
||||
return TextEditingValue(
|
||||
text: newString.toString(),
|
||||
selection: TextSelection.collapsed(
|
||||
offset: newString.length - selectionIndex,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// If the new value and old value are the same, just return as-is
|
||||
return newValue;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user