About securing password field in textformfield in flutter - flutter

I want to hide completely the password field, I set obscure text true but it shows the characters as I type them how hide completely the characters?

If you want completely hide it, you must use controller and implement like this:
class TextFieldPassWord extends StatefulWidget {
#override
_TextFieldPassWordState createState() => _TextFieldPassWordState();
}
class _TextFieldPassWordState extends State<TextFieldPassWord> {
String _valueShow = "";
String _value = "";
#override
Widget build(BuildContext context) {
return Scaffold(
body: TextField(
controller: TextEditingController.fromValue(
TextEditingValue(
text: _valueShow,
selection: TextSelection.collapsed(offset: _valueShow.length),
),
),
onChanged: (String str) {
String value = "";
if (str.length > _value.length) {
value += str.substring(_value.length, str.length);
}
if (str.length < _value.length) {
value = _value.substring(1, str.length);
}
String valueToShow = "*" * str.length;
setState(() {
_valueShow = valueToShow;
_value = value;
});
},
),
);
}
}

Related

How to solve range error in growable list?

When I am calling getUserById() function everything works fine and the growable string works fine but when I use the same variable inside a text widget then it shows RangeError.
The problem is occuring only when I try to use a growable list of string named as dataAsString inside the build.
Here is the Code with Error. Go to the scaffold where I have commented the line of error
import 'package:Healthwise/helpers/user.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import '../helpers/backEnd.dart';
import '../helpers/frontEnd.dart';
class ResultPage extends StatefulWidget {
const ResultPage({Key? key}) : super(key: key);
#override
State<ResultPage> createState() => _ResultPageState();
}
class _ResultPageState extends State<ResultPage> {
// String docId = '';
String objectToString = '';
String e = '';
//This variable is creating the problem...
// I have tried this by using a final instead of var, but nothing worked.
var dataAsString = <String>[];
#override
void initState() {
super.initState();
// getUsers();
getUserById();
}
getUserById() {
final String id = itemName;
userRef.doc(id).get().then((DocumentSnapshot doc) {
// final x = doc.data();
// docId= doc.id;
objectToString = doc.data().toString();
String temp = '';
// print(doc.data());
// print(doc.id);
int i = 1;
// int j = 0;
bool end = false;
//We are just parsing the object into string.
while (objectToString[i] != '}') {
if (objectToString[i - 1] == ' ' && objectToString[i - 2] == ':') {
while (objectToString[i] != ',' && end != true) {
// print(z[i]);
temp += objectToString[i];
if (objectToString[i + 1] != '}') {
i++;
} else {
end = true;
}
}
//Here I add all the strings to list...
// This line works fine.
dataAsString.add(temp);
temp = '';
// j++;
print("The code below this line prints everything perfectly");
print(dataAsString.length);
print(dataAsString[0]);
}
i++;
}
// print(dataAsString[0]);
// print(dataAsString[1]);
// print("+++++++++++");
// print(dataAsString[2]);
// for (var k in dataAsString) {
// print(k);
// }
// print(dataAsString);
// setState(() {});
});
}
// getUsers() {
// userRef.get().then((QuerySnapshot snapshot) {
// snapshot.docs.forEach((DocumentSnapshot doc) {
// print(doc.data());
// print(doc.id);
// print(doc.exists);
// });
// });
// }
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(backgroundColor: primary_color, title: Text("Apple")),
body: Container(
child: Column(children: [
ListTile(
//The problem arises here and the app do not crash if I run the same code with just a //string in place of dataAsString[0]
title: Text(dataAsString[0]),
),
ListTile(
title: Text(dataAsString[1]),
),
ListTile(
title: Text(dataAsString[2]),
),
]),
),
);
}
}
You cant have data on dataAsString because you are using future(.then) on fetching data. You can do value check like
Text( dataAsString.isNotEmpty? dataAsString[0]: "0 is empty"),
Text( dataAsString.length>2? dataAsString[1]: "1 index is empty"),
Text( dataAsString.length>3? dataAsString[2]: "3rd item is empty"),
It's cause your dataAsString ins't ready on first Flutter rendered frame. So, you need to wait for the getUserById finish to access the dataAsString values.
You can use a builder to check if the data is ready in a readable way.
Builder(
builder: (context) {
if (dataAsString.length >= 2) {
return Column(children: [
ListTile(
title: Text(dataAsString[0]),
),
ListTile(
title: Text(dataAsString[1]),
),
ListTile(
title: Text(dataAsString[2]),
),
]);
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
},
),
Warning: it'll work cause you're calling setState when you finish the async task.

Flutter Slider how to Show Label instead of Values?

In Flutter, Slider, I want to show label instead of Values. The idea is for Search If I want to specify it at City level ( the lowest radius of search)
And next at County
Next at State level
Next at Country
and so on , last being at World Level ( the highest).
Currently Slider only displays numerical values.
Please use below code snippet
class DemoContent extends StatefulWidget {
const DemoContent({Key? key}) : super(key: key);
#override
State<DemoContent> createState() => _DemoContentState();
}
class _DemoContentState extends State<DemoContent> {
double _searchLevel = 0.0;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Slider(
value: _searchLevel,
onChanged: (value) {
setState(() {
_searchLevel = value;
});
},
max: 4.0,
min: 0.0,
divisions: 4,
label: _getLabel(),
),
),
);
}
String _getLabel(){
String label = '';
if(_searchLevel == 0.0){
label = 'City';
}else if(_searchLevel == 1.0){
label = 'County';
}else if(_searchLevel == 2.0){
label = 'State';
} else if(_searchLevel == 3.0){
label = 'Country';
}else if(_searchLevel == 4.0){
label = 'World';
}
return label;
}
}

Can not call list from function

There is no problem calling class and make list. My problem is I can not reach that list in statefull widget. I miss something...
I call API for data and get "data". It's simply live-search with php.
You can see my try in code where I wrote
Text(tagObjs), //////////THİS PART CANNOT CALL LIST
class Body extends StatefulWidget {
#override
_BodyState createState() => _BodyState();
}
class _BodyState extends State<Body> {
bool searching = false;
String term;
bool error;
void getSuggestion() async {
var jsonResponse;
String url = "API";
//get suggestion function
var res = await http.post(url + "?term=" + Uri.encodeComponent(term));
if (res.statusCode == 200) {
setState(() {
jsonResponse = json.decode(res.body);
var tagObjsJson = jsonResponse['data'] as List;////////////MAKE LIST PART
List<Tag> tagObjs =
tagObjsJson.map((tagJson) => Tag.fromJson(tagJson)).toList();
print(tagObjs[0]); ////WORK FINE
});
} else {
//there is error
setState(() {
error = true;
});
}
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: SingleChildScrollView(
.............
children: [
TextFormField(
..........
onChanged: (value) {
term = value; //update the value of query
getSuggestion(); //start to get suggestion
},
),
Text(tagObjs), //////////THİS PART CANNOT CALL LIST
],
),
),
),
));
}
}
//search suggestion data model to serialize JSON data
class Tag {
...........
}
My goal is basicly do foreach in php. With Listview.Builder I am gonna create Rows...
Declare List<Tag> tagObjs as a class property like searching, term, and error.
List<Tag> tagObjs = [];
bool searching = false;
String term;
bool error;
and remove List<Tag> from inside getSuggestion
tagObjs = tagObjsJson.map((tagJson) => Tag.fromJson(tagJson)).toList();

Flutter: How to insert text in middle of text field text

I have a text field in flutter and an emoji picker button. On selecting an emoji I need to insert it at the current cursor position.
How can I achieve this?
Currently using TextEditingController I'm only able to append the emoji. I'm not able to get the current cursor offset.
emojiPicker() {
return EmojiPicker(
rows: 3,
columns: 7,
recommendKeywords: null,
indicatorColor: flujoAccentColor,
onEmojiSelected: (emoji, category) {
print(emoji);
_messageInputController.text =
_messageInputController.text + emoji.emoji;
}
);
}
Use _txtController.selection to get the selection (or cursor position).
replace the selection with selected emoji.
then fix the selection(or cursor position) of the controller
import 'package:emoji_picker/emoji_picker.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(home: HomePage()));
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
TextEditingController _messageInputController;
#override
void initState() {
_messageInputController = TextEditingController();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Demo"),
),
body: SafeArea(
child: Column(
children: <Widget>[
EmojiPicker(
rows: 3,
columns: 7,
recommendKeywords: null,
indicatorColor: Colors.red,
onEmojiSelected: (emoji, category) {
String text = _messageInputController.text;
TextSelection textSelection = _messageInputController.selection;
String newText = text.replaceRange(
textSelection.start, textSelection.end, emoji.emoji);
final emojiLength = emoji.emoji.length;
_messageInputController.text = newText;
_messageInputController.selection = textSelection.copyWith(
baseOffset: textSelection.start + emojiLength,
extentOffset: textSelection.start + emojiLength,
);
},
),
TextField(
controller: _messageInputController,
),
],
),
),
);
}
}
with this you can not only insert the selected emoji at cursor position, but also can replace some selected text
This is a slight modification to CrazyLazyCat's answer.
void _insertText(String inserted) {
final text = _controller.text;
final selection = _controller.selection;
final newText = text.replaceRange(selection.start, selection.end, inserted);
_controller.value = TextEditingValue(
text: newText,
selection: TextSelection.collapsed(offset: selection.baseOffset + inserted.length),
);
}
Notes:
_controller is a TextEditingController.
If you are changing both the text and the selection then you should use a TextEditingValue rather than changing them individually (since they each trigger an update).
Generally if you insert something you want the cursor to appear after then insert, thus the TextSelection.collapsed with the adjusted index.
i have another solution beside text.replaceRange.
All you need is :
TextEditingController _tec;
String youWillAddtoTEC = "your emoji or your clipboard data or else";
String beforeCursorPositionAtTEC = tec.selection.textBefore(tec.text);
String afterCursorPositionAtTEC = tec.selection.textAfter(tec.text);
String result = beforeCursorPositionAtTEC + youWillAddtoTEC + afterCursorPositionAtTEC;
and then add result to tec, or any widget your need:
tec.text = result;
for the selection or cursor position is same with above, but if you need place cursor after the "youWillAddToTEC" you can do like this:
tec.selection = TextSelection.collapsed(offset: tec.selection.start + youWillAddtoTEC.lenght);
If you want to replace the selection of text field with a new string, I found the method below is useful.
void replaceTextSelectionWith(TextEditingController textEditingController, Function(String selection) getReplaceString)
{
final text = textEditingController.text;
final selection = textEditingController.selection;
final replaceText = getReplaceString(selection.textInside(text)) as String;
final newText = text.replaceRange(selection.start, selection.end, replaceText);
textEditingController.value =
TextEditingValue(text: newText, selection: TextSelection.collapsed(offset: selection.start + replaceText.length));
}
And use it like this
replaceTextSelectionWith(textEditingController, (selection) => '**$selection**');

Flutter Widget that shows text line by line?

Is there a widget in Flutter that allows children Text widgets to be shown line by line at every press of the widget? This should act similar to how bulleted lines in a powerpoint presentation act after every click.
I just tested and it works, probably I did not cover some edge cases, but it is not a lot of work...
//I would call it TIM like VIM :P
class TextIMproved extends StatefulWidget {
final String _longString;
final int _numberOfWordsPerRow;
TextIMproved(this._numberOfWordsPerRow, this._longString);
#override
_TextIMprovedState createState() => _TextIMprovedState(_numberOfWordsPerRow, _longString);
}
class _TextIMprovedState extends State<TextIMproved> {
final String longString;
List<String> listString;
int _numberOfWordsPerRow;
String strPopulated;
String strToDisplay='';
_TextIMprovedState(this._numberOfWordsPerRow, this.longString);
#override
void initState() {
super.initState();
listString = longString.split(' ');
splitString();
}
#override
Widget build(BuildContext context) {
return GestureDetector(
child: Container(
child: Text(strToDisplay, maxLines: longString.length ~/ _numberOfWordsPerRow + _numberOfWordsPerRow,),
),
onTap: splitString,
);
}
void splitString() {
//1.prepare empty string
strPopulated = '';
//2.populate string
int len = listString.length <_numberOfWordsPerRow ? listString.length : _numberOfWordsPerRow;
for (int i = 0; i < len; i++) {
strPopulated += listString[i] + ' ';
}
//3. display portion of string
setState(() {
strToDisplay += strPopulated;
});
//4.remove displayed text
List<String> listToremove = strPopulated.split(' ');
for (String str in listToremove) {
listString.remove(str);
}
}
}
EDIT:
you can add animation to this widget...